Пример #1
0
    def get(self):
        """
        后台管理员操作日志
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?account=panda&date=20190901&export=1"
            ).as_response()

        account = request.args['account']
        if account:
            user = AdminUser.query_user(account=account)
            if not user:
                return ResponseSuccess(message="用户不存在,请检查参数。account:%s" %
                                       account).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()

        events = AdminLog.query_by_date(date)
        if account:
            events = events.filter_by(account=account)

        rst = list()

        for event in events:
            rst.append(
                dict(
                    create_time=event.create_time,
                    account=event.account,
                    url=event.url,
                    ip=event.ip,
                    module=event.module.desc,
                    model=event.model,
                    model_id=event.model_id,
                    data_before=event.data_before,
                    data_after=event.data_after,
                ))

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

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

        return ResponseSuccess(bs_data=rst).as_response()
Пример #2
0
 def _parse_suffix(cls, *args, **kwargs):
     """
     表后缀
     :param args:
     :param kwargs:
     :return:
     """
     return DateTimeKit.datetime_to_str(
         kwargs['date'], DateTimeFormatEnum.TIGHT_MONTH_FORMAT)
Пример #3
0
    def test_datetime_kit(self):
        t = DateTimeKit.gen_midnight_timestamp()
        self.print("gen_midnight_timestamp, t: %s" % t)
        self.assertIsInstance(t, int)

        d = DateTimeKit.timestamp_to_datetime(t)
        self.print("timestamp_to_datetime, d: %s" % d)
        self.assertIsInstance(d, datetime.datetime)

        t = DateTimeKit.datetime_to_timestamp(d)
        self.print("datetime_to_timestamp, t: %s" % t)
        self.assertIsInstance(t, int)

        s = DateTimeKit.datetime_to_str(d)
        self.print("datetime_to_str, s: %s" % s)
        self.assertIsInstance(s, str)

        d = DateTimeKit.str_to_datetime(s)
        self.print("str_to_datetime, d: %s" % d)
        self.assertIsInstance(d, datetime.datetime)

        d = DateTimeKit.get_cur_date()
        self.print("get_cur_date, d: %s" % d)
        self.assertIsInstance(d, datetime.date)

        t = DateTimeKit.datetime_to_timestamp(d)
        self.print("datetime_to_timestamp, t: %s" % t)
        self.assertIsInstance(t, int)

        s = DateTimeKit.datetime_to_str(d)
        self.print("datetime_to_str, s: %s" % s)
        self.assertIsInstance(s, str)

        cur_time = DateTimeKit.get_cur_datetime()
        rst = DateTimeKit.is_month_begin_time(cur_time)
        self.assertFalse(rst)

        someday = DateTimeKit.to_date(year=2019, month=1, day=1)
        rst = DateTimeKit.is_month_begin_time(someday)
        self.assertTrue(rst)

        someday = DateTimeKit.to_date(year=2019, month=2, day=2)
        rst = DateTimeKit.is_month_begin_time(someday)
        self.assertFalse(rst)
Пример #4
0
class MonthMix(BaseMix):
    """
    按月分表的模型
    """
    MAX_MONTHS = TABLE_MAX_MONTHS
    __OLDEST_DATE = TABLE_BEGIN_TIME
    TABLE_SUFFIXES = [
        DateTimeKit.datetime_to_str(x, DateTimeFormatEnum.TIGHT_MONTH_FORMAT)
        for x in DateTimeKit.gen_month_range(__OLDEST_DATE, months=MAX_MONTHS)
    ]

    @classmethod
    def is_valid_shard_date(cls, date):
        """
        判断日期是否小于最小的分表日期
        :param date:
        :return:
        """
        if date.year < cls.__OLDEST_DATE.year or (
                date.year == cls.__OLDEST_DATE.year
                and date.month < cls.__OLDEST_DATE.month):
            return False

        return True

    @classmethod
    def _check_required_params(cls, **kwargs):
        """
        必填参数检查
        :param kwargs:
        :return:
        """
        date = kwargs.get('date')

        if not date or not DateTimeKit.is_datetime(date):
            raise ShardParamsException(
                'date is required for cls: %s, kwargs: %s' %
                (cls.__name__, kwargs))

        if not cls.is_valid_shard_date(date):
            raise ShardDateException(
                'sharding date must gte %s, cls: %s, kwargs: %s' %
                (cls.__OLDEST_DATE, cls.__name__, kwargs))

    @classmethod
    def _parse_suffix(cls, *args, **kwargs):
        """
        表后缀
        :param args:
        :param kwargs:
        :return:
        """
        return DateTimeKit.datetime_to_str(
            kwargs['date'], DateTimeFormatEnum.TIGHT_MONTH_FORMAT)
Пример #5
0
def withdraw_epay_tong():
    from app.main import flask_app
    with flask_app.app_context():

        tasks = list(OrderTasks.query_all())
        for task in tasks:
            order_id = task.order_id

            batch_date = DateTimeKit.datetime_to_str(task.create_time, DateTimeFormatEnum.TIGHT_DAY_FORMAT)

            current_app.logger.info('EpayTong withdraw check: order_id: %s, batch_date: %s', order_id, batch_date)
            order = WithdrawTransactionCtl.get_order_by_order_id(order_id)
            current_app.logger.info('EpayTong withdraw check: order_state: %s, state_type: %s', order.state,
                                     type(order.state))

            if not order:
                current_app.logger.info('EpayTong withdraw check, order_id: %s', order_id)
                OrderTasks.delete_task(task_id=task.id)
                continue

            if order.state.name == OrderStateEnum.SUCCESS.name or order.state.name == OrderStateEnum.FAIL.name:
                OrderTasks.delete_task(task_id=task.id)
                continue

            elif order.state.name != "DEALING":
                current_app.logger.info('EpayTong withdraw check, order_id: %s, order_state: %s', order_id,
                                         order.state)
                continue

            current_app.logger.info('EpayTong withdraw check, order_id: %s, order_state: %s', order_id,
                                     order.state)

            params = {
                "tx_id": order.sys_tx_id,
                "batch_date": batch_date
            }
            rst = EpayTongWithdrawRequest(channel_enum=ChannelConfigEnum.CHANNEL_6013).launch_pay(params)

            if rst['code'] == 0:
                tx_amount = rst['data']['tx_amount']
                code = rst['data']['tradeFeedbackcode']
                print(code, "******************")
                if code == "成功":
                    if WithdrawTransactionCtl.order_success(order, tx_amount):
                        OrderTasks.delete_task(task_id=task.id)

                elif code == "失败":
                    if WithdrawTransactionCtl.order_fail(order):
                        OrderTasks.delete_task(task_id=task.id)
Пример #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 export_deposit_list_csv(cls, order_list, order_detail_dict, all_channels):
        """
        导出充值订单列表
        :param order_list:
        :param order_detail_dict:
        :param all_channels:
        :return:
        """
        # 用户id、系统订单号、商户订单号、创建时间、完成时间、商户、通道商户号、通道、发起金额、实际支付金额、优惠金额、手续费、
        # 成本金额、收入金额、订单状态、充值类型
        data = list()

        for order in order_list:
            channel = all_channels[order.channel_id]
            order_detail = order_detail_dict[order.order_id]

            data.append({
                "用户ID": order.uid,
                "系统订单号": order.sys_tx_id,
                "商户订单号": order.mch_tx_id,
                "创建时间": order.str_create_time,
                "完成时间": order_detail.str_done_time,
                "商户": order.merchant.name,
                "通道商户号": channel.channel_enum.conf['mch_id'],
                "通道": channel.channel_enum.desc,
                "发起金额": str(order.amount),
                "实际支付金额": str(order.tx_amount),
                "优惠金额": str(order_detail.offer),
                "手续费": str(order_detail.fee),
                "成本金额": str(order_detail.cost),
                "收入金额": str(order_detail.profit),
                "订单状态": order.state.desc,
                "充值类型": order.source.desc,
            })

        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())
Пример #8
0
    def launch_pay(self, params_dict: dict):
        """
        发起代付
        :param params_dict:
        :return:
        """

        url = self.gen_url(params_dict['tx_id'])

        params_dict['batch_date'] = DateTimeKit.datetime_to_str(
            DateTimeKit.get_cur_datetime(),
            DateTimeFormatEnum.TIGHT_DAY_FORMAT)
        request_dict, sign_str = self.construct_request(params_dict)

        sign = CallbackEpayTong.generate_sign(sign_str)

        request_dict["sign"] = sign
        request_dict["signType"] = "SHA"

        try:
            headers = {"Content-Type": "application/x-www-form-urlencoded"}
            current_app.logger.info('EpayTong withdraw, url: %s, data: %s',
                                    url, request_dict)
            resp = requests.post(url=url, data=request_dict, headers=headers)
            current_app.logger.info(
                'EpayTong withdraw, status_code: %s, content: %s',
                resp.status_code, resp.text)
        except Exception as e:
            current_app.logger.fatal(traceback.format_exc())
            return dict(
                code=-100,
                msg="http请求失败",
                data=dict(),
            )

        print(resp.json(), resp.text, resp.content)
        return self.parse_response(resp, params_dict)
Пример #9
0
    def export_withdraw_list_csv(cls, order_list, order_detail_dict, all_channels):
        """
        导出提现订单列表
        :param order_list:
        :param order_detail_dict:
        :param all_channels:
        :return:
        """
        # 用户id、系统订单号、商户订单号、创建时间、完成时间、商户、通道商户号、通道、提现金额、手续费、成本金额、收入金额、订单状态、出款类型、备注
        data = list()

        for order in order_list:
            channel = all_channels.get(order.channel_id)
            order_detail = order_detail_dict[order.order_id]
            data.append({
                "用户ID": order.uid,
                "系统订单号": order.sys_tx_id,
                "商户订单号": order.mch_tx_id,
                "创建时间": order.str_create_time,
                "完成时间": order_detail.str_done_time,
                "商户": order.merchant.name,
                "通道商户号": channel.channel_enum.conf['mch_id'] if channel else '',
                "通道": channel.channel_enum.desc if channel else '',
                "提现金额": str(order.amount),
                "手续费": str(order_detail.fee),
                "成本金额": str(order_detail.cost),
                "收入金额": str(order_detail.profit),
                "订单状态": order.state.desc,
                "出款类型": order.source.desc,
                "备注": order_detail.comment or '',
            })

        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())
Пример #10
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)
Пример #11
0
    def get(self):
        """
        订单修改日志
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message=
                "参数规则:?merchant=test&date=20190901&order_id=123&uid=123&ref_id=xxx&export=1,"
                "必填参数:merchant,"
                "可选参数:date,order_id,uid,ref_id,export,"
                "当不填写date时,默认查询当天所有的数据").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()

        q_params = dict()
        order_id = request.args.get('order_id')
        try:
            order_id = OrderUtils.parse_tx_id(order_id)
        except:
            pass
        if order_id:
            q_params['order_id'] = order_id
        uid = request.args.get('uid')
        if uid:
            q_params['uid'] = uid
        ref_id = request.args.get('ref_id')
        if ref_id:
            q_params['ref_id'] = ref_id
        if not q_params:
            return ResponseSuccess(
                message="必须输入 order_id/uid/ref_id 其中一个或多个参数").as_response()

        events = OrderEvent.query_model(query_fields=q_params, date=date)

        rst = list()

        for event in events:
            rst.append(
                dict(
                    create_time=event.create_time,
                    order_id=event.order_id,
                    uid=event.uid,
                    ref_id=event.ref_id,
                    data_before=event.data_before,
                    data_after=event.data_after,
                ))

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

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

        return ResponseSuccess(bs_data=rst).as_response()
Пример #12
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())
Пример #13
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()
Пример #14
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()
Пример #15
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())
Пример #16
0
    def construct_request(self, params_dict: dict):
        tx_id = params_dict['tx_id']
        amount = Decimal(params_dict['amount'])
        bank_code = params_dict['bank_code']
        bank_account = params_dict['bank_account']
        bank_number = params_dict['bank_number']
        request_fields = ['merchantId', 'batchNo', 'batchRecord', 'currencyCode', 'totalAmount', 'payDate',
                          'isWithdrawNow',
                          'notifyUrl',
                          'signType', 'sign', 'detailList']
        detail_list = ['receiveType', 'accountType', 'serialNo', 'amount', 'bankName', 'bankNo', 'receiveName']
        fields = sorted(request_fields)
        request_dict = {}
        for field in fields:
            if field == 'merchantId':
                request_dict[field] = self.third_config['mch_id']
            elif field == 'batchNo':
                request_dict[field] = tx_id
            elif field == 'batchRecord':
                request_dict[field] = 1
            elif field == 'currencyCode':
                request_dict[field] = 'CNY'
            # 交易类型 固定值
            elif field == 'totalAmount':
                tx_amount = amount
                tx_amount = str(tx_amount)
                if tx_amount.find('.') < 0:
                    tx_amount += '.00'
                request_dict[field] = tx_amount
            # 交易金额 单位 分
            elif field == 'payDate':
                request_dict[field] = DateTimeKit.datetime_to_str(DateTimeKit.get_cur_datetime(),
                                                                  DateTimeFormatEnum.TIGHT_DAY_FORMAT)
            # 后台回调地址
            elif field == 'isWithdrawNow':
                request_dict[field] = '3'
            # 开户人名称
            elif field == 'notifyUrl':
                request_dict[field] = self.third_config['callback_url']
            elif field == 'signType':
                request_dict[field] = 'RSA'
            elif field == 'detailList':
                detail = request_dict.get(field, [])
                detail_dict = {}
                for item in detail_list:
                    if item == 'receiveType':
                        detail_dict[item] = '个人'
                    elif item == 'accountType':
                        detail_dict[item] = '储蓄卡'
                    elif item == 'serialNo':
                        detail_dict[item] = tx_id
                    elif item == 'amount':
                        tx_amount = str(amount)
                        if tx_amount.find('.') < 0:
                            tx_amount += '.00'
                        detail_dict[item] = tx_amount
                    elif item == 'bankName':
                        detail_dict[item] = bank_code
                    elif item == 'bankNo':
                        detail_dict[item] = bank_number
                    elif item == 'receiveName':
                        detail_dict[item] = bank_account
                detail.append(detail_dict)
                request_dict[field] = detail

        no_need_fields = ['detailList', 'signType', 'sign']
        request_body_str = "&".join(["{}={}".format(k, request_dict[k]) for k in fields if
                                     k not in no_need_fields and request_dict.get(k, False)])
        sign = CallbackOnePay.gen_sign(body_str=request_body_str, third_config=self.third_config)
        request_dict['sign'] = sign
        return request_dict
Пример #17
0
 def str_alloc_time(self):
     if self.alloc_time:
         return DateTimeKit.datetime_to_str(self.alloc_time)
     return ''
Пример #18
0
    def __test_api_channel(self):
        # 充值通道管理 新增通道
        channel_enum = ChannelConfigEnum.CHANNEL_1001
        post_data = dict(channel_id=channel_enum.value,
                         fee="2.3",
                         fee_type="1",
                         limit_per_min="2000",
                         limit_per_max="50000",
                         limit_day_max="50000",
                         start_time="09:00",
                         end_time="23:59",
                         state="10",
                         settlement_type="1",
                         priority="1")

        post_data["state"] = 10
        # 数值型参数类型错误
        self.path = '/channel/deposit/add'

        response = self.do_request(post_data)
        self.assertEqual(response.status_code, ParameterException.code)
        self.assertEqual(response.json['error_code'],
                         ParameterException.error_code)
        # print(response.json['message'], "this field must be String type")
        post_data["state"] = "10"

        # 测试交易日期为空的情况
        response = self.do_request(post_data)
        print(response.json)
        self.assertEqual(ResponseSuccess.code, response.status_code,
                         response.json['message'])
        self.assertEqual(ResponseSuccess.error_code,
                         response.json['error_code'], response.json['message'])
        # print(response.json['message'], "this field must be String type")
        post_data['maintain_begin'] = "2019-09-27 09:10:00"
        post_data['maintain_end'] = "2019-10-20 23:09:00"

        # 测试每笔交易上限大于日交易上限
        post_data['limit_day_max'] = "40000"
        response = self.do_request(post_data)
        print(response.json)
        self.assertEqual(PerLimitMustLittleDayLimitError.code,
                         response.status_code)
        self.assertEqual(PerLimitMustLittleDayLimitError.error_code,
                         response.json['error_code'])
        # print(response.json['message'], "this field must be String type")
        # self.assertEqual(response.json['message'], "单笔交易最大值必须小于当日交易限额")
        post_data['limit_day_max'] = "60000"

        # 时间类型参数业务数据不对
        post_data["maintain_begin"] = "2020-08-23 09:30:00"
        response = self.do_request(post_data)
        self.assertEqual(response.status_code, DateStartMoreThanError.code)
        self.assertEqual(response.json['error_code'],
                         DateStartMoreThanError.error_code)
        self.assertEqual(response.json['message'],
                         DateStartMoreThanError.message)
        post_data["maintain_begin"] = "2019-09-27 09:00:00"

        # 业务类型数据不对
        post_data["limit_per_min"] = "100000"
        response = self.do_request(post_data)
        self.assertEqual(response.status_code, DataStartMoreThanError.code)
        self.assertEqual(response.json['error_code'],
                         DataStartMoreThanError.error_code)
        self.assertEqual(response.json['message'],
                         DataStartMoreThanError.message)
        post_data["limit_per_min"] = "2000"

        # 时间类型数据格式错误
        post_data["maintain_begin"] = "2019/09/27 09:00:00"
        response = self.do_request(post_data)
        self.assertEqual(response.status_code, ParameterException.code)
        self.assertEqual(response.json['error_code'],
                         ParameterException.error_code)
        # self.assertEqual(response.json['message'], "无效的时间格式")
        post_data["maintain_begin"] = "2019-09-27 09:00:00"

        # 测试成功添加数据
        response = self.do_request(post_data)
        self.assertEqual(response.status_code, ResponseSuccess.code)
        channel = ChannelConfig.query_latest_one(
            dict(channel_enum=channel_enum))
        self.assertEqual(channel.channel_enum.value, post_data['channel_id'])
        self.assertEqual(channel.settlement_type.value,
                         int(post_data['settlement_type']))

        # 渠道管理:编辑通道

        self.path = '/channel/deposit/edit'
        post_data['settlement_type'] = '3'
        response = self.do_request(post_data)
        self.assertEqual(response.status_code, ResponseSuccess.code)
        channel = ChannelConfig.query_latest_one(
            dict(channel_enum=channel_enum))
        self.assertEqual(channel.channel_enum.value, post_data['channel_id'])
        self.assertEqual(channel.settlement_type.value, 3)

        # 测试 不支持的 枚举类型数据
        self.path = '/channel/deposit/edit'
        post_data['state'] = '110'
        response = self.do_request(post_data)
        self.assertEqual(response.status_code, ParameterException.code)
        self.assertEqual(response.json['error_code'],
                         ParameterException.error_code)
        # self.assertEqual(response.json['message'], "无效的通道状态")
        post_data['state'] = "10"

        # 代付通道管理: 新增代付通道

        self.path = "/channel/withdraw/add"
        withdraw_postdata = dict(channel_id=channel_enum.value,
                                 fee="2.3",
                                 fee_type="1",
                                 limit_per_min="2000",
                                 limit_per_max="50000",
                                 limit_day_max="50000",
                                 start_time="09:00",
                                 end_time="23:59",
                                 maintain_begin="2019-09-27 09:00:00",
                                 maintain_end="2019-10-20 23:00:00",
                                 state="10",
                                 banks=["1", "2", "4", "6", "3", "5", "15"])

        # 测试参数类型错误
        withdraw_postdata['channel_id'] = '123'
        response = self.do_request(withdraw_postdata)
        self.assertEqual(response.status_code, ParameterException.code)
        self.assertEqual(response.json['error_code'],
                         ParameterException.error_code)
        # self.assertEqual(response.json['message'], str({'channel_id': 'this field must be Integer type'}))

        # 测试时间格式错误
        withdraw_postdata['channel_id'] = channel_enum.value
        withdraw_postdata["maintain_begin"] = "2019/09/27 09:00:00"
        response = self.do_request(withdraw_postdata)
        self.assertEqual(response.status_code, ParameterException.code)
        self.assertEqual(response.json['error_code'],
                         ParameterException.error_code)
        # self.assertEqual(response.json['message'], "无效的时间格式")
        withdraw_postdata["maintain_begin"] = "2019-09-27 09:00:00"

        # 测试成功添加代付通道
        ProxyChannelConfig.delete_all()
        response = self.do_request(withdraw_postdata)
        self.assertEqual(response.status_code, ResponseSuccess.code)
        self.assertEqual(response.json['error_code'],
                         ResponseSuccess.error_code)

        channel = ProxyChannelConfig.query_latest_one(
            dict(channel_enum=channel_enum))
        self.assertEqual(withdraw_postdata['maintain_begin'],
                         DateTimeKit.datetime_to_str(channel.maintain_begin))
        self.assertEqual(withdraw_postdata['channel_id'],
                         channel.channel_enum.value)

        # 测试编辑 代付通道
        self.path = "/channel/withdraw/edit"

        withdraw_postdata['banks'] = ["4", "6", "3"]
        withdraw_postdata['limit_day_max'] = '180000'
        withdraw_postdata['maintain_begin'] = "2019-10-30 09:30:01"
        withdraw_postdata['maintain_end'] = "2019-12-30 09:30:01"
        response = self.do_request(withdraw_postdata)
        self.assertEqual(response.status_code, ResponseSuccess.code)
        self.assertEqual(response.json['error_code'],
                         ResponseSuccess.error_code)

        channel = ProxyChannelConfig.query_latest_one(
            dict(channel_enum=channel_enum))
        self.assertEqual(channel_enum.value, channel.channel_enum.value)
        self.assertEqual(withdraw_postdata['maintain_begin'],
                         DateTimeKit.datetime_to_str(channel.maintain_begin))
        self.assertEqual(withdraw_postdata['maintain_end'],
                         DateTimeKit.datetime_to_str(channel.maintain_end))
        self.assertEqual(
            [PaymentBankEnum(4),
             PaymentBankEnum(6),
             PaymentBankEnum(3)], channel.banks)
        self.assertEqual(180000, channel.limit_day_max)

        # 测试代付列表
        self.path = "/channel/withdraw/list"

        response = self.do_request()
        self.assertEqual(response.status_code, ResponseSuccess.code)
        self.assertEqual(response.json['error_code'],
                         ResponseSuccess.error_code)
        self.assertEqual('1', response.json['data']['counts'])
        self.assertEqual(channel_enum.value,
                         response.json['data']['withdraws'][0]['channel_id'])

        ProxyChannelConfig.delete_all()
Пример #19
0
 def str_done_time(self):
     if self.done_time:
         return DateTimeKit.datetime_to_str(self.done_time)
     return ''
Пример #20
0
 def get_suffix(self, cur_datetime=None):
     cur_datetime = cur_datetime or DateTimeKit.get_cur_datetime()
     return DateTimeKit.datetime_to_str(cur_datetime, self.suffix_format)
Пример #21
0
 def str_create_time(self):
     if self.create_time:
         return DateTimeKit.datetime_to_str(self.create_time)
     return ''
Пример #22
0
 def str_update_time(self):
     return DateTimeKit.datetime_to_str(self.update_time)