예제 #1
0
    def post(self):
        """
        商户编辑 编辑费率
        """
        # 验证费率表单
        form, error = EditMerchantRateForm().request_validate()
        if error:
            return error.as_response()

        merchant = form.data['name']
        merchant_fee_dict = []

        for item in form.deposit_info:
            merchant_fee_dict.append(dict(
                merchant=merchant,
                payment_way=PayTypeEnum.DEPOSIT,
                value=item.data['value'],
                fee_type=item.data['fee_type'],
                payment_method=item.data['name'],
            ))

        if form.withdraw_info.data['value']:
            merchant_fee_dict.append(dict(
                merchant=merchant,
                payment_way=PayTypeEnum.WITHDRAW,
                value=form.withdraw_info.data['value'],
                fee_type=form.withdraw_info.data['fee_type'],
                cost_type=form.withdraw_info.data['cost_type'],
            ))

        MerchantFeeConfig.update_fee_config(merchant, merchant_fee_dict)

        return ResponseSuccess().as_response()
예제 #2
0
    def post(self):
        """
        商户列表
        :return:
        """
        merchant_list = list()

        merchants = MerchantInfo.query_all()

        all_configs = MerchantFeeConfig.query_all()
        all_configs = MerchantFeeConfig.filter_latest_items(all_configs)

        merchant_all_configs = defaultdict(list)
        for fee in all_configs:
            merchant_all_configs[fee.merchant].append(fee)

        for merchant in merchants:
            fee_configs = merchant_all_configs.get(merchant.merchant)
            if not fee_configs:
                continue

            withdraw_fees = [x for x in fee_configs if x.payment_way == PayTypeEnum.WITHDRAW]
            recharge_fees = [x for x in fee_configs if x.payment_way == PayTypeEnum.DEPOSIT]

            withdraw_desc = ''
            cost_type = None
            if withdraw_fees:
                withdraw_desc = withdraw_fees[0].value_description
                cost_type = withdraw_fees[0].cost_type.name

            merchant_list.append(dict(
                id=merchant.id,
                name=merchant.merchant.name,
                balance_total=merchant.balance_total,
                balance_available=merchant.balance_available,
                balance_income=merchant.balance_income,
                balance_frozen=merchant.balance_frozen,
                type=merchant.m_type.name,
                domains='\n'.join(MerchantDomainConfig.get_domains(merchant.merchant)),
                state=merchant.state.name,
                channel_fees=dict(
                    withdraw=withdraw_desc,
                    cost_type=cost_type,
                    deposit=[
                        dict(
                            desc=x.payment_method.desc,
                            value=x.payment_method.value,
                            rate=x.value_description,
                        )
                        for x in recharge_fees
                    ]
                )
            ))

        data = dict(counts=len(merchant_list), merchants=merchant_list)

        return MerchantListResult(bs_data=data).as_response()
예제 #3
0
    def get(self):
        """
        商户配置查询
        :return:
        """
        if not request.args:
            return ResponseSuccess(message="参数规则:?merchant=test").as_response()

        try:
            merchant = MerchantEnum.from_name(request.args['merchant'])
        except:
            return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" %
                                   MerchantEnum.get_names()).as_response()

        merchant_info = MerchantInfo.query_merchant(merchant)
        if not merchant_info:
            return ResponseSuccess(message="未创建商户").as_response()

        bs_data = dict(
            balance=dict(
                balance_total=str(merchant_info.balance_total),
                balance_available=str(merchant_info.balance_available),
                balance_income=str(merchant_info.balance_income),
                balance_frozen=str(merchant_info.balance_frozen),
            ),
            merchant=merchant.name,
            domains=MerchantDomainConfig.get_domains(merchant),
            # db=DBEnum(merchant.name).get_db_name(),
        )

        deposit_fees = MerchantFeeConfig.query_active_configs(
            query_fields=dict(
                merchant=merchant,
                payment_way=PayTypeEnum.DEPOSIT,
            ))
        deposit_fees = MerchantFeeConfig.filter_latest_items(deposit_fees)
        if not deposit_fees:
            return MerchantConfigDepositError(bs_data=bs_data).as_response()
        bs_data['deposit_fees'] = [x.short_description for x in deposit_fees]

        withdraw_fees = MerchantFeeConfig.query_latest_one(query_fields=dict(
            merchant=merchant,
            payment_way=PayTypeEnum.WITHDRAW,
        ))
        if not withdraw_fees:
            return MerchantConfigWithdrawError(bs_data=bs_data).as_response()
        bs_data['withdraw_fees'] = withdraw_fees.short_description

        channels = ChannelListHelper.get_available_channels(
            merchant, PayTypeEnum.DEPOSIT)
        bs_data['deposit_channels'] = [x.short_description for x in channels]

        channels = ChannelListHelper.get_available_channels(
            merchant, PayTypeEnum.WITHDRAW)
        bs_data['withdraw_channels'] = [x.short_description for x in channels]

        return ResponseSuccess(bs_data=bs_data).as_response()
예제 #4
0
    def post(self):
        """
            检查手机号是否已经注册
        """
        form, error = MobileRegisterCheckForm().request_validate()
        if error:
            return error.as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.DEPOSIT,
        )):
            return MerchantConfigDepositError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.WITHDRAW,
        )):
            return MerchantConfigWithdrawError().as_response()

        return ResponseSuccess().as_response()
예제 #5
0
 def check_result(self, conf_dict):
     payment_method = conf_dict.get('payment_method')
     conf = MerchantFeeConfig.query_latest_one(query_fields=dict(
         merchant=conf_dict['merchant'],
         payment_way=conf_dict['payment_way'],
         payment_method=payment_method
     ))
     self.assertIsNotNone(conf)
     self.assertEqual(conf_dict['merchant'], conf['merchant'])
     if payment_method:
         self.assertEqual(conf_dict['payment_method'], conf['payment_method'])
     self.assertEqual(conf_dict['fee_type'], conf['fee_type'])
     self.assertEqual(conf_dict['value'], conf['value'])
예제 #6
0
    def init_merchant(cls):
        # 先创建商户
        if not cls.get_merchant_info():
            MerchantInfo.create_merchant(m_name=cls.merchant,
                                         m_type=MerchantTypeEnum.TEST)

            # 给商户加钱
            rst, msg = MerchantBalanceEvent.update_balance(
                merchant=cls.merchant,
                ref_id=OrderUtils.gen_unique_ref_id(),
                source=OrderSourceEnum.MANUALLY,
                order_type=PayTypeEnum.MANUALLY,
                bl_type=BalanceTypeEnum.AVAILABLE,
                ad_type=BalanceAdjustTypeEnum.PLUS,
                tx_id=OrderUtils.gen_normal_tx_id(10),
                value=100000000,
                comment="手动脚本修改商户可用余额")
            # print(rst, msg)

        merchant_fee_list = list()
        if not cls.get_merchant_fee_config(PayTypeEnum.DEPOSIT):
            # 商户费率配置
            merchant_fee_list.append(
                dict(
                    merchant=cls.merchant,
                    payment_way=PayTypeEnum.DEPOSIT,
                    value="3",
                    fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                    payment_method=cls.channel_enum.conf.payment_method,
                ))
            MerchantFeeConfig.update_fee_config(cls.merchant,
                                                merchant_fee_list)

            # 商户费率配置
            merchant_fee_list.append(
                dict(
                    merchant=cls.merchant,
                    payment_way=PayTypeEnum.DEPOSIT,
                    value="3",
                    fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                    payment_method=cls.channel_enum2.conf.payment_method,
                ))
            MerchantFeeConfig.update_fee_config(cls.merchant,
                                                merchant_fee_list)

        if not cls.get_merchant_fee_config(PayTypeEnum.WITHDRAW):
            merchant_fee_list.append(
                dict(merchant=cls.merchant,
                     payment_way=PayTypeEnum.WITHDRAW,
                     value="3.2",
                     fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER))
            MerchantFeeConfig.update_fee_config(cls.merchant,
                                                merchant_fee_list)

        merchant_config = cls.get_merchant_fee_config(PayTypeEnum.DEPOSIT)
        assert merchant_config.fee_type == PaymentFeeTypeEnum.PERCENT_PER_ORDER

        merchant_config = cls.get_merchant_fee_config(PayTypeEnum.WITHDRAW)
        assert merchant_config.fee_type == PaymentFeeTypeEnum.PERCENT_PER_ORDER
예제 #7
0
    def post(self):
        """
        手机号码注册
        :return:
        """
        # 验证 手机号 验证码  密码格式
        form, error = PasswordForm().request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(
                form.auth_code.data):
            return AuthCodeError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.DEPOSIT,
        )):
            return MerchantConfigDepositError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.WITHDRAW,
        )):
            return MerchantConfigWithdrawError().as_response()

        User.register_account(
            merchant=form.merchant.data,
            account=form.number.data,
            ac_type=AccountTypeEnum.MOBILE,
            login_pwd=form.password.data,
        )

        return ResponseSuccess().as_response()
예제 #8
0
    def get(self):
        """
        查询可用的通道
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?tx_id=xxxx,交易ID,必填").as_response()

        try:
            tx_id = request.args['tx_id']
        except:
            return ResponseSuccess(message="必填交易ID").as_response()

        order = OrderDeposit.query_by_tx_id(tx_id)
        if not order:
            return ResponseSuccess(message="订单不存在,请确认交易号是否正确: %s" %
                                   tx_id).as_response()

        order_detail = OrderDetailDeposit.query_by_tx_id(tx_id)

        channel = ChannelConfig.query_by_channel_id(order.channel_id)
        fee_config = MerchantFeeConfig.query_by_config_id(order.mch_fee_id)

        order_info = dict(
            order_id=order.order_id,
            create_time=order.str_create_time,
            uid=order.uid,
            sys_tx_id=order.sys_tx_id,
            mch_tx_id=order.mch_tx_id,
            channel_tx_id=order.channel_tx_id,
            amount=str(order.amount),
            tx_amount=str(order.tx_amount),
            source=order.source.desc,
            pay_method=order.pay_method.desc,
            state=order.state.desc,
            settle=order.settle.desc,
            deliver=order.deliver.desc,
            channel_id=order.channel_id,
            channel=channel.short_description,
            mch_fee_id=order.mch_fee_id,
            mch_fee=fee_config.short_description,
            in_type=order_detail.in_type.desc,
            offer=str(order_detail.offer),
            fee=str(order_detail.fee),
            cost=str(order_detail.cost),
            profit=str(order_detail.profit),
            ip=order_detail.ip,
        )

        return ResponseSuccess(bs_data=order_info).as_response()
예제 #9
0
    def post(self):
        """
        新建商户 新增费率
        """
        form, error = MerchantFeeAddForm().request_validate()
        if error:
            return error.as_response()

        # 充值费率设置
        for item in form.deposit_info:
            if not isinstance(item.data['value'], str):
                return ParameterException(message="充值费率必须传入字符串类型").as_response()

        # 提现费率
        if not isinstance(form.withdraw_info.data['value'], str):
            return ParameterException(message="提现费率必须传入字符串类型").as_response()

        merchant = form.data['name']

        # 第一步向数据库中插入商户数据
        models = MerchantInfo.create_merchant_models(merchant, form.data['type'])

        # 充值费率设置
        merchant_fee_dict = []
        for item in form.deposit_info:
            merchant_fee_dict.append(dict(
                merchant=merchant,
                payment_way=PayTypeEnum.DEPOSIT,
                value=item.data['value'],
                fee_type=item.data['fee_type'],
                payment_method=item.data['name'],
            ))

        # 提现费率
        merchant_fee_dict.append(dict(
            merchant=merchant,
            payment_way=PayTypeEnum.WITHDRAW,
            value=form.withdraw_info.data['value'],
            fee_type=form.withdraw_info.data['fee_type'],
            cost_type=form.withdraw_info.data['cost_type'],
        ))

        rst, error = MerchantFeeConfig.update_fee_config(merchant, merchant_fee_dict, models)
        if error:
            return error.as_response()

        return ResponseSuccess().as_response()
예제 #10
0
    def get_available_channels(cls, merchant, payment_way: PayTypeEnum, amount=0, client_ip=None, payment_type=None):
        """
        获取可用的通道
        :param merchant: 
        :param payment_way:
        :param amount:
        :param client_ip:
        :param payment_type:
        :return:
        """

        channels = list()

        # 找出最新版本的商户费率配置
        merchant_fees = MerchantFeeConfig.get_latest_active_configs(merchant=merchant, payment_way=payment_way)
        if not merchant_fees:
            return channels

        # 充值需要判断到通道支付方式是否已经在商户配置费率
        # 提现配置没有payment_method,列表置为空,不用判断
        payment_methods = [m.payment_method for m in merchant_fees if m.payment_method]

        routers_dict = cls.get_router2_dict()
        channel_configs = cls.get_config_channels(payment_way)

        for channel in channel_configs:
            channel_enum = channel.channel_enum

            router = routers_dict.get(channel_enum)
            if router and not router.is_router_match(merchant=merchant, amount=amount):
                continue

            if payment_type and channel_enum.conf['payment_type'] != payment_type:
                # 支付类型不匹配
                continue

            if payment_methods and channel_enum.conf['payment_method'] not in payment_methods:
                # 过滤掉未设置费率的支付方式
                continue

            if not channel.is_channel_valid(merchant.is_test, amount=amount, client_ip=client_ip):
                continue

            channels.append(channel)

        return channels
예제 #11
0
    def order_create(cls,
                     user,
                     amount,
                     client_ip,
                     user_bank_id=None,
                     bank_info=None,
                     notify_url=None,
                     mch_tx_id=None,
                     extra=None):
        """
        申请创建订单
        :return:
        """
        params = copy.deepcopy(locals())
        params.pop('cls')

        order = None

        if not bank_info:
            card_entry = BankCard.query_bankcard_by_id(card_id=user_bank_id)
            if not card_entry:
                msg = '%s, params: %s' % (WithdrawBankNoExistError.message,
                                          params)
                current_app.logger.error(msg)
                return order, WithdrawBankNoExistError()

        # 判断 金额是否在有效范围 获取代付系统当前最高最低交易金额
        # limit_min, limit_max = ChannelLimitCacheCtl(PayTypeEnum.WITHDRAW).get_channel_limit()
        # if amount < limit_min or amount > limit_max:
        if ChannelListHelper.is_amount_out_of_range(
                amount=amount,
                merchant=user.merchant,
                payment_way=PayTypeEnum.WITHDRAW,
                client_ip=client_ip):
            msg = '%s, params: %s' % (WithdrawOrderAmountInvalidError.message,
                                      params)
            current_app.logger.error(msg)
            return order, WithdrawOrderAmountInvalidError()

        # 商户配置信息
        merchant_config = MerchantFeeConfig.query_latest_one(query_fields=dict(
            merchant=user.merchant,
            payment_way=PayTypeEnum.WITHDRAW,
        ))

        # 手续费计算
        fee_value = FeeCalculator.calc_fee(amount, merchant_config.fee_type,
                                           merchant_config.value)
        user_fee = merchant_fee = 0
        if merchant_config.cost_type == CostTypeEnum.MERCHANT:
            merchant_fee = fee_value
        elif merchant_config.cost_type == CostTypeEnum.USER:
            user_fee = fee_value
            # 用户实际到账金额要减去手续费
            amount -= user_fee

        # 用户余额判断
        if user.uid:
            user_balance = UserBalance.query_balance(
                uid=user.uid, merchant=user.merchant).first()
            if user_balance.real_balance < amount + user_fee:
                msg = '%s, params: %s' % ("用户余额不足", params)
                current_app.logger.error(msg)
                return order, AccountBalanceInsufficientError(message="用户余额不足")

        # 判断商户余额是否充足
        merchant_balance = MerchantInfo.query_merchant(m_name=user.merchant)
        if merchant_balance.balance_available <= amount + merchant_fee:
            msg = '%s, params: %s' % ("商户余额不足", params)
            current_app.logger.error(msg)
            return order, AccountBalanceInsufficientError(message="商户余额不足")

        # 订单来源
        source = OrderSourceEnum.TESTING if user.is_test_user else OrderSourceEnum.ONLINE

        try:
            # 创建提现订单/扣商户余额/扣用户余额,在同一个事务里面
            with db.auto_commit():
                order, ref_id = OrderCreateCtl.create_order_event(
                    uid=user.uid,
                    amount=amount,
                    merchant=user.merchant,
                    source=source,
                    order_type=PayTypeEnum.WITHDRAW,
                    in_type=InterfaceTypeEnum.CASHIER_H5,
                    bank_id=user_bank_id,  # 提现时需要填入 银行卡信息
                    mch_fee_id=merchant_config.config_id,
                    mch_tx_id=mch_tx_id,
                    ip=client_ip,
                    fee=fee_value,
                    cost_type=merchant_config.cost_type,
                    notify_url=notify_url,
                    bank_info=bank_info,
                    extra=extra,
                    commit=False,
                )

                if not order:
                    msg = '%s, params: %s' % (WithdrawOrderCreateError.message,
                                              params)
                    current_app.logger.error(msg)
                    raise WithdrawOrderCreateError()

                # 扣提现金额
                flag, msg = MerchantBalanceEvent.update_balance(
                    merchant=user.merchant,
                    ref_id=ref_id,
                    source=source,
                    order_type=PayTypeEnum.WITHDRAW,
                    bl_type=BalanceTypeEnum.AVAILABLE,
                    value=amount,
                    ad_type=BalanceAdjustTypeEnum.MINUS,
                    tx_id=order.sys_tx_id,
                    commit=False,
                )
                if flag < 0:
                    msg = '%s, params: %s' % ("扣商户余额失败, %s" % msg, params)
                    current_app.logger.error(msg)
                    raise DepositCallbackUserBalanceError(message="扣商户余额失败")

                if merchant_fee:
                    # 扣商户手续费
                    flag, msg = MerchantBalanceEvent.update_balance(
                        merchant=user.merchant,
                        ref_id=OrderUtils.gen_unique_ref_id(),
                        source=source,
                        order_type=PayTypeEnum.FEE,
                        bl_type=BalanceTypeEnum.AVAILABLE,
                        value=merchant_fee,
                        ad_type=BalanceAdjustTypeEnum.MINUS,
                        tx_id=order.sys_tx_id,
                        commit=False,
                    )
                    if flag < 0:
                        msg = '%s, params: %s' % ("扣商户手续费失败, %s" % msg, params)
                        current_app.logger.error(msg)
                        raise DepositCallbackUserBalanceError(
                            message="扣商户手续费失败")

                if user_fee:
                    # 扣除用户手续费
                    flag, msg = UserBalanceEvent.update_user_balance(
                        uid=user.uid,
                        merchant=user.merchant,
                        ref_id=OrderUtils.gen_unique_ref_id(),
                        source=source,
                        order_type=PayTypeEnum.FEE,
                        bl_type=BalanceTypeEnum.AVAILABLE,
                        value=user_fee,
                        ad_type=BalanceAdjustTypeEnum.MINUS,
                        tx_id=order.sys_tx_id,
                        commit=False,
                    )
                    if flag < 0:
                        msg = '%s, params: %s' % ("扣用户手续费失败, %s" % msg, params)
                        current_app.logger.error(msg)
                        raise DepositCallbackUserBalanceError(
                            message="扣用户手续费失败")

                # 扣除用户余额
                flag, msg = UserBalanceEvent.update_user_balance(
                    uid=user.uid,
                    merchant=user.merchant,
                    ref_id=ref_id,
                    source=source,
                    order_type=PayTypeEnum.WITHDRAW,
                    bl_type=BalanceTypeEnum.AVAILABLE,
                    value=amount,
                    ad_type=BalanceAdjustTypeEnum.MINUS,
                    tx_id=order.sys_tx_id,
                    commit=False,
                )
                if flag < 0:
                    msg = '%s, params: %s' % ("扣用户余额失败, %s" % msg, params)
                    current_app.logger.error(msg)
                    raise DepositCallbackUserBalanceError(message="扣用户余额失败")

        except APIException as e:
            current_app.logger.error(traceback.format_exc())
            return order, e

        return order, None
예제 #12
0
    def success_order_process(cls,
                              order,
                              tx_amount,
                              channel_tx_id=None,
                              comment: str = '',
                              op_account=None,
                              commit=True):
        """
        处理充值成功的订单
        :param order:
        :param tx_amount: 实际支付金额
        :param channel_tx_id: 通道订单号
        :param comment: 备注
        :param op_account: 备注
        :param commit: 是否立即提交事务
        :return:
        """
        params = copy.deepcopy(locals())
        params.pop('cls')
        params.pop('order')
        params['tx_id'] = order.sys_tx_id

        rst = dict(
            code=0,
            msg='',
        )

        # 计算一笔订单的各种费用
        channel_config = ChannelConfig.query_by_channel_id(order.channel_id)
        merchant_config = MerchantFeeConfig.query_by_config_id(
            order.mch_fee_id)
        order_fee = OrderFeeHelper.calc_order_fee(order, tx_amount,
                                                  channel_config,
                                                  merchant_config)

        try:
            with db.auto_commit(commit):
                order, ref_id = OrderUpdateCtl.update_order_event(
                    order.order_id,
                    uid=order.uid,
                    merchant=order.merchant,
                    state=OrderStateEnum.SUCCESS,
                    channel_tx_id=channel_tx_id,
                    tx_amount=tx_amount,
                    offer=order_fee['offer'],  # 优惠金额
                    fee=order_fee['merchant_fee'],  # 手续费
                    cost=order_fee['channel_cost'],  # 成本金额
                    profit=order_fee['profit'],  # 利润(收入)金额
                    commit=False,
                    pay_method=channel_config.channel_enum.
                    conf['payment_method'],
                    comment=comment,
                    op_account=op_account,
                )
                if not order:
                    msg = '订单更新失败, params: %s' % params
                    raise RuntimeError(msg)

                # 给用户充值
                code, msg = UserBalanceEvent.update_user_balance(
                    uid=order.uid,
                    merchant=order.merchant,
                    ref_id=ref_id,
                    source=order.source,
                    order_type=order.order_type,
                    bl_type=BalanceTypeEnum.AVAILABLE,
                    value=order.amount,
                    ad_type=BalanceAdjustTypeEnum.PLUS,
                    comment=comment,
                    tx_id=order.sys_tx_id,
                    commit=False,
                )
                if code != 0:
                    raise RuntimeError(msg)

                # 根据结算类型获取商户余额变更类型
                balance_type = SettleHelper.get_balance_type_by_settle(
                    channel_config.settlement_type)

                # 更新商户余额,加用户充值金额
                code, msg = MerchantBalanceEvent.update_balance(
                    merchant=order.merchant,
                    ref_id=ref_id,
                    source=order.source,
                    order_type=order.order_type,
                    bl_type=balance_type,
                    value=order.amount,
                    ad_type=BalanceAdjustTypeEnum.PLUS,
                    tx_id=order.sys_tx_id,
                    comment=comment,
                    commit=False,
                )
                if code != 0:
                    raise RuntimeError(msg)

                # 更新商户余额,扣手续费
                ref_id = OrderUtils.gen_unique_ref_id()
                code, msg = MerchantBalanceEvent.update_balance(
                    merchant=order.merchant,
                    ref_id=ref_id,
                    source=order.source,
                    order_type=PayTypeEnum.FEE,
                    bl_type=balance_type,
                    value=order_fee['merchant_fee'],
                    ad_type=BalanceAdjustTypeEnum.MINUS,
                    tx_id=order.sys_tx_id,
                    comment=comment,
                    commit=False,
                )
                if code != 0:
                    raise RuntimeError(msg)

        except RuntimeError as e:
            current_app.logger.error('An error occurred.', exc_info=True)
            return False

        # 累计当天通道充值额度
        ChannelLimitCacheCtl.add_day_amount(channel_config.channel_enum,
                                            order.amount)

        cls.do_notify(order)

        return True
예제 #13
0
 def get_merchant_fee_config(cls, payment_way: PayTypeEnum):
     return MerchantFeeConfig.query_latest_one(query_fields=dict(
         merchant=cls.merchant,
         payment_way=payment_way,
     ))
예제 #14
0
    def render_page(cls):
        """
        渲染页面
        :return:
        """
        print(request.args)

        try:
            order_id = request.args['order_id']
        except:
            return TemplateKit.render_template('deposit_simple.html', body="参数错误")

        order = DepositTransactionCtl.get_order_by_order_id(order_id)
        if not order:
            return TemplateKit.render_template('deposit_simple.html', body="订单不存在")

        cache = DepositPageRenderCache(order.order_id)
        cache_data = cache.get_content()
        print("&&&&&&&&&&&&&&", cache_data)
        if not cache_data:
            return TemplateKit.render_template('deposit_simple.html', body="订单已经过期")

        is_h5 = False
        prompt_msgs = []
        channel_enum = cache_data.get('channel_enum')
        if channel_enum:
            channel_enum = ChannelConfigEnum(int(channel_enum))
            prompt_msgs = channel_enum.get_prompt_info_detail()
            is_h5 = channel_enum.conf.payment_method.is_h5

        if cache_data['render_type'] == SdkRenderType.QR_CODE:
            merchant_config = MerchantFeeConfig.query_by_config_id(order.mch_fee_id)
            b64_img = QRCodeKit.gen_base64_qr_code_png(cache_data['render_content'])
            return TemplateKit.render_template(
                'deposit_qrcode.html',
                b64_img=b64_img,
                payment_type=merchant_config.payment_method.desc,
                sys_tx_id=order.sys_tx_id,
                amount=str(order.amount),
                valid_time=cache.EXPIRATION,
                payment_url=cache_data['render_content'] if is_h5 else None,
                prompt_msgs=prompt_msgs,
            )

        if cache_data['render_type'] == SdkRenderType.FORM:
            return TemplateKit.render_template('deposit_base.html', body=cache_data['render_content'])

        if cache_data['render_type'] == SdkRenderType.HTML:
            return TemplateKit.render_template_string(cache_data['render_content'])

        if cache_data['render_type'] == SdkRenderType.TRANSFER:
            data = json.loads(cache_data['render_content'], encoding='utf8')
            return TemplateKit.render_template(
                'bank.html',
                CardName=data['CardName'],
                CardNumber=data['CardNumber'],
                BankName=data['BankName'],
                amount=data['amount'],
                tx_id=data['tx_id'],
                start_time=data['start_time']
            )

        current_app.logger.error('failed to render page, order_id: %s, cache_data: %s', order.order_id, cache_data)

        return TemplateKit.render_template('deposit_simple.html', body="渲染失败")
예제 #15
0
    def order_create(cls,
                     user,
                     amount,
                     channel_enum,
                     client_ip,
                     source: OrderSourceEnum,
                     in_type: InterfaceTypeEnum,
                     notify_url=None,
                     result_url=None,
                     mch_tx_id=None,
                     extra=None):
        """
        申请创建订单
        :return:
        """
        merchant = user.merchant

        # 找出最新版本的商户费率配置
        channel_config = ChannelConfig.query_latest_one(query_fields=dict(
            channel_enum=channel_enum))
        if not channel_config:
            current_app.logger.error(
                'no channel config found, channel_enum: %s', channel_enum.desc)
            return None, InvalidDepositChannelError()

        if channel_config.is_in_maintain_time():
            current_app.logger.error('channel in maintain, channel_enum: %s',
                                     channel_enum.desc)
            return None, ChannelNoValidityPeriodError(message="通道(%s)维护中" %
                                                      channel_enum.desc)

        if not channel_config.is_in_trade_time():
            current_app.logger.error(
                'channel not in trade time, channel_enum: %s',
                channel_enum.desc)
            return None, ChannelNoValidityPeriodError(
                message="当前时间不在通道(%s)交易时间内" % channel_enum.desc)

        if channel_config.is_amount_per_limit(amount):
            current_app.logger.error(
                'per amount limit, channel_enum: %s, amount: %s',
                channel_enum.desc, amount)
            return None, DepositOrderAmountInvalidError(
                message="%s,通道(%s)" %
                (DepositOrderAmountInvalidError.message, channel_enum.desc))

        if channel_enum.is_fixed_amount_channel(
        ) and not channel_enum.is_amount_in_fixed_list(amount):
            current_app.logger.error(
                'invalid amount, channel: %s, input amount: %s, fixed amounts: %s',
                channel_enum.desc, amount, channel_enum.get_fixed_amounts())
            return DepositOrderAmountInvalidError(message="固额支付类型额度匹配失败")

        if not channel_config.state.is_available(user.is_test_user):
            current_app.logger.error(
                'channel state not available, channel_enum: %s, uid: %s, merchant: %s',
                channel_enum.desc, user.uid, merchant.name)
            return None, ChannelNoValidityPeriodError(
                message="通道(%s)状态:%s" %
                (channel_enum.desc, channel_config.state.desc))

        # 找出最新版本的商户费率配置
        merchant_fee = MerchantFeeConfig.query_latest_one(
            query_fields=dict(merchant=merchant,
                              payment_way=PayTypeEnum.DEPOSIT,
                              payment_method=channel_enum.conf.payment_method))

        if not merchant_fee:
            current_app.logger.error(
                'no merchant fee config for channel, channel_enum: %s, uid: %s, merchant: %s',
                channel_enum.desc, user.uid, merchant.name)
            return None, MerchantConfigDepositError()

        kwargs = dict(
            uid=user.uid,
            merchant=merchant,
            amount=amount,
            channel_id=channel_config.channel_id,
            mch_fee_id=merchant_fee.config_id,
            order_type=PayTypeEnum.DEPOSIT,
            source=source,
            in_type=in_type,
            ip=client_ip,
            pay_method=channel_enum.conf.payment_method,
            notify_url=notify_url,
            result_url=result_url,
            mch_tx_id=mch_tx_id,
            extra=extra,
        )

        try:
            order, _ = OrderCreateCtl.create_order_event(**kwargs)
        except Exception as e:
            return None, PreOrderCreateError(message=str(e))

        if not order:
            return None, PreOrderCreateError()

        return order, None
예제 #16
0
    def __test_api_withdraw(self):
        """
        1. 新建用户提现订单
        :return:
        """
        order_cls = OrderWithdraw
        uid = 1000

        channel_enum = ChannelConfigEnum.CHANNEL_1001

        banks = [
            PaymentBankEnum(int(bank))
            for bank in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
        ]
        proxy_channel = dict(fee=Decimal("2.5"),
                             fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                             limit_per_min=300,
                             limit_per_max=1000,
                             limit_day_max=0,
                             trade_begin_hour=0,
                             trade_begin_minute=0,
                             trade_end_hour=23,
                             trade_end_minute=59,
                             maintain_begin=DateTimeKit.str_to_datetime(
                                 "2019-12-11 09:00:00",
                                 DateTimeFormatEnum.SECONDS_FORMAT),
                             maintain_end=DateTimeKit.str_to_datetime(
                                 "2025-12-20 23:00:00",
                                 DateTimeFormatEnum.SECONDS_FORMAT),
                             state=ChannelStateEnum.TESTING,
                             banks=banks)
        ProxyChannelConfig.update_channel(channel_enum, **proxy_channel)

        merchant = MerchantEnum.TEST

        # 准备配置数据
        bank = BankCard.add_bank_card(
            merchant,
            uid=uid,
            bank_name="中国工商银行",
            bank_code="ICBC",
            card_no="6212260405014627955",
            account_name="张三",
            branch="广东东莞东莞市长安镇支行",
            province="广东省",
            city="东莞市",
        )

        OrderMixes.add_one_channel_config(channel_enum)
        OrderMixes.add_one_merchant_config(merchant,
                                           channel_enum,
                                           payment_way=PayTypeEnum.WITHDRAW)

        channel_config = ChannelConfig.query_latest_one(
            dict(channel_enum=channel_enum))

        merchant_fee_config = MerchantFeeConfig.query_latest_one(
            dict(
                merchant=merchant,
                payment_way=PayTypeEnum.WITHDRAW,
                payment_method=channel_enum.conf.payment_method,
            ))

        amount = Decimal("500")
        fee = BalanceKit.round_4down_5up(
            Decimal(merchant_fee_config.value) * amount / Decimal(100))
        # 创建提现订单
        params = dict(
            uid=uid,
            merchant=merchant,
            channel_id=channel_config.channel_id,
            mch_fee_id=merchant_fee_config.config_id,
            source=OrderSourceEnum.TESTING,
            order_type=PayTypeEnum.WITHDRAW,
            in_type=InterfaceTypeEnum.CASHIER_H5,
            amount=amount,
            bank_id=bank.id,
            fee=fee,
        )
        order, ref_id = OrderCreateCtl.create_order_event(**params)
        event = OrderEvent.query_one(dict(ref_id=ref_id),
                                     merchant=merchant,
                                     date=order.create_time)

        data = order_cls.query_by_order_id(order_id=event.order_id,
                                           merchant=merchant)

        begin_time, end_time = DateTimeKit.get_month_begin_end(
            year=int(DateTimeKit.get_cur_datetime().year),
            month=int(DateTimeKit.get_cur_datetime().month))
        withdraw_params = dict(merchant_name="TEST",
                               page_size=10,
                               page_index=1,
                               begin_time=DateTimeKit.datetime_to_str(
                                   begin_time,
                                   DateTimeFormatEnum.SECONDS_FORMAT),
                               end_time=DateTimeKit.datetime_to_str(
                                   end_time,
                                   DateTimeFormatEnum.SECONDS_FORMAT),
                               state="0")

        self.path = "/trade_manage/withdraw/list"
        # 通过接口 查询提现订单
        response = self.do_request(json_data=withdraw_params)
        print(response.json, "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
        self.assertEqual("1", response.json['data']['total'])
        self.assertEqual("待认领", response.json['data']['entries'][0]['state'])

        self.path = "/trade_manage/order/allowed"
        # 通过接口, 认领订单
        allowed_params = dict(order_id=order.id, merchant_name="TEST")
        response = self.do_request(allowed_params)
        self.assertEqual(ResponseSuccess.code, response.status_code)
        self.assertEqual(ResponseSuccess.error_code,
                         response.json['error_code'])
        # 查询当前订单状态是否已修改为已认领
        data = order_cls.query_by_order_id(order_id=event.order_id,
                                           merchant=merchant)
        self.assertEqual(OrderStateEnum.ALLOC, data.state)

        # 通过接口查询 审核列表 已有的认领订单为1
        self.path = '/trade_manage/withdraw/review/list'

        request_review_params = dict(
            year=str(DateTimeKit.get_cur_datetime().year),
            mouth=str(DateTimeKit.get_cur_datetime().month))
        response = self.do_request(json_data=request_review_params)
        self.assertEqual(1, len(response.json['data']['entries']))
        self.assertEqual("已认领", response.json['data']['entries'][0]['state'])

        # 通过接口查询 当前可用的 代付通道
        proxy_channel_suppor = dict(bank_type=bank.bank_enum.name,
                                    merchant_name="TEST",
                                    amount=str(amount))

        self.path = "/trade_manage/withdraw/available/channel"

        response = self.do_request(json_data=proxy_channel_suppor)
        self.assertEqual(WithdrawBankEntryResult.code, response.status_code)
        self.assertEqual(WithdrawBankEntryResult.error_code,
                         response.json['error_code'])
        self.assertEqual(
            channel_enum.conf['provider'] + channel_enum.conf['mch_id'],
            response.json['data']['entries'][0]['key'])

        # 测试人工出款 处理订单
        self.path = '/trade_manage/withdraw/person/execute'

        execute_params = dict(order_id=order.order_id, merchant="Test")

        response = self.do_request(json_data=execute_params)
        self.assertEqual(ResponseSuccess.code, response.status_code)
        self.assertEqual(ResponseSuccess.error_code,
                         response.json['error_code'])
        data = order_cls.query_by_order_id(order_id=event.order_id,
                                           merchant=merchant)
        self.assertEqual(OrderStateEnum.DEALING, data.state)

        # 测试人工出款  出款

        self.path = "/trade_manage/withdraw/person/done"
        done_params = dict(order_id=order.order_id,
                           merchant='TEST',
                           comment='测试',
                           fee='5')

        response = self.do_request(json_data=done_params)
        self.assertEqual(ResponseSuccess.code, response.status_code)
        self.assertEqual(ResponseSuccess.error_code,
                         response.json['error_code'])
        data = order_cls.query_by_order_id(order_id=event.order_id,
                                           merchant=merchant)
        self.assertEqual(OrderStateEnum.SUCCESS, data.state)
예제 #17
0
    def post(self):
        """
        用户登陆获取token
        :return:
        """

        # 验证登陆表单是否正确
        form, error = LoginForm().request_validate()
        if error:
            return error.as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.DEPOSIT,
        )):
            return MerchantConfigDepositError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.WITHDRAW,
        )):
            return MerchantConfigWithdrawError().as_response()

        # 验证手机号是否已注册
        user_info = User.query_user(form.merchant.data,
                                    account=form.number.data)
        if not user_info:
            return AccountNotExistError().as_response()

        if user_info.state == AccountStateEnum.INACTIVE:
            return DisableUserError().as_response()

        # 验证用户名 密码是否正确
        if not User.verify_login(merchant=form.merchant.data,
                                 account=form.number.data,
                                 password=form.password.data):
            UserPasswordLimitCache(mobile_number=form.number.data).incr_times()

            # 获取密码输入错误次数是否达到上限
            if UserPasswordLimitCache(
                    mobile_number=form.number.data).is_limited():
                User.update_user_state(form.merchant.data,
                                       account=form.number.data,
                                       state=AccountStateEnum.INACTIVE)
                return OriPasswordError().as_response()
            return LoginPasswordError().as_response()

        UserPasswordLimitCache(mobile_number=form.number.data).delete_cache()

        # 生成token 返回给客户端
        token = UserLoginToken.generate_token(
            uid=user_info.uid, merchant=form.merchant.data.value)

        # 显示用户名
        bind_info = UserBindInfo.query_bind_by_uid(user_info.uid)
        if bind_info:
            bind_name = bind_info.name
        else:
            bind_name = PhoneNumberParser.hide_number(user_info.account)

        return ResponseSuccessLogin(bs_data=dict(
            token=token,
            service_url=SERVICE_URL,
            permissions=user_info.permission_names,
            bind_name=bind_name,
            user_flag=user_info.flag.name,
        )).as_response()
예제 #18
0
    def test_merchant_fee_config_model(self):
        # 添加测试
        count = 0
        latest_count = 0
        for merchant in MerchantEnum:
            for payment_way in PayTypeEnum:
                if payment_way == PayTypeEnum.DEPOSIT:
                    for payment_method in PayMethodEnum:
                        for fee_type in PaymentFeeTypeEnum:
                            params = [
                                dict(
                                    merchant=merchant,
                                    payment_way=payment_way,
                                    payment_method=payment_method,
                                    fee_type=fee_type,
                                    value=Decimal("1.22"),
                                ),
                            ]
                            self.add_one_config(merchant, params)
                            count += 1
                        latest_count += 1
                else:
                    for fee_type in PaymentFeeTypeEnum:
                        params = [
                            dict(
                                merchant=merchant,
                                payment_way=payment_way,
                                fee_type=fee_type,
                                value=Decimal("3.22"),
                            ),
                        ]
                        self.add_one_config(merchant, params)
                        count += 1
                    latest_count += 1

        all_configs = MerchantFeeConfig.query_all()
        add_num = len(list(all_configs))
        self.assertEqual(count, add_num)

        latest_configs = MerchantFeeConfig.filter_latest_items(all_configs)
        x_latest_count = len(list(latest_configs))
        self.assertEqual(len(MerchantEnum.get_names()), x_latest_count)

        # 修改测试
        count = 0
        for merchant in MerchantEnum:
            for payment_way in PayTypeEnum:
                if payment_way == PayTypeEnum.DEPOSIT:
                    for payment_method in PayMethodEnum:
                        for fee_type in PaymentFeeTypeEnum:
                            params = [
                                dict(
                                    merchant=merchant,
                                    payment_way=payment_way,
                                    payment_method=payment_method,
                                    fee_type=fee_type,
                                    value=Decimal("1.33"),
                                ),
                            ]
                            self.add_one_config(merchant, params)
                            count += 1
                else:
                    for fee_type in PaymentFeeTypeEnum:
                        params = [
                            dict(
                                merchant=merchant,
                                payment_way=payment_way,
                                fee_type=fee_type,
                                value=Decimal("2.33"),
                            ),
                        ]
                        self.add_one_config(merchant, params)
                        count += 1

        add_num += count

        # 更新不会增加条目
        all_configs = MerchantFeeConfig.query_all()
        num = len(list(all_configs))
        self.assertEqual(add_num, num)

        latest_configs = MerchantFeeConfig.filter_latest_items(all_configs)
        x_latest_count = len(list(latest_configs))
        self.assertEqual(len(MerchantEnum.get_names()), x_latest_count)

        # 批量修改测试
        count = 0
        valid_count = 0
        for merchant in MerchantEnum:
            params = []
            for payment_way in PayTypeEnum:
                if payment_way == PayTypeEnum.DEPOSIT:
                    for payment_method in PayMethodEnum:
                        params.append(dict(
                            merchant=merchant,
                            payment_way=payment_way,
                            payment_method=payment_method,
                            fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                            value=Decimal("1.22"),
                        ))
                        count += 1
                else:
                    params.append(dict(
                        merchant=merchant,
                        payment_way=payment_way,
                        fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                        value=Decimal("3.22"),
                    ))
                    count += 1

            valid_count += len(params)
            self.add_one_config(merchant, params)

        add_num += count

        all_configs = MerchantFeeConfig.query_all()
        num = len(list(all_configs))
        self.assertEqual(add_num, num)

        latest_configs = MerchantFeeConfig.filter_latest_items(all_configs)
        x_latest_count = len(list(latest_configs))
        self.assertEqual(valid_count, x_latest_count)

        MerchantFeeConfig.delete_all()
        num = len(list(MerchantFeeConfig.query_all()))
        self.assertEqual(0, num)
예제 #19
0
    def order_fail(cls, order):
        """
        订单失败处理
        :return:
        """
        params = copy.deepcopy(locals())
        params.pop('cls')
        params.pop('order')
        params['tx_id'] = order.sys_tx_id

        rst = dict(
            code=0,
            msg='',
        )

        # 手续费存在订单详情里面
        order_detail = OrderDetailWithdraw.query_by_order_id(
            order.merchant, order.order_id, order.create_time)
        merchant_config = MerchantFeeConfig.query_by_config_id(
            order.mch_fee_id)

        try:
            # 创建提现订单/扣商户余额/扣用户余额,在同一个事务里面
            with db.auto_commit():
                order, ref_id = OrderUpdateCtl.update_order_event(
                    order.order_id,
                    uid=order.uid,
                    merchant=order.merchant,
                    state=OrderStateEnum.FAIL,
                    commit=False,
                )
                if not order:
                    raise RuntimeError('提现订单修改失败状态失败, params: %s' % params)

                # 给商户退回提现订单的发起金额
                flag, msg = MerchantBalanceEvent.update_balance(
                    merchant=order.merchant,
                    ref_id=ref_id,
                    source=order.source,
                    order_type=PayTypeEnum.REFUND,
                    bl_type=BalanceTypeEnum.AVAILABLE,
                    # 订单发起金额
                    value=order.amount,
                    ad_type=BalanceAdjustTypeEnum.PLUS,
                    tx_id=order.sys_tx_id,
                    commit=False,
                )
                # print('update_balance', flag, msg)
                if flag < 0:
                    raise RuntimeError(msg + ", params: %s" % params)

                if merchant_config.cost_type == CostTypeEnum.MERCHANT:
                    # 给商户退回提手续费
                    flag, msg = MerchantBalanceEvent.update_balance(
                        merchant=order.merchant,
                        ref_id=OrderUtils.gen_unique_ref_id(),
                        tx_id=order.sys_tx_id,
                        source=order.source,
                        order_type=PayTypeEnum.FEE,
                        bl_type=BalanceTypeEnum.AVAILABLE,
                        # 收取商户的手续费
                        value=order_detail.fee,
                        ad_type=BalanceAdjustTypeEnum.PLUS,
                        commit=False,
                    )
                    # print('update_balance', flag, msg)
                    if flag < 0:
                        raise RuntimeError(msg + ", params: %s" % params)

                refund_fee = order.amount
                if merchant_config.cost_type == CostTypeEnum.USER:
                    # 给用户退回手续费
                    refund_fee += order_detail.fee

                # 给用户退回发起金额
                flag, msg = UserBalanceEvent.update_user_balance(
                    uid=order.uid,
                    merchant=order.merchant,
                    ref_id=ref_id,
                    source=order.source,
                    order_type=PayTypeEnum.REFUND,
                    bl_type=BalanceTypeEnum.AVAILABLE,
                    # 订单发起金额
                    value=refund_fee,
                    ad_type=BalanceAdjustTypeEnum.PLUS,
                    tx_id=order.sys_tx_id,
                    commit=False,
                )
                # print('update_user_balance', flag, msg)
                if flag < 0:
                    raise RuntimeError(msg + ", params: %s" % params)

        except APIException as e:
            current_app.logger.error(traceback.format_exc())
            return False

        cls.do_notify(order=order)

        return True
예제 #20
0
    def manually_withdraw_failed(cls, admin_user, merchant, order_id):
        """
        手动更新提款状态为失败
        退款/审核拒绝
                流程:
            1. 获取创建订单时 扣除 用户及商户的费用
                获取订单 withdrawOrderDetail 数据, 获取 手续费 提现金额
            2. 给用户和商户新增费用
                更新 UserBalance 表
                更新 MerchantBalance表
            3. 修改订单状态
                更新 OrderUpdateCtl
        :param admin_user:
        :param merchant:
        :param order_id:
        :return:
        """
        # 查询该笔订单是否存在
        withdraw_entry = OrderWithdraw.query_by_order_id(merchant=merchant,
                                                         order_id=order_id)
        # 判断是否存在
        if not withdraw_entry:
            return OrderInfoMissingError()

        # 判断订单状态是否为 已认领 或 提现成功
        if withdraw_entry.state not in [
                OrderStateEnum.ALLOC, OrderStateEnum.SUCCESS
        ]:
            return BankOrderStateError()

        detail = OrderDetailWithdraw.query_by_order_id(
            order_id=withdraw_entry.order_id,
            merchant=merchant,
            create_time=withdraw_entry.create_time)
        if not detail:
            return NosuchOrderDetailDataError()

        # 提现订单 手续费 提现订单费用
        fee = detail.fee
        amount = detail.amount

        comment = "出款失败" if withdraw_entry.state == OrderStateEnum.SUCCESS else "系统拒绝"
        order_type = PayTypeEnum.REFUND if withdraw_entry.state == OrderStateEnum.SUCCESS else PayTypeEnum.MANUALLY

        merchant_config = MerchantFeeConfig.query_by_config_id(
            withdraw_entry.mch_fee_id)

        # 更新订单状态
        try:
            with db.auto_commit():

                order, ref_id = OrderUpdateCtl.update_order_event(
                    withdraw_entry.order_id,
                    uid=int(withdraw_entry.uid),
                    merchant=merchant,
                    state=OrderStateEnum.FAIL,
                    tx_amount=withdraw_entry.amount,
                    deliver_type=DeliverTypeEnum.MANUALLY,
                    op_account=admin_user.account,
                    commit=False)

                if not order:
                    msg = WithdrawOrderStateChangeError.message
                    current_app.logger.error(msg)
                    raise WithdrawOrderStateChangeError()

                # 加提现金额
                flag, msg = MerchantBalanceEvent.update_balance(
                    merchant=merchant,
                    ref_id=ref_id,
                    order_type=order_type,
                    bl_type=BalanceTypeEnum.AVAILABLE,
                    value=amount,
                    ad_type=BalanceAdjustTypeEnum.PLUS,
                    tx_id=order.sys_tx_id,
                    source=OrderSourceEnum.MANUALLY,
                    comment=comment,
                    commit=False,
                )
                if flag < 0:
                    msg = '%s' % ("提现退回增加商户余额失败, %s" % msg)
                    current_app.logger.error(msg)
                    raise DepositCallbackUserBalanceError()

                if merchant_config.cost_type == CostTypeEnum.MERCHANT:
                    # 给商户加手续费
                    flag, msg = MerchantBalanceEvent.update_balance(
                        merchant=merchant,
                        ref_id=OrderUtils.gen_unique_ref_id(),
                        order_type=PayTypeEnum.FEE,
                        bl_type=BalanceTypeEnum.AVAILABLE,
                        value=fee,
                        ad_type=BalanceAdjustTypeEnum.PLUS,
                        tx_id=order.sys_tx_id,
                        commit=False,
                        comment=comment,
                        source=OrderSourceEnum.MANUALLY)
                    if flag < 0:
                        msg = '%s' % ("提现退款增加商户手续费失败, %s" % msg)
                        current_app.logger.error(msg)
                        raise DepositCallbackUserBalanceError()

                refund_fee = amount
                if merchant_config.cost_type == CostTypeEnum.USER:
                    # 给用户退回手续费
                    refund_fee += fee

                # 增加用户余额
                flag, msg = UserBalanceEvent.update_user_balance(
                    uid=order.uid,
                    merchant=merchant,
                    ref_id=ref_id,
                    order_type=order_type,
                    bl_type=BalanceTypeEnum.AVAILABLE,
                    value=refund_fee,
                    ad_type=BalanceAdjustTypeEnum.PLUS,
                    tx_id=order.sys_tx_id,
                    commit=False,
                    comment=comment,
                    source=OrderSourceEnum.MANUALLY)
                if flag < 0:
                    msg = '%s' % ("提现退款增加用户余额失败, %s" % msg)
                    current_app.logger.error(msg)
                    raise DepositCallbackUserBalanceError()

        except APIException as e:
            current_app.logger.error(traceback.format_exc())
            return e

        cls.do_notify(
            order=order,
            op_account=admin_user.account,
            comment=comment,
        )

        return ResponseSuccess()
예제 #21
0
    def __test_api_deposit(self):
        self.path = "/auth/account/register"
        register_data = dict(number="+8618912341234",
                             auth_code="8888",
                             password="******")

        response = self.do_request(register_data)
        self.assertEqual(ResponseSuccess.code, response.status_code)
        self.assertEqual(ResponseSuccess.error_code,
                         response.json['error_code'])

        self.path = '/auth/account/login'

        login_data = dict(number="+8618912341234",
                          password="******")
        response = self.do_request(login_data)
        print(response.json)
        self.assertEqual(ResponseSuccessLogin.code, response.status_code)
        self.assertEqual(ResponseSuccessLogin.error_code,
                         response.json['error_code'])
        self.token = response.json['data']['token']

        kwargs = dict(
            fee="2.5",
            fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
            limit_per_min="200",
            limit_per_max="10000",
            trade_begin_hour="00",
            trade_begin_minute="00",
            trade_end_hour="23",
            trade_end_minute="59",
            maintain_begin=DateTimeKit.str_to_datetime("2019-09-07 09:00:00"),
            maintain_end=DateTimeKit.str_to_datetime("2019-09-07 09:00:00"),
            settlement_type=SettleTypeEnum.D0,
            state=ChannelStateEnum.TESTING,
            priority="101")

        # print(channel1['channel_id'])
        ChannelConfig.update_channel(ChannelConfigEnum.CHANNEL_1001, **kwargs)

        merchant = MerchantEnum.TEST
        merchant_fee_list = [
            dict(merchant=merchant,
                 payment_way=PayTypeEnum.DEPOSIT,
                 value="3",
                 fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                 payment_method=PayMethodEnum.ZHIFUBAO_SAOMA),
            dict(merchant=merchant,
                 payment_way=PayTypeEnum.WITHDRAW,
                 value="3.2",
                 fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER)
        ]

        ret, error = MerchantFeeConfig.update_fee_config(
            merchant, merchant_fee_list)

        self.path = "/deposit/limit/config/get"
        response = self.do_request()
        self.assertEqual(ResponseDepositLimitConfig.code, response.status_code)
        self.assertEqual(ResponseDepositLimitConfig.error_code,
                         response.json['error_code'])

        self.path = "/deposit/payment/type/list"
        response = self.do_request(dict(amount=500))
        self.assertEqual(ResponsePaymentType.code, response.status_code)
        self.assertEqual(ResponsePaymentType.error_code,
                         response.json['error_code'], response.json['message'])

        self.path = "/deposit/order/create"
        create_order_data = dict(
            payment_type="20",
            amount="400.03",
            channel_id=ChannelConfigEnum.CHANNEL_1001.value,
        )

        response = self.do_request(create_order_data)
        self.assertEqual(InvalidDepositPaymentTypeError.code,
                         response.status_code)
        self.assertEqual(InvalidDepositPaymentTypeError.error_code,
                         response.json['error_code'], response.json['message'])

        # create_order_data['payment_type'] = '10'
        # response = self.do_request(create_order_data)
        # self.assertEqual(ResponseSuccess.code, response.status_code)
        # self.assertEqual(ResponseSuccess.error_code, response.json['error_code'])

        # create_order_data['channel_id'] = '105'
        # response = self.do_request(create_order_data)
        # self.assertEqual(InvalidDepositChannelError.code, response.status_code)
        # self.assertEqual(InvalidDepositChannelError.error_code, response.json['error_code'])

        # create_order_data['channel_id'] = '101'
        # create_order_data['payment_type'] = "20"
        # response = self.do_request(create_order_data)
        # self.assertEqual(ChannelNoValidityPeriodError.code, response.status_code)
        # self.assertEqual(ChannelNoValidityPeriodError.error_code, response.json['error_code'])

        # create_order_data['payment_type'] = "30"
        # create_order_data['channel_id'] = '107'
        # response = self.do_request(create_order_data)
        # self.assertEqual(ResponseSuccess.code, response.status_code)
        # self.assertEqual(ResponseSuccess.error_code, response.json['error_code'])

        self.path = "/user/balance/get"
        response = self.do_request()
        print(response.json)
        self.assertEqual(ResponseUserBalance.code, response.status_code)
        self.assertEqual(ResponseUserBalance.error_code,
                         response.json['error_code'])
예제 #22
0
    def __test_api_withdraw(self):
        """
        后台准备数据:
            充值通道数据
            代付通道数据
            商户费率配置数据

        钱包端:
            1. 创建充值订单
            2. 充值
            3. 用户设置支付密码
            4. 用户绑定银行卡
            5. 获取充值配置信息(用户余额,充值最低最高限制)

        发起提现请求:

        :return:
        """
        merchant = MerchantEnum.from_name("TEST")
        info = dict(merchant=merchant,
                    account="+8618988888888",
                    auth_code="8888",
                    password="******",
                    trade_pwd="b943a52cc24dcdd12bf2ba3afda92351",
                    ac_type=AccountTypeEnum.MOBILE)
        user = User.register_account(info['merchant'], info['account'],
                                     info['ac_type'], info['password'])

        self.path = '/auth/account/login'

        login_data = dict(number=info['account'], password=info['password'])
        response = self.do_request(login_data)
        self.assertEqual(ResponseSuccessLogin.code, response.status_code)
        self.assertEqual(ResponseSuccessLogin.error_code,
                         response.json['error_code'])
        self.token = response.json['data']['token']

        self.path = "/withdraw/banks/list"

        # 1. 向数据库添加代付通道信息
        withdraw_item = dict(fee="2.5",
                             fee_type=PaymentFeeTypeEnum(1),
                             limit_per_min="200",
                             limit_per_max="5000",
                             limit_day_max="50000",
                             trade_begin_hour="00",
                             trade_begin_minute="00",
                             trade_end_hour="23",
                             trade_end_minute="59",
                             maintain_begin=DateTimeKit.str_to_datetime(
                                 "2019-09-27 00:00:00",
                                 DateTimeFormatEnum.SECONDS_FORMAT),
                             maintain_end=DateTimeKit.str_to_datetime(
                                 "2019-10-20 23:59:00",
                                 DateTimeFormatEnum.SECONDS_FORMAT),
                             state=ChannelStateEnum(10),
                             banks=[
                                 PaymentBankEnum(1),
                                 PaymentBankEnum(2),
                                 PaymentBankEnum(4),
                                 PaymentBankEnum(3),
                                 PaymentBankEnum(15)
                             ])

        ProxyChannelConfig.update_channel(ChannelConfigEnum.CHANNEL_1001,
                                          **withdraw_item)

        # 2. 向数据库插入 商户费率配置信息
        # 充值费率设置
        merchant_fee_dict = []
        merchant_fee_dict.append(
            dict(
                merchant=MerchantEnum.from_name('TEST'),
                payment_way=PayTypeEnum.DEPOSIT,
                value="3.5",
                fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                payment_method=PayMethodEnum.ZHIFUBAO_SAOMA,
            ))

        # 提现费率
        merchant_fee_dict.append(
            dict(
                merchant=MerchantEnum.from_name('TEST'),
                payment_way=PayTypeEnum.WITHDRAW,
                value="3.5",
                fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
            ))

        rst, error = MerchantFeeConfig.update_fee_config(
            merchant, merchant_fee_dict)
        self.assertEqual(True, rst)

        # 3. 给用户和商户充值
        uid = user.uid

        ref_id = hashlib.md5('lakjdflasjfadl;kfja'.encode('utf8')).hexdigest()

        data = dict(
            uid=uid,
            merchant=merchant,
            ref_id=ref_id,
            source=OrderSourceEnum.TESTING,
            order_type=PayTypeEnum.DEPOSIT,
            bl_type=BalanceTypeEnum.AVAILABLE,
            ad_type=BalanceAdjustTypeEnum.PLUS,
            tx_id=OrderUtils.gen_normal_tx_id(uid),
            value=Decimal("10000.00"),
            comment="xxx",
        )
        rst, msg = UserBalanceEvent.update_user_balance(**data)
        self.assertEqual(0, rst)

        balance = UserBalance.query_balance(data['uid'],
                                            data['merchant']).first()

        # 添加商户余额
        data = dict(
            merchant=MerchantEnum.TEST,
            source=OrderSourceEnum.TESTING,
            order_type=PayTypeEnum.DEPOSIT,
            bl_type=BalanceTypeEnum.AVAILABLE,
            ad_type=BalanceAdjustTypeEnum.PLUS,
            tx_id=OrderUtils.gen_normal_tx_id(100),
            value=Decimal("10000.00"),
            comment=msg,
        )

        ref_id = hashlib.md5(
            RandomString.gen_random_str(
                length=128).encode('utf8')).hexdigest()
        data['ref_id'] = ref_id
        event_check = dict(total=1)
        event_check.update(data)
        rst, msg = MerchantBalanceEvent.update_balance(**data)

        self.assertEqual(0, rst)

        # 设置支付密码
        flag = User.set_payment_password(merchant,
                                         uid=uid,
                                         trade_pwd=info["trade_pwd"])

        self.assertEqual(True, flag)

        # 绑定银行卡
        bank_info = {
            "payment_password": info['trade_pwd'],
            "bank_name": "中国工商银行",
            "bank_code": "ICBC",
            "card_no": "6212260405014627955",
            "account_name": "张三",
            "branch": "广东东莞东莞市长安镇支行",
            "province": "广东省",
            "city": "东莞市"
        }

        flag = BankCard.add_bank_card(merchant,
                                      uid=uid,
                                      bank_name=bank_info['bank_name'],
                                      bank_code=bank_info['bank_code'],
                                      card_no=bank_info['card_no'],
                                      account_name=bank_info['account_name'],
                                      branch=bank_info['branch'],
                                      province=bank_info['province'],
                                      city=bank_info['city'])
        self.assertEqual(bank_info['card_no'], flag.card_no)

        self.path = "/withdraw/limit/config/get"
        response = self.do_request()
        self.assertEqual(ResponseBankWithdraw.code, response.status_code)
        self.assertEqual(ResponseBankWithdraw.error_code,
                         response.json['error_code'])
        self.assertEqual("10000", response.json['data']['balance'])
        self.assertEqual("200", response.json['data']['limit_min'])
        self.assertEqual("5000", response.json['data']['limit_max'])

        self.path = "/withdraw/order/create"
        create_data = dict(amount=1000.001,
                           user_bank=1,
                           trade_password=info['trade_pwd'])

        # 测试小于 最低限额

        create_data['amount'] = 100

        response = self.do_request(json_data=create_data)
        self.assertEqual(WithdrawOrderAmountInvalidError.code,
                         response.status_code)
        self.assertEqual(WithdrawOrderAmountInvalidError.error_code,
                         response.json['error_code'])

        create_data['amount'] = 6000

        response = self.do_request(json_data=create_data)
        self.assertEqual(WithdrawOrderAmountInvalidError.code,
                         response.status_code)
        self.assertEqual(WithdrawOrderAmountInvalidError.error_code,
                         response.json['error_code'])

        create_data['amount'] = str(500.56)
        create_data['user_bank'] = 100

        response = self.do_request(json_data=create_data)
        self.assertEqual(WithdrawBankNoExistError.code, response.status_code)
        self.assertEqual(WithdrawBankNoExistError.error_code,
                         response.json['error_code'], response.json['message'])

        use_balance = UserBalance.query_balance(user.uid, merchant).first()
        ori_merchant = MerchantInfo.query_merchant(merchant)

        balance = ori_merchant.bl_ava - BalanceKit.round_4down_5up(
            Decimal(create_data['amount'])) * 100 - BalanceKit.round_4down_5up(
                Decimal(create_data['amount']) * Decimal(3.5))
        merchant_balance = BalanceKit.round_4down_5up(
            balance / Decimal(100)) * 100

        u_balance = BalanceKit.round_4down_5up(
            Decimal(use_balance.balance) / Decimal(100) -
            Decimal(create_data['amount'])) * Decimal(100)
        create_data['user_bank'] = 1

        response = self.do_request(json_data=create_data)
        self.assertEqual(ResponseSuccess.code, response.status_code)
        self.assertEqual(ResponseSuccess.error_code,
                         response.json['error_code'])

        cur_balance = UserBalance.query_balance(user.uid, merchant).first()
        cur_merchant = MerchantInfo.query_merchant(merchant)

        self.assertEqual(int(merchant_balance), int(cur_merchant.bl_ava))
        self.assertEqual(int(u_balance), int(cur_balance.balance))
예제 #23
0
 def add_one_config(self, merchant, params):
     MerchantFeeConfig.update_fee_config(merchant, params)
     for conf_dict in params:
         self.check_result(conf_dict)
예제 #24
0
    def __add_event(self, uid, merchant, channel_enum, order_type):

        order_cls = OrderDeposit if order_type == PayTypeEnum.DEPOSIT else OrderWithdraw

        channel_config = ChannelConfig.query_latest_one(
            dict(channel_enum=channel_enum))
        merchant_fee_config = MerchantFeeConfig.query_latest_one(
            dict(
                merchant=merchant,
                payment_way=PayTypeEnum.DEPOSIT,
                payment_method=channel_enum.conf.payment_method,
            ))

        params = dict(
            uid=uid,
            merchant=merchant,
            channel_id=channel_config.channel_id,
            mch_fee_id=merchant_fee_config.config_id,
            source=OrderSourceEnum.TESTING,
            order_type=order_type,
            in_type=InterfaceTypeEnum.CASHIER_H5,
            amount=Decimal("500"),
            comment='谢谢',
            op_account='xxx',
            bank_id=123,
            fee=10 if order_type == PayTypeEnum.WITHDRAW else 0,
        )
        order, ref_id = OrderCreateCtl.create_order_event(**params)
        self.assertIsNotNone(order)

        event = OrderEvent.query_one(dict(ref_id=ref_id),
                                     merchant=merchant,
                                     date=order.create_time)
        self.assertIsNotNone(event)
        self.assertEqual(order.order_id, event.order_id)
        self.assertEqual(order.uid, event.uid)
        self.assertEqual(ref_id, event.ref_id)

        order = order_cls.query_by_order_id(order_id=event.order_id,
                                            merchant=merchant)
        self.assertIsNotNone(order)
        self.assertEqual(params['uid'], order.uid)
        self.assertEqual(params['merchant'], order.merchant)
        self.assertEqual(params['channel_id'], order.channel_id)
        self.assertEqual(params['source'], order.source)
        self.assertEqual(params['amount'], order.amount)
        self.assertTrue(len(order.mch_tx_id) > 0)
        self.assertTrue(len(order.sys_tx_id) > 0)

        # 更新订单
        order, ref_id = OrderUpdateCtl.update_order_event(
            order_id=order.order_id,
            uid=order.uid,
            merchant=merchant,
            state=OrderStateEnum.SUCCESS
            if order_type == PayTypeEnum.DEPOSIT else OrderStateEnum.ALLOC,
            tx_amount=Decimal("500.32"),
            channel_tx_id='1232283838229929292',
            settle=SettleStateEnum.DONE,
            deliver=DeliverStateEnum.DONE,
            channel_id=channel_config.channel_id,
            mch_fee_id=merchant_fee_config.config_id,
            op_account='xxxx',
            comment='改了改了',
            offer=Decimal('1.22'),
            fee=Decimal('1.22'),
            cost=Decimal('1.22'),
            profit=Decimal('1.22'),
            deliver_type=DeliverTypeEnum.PROXY,
            alloc_time=DateTimeKit.get_cur_datetime(),
            deal_time=DateTimeKit.get_cur_datetime(),
        )
        self.assertIsNotNone(order)

        event = OrderEvent.query_one(dict(ref_id=ref_id),
                                     merchant=merchant,
                                     date=order.create_time)
        self.assertEqual(order.order_id, event.order_id)
        self.assertEqual(order.uid, event.uid)
        self.assertEqual(ref_id, event.ref_id)

        order3 = order_cls.query_by_order_id(order_id=event.order_id,
                                             merchant=merchant)
        self.assertIsNotNone(order3)
        self.assertEqual(params['uid'], order3.uid)
        self.assertEqual(params['merchant'], order3.merchant)
        self.assertEqual(params['channel_id'], order3.channel_id)
        self.assertEqual(params['source'], order3.source)
        self.assertEqual(Decimal("500.32"), order3.tx_amount)
        self.assertEqual(order.order_id, order3.order_id)
        self.assertEqual(order.mch_tx_id, order3.mch_tx_id)
        self.assertEqual(order.sys_tx_id, order3.sys_tx_id)

        order3 = order_cls.query_by_tx_id(tx_id=order.sys_tx_id)
        self.assertIsNotNone(order3)
        self.assertEqual(params['uid'], order3.uid)
        self.assertEqual(params['merchant'], order3.merchant)
        self.assertEqual(params['channel_id'], order3.channel_id)
        self.assertEqual(params['source'], order3.source)
        self.assertEqual(Decimal("500.32"), order3.tx_amount)
        self.assertEqual(order.order_id, order3.order_id)
        self.assertEqual(order.mch_tx_id, order3.mch_tx_id)
        self.assertEqual(order.sys_tx_id, order3.sys_tx_id)

        order3 = order_cls.query_by_uid_someday(
            merchant=merchant, uid=uid, someday=order.create_time).all()[0]
        self.assertIsNotNone(order3)
        self.assertEqual(params['uid'], order3.uid)
        self.assertEqual(params['merchant'], order3.merchant)
        self.assertEqual(params['channel_id'], order3.channel_id)
        self.assertEqual(params['source'], order3.source)
        self.assertEqual(Decimal("500.32"), order3.tx_amount)
        self.assertEqual(order.order_id, order3.order_id)
        self.assertEqual(order.mch_tx_id, order3.mch_tx_id)
        self.assertEqual(order.sys_tx_id, order3.sys_tx_id)

        begin_time, end_time = DateTimeKit.get_day_begin_end(order.create_time)
        orders = order_cls.query_by_create_time(begin_time,
                                                end_time,
                                                merchant=merchant,
                                                uid=uid).all()
        order3 = orders[-1]
        self.assertIsNotNone(order3)
        self.assertFalse(order3.is_cold_table())
        self.assertEqual(params['uid'], order3.uid)
        self.assertEqual(params['merchant'], order3.merchant)
        self.assertEqual(params['channel_id'], order3.channel_id)
        self.assertEqual(params['source'], order3.source)
        self.assertEqual(Decimal("500.32"), order3.tx_amount)
        self.assertEqual(order.order_id, order3.order_id)
        self.assertEqual(order.mch_tx_id, order3.mch_tx_id)
        self.assertEqual(order.sys_tx_id, order3.sys_tx_id)

        # 冷表查询测试
        begin_time, end_time = DateTimeKit.get_day_begin_end(order.create_time)
        clean_date = order_cls.get_clean_date()
        if clean_date.month == begin_time.month:
            begin_time = clean_date
            orders = order_cls.query_by_create_time(begin_time,
                                                    end_time,
                                                    merchant=merchant,
                                                    uid=uid).all()
            order3 = orders[-1]
            self.assertIsNotNone(order3)
            self.assertTrue(order3.is_cold_table())
            self.assertEqual(params['uid'], order3.uid)
            self.assertEqual(params['merchant'], order3.merchant)
            self.assertEqual(params['channel_id'], order3.channel_id)
            self.assertEqual(params['source'], order3.source)
            self.assertEqual(Decimal("500.32"), order3.tx_amount)
            self.assertEqual(order.order_id, order3.order_id)
            self.assertEqual(order.mch_tx_id, order3.mch_tx_id)
            self.assertEqual(order.sys_tx_id, order3.sys_tx_id)
예제 #25
0
    def __test_callback_ponypay_deposit(self):
        self.path = "/callback/ponypay/deposit"

        # 初始化数据
        kwargs = dict(
            fee="2.5",
            fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
            limit_per_min="200",
            limit_per_max="10000",
            trade_begin_hour="00",
            trade_begin_minute="00",
            trade_end_hour="23",
            trade_end_minute="59",
            maintain_begin=DateTimeKit.str_to_datetime("2019-09-07 09:00:00"),
            maintain_end=DateTimeKit.str_to_datetime("2019-09-07 09:00:00"),
            settlement_type=SettleTypeEnum.D0,
            state=ChannelStateEnum.TESTING,
            priority="101")
        rst, error = ChannelConfig.update_channel(
            ChannelConfigEnum.CHANNEL_1001, **kwargs)
        self.assertEqual(rst, True)
        self.assertEqual(error, None)
        # ChannelLimitCacheCtl(PayTypeEnum.DEPOSIT).sync_db_channels_to_cache()

        merchant = MerchantEnum.TEST
        merchant_fee_list = [
            dict(merchant=merchant,
                 payment_way=PayTypeEnum.DEPOSIT,
                 value="3",
                 fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                 payment_method=PayMethodEnum.ZHIFUBAO_SAOMA),
            dict(merchant=merchant,
                 payment_way=PayTypeEnum.WITHDRAW,
                 value="3.2",
                 fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER)
        ]

        ret, error = MerchantFeeConfig.update_fee_config(
            merchant, merchant_fee_list)
        self.assertEqual(rst, True)
        self.assertEqual(error, None)

        info = dict(
            account="+8618977772222",
            merchant=MerchantEnum.TEST,
            ac_type=AccountTypeEnum.MOBILE,
            login_pwd="123456789",
        )
        MerchantInfo.create_merchant(MerchantEnum.TEST, MerchantTypeEnum.TEST)
        user = User.register_account(merchant=info['merchant'],
                                     account=info['account'],
                                     ac_type=info['ac_type'],
                                     login_pwd=info['login_pwd'])

        uid = user.id
        channel_config = ChannelConfig.query_latest_one(query_fields=dict(
            channel_enum=ChannelConfigEnum.CHANNEL_1001))
        channel_conf = ChannelConfigEnum.CHANNEL_1001.conf
        channel_conf['white_ip'].append("127.0.0.1")
        merchant_fee = MerchantFeeConfig.query_latest_one(
            query_fields=dict(merchant=MerchantEnum.TEST,
                              payment_way=PayTypeEnum.DEPOSIT,
                              payment_method=channel_conf.payment_method))

        self.__test_callback_order_success(uid, channel_config, merchant_fee,
                                           '1')
        self.__test_callback_order_success(uid, channel_config, merchant_fee,
                                           '-1')

        stop = 1
예제 #26
0
    def post(self):
        """
        手动补单
        :return:
        """
        form, error = CreateDepositOrderForm().request_validate()
        if error:
            return error.as_response()
        '''
        根据商户查询用户是否存在
        构造数据
        创建充值订单
        更改订单状态为完成
        '''
        # 根据商户查询用户是否存在
        user = User.query_user(form.merchant.data, uid=form.uid.data)
        if not user:
            return AccountNotExistError().as_response()

        # 构造数据
        client_ip = form.client_ip.data
        channel_enum = form.channel_id.data
        payment_type = form.payment_type.data
        amount = Decimal(form.amount.data)

        # 判断当前传入的支付类型是否该渠道支持
        if payment_type != channel_enum.conf['payment_type']:
            return InvalidDepositPaymentTypeError()

        merchant = form.merchant.data

        # 找出最新版本的商户费率配置
        channel_config = ChannelConfig.query_latest_one(query_fields=dict(
            channel_enum=channel_enum))
        if not channel_config:
            return InvalidDepositChannelError().as_response()

        if not channel_config.is_channel_valid(merchant.is_test):
            return ChannelNoValidityPeriodError().as_response()

        if ChannelListHelper.is_amount_out_of_range(
                amount=amount,
                merchant=merchant,
                payment_way=PayTypeEnum.DEPOSIT,
                client_ip=client_ip):
            return DepositOrderAmountInvalidError().as_response()

        # limit_min, limit_max = ChannelLimitCacheCtl(
        #     PayTypeEnum.DEPOSIT).get_channel_limit()
        # try:
        #     if limit_min > amount or limit_max < amount:
        #         return DepositOrderAmountInvalidError().as_response()
        # except Exception as e:
        #     return MustRequestDepositLimitError().as_response()

        # 找出最新版本的商户费率配置
        merchant_fee = MerchantFeeConfig.query_latest_one(
            query_fields=dict(merchant=merchant,
                              payment_way=PayTypeEnum.DEPOSIT,
                              payment_method=channel_enum.conf.payment_method))

        if not merchant_fee:
            return MerchantConfigDepositError().as_response()

        try:
            with db.auto_commit():
                # 创建待支付订单
                order, _ = OrderCreateCtl.create_order_event(
                    uid=user.uid,
                    merchant=merchant,
                    amount=amount,
                    channel_id=channel_config.channel_id,
                    mch_fee_id=merchant_fee.config_id,
                    order_type=PayTypeEnum.DEPOSIT,
                    source=OrderSourceEnum.MANUALLY,
                    in_type=InterfaceTypeEnum.CASHIER_H5,
                    ip=client_ip,
                    pay_method=channel_enum.conf.payment_method,
                    op_account=g.user.account,  # 后台管理员账号,后台人工修改数据时必填
                    comment=form.remark.data,  # 管理后台修改备注,后台人工修改数据时必填
                    mch_tx_id=form.mch_tx_id.data,
                    commit=False,
                )
                if not order:
                    raise Exception('order create failed')

                # 支付成功
                if not DepositTransactionCtl.success_order_process(
                        order=order,
                        tx_amount=amount,
                        channel_tx_id=form.mch_tx_id.data,
                        comment="手动补单订单",
                        commit=False,
                ):
                    raise Exception('order process failed')
        except Exception as e:
            if str(e).find("Duplicate entry") >= 0:
                return PreOrderCreateError(message="商户订单号重复: {}".format(
                    form.mch_tx_id.data)).as_response()
            return PreOrderCreateError(message=str(e)).as_response()

        return ResponseSuccess().as_response()