Пример #1
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()
Пример #2
0
    def get(self):
        """
        查询可用的通道
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?merchant=test&interface=&amount=&uid="
            ).as_response()

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

        try:
            interface = request.args.get('interface')
            if interface:
                interface = InterfaceTypeEnum.from_name(interface)
        except:
            return ResponseSuccess(
                message="请输入正确的 interface,有效的 interface 包括:%s" %
                InterfaceTypeEnum.get_names()).as_response()

        try:
            amount = request.args.get('amount') or 0
            if amount:
                amount = Decimal(amount)
        except:
            return ResponseSuccess(message="请输入正确的 amount")

        try:
            uid = request.args.get('uid')
            if uid:
                uid = int(uid)
        except:
            return ResponseSuccess(message="请输入正确的 uid")

        routers = ChannelListHelper.get_channel_payment_type_router(
            interface=interface,
            amount=amount,
            merchant=merchant,
            uid=uid,
        )
        channels = ChannelListHelper.get_available_channels(
            merchant, PayTypeEnum.DEPOSIT)
        payment_type_list = ChannelListHelper.choice_one_channel_for_payment_type(
            channels, routers, merchant, amount)

        for item in payment_type_list:
            item['limit_min'] = str(item['limit_min'])
            item['limit_max'] = str(item['limit_max'])

        return ResponseSuccess(bs_data=payment_type_list).as_response()
Пример #3
0
    def get(self):
        """
        给用户绑定信息
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message=
                "参数规则:?merchant=test&account=861891111&perm=DEPOSIT|BINDCARD"
            ).as_response()

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

        try:
            account = request.args['account']
            account = '+' + account.strip('+').strip()
            if not PhoneNumberParser.is_valid_number(account):
                raise
        except:
            return ResponseSuccess(
                message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999"
            ).as_response()

        try:
            perms = request.args['perm'].split('|')
            perms = [UserPermissionEnum.from_name(perm) for perm in perms]
        except:
            return ResponseSuccess(
                message="标签权限,有效的权限包括: %s" %
                UserPermissionEnum.get_name_list()).as_response()

        user = User.query_user(merchant, account=account)
        if not user:
            return ResponseSuccess(message="手机号码未注册").as_response()

        User.update_user_permission(merchant, perms, account=account)
        user = User.query_user(merchant, account=account)

        bs_data = dict(
            account=account,
            uid=user.uid,
            perms=user.permission_names,
        )
        return ResponseSuccess(bs_data=bs_data).as_response()
Пример #4
0
    def get(self):
        """
        给用户绑定信息
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?merchant=test&account=861891111&flag=VIP"
            ).as_response()

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

        try:
            account = request.args['account']
            account = '+' + account.strip('+').strip()
            if not PhoneNumberParser.is_valid_number(account):
                raise
        except:
            return ResponseSuccess(
                message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999"
            ).as_response()

        try:
            flag = AccountFlagEnum.from_name(request.args['flag'])
        except:
            return ResponseSuccess(
                message="标签错误,有效的标签包括: %s" %
                AccountFlagEnum.get_name_list()).as_response()

        user = User.query_user(merchant, account=account)
        if not user:
            return ResponseSuccess(message="手机号码未注册").as_response()

        User.update_user_flag(merchant, flag, account=account)
        user = User.query_user(merchant, account=account)

        bs_data = dict(
            account=account,
            uid=user.uid,
            flag=user.flag.desc,
            is_auth=user.is_official_auth,
            cache_flag=UserFlagCache(user.uid).get_flag().name,
        )
        return ResponseSuccess(bs_data=bs_data).as_response()
Пример #5
0
def verify_credential(token):
    """
    使用basic auth进行JWT token鉴权
    加了装饰器 @auth.login_required 的view都需要先进这个函数进行token鉴权
    :param token:
    :return:
    """

    # 初始化g对象的error属性
    g.error = None

    rst = UserLoginToken.verify_token(token)
    if isinstance(rst, (APIException, )):
        # token 验证失败
        g.error = rst
        return False

    # 账户被封处理
    merchant = MerchantEnum(rst['merchant'])
    user = User.query_user(merchant=merchant, uid=rst['uid'])
    if not user:
        # 用户不存在
        g.error = AccountNotExistError()
        return False

    if not user.is_active:
        g.error = DisableUserError()
        return False

    g.user = user
    return True
Пример #6
0
    def get(self):
        """
        检查热表数据
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?merchant=test&date=20190901").as_response()

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

        try:
            date = request.args.get('date')
            if date:
                date = DateTimeKit.str_to_datetime(
                    date, DateTimeFormatEnum.TIGHT_DAY_FORMAT, to_date=True)
            else:
                date = DateTimeKit.get_cur_date()
        except:
            return ResponseSuccess(
                message="请输入有效的查询日期,格式为:20190901").as_response()

        kwargs = dict(
            date=date,
            merchant=merchant,
            only_hot=request.args.get('only_hot'),
            only_cold=request.args.get('only_cold'),
        )

        rst = dict(
            OrderDeposit=OrderDeposit.query_by_date(date, **kwargs).count(),
            OrderWithdraw=OrderWithdraw.query_by_date(date, **kwargs).count(),
            OrderDetailDeposit=OrderDetailDeposit.query_by_date(
                date, **kwargs).count(),
            OrderDetailWithdraw=OrderDetailWithdraw.query_by_date(
                date, **kwargs).count(),
        )
        kwargs['merchant'] = merchant.name
        kwargs['date'] = DateTimeKit.datetime_to_str(date)
        rst['kwargs'] = kwargs

        return ResponseSuccess(bs_data=rst).as_response()
Пример #7
0
    def validate_name(self, value):
        try:
            self.name.data = MerchantEnum.from_name(value.data)
        except Exception:
            raise StopValidation("无效的商户名称")

        if not MerchantInfo.query_merchant(self.name.data):
            raise StopValidation("未创建的商户")
Пример #8
0
 def validate_merchant_name(self, value):
     try:
         if value.data:
             self.merchant_name.data = MerchantEnum.from_name(value.data)
         else:
             self.merchant_name.data = None
     except Exception as e:
         raise StopValidation("无效的商户名称")
Пример #9
0
 def validate_merchants(self, value):
     try:
         if value.data:
             self.merchants.data = [
                 MerchantEnum.from_name(x) for x in value.data
             ]
         else:
             self.merchants.data = []
     except Exception as e:
         raise StopValidation("无效的 merchants 参数")
Пример #10
0
    def get(self):
        """
        查询用户余额
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?account=8613812349999&merchant=test"
            ).as_response()

        try:
            account = request.args.get('account')
            if account:
                account = '+' + account.strip('+').strip()
                if not PhoneNumberParser.is_valid_number(account):
                    raise
            else:
                raise
        except:
            return ResponseSuccess(
                message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999"
            ).as_response()

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

        user = User.query_user(merchant, account=account)
        if not user:
            return ResponseSuccess(message="手机号码未注册, account: %s" %
                                   account).as_response()

        user_balance = UserBalance.query_balance(user.uid, merchant).first()

        return ResponseSuccess(bs_data=dict(
            account=account,
            uid=user.uid,
            balance=str(user_balance.real_balance),
        )).as_response()
Пример #11
0
    def post(self):
        """
        通道管理: 获取通道配置信息
        :return:
        """
        form, error = ChannelConfigQueryForm().request_validate()
        if error:
            return error.as_response()

        pay_type = form.pay_type.data

        config_channels_dict = ChannelListHelper.get_config_channels(
            pay_type, ret_dict=True)

        if pay_type == PayTypeEnum.DEPOSIT:
            configs = [
                c for c in ChannelConfigEnum if
                c.value not in config_channels_dict and c.conf['payment_type']
            ]
        else:
            configs = [
                c for c in ChannelConfigEnum
                if c.value not in config_channels_dict
                and not c.conf['payment_type']
            ]

        channel_config_list = [
            dict(
                channel_id=i.value,
                channel_desc=i.desc,
                id=i.conf["id"],
                provider=i.conf["provider"],
                name=i.conf["name"],
                payment_type=i.conf["payment_type"].desc
                if i.conf['payment_type'] else '',
                payment_method=i.conf["payment_method"].desc
                if i.conf['payment_method'] else '',
            ) for i in configs
        ]

        data = dict(
            channel_config=channel_config_list,
            payment_fee_type=PaymentFeeTypeEnum.get_desc_value_pairs(),
            settlement_type=SettleTypeEnum.get_name_value_pairs(),
            channel_state=ChannelStateEnum.get_desc_value_pairs(),
            banks=PaymentBankEnum.get_desc_value_pairs(),
            # banks=[item.value for item in PaymentBankEnum],
            interfaces=InterfaceTypeEnum.get_name_value_pairs(),
            payment_method=PayMethodEnum.get_desc_value_pairs(),
            merchant_name=MerchantEnum.get_name_value_pairs(),
            payment_types=PaymentTypeEnum.get_desc_name_pairs(),
        )
        return ChannelConfigResult(bs_data=data).as_response()
Пример #12
0
 def post(self):
     """
     获取创建商户所需的配置信息
     :return:
     """
     result = dict(
         merchant_names=MerchantEnum.get_name_type_pairs(),
         payment_methods=PayMethodEnum.get_desc_value_pairs(),
         withdraw_type=DeliverTypeEnum.get_desc_value_pairs(),
         channels_withdraw=ChannelConfigEnum.get_withdraw_desc_name_pairs(),
         channels_deposit=ChannelConfigEnum.get_deposit_desc_name_pairs(),
     )
     return MerchantConfigResult(bs_data=result).as_response()
Пример #13
0
    def post(self):
        """
        商户基本信息
        :return:
        """
        user = g.user
        info = MerchantInfo.query_merchant(MerchantEnum(user.mid))
        if not info:
            return MerchantInfoNoExistError().as_response()

        merchant_info = dict(account=user.account,
                             balance_total=info.balance_total,
                             available_balance=info.balance_available,
                             incoming_balance=info.balance_income,
                             frozen_balance=info.balance_frozen)
        return MerchantBaseInfoResponse(bs_data=merchant_info).as_response()
Пример #14
0
    def get(self):
        """
        联通性测试
        :return:
        """
        from scripts.admin_user import init_merchant_user

        if not request.args:
            return ResponseSuccess(message="参数规则:?merchant=TEST").as_response()

        try:
            account = request.args['merchant']
        except:
            return ResponseSuccess(message="请输入商户分配的账号名称").as_response()

        try:
            merchant = MerchantEnum.from_name(account)
        except:
            return ResponseSuccess(message="请输入有效的商户名称").as_response()

        account, password = init_merchant_user(merchant.value, merchant.name,
                                               None)
        return ResponseSuccess(
            bs_data=dict(account=account, password=password)).as_response()
Пример #15
0
 def merchant(self) -> MerchantEnum:
     return MerchantEnum(self._merchant)
Пример #16
0
        ),
        'deposit_info': fields.List(fields.Nested(DepositTypeList)),
        'withdraw_info': fields.Nested(WithdrawType)
    })

#####################################################
# 商户余额编辑
#####################################################

MerchantBalanceEdit = api.model(
    'MerchantBalanceEdit', {
        'name':
        fields.String(
            required=True,
            description='商户名称',
            example=MerchantEnum.description(),
        ),
        'adjustment_type':
        fields.String(
            required=True,
            description='调整类型',
            example=ManualAdjustmentType.description(),
        ),
        'amount':
        fields.String(
            required=True,
            description='调整金额(浮点数转为字符串)',
            example="500.34",
        ),
        'reason':
        fields.String(required=True, description='原因说明', example="原因说明.....")
Пример #17
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)
Пример #18
0
 def merchants(self):
     if not self._merchants:
         return []
     _values = StringParser(',', int).split(self._merchants)
     return [MerchantEnum(v) for v in _values]
Пример #19
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))
Пример #20
0
    def post(self):
        """
        商户提现订单查询
        :return:
        """
        form, error = WithdrawOrderSelectForm().request_validate()
        if error:
            return error.as_response()

        user = g.user

        try:
            order_list_query = OrderWithdraw.query_by_create_time(
                begin_time=form.start_datetime.data,
                end_time=form.end_datetime.data,
                merchant=MerchantEnum(user.mid))

        except MultiMonthQueryException as e:
            return MultiMonthQueryError().as_response()

        kwargs = {}
        tx_id = form.order_id.data
        if tx_id:
            if OrderUtils.is_sys_tx_id(tx_id):
                kwargs["sys_tx_id"] = tx_id
            else:
                kwargs["mch_tx_id"] = tx_id

        if form.state.data != "0":
            kwargs["_state"] = form.state.data.value

        query = order_list_query.filter_by(**kwargs)
        pagination = query.paginate(form.page_index.data, form.page_size.data,
                                    False)

        entries = pagination.items
        total = pagination.total

        bank_lst = list(set([o.bank_id for o in entries]))
        kwargs = {}

        if tx_id and entries:
            kwargs['id'] = entries[0].order_id

        bank_items = dict()
        if not MerchantEnum(user.mid).is_api_merchant:
            bank_items = {
                bank.id: bank
                for bank in BankCard.query.filter(BankCard.id.in_(
                    bank_lst)).all()
            }
        order_items = {
            item.id: item
            for item in OrderDetailWithdraw.query_by_create_time(
                begin_time=form.start_datetime.data,
                end_time=form.end_datetime.data,
                merchant=MerchantEnum(user.mid)).filter_by(**kwargs).all()
        }

        items = []
        for order in entries:
            if not MerchantEnum(user.mid).is_api_merchant:
                bank = bank_items.get(order.bank_id, {})
            else:
                bank = order.get_bank_card()
            detail = order_items.get(order.order_id, {})
            if not bank or not detail:
                continue
            items.append(
                dict(mch_tx_id=order.mch_tx_id,
                     sys_tx_id=order.sys_tx_id,
                     amount=detail.amount,
                     fee=detail.fee,
                     account_name=bank.account_name,
                     bank_name=bank.bank_name,
                     branch="{}{}{}".format(bank.province, bank.city,
                                            bank.branch),
                     card_no=bank.card_no,
                     create_time=order.str_create_time,
                     done_time=order.update_time,
                     state=order.state.desc,
                     deliver=order.deliver.desc))
        items = sorted(items, key=lambda item: item['create_time'])
        return MerchantWithdrawOrderResult(
            bs_data=dict(entries=items, total=total)).as_response()
Пример #21
0
    "fee_type": fields.Nested(DescValuePair),
    "limit_per_min": fields.String(required=True, description='单笔交易下限'),
    "limit_per_max": fields.String(required=True, description='单笔交易上限'),
    "limit_day_max": fields.String(required=True, description='日交易限额'),
    "settlement_type": fields.Nested(NameValuePair),
    "trade_start_time": fields.String(required=True, description='交易开始时间'),
    "trade_end_time": fields.String(required=True, description='交易结束时间'),
    "main_time": fields.Nested(maintain_datetime),
    "state": fields.Nested(DescValuePair, description="可操作类型列表"),
    "reason": fields.String(required=True, description='不可用原因'),
    "priority": fields.String(required=True, description='优先级'),
    "merchants": fields.List(
        fields.String,
        required=True,
        description='适用的商户列表',
        example=MerchantEnum.get_names(),
    ),
})

ChannelList = api.model('ChannelList', {
    'counts': fields.String(
        required=True,
        description='渠道总个数',
        example="10"
    ),
    'channels': fields.List(fields.Nested(ChannelItem)),
})


class ChannelListResult(ResponseSuccess):
    data_model = ChannelList
Пример #22
0
    def post(self):
        """
        商户充值订单查询数据导出
        :return:
        """
        form, error = DepositOrderSelectForm().request_validate()
        if error:
            return error.as_response()

        user = g.user

        try:
            order_list_query = OrderDeposit.query_by_create_time(
                begin_time=form.start_datetime.data,
                end_time=form.end_datetime.data,
                merchant=MerchantEnum(user.mid))
        except MultiMonthQueryException as e:
            return MultiMonthQueryError().as_response()

        kwargs = {}
        if form.order_id.data:
            kwargs["sys_tx_id"] = form.order_id.data

        if form.state.data != "0":
            kwargs["_state"] = form.state.data.value

        entries = order_list_query.filter_by(**kwargs).all()

        items = []
        channel_lst = list(set([o.channel_id for o in entries]))
        channel_items = {
            Channel.id: Channel
            for Channel in ChannelConfig.query.filter(
                ChannelConfig.id.in_(channel_lst)).all()
        }
        kwargs = {}
        if form.order_id.data and entries:
            kwargs['id'] = entries[0].order_id
        order_items = {
            item.id: item
            for item in OrderDetailDeposit.query_by_create_time(
                begin_time=form.start_datetime.data,
                end_time=form.end_datetime.data,
                merchant=MerchantEnum(user.mid)).filter_by(**kwargs).all()
        }
        for order in entries:
            item_channel = channel_items.get(order.channel_id, {})
            detail = order_items.get(order.order_id, {})
            if not item_channel or not detail:
                continue

            items.append(
                dict(mch_tx_id=order.mch_tx_id,
                     sys_tx_id=order.sys_tx_id,
                     payment_type=item_channel.channel_enum.
                     conf['payment_type'].desc,
                     amount=detail.amount,
                     tx_amount=detail.tx_amount,
                     fee=detail.fee,
                     create_time=order.str_create_time,
                     done_time=order.update_time,
                     state=order.state.desc,
                     deliver=order.deliver.desc))
        items = sorted(items, key=lambda item: item['create_time'])

        if items:
            data = list()
            for item in items:
                data.append({
                    "商户订单号": item['mch_tx_id'],
                    "支付方式": item['payment_type'],
                    "发起金额": str(item['amount']),
                    "实际支付金额": str(item['tx_amount']),
                    "手续费": str(item['fee']),
                    "创建时间": item['create_time'],
                    "完成时间": item['done_time'],
                    "订单状态": item['state'],
                    "通知状态": item['deliver']
                })

            filename = 'epay_deposit_record_%s.csv' % (
                DateTimeKit.datetime_to_str(
                    DateTimeKit.get_cur_datetime(),
                    DateTimeFormatEnum.TIGHT_DAY_FORMAT))

            return CsvKit.send_csv(data,
                                   filename=filename,
                                   fields=data[0].keys())
Пример #23
0
    def post(self):
        """
        商户提现订单查询
        :return:
        """
        form, error = WithdrawOrderSelectForm().request_validate()
        if error:
            return error.as_response()

        user = g.user

        try:
            order_list_query = OrderWithdraw.query_by_create_time(
                begin_time=form.start_datetime.data,
                end_time=form.end_datetime.data,
                merchant=MerchantEnum(user.mid))

        except MultiMonthQueryException as e:
            return MultiMonthQueryError().as_response()

        kwargs = {}
        if form.order_id.data:
            kwargs["mch_tx_id"] = form.order_id.data

        if form.state.data != "0":
            kwargs["_state"] = form.state.data.value

        entries = order_list_query.filter_by(**kwargs).all()

        bank_lst = list(set([o.bank_id for o in entries]))
        kwargs = {}

        if form.order_id.data and entries:
            kwargs['id'] = entries[0].order_id
        if not MerchantEnum(user.mid).is_api_merchant:
            bank_items = {
                bank.id: bank
                for bank in BankCard.query.filter(BankCard.id.in_(
                    bank_lst)).all()
            }
        order_items = {
            item.id: item
            for item in OrderDetailWithdraw.query_by_create_time(
                begin_time=form.start_datetime.data,
                end_time=form.end_datetime.data,
                merchant=MerchantEnum(user.mid)).filter_by(**kwargs).all()
        }

        items = []
        for order in entries:
            if not MerchantEnum(user.mid).is_api_merchant:
                bank = bank_items.get(order.bank_id, {})
            else:
                bank = order.get_bank_card()
            detail = order_items.get(order.order_id, {})
            if not bank or not detail:
                continue
            items.append(
                dict(mch_tx_id=order.mch_tx_id,
                     sys_tx_id=order.sys_tx_id,
                     amount=detail.amount,
                     fee=detail.fee,
                     account_name=bank.account_name,
                     bank_name=bank.bank_name,
                     branch="{}{}{}".format(bank.province, bank.city,
                                            bank.branch),
                     card_no=bank.card_no,
                     create_time=order.str_create_time,
                     done_time=order.update_time,
                     state=order.state.desc,
                     deliver=order.deliver.desc))
        items = sorted(items, key=lambda item: item['create_time'])

        if items:
            data = list()
            for item in items:
                data.append({
                    "商户订单号": item['mch_tx_id'],
                    "提现金额": str(item['amount']),
                    "手续费": str(item['fee']),
                    "开户名": item['account_name'],
                    "开户银行": item['bank_name'],
                    "开户地址": item['branch'],
                    "银行卡号": item['card_no'],
                    "创建时间": item['create_time'],
                    "完成时间": item['done_time'],
                    "订单状态": item['state'],
                    "通知状态": item['deliver']
                })

            filename = 'epay_withdraw_record_%s.csv' % (
                DateTimeKit.datetime_to_str(
                    DateTimeKit.get_cur_datetime(),
                    DateTimeFormatEnum.TIGHT_DAY_FORMAT))

            return CsvKit.send_csv(data,
                                   filename=filename,
                                   fields=data[0].keys())
Пример #24
0
    def get(self):
        """
        查询商户余额变更流水
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?merchant=test&date=20190901&export=1"
            ).as_response()

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

        try:
            date = request.args.get('date')
            if date:
                date = DateTimeKit.str_to_datetime(
                    date, DateTimeFormatEnum.TIGHT_DAY_FORMAT, to_date=True)
            else:
                date = DateTimeKit.get_cur_date()
        except:
            return ResponseSuccess(
                message="请输入有效的查询日期,格式为:20190901").as_response()

        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),
        )

        events = MerchantBalanceEvent.query_by_date(date,
                                                    merchant=merchant,
                                                    date=date)

        rst = dict(
            data=list(),
            sum_value=0,
            balance=balance,
        )

        rst['sql'] = str(events)

        for event in events:
            rst['sum_value'] += event.value_real
            rst['data'].append(
                dict(
                    create_time=event.create_time,
                    ref_id=event.ref_id,
                    order_type=event.order_type.desc,
                    source=event.source.desc,
                    bl_type=event.bl_type.desc,
                    value=str(event.value_real),
                    ad_type=event.ad_type.desc,
                    tx_id=event.tx_id,
                    comment=event.comment,
                ))

        rst['data'] = sorted(rst['data'],
                             key=lambda x: x['create_time'],
                             reverse=True)
        for x in rst['data']:
            x['create_time'] = DateTimeKit.datetime_to_str(x['create_time'])

        if rst['data'] and request.args.get('export'):
            filename = 'merchant_balance_events_%s.csv' % DateTimeKit.datetime_to_str(
                date, DateTimeFormatEnum.TIGHT_DAY_FORMAT)
            return CsvKit.send_csv(rst['data'],
                                   filename=filename,
                                   fields=rst['data'][0].keys())

        rst['sum_value'] = str(rst['sum_value'])

        return ResponseSuccess(bs_data=rst).as_response()
Пример #25
0
    def get(self):
        """
        查询用户余额变更流水
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message=
                "参数规则:?merchant=test&account=8618912341234&date=20190901&export=1"
            ).as_response()

        try:
            account = request.args.get('account')
            if account:
                account = '+' + account.strip('+').strip()
                if not PhoneNumberParser.is_valid_number(account):
                    raise
        except:
            return ResponseSuccess(
                message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999"
            ).as_response()

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

        try:
            date = request.args.get('date')
            if date:
                date = DateTimeKit.str_to_datetime(
                    date, DateTimeFormatEnum.TIGHT_DAY_FORMAT, to_date=True)
            else:
                date = DateTimeKit.get_cur_date()
        except:
            return ResponseSuccess(
                message="请输入有效的查询日期,格式为:20190901").as_response()

        rst = dict(
            data=list(),
            sum_value=0,
        )

        events = UserBalanceEvent.query_by_date(date,
                                                merchant=merchant,
                                                date=date)
        if account:
            user = User.query_user(merchant, account=account)
            if not user:
                return ResponseSuccess(message="用户不存在,请检查参数。商户:%s,手机号码:%s" %
                                       (merchant.name, account))

            user_balance = UserBalance.query_balance(user.uid,
                                                     merchant).first()
            rst.update(user=dict(
                account=user.account,
                uid=user.uid,
                user_balance=str(user_balance.real_balance),
            ))
            events = events.filter_by(uid=user.uid)

        rst['sql'] = str(events)
        for event in events:
            rst['sum_value'] += event.value_real
            rst['data'].append(
                dict(
                    create_time=event.create_time,
                    uid=event.uid,
                    ref_id=event.ref_id,
                    order_type=event.order_type.desc,
                    source=event.source.desc,
                    bl_type=event.bl_type.desc,
                    value=str(event.value_real),
                    ad_type=event.ad_type.desc,
                    tx_id=event.tx_id,  # 大整数,转为字符串
                    comment=event.comment,
                    extra=event.raw_extra,
                ))

        rst['data'] = sorted(rst['data'],
                             key=lambda x: x['create_time'],
                             reverse=True)
        for x in rst['data']:
            x['create_time'] = DateTimeKit.datetime_to_str(x['create_time'])

        if rst['data'] and request.args.get('export'):
            filename = 'user_balance_events_%s.csv' % DateTimeKit.datetime_to_str(
                date, DateTimeFormatEnum.TIGHT_DAY_FORMAT)
            return CsvKit.send_csv(rst['data'],
                                   filename=filename,
                                   fields=rst['data'][0].keys())

        rst['sum_value'] = str(rst['sum_value'])

        return ResponseSuccess(bs_data=rst).as_response()
Пример #26
0
    def post(self):
        """
        商户充值订单查询
        :return:
        """
        form, error = DepositOrderSelectForm().request_validate()
        if error:
            return error.as_response()

        user = g.user

        try:
            order_list_query = OrderDeposit.query_by_create_time(
                begin_time=form.start_datetime.data,
                end_time=form.end_datetime.data,
                merchant=MerchantEnum(user.mid))
        except MultiMonthQueryException as e:
            return MultiMonthQueryError().as_response()

        kwargs = {}
        tx_id = form.order_id.data
        if tx_id:
            if OrderUtils.is_sys_tx_id(tx_id):
                kwargs["sys_tx_id"] = tx_id
            else:
                kwargs["mch_tx_id"] = tx_id

        if form.state.data != "0":
            kwargs["_state"] = form.state.data.value

        query = order_list_query.filter_by(**kwargs)
        pagination = query.paginate(form.page_index.data, form.page_size.data,
                                    False)

        entries = pagination.items
        total = pagination.total

        items = []
        channel_lst = list(set([o.channel_id for o in entries]))
        channel_items = {
            Channel.id: Channel
            for Channel in ChannelConfig.query.filter(
                ChannelConfig.id.in_(channel_lst)).all()
        }
        kwargs = {}
        if tx_id and entries:
            kwargs['id'] = entries[0].order_id
        order_items = {
            item.id: item
            for item in OrderDetailDeposit.query_by_create_time(
                begin_time=form.start_datetime.data,
                end_time=form.end_datetime.data,
                merchant=MerchantEnum(user.mid)).filter_by(**kwargs).all()
        }
        for order in entries:
            item_channel = channel_items.get(order.channel_id, {})
            detail = order_items.get(order.order_id, {})
            if not item_channel or not detail:
                continue

            items.append(
                dict(mch_tx_id=order.mch_tx_id,
                     sys_tx_id=order.sys_tx_id,
                     payment_type=item_channel.channel_enum.
                     conf['payment_type'].desc,
                     amount=detail.amount,
                     tx_amount=detail.tx_amount,
                     fee=detail.fee,
                     create_time=order.str_create_time,
                     done_time=order.update_time,
                     state=order.state.desc,
                     deliver=order.deliver.desc))
        items = sorted(items, key=lambda item: item['create_time'])
        return MerchantDepositOrderResult(
            bs_data=dict(entries=items, total=total)).as_response()
Пример #27
0
from app.enums.balance import ManualAdjustmentType
from app.enums.trade import PaymentFeeTypeEnum, PayMethodEnum, OrderSourceEnum, OrderStateEnum, DeliverTypeEnum, \
    DeliverStateEnum, PaymentBankEnum, PayTypeEnum
from app.extensions.ext_api import api_backoffice as api
from app.libs.error_code import ResponseSuccess
from config import MerchantEnum

###################################################
# withdraw list
###################################################

NameTypePair = api.model(
    "NameTypePair", {
        "name":
        fields.String(
            description=MerchantEnum.description(),
            example=MerchantEnum.QF2.name,
        ),
        "type":
        fields.String(
            description=MerchantTypeEnum.description(),
            example=MerchantTypeEnum.NORMAL.value,
        )
    })

DescValuePair = api.model(
    "DescValuePair", {
        "desc":
        fields.String(
            description="支付方式描述",
            example=PayMethodEnum.WEIXIN_H5.desc,
Пример #28
0
 def validate_account(self, value):
     try:
         self.account.data = MerchantEnum.from_name(value.data)
     except Exception as e:
         raise StopValidation("无效的商户名称")
Пример #29
0
 def validate_merchant_id(self, value):
     try:
         self.merchant_id.data = MerchantEnum(int(value.data))
     except Exception as e:
         raise StopValidation("无效的 merchant_id")
Пример #30
0
    def get(self):
        """
        给用户绑定信息
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?merchant=test&account=861891111&name=大王&unbind="
            ).as_response()

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

        try:
            account = request.args['account']
            account = '+' + account.strip('+').strip()
            if not PhoneNumberParser.is_valid_number(account):
                raise
        except:
            return ResponseSuccess(
                message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999"
            ).as_response()

        try:
            name = request.args['name']
        except:
            return ResponseSuccess(message="绑定名称必填").as_response()

        user = User.query_user(merchant, account=account)
        if not user:
            return ResponseSuccess(message="手机号码未注册").as_response()

        bind_info = UserBindInfo.query_bind_by_uid(user.uid)

        if request.args.get('unbind'):
            if not bind_info:
                return ResponseSuccess(message="未绑定任何别名,无需解绑").as_response()

            if UserBindInfo.unbind_account(user.uid):
                return ResponseSuccess(message="解绑成功").as_response()
            else:
                return ResponseSuccess(message="解绑失败").as_response()
        else:
            if not bind_info:
                if UserBindInfo.bind_account(user.uid,
                                             merchant,
                                             account=user.account,
                                             name=name):
                    msg = "绑定成功"
                else:
                    msg = "绑定失败"
                    return ResponseSuccess(message=msg).as_response()
            else:
                msg = "无需重复绑定,已经绑定名称:%s" % bind_info.name

            bind_info = UserBindInfo.query_bind_by_uid(user.uid)
            bs_data = dict(
                name=bind_info.name,
                account=bind_info.account,
                uid=user.uid,
            )
            return ResponseSuccess(bs_data=bs_data, message=msg).as_response()