예제 #1
0
    def post(self):
        """
        后台配置信息
        :return:
        """
        # 获取 充值通道信息
        channel_list = []
        channels = ChannelConfig.query_all()
        channels = ChannelConfig.filter_latest_items(channels)
        for channel in channels:
            channel_enum = channel.channel_enum
            channel_list.append(
                dict(desc=channel_enum.desc, value=channel_enum.value))

        # 获取商户数据
        merchant_list = [
            dict(desc=m.name, value=m.value) for m in MerchantEnum
        ]
        # 获取支付类型
        payment_type_list = [
            dict(desc=p.desc, value=p.value) for p in PaymentTypeEnum
        ]

        return BackOfficeConfigResult(
            bs_data=dict(merchant=merchant_list,
                         payment_type=payment_type_list,
                         deposit_channel=channel_list)).as_response()
예제 #2
0
    def __update_channel(self, data, latest, count):
        ChannelConfig.update_channel(**data)

        channels = ChannelConfig.query_all()
        self.assertEqual(count, len(channels))

        all_configs = list(ChannelConfig.filter_latest_items(channels))
        self.assertEqual(latest, len(all_configs))
예제 #3
0
    def get(self):
        """
        立马付充值回调
        :return:
        """
        if not EnvironEnum.is_local_evn(current_app.config['FLASK_ENV']):
            # 无论如何都记录一条log
            current_app.logger.info(
                'ponypay withdraw callback, ip: %s, data: %s',
                IpKit.get_remote_ip(), request.args)

        form, error = PonyPayWithdrawForm().request_validate()
        if error:
            current_app.logger.fatal('msg: %s, data: %s', error.message,
                                     request.args)
            return BaseResponse('FAIlURE')

        # 交易订单id
        tx_id = form.corderid.data
        # 实际支付金额
        tx_amount = Decimal(form.money.data)
        # 订单状态: 成功/失败
        status = form.status.data
        # 签名
        sign = form.sign.data
        # 客户端IP
        client_ip = form.client_ip.data

        order = WithdrawTransactionCtl.get_order(tx_id)
        if not order:
            return BaseResponse('FAIlURE')

        channel_config = ChannelConfig.query_by_channel_id(order.channel_id)
        controller = WithdrawCallbackPonypay(channel_config.channel_enum)

        # IP白名单校验
        if not controller.check_ip(client_ip):
            current_app.logger.fatal('ip not allow, client_ip: %s, data: %s',
                                     client_ip, request.args)
            return BaseResponse('FAIlURE')

        # 签名验证
        if not controller.check_sign(tx_id, tx_amount, sign):
            current_app.logger.fatal('invalid sign, client_ip: %s, data: %s',
                                     client_ip, request.args)
            return BaseResponse('FAIlURE')

        if status == '1':
            # 支付成功
            if not WithdrawTransactionCtl.order_success(order, tx_amount):
                return BaseResponse('FAIlURE')
        else:
            # 支付失败
            if not WithdrawTransactionCtl.order_fail(order):
                return BaseResponse('FAIlURE')

        return BaseResponse('SUCCESS')
예제 #4
0
    def post(self):
        """
        通道管理: 新建通道
        :return:
        """

        form, error = ChannelAddForm().request_validate()
        if error:
            return error.as_response()

        # if form.start_time.data >= form.end_time.data:
        #     return DateStartMoreThanError().as_response()

        if form.maintain_begin.data:
            if form.maintain_begin.data >= form.maintain_end.data or form.maintain_begin.data < DateTimeKit.get_cur_datetime(
            ):
                return DateStartMoreThanError().as_response()

        if Decimal(form.limit_per_min.data) >= Decimal(
                form.limit_per_max.data):
            return DataStartMoreThanError().as_response()

        if form.limit_day_max.data and Decimal(
                form.limit_per_max.data) > Decimal(form.limit_day_max.data):
            return PerLimitMustLittleDayLimitError().as_response()

        kwargs = dict(fee=form.fee.data,
                      fee_type=form.fee_type.data,
                      limit_per_min=form.limit_per_min.data,
                      limit_per_max=form.limit_per_max.data,
                      limit_day_max=form.limit_day_max.data
                      if form.limit_day_max.data != "" else 0,
                      trade_begin_hour=form.start_time.data.hour,
                      trade_begin_minute=form.start_time.data.minute,
                      trade_end_hour=form.end_time.data.hour,
                      trade_end_minute=form.end_time.data.minute,
                      maintain_begin=form.maintain_begin.data,
                      maintain_end=form.maintain_end.data,
                      settlement_type=form.settlement_type.data,
                      state=form.state.data,
                      priority=form.priority.data)

        rst, error = ChannelConfig.update_channel(form.channel_id.data,
                                                  **kwargs)
        if error:
            return error.as_response()

        # 同步缓存
        # ChannelLimitCacheCtl(PayTypeEnum.DEPOSIT).sync_db_channels_to_cache()

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

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

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

        order_detail = OrderDetailDeposit.query_by_tx_id(tx_id)

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

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

        return ResponseSuccess(bs_data=order_info).as_response()
예제 #6
0
    def do_ponypay_withdraw_callback(self, status):
        amount = tx_amount = Decimal("100.25")

        # 生成一个可以回调的订单
        order = InitData.init_withdraw_order_deal(amount)

        channel_config = ChannelConfig.query_by_channel_id(order.channel_id)
        controller = WithdrawCallbackPonypay(channel_config.channel_enum)
        sign = controller.generate_sign(order.sys_tx_id, tx_amount)

        self.path = "/callback/ponypay/withdraw"
        params = """merchant_id={}&corderid={}&money={}&status={}&sign={}""".format(
            controller.third_config['mch_id'],
            order.sys_tx_id,
            tx_amount,
            status,
            sign,
        )
        response = self.do_get_request(params=params)
        self.assertEqual(200, response.status_code)
        self.assertEqual("SUCCESS", response.data.decode("utf-8"))
예제 #7
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()
예제 #8
0
    def post(self):
        """
        充值通道列表
        :return:
        """

        router2_dict = ChannelListHelper.get_router2_dict()

        channel_list = []
        channels = ChannelConfig.query_all()
        channels = ChannelConfig.filter_latest_items(channels)
        for channel in channels:
            channel_enum = channel.channel_enum
            channel_conf = channel_enum.conf

            merchants = list()
            router = router2_dict.get(channel_enum)
            if router:
                merchants = router.merchants

            channel_list.append(
                dict(
                    channel_id=channel_enum.value,
                    channel_desc=channel_enum.desc,
                    id=channel_conf['mch_id'],
                    provider=channel_conf['provider'],
                    payment_type=dict(desc=PaymentTypeEnum(
                        channel_conf['payment_type']).desc,
                                      value=PaymentTypeEnum(
                                          channel_conf['payment_type']).value),
                    payment_method=dict(
                        desc=PayMethodEnum(
                            channel_conf['payment_method']).desc,
                        value=PayMethodEnum(
                            channel_conf['payment_method']).value),
                    fee=channel.fee,
                    fee_type=dict(
                        desc=PaymentFeeTypeEnum(channel.fee_type).desc,
                        value=PaymentFeeTypeEnum(channel.fee_type).value),
                    limit_per_min=channel.limit_per_min,
                    limit_per_max=channel.limit_per_max,
                    limit_day_max=channel.limit_day_max,
                    settlement_type=dict(
                        key=SettleTypeEnum(channel.settlement_type).value,
                        value=SettleTypeEnum(channel.settlement_type).name),
                    trade_start_time=":".join([
                        str(channel.trade_begin_hour),
                        str(channel.trade_begin_minute)
                    ]),
                    # trade_start_time=dict(trade_begin_hour=channel.trade_begin_hour,
                    #                       trade_begin_minute=channel.trade_begin_minute),
                    trade_end_time=":".join([
                        str(channel.trade_end_hour),
                        str(channel.trade_end_minute)
                    ]),
                    # trade_end_time=dict(trade_end_hour=channel.trade_end_hour,
                    #                     trade_end_minute=channel.trade_end_minute),
                    main_time=dict(maintain_begin=channel.maintain_begin
                                   if channel.maintain_begin else None,
                                   maintain_end=channel.maintain_end
                                   if channel.maintain_end else None),
                    state=dict(desc=channel.state.desc,
                               value=channel.state.value),
                    reason=channel.get_reason_desc(),
                    priority=channel.priority,
                    merchants=[x.name for x in merchants],
                ))
        channel_list = sorted(channel_list,
                              key=lambda item: item['state']['value'])
        data = dict(counts=len(channel_list), channels=channel_list)

        return ChannelListResult(bs_data=data).as_response()
예제 #9
0
    def query_withdraw_order_list(cls, form, export=False):
        """
        查询提现订单列表
        :param form:
        :param export:
        :return:
        """

        merchant = form.merchant_name.data

        if not form.begin_time.data:
            begin_time, end_time = DateTimeKit.get_day_begin_end(DateTimeKit.get_cur_date())
        else:
            begin_time = form.begin_time.data
            end_time = form.end_time.data

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

        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

        try:
            order_list = OrderWithdraw.query_by_create_time(begin_time=begin_time, end_time=end_time,
                                                            merchant=merchant).filter_by(**kwargs)
        except MultiMonthQueryException:
            return MultiMonthQueryError().as_response()

        all_channels = dict([(x.channel_id, x) for x in ChannelConfig.query_all()])
        order_detail_dict = dict()

        order_list = OrderFilters.filter_from_order_list(order_list, filters=[
            functools.partial(OrderFilters.filter_tx_id, tx_id),
            functools.partial(OrderFilters.filter_channel, all_channels, form.channel.data),
        ])

        if order_list:
            # 订单详情列表
            order_detail_list = OrderDetailWithdraw.query_by_create_time(begin_time=begin_time, end_time=end_time,
                                                                         merchant=merchant)

            # 订单列表和订单详情列表相互过滤
            order_list, order_detail_dict = OrderFilters.filter_from_detail_list(
                order_list, order_detail_list,
                filters=[
                    functools.partial(
                        OrderFilters.filter_done_time,
                        form.done_begin_time.data,
                        form.done_end_time.data),
                ])

            # 按时间倒序
            order_list = sorted(order_list, key=itemgetter('create_time'), reverse=True)

        if export and order_list:
            return CsvOrderExport.export_withdraw_list_csv(order_list, order_detail_dict, all_channels)

        return cls.render_withdraw_list(form, order_list, order_detail_dict)
예제 #10
0
    def post(self):
        """
        充值订单详情
        :return:
        """
        # form表单验证用提款的
        form, error = WithDrawBankForm().request_validate()
        if error:
            return error.as_response()

        # 取得订单id
        order_id = form.order_id.data
        # 根据订单id获取对应的商户 用户id
        order_map = GlobalOrderId.query_global_id(order_id)
        # 获取商户id
        merchant = order_map.merchant

        # 根据商户id 订单id查询具体的订单信息
        entry = OrderDeposit.query_by_order_id(order_id=order_id,
                                               merchant=merchant)

        # 查询对应的订单详情表
        detail = OrderDetailDeposit.query_by_order_id(merchant=merchant,
                                                      order_id=order_id)

        # 拼接返回数据
        detail_head = dict(
            source=entry.source.desc,
            create_time=entry.str_create_time,
            done_time=detail.str_done_time,
            mch_tx_id=entry.mch_tx_id,
            sys_tx_id=entry.sys_tx_id,
            state=entry.state.get_back_desc(PayTypeEnum.DEPOSIT),
            settle=entry.settle.desc,
            deliver=entry.deliver.desc,
            amount=entry.amount,
        )
        order_merchant_info = dict(merchant_name=merchant.name,
                                   offer=detail.offer,
                                   fee=detail.fee,
                                   cost=detail.cost,
                                   profit=detail.profit)
        deliver_info = None
        if entry.channel_id:
            proxy_entry = ChannelConfig.query_by_channel_id(entry.channel_id)
            channel_enum = proxy_entry.channel_enum

            deliver_info = dict(channel_name=channel_enum.desc,
                                mch_id=channel_enum.conf['mch_id'],
                                channel_tx_id=entry.channel_tx_id)
        user_info = dict(
            user_id=entry.uid,
            ip=detail.ip,
            location=GeoIpKit(detail.ip).location,
            device="",
        )

        event_entries = OrderEvent.query_model(
            query_fields=dict(order_id=entry.order_id), date=entry.create_time)

        event_log_list = list()

        for event in event_entries:
            order_event = event.data_after[0]
            order_event.update(event.data_after[1])

            if 'state' in order_event:
                state = list(order_event['state'].keys())[0]
                event_log_list.append(
                    dict(
                        operate_type=OrderStateEnum.from_name(
                            state).get_back_desc(PayTypeEnum.DEPOSIT),
                        operator=order_event.get('op_account') or '',
                        result="成功",
                        operate_time=DateTimeKit.timestamp_to_datetime(
                            order_event['update_time']),
                        comment=order_event.get('comment') or '',
                    ))

            if 'deliver' in order_event:
                deliver = list(order_event['deliver'].keys())[0]
                event_log_list.append(
                    dict(
                        operate_type=DeliverStateEnum.from_name(deliver).desc,
                        operator=order_event.get('op_account') or '',
                        result="成功",
                        operate_time=DateTimeKit.timestamp_to_datetime(
                            order_event['update_time']),
                        comment=order_event.get('comment') or '',
                    ))

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

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

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

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

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

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

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

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

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

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

        cls.do_notify(order)

        return True
예제 #12
0
 def get_deposit_channel2(cls):
     return ChannelConfig.query_latest_one(query_fields=dict(
         channel_enum=cls.channel_enum2))
예제 #13
0
    def init_channel2(cls):
        if not cls.get_deposit_channel2():
            # 充值通道配置
            kwargs = dict(fee="2.5",
                          fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                          limit_per_min="500",
                          limit_per_max="20000",
                          trade_begin_hour="0",
                          trade_begin_minute="0",
                          trade_end_hour="0",
                          trade_end_minute="0",
                          maintain_begin=DateTimeKit.str_to_datetime(
                              "2019-09-07 09:00:00"),
                          maintain_end=DateTimeKit.str_to_datetime(
                              "2019-09-07 09:00:00"),
                          settlement_type=SettleTypeEnum.D0,
                          state=ChannelStateEnum.TESTING
                          if cls.merchant.is_test else ChannelStateEnum.ONLINE,
                          priority="101")

            ChannelConfig.update_channel(cls.channel_enum2, **kwargs)
            channel_config = ChannelConfig.query_latest_one(query_fields=dict(
                channel_enum=cls.channel_enum2))
            # print(channel_config)

            # limit_min, limit_max = ChannelLimitCacheCtl(PayTypeEnum.DEPOSIT).get_channel_limit()
            limit_min, limit_max = ChannelListHelper.get_channel_limit_range(
                merchant=cls.merchant,
                payment_way=PayTypeEnum.DEPOSIT,
            )
            # print('limit_min: %s, limit_max: %s' % (limit_min, limit_max))
            assert 0 != limit_min
            assert 0 != limit_max

        if not cls.get_withdraw_channel2():
            # 提款代付通道配置
            withdraw_item = dict(
                fee="1.3",
                fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER,
                limit_per_min="300",
                limit_per_max="10000",
                limit_day_max="500000",
                trade_begin_hour="0",
                trade_begin_minute="0",
                trade_end_hour="0",
                trade_end_minute="0",
                maintain_begin=DateTimeKit.str_to_datetime(
                    "2019-09-07 09:00:00"),
                maintain_end=DateTimeKit.str_to_datetime(
                    "2019-09-07 09:00:00"),
                state=ChannelStateEnum.TESTING
                if cls.merchant.is_test else ChannelStateEnum.ONLINE,
                banks=[
                    PaymentBankEnum.ZHONGGUO,
                    PaymentBankEnum.GONGSHANG,
                    PaymentBankEnum.JIANSHE,
                ])
            ProxyChannelConfig.update_channel(cls.channel_enum2,
                                              **withdraw_item)

            channel_config = ProxyChannelConfig.query_latest_one(
                query_fields=dict(channel_enum=cls.channel_enum2))
            # print(channel_config)

            # limit_min, limit_max = ChannelLimitCacheCtl(PayTypeEnum.WITHDRAW).get_channel_limit()
            limit_min, limit_max = ChannelListHelper.get_channel_limit_range(
                merchant=cls.merchant,
                payment_way=PayTypeEnum.WITHDRAW,
            )
            # print('limit_min: %s, limit_max: %s' % (limit_min, limit_max))
            assert 0 != limit_min
            assert 0 != limit_max
예제 #14
0
    def post(self):
        """
        手动补单
        :return:
        """
        form, error = CreateDepositOrderForm().request_validate()
        if error:
            return error.as_response()
        '''
        根据商户查询用户是否存在
        构造数据
        创建充值订单
        更改订单状态为完成
        '''
        # 根据商户查询用户是否存在
        user = User.query_user(form.merchant.data, uid=form.uid.data)
        if not user:
            return AccountNotExistError().as_response()

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

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

        merchant = form.merchant.data

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

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

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

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

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

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

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

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

        return ResponseSuccess().as_response()
예제 #15
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)
예제 #16
0
    def order_create(cls,
                     user,
                     amount,
                     channel_enum,
                     client_ip,
                     source: OrderSourceEnum,
                     in_type: InterfaceTypeEnum,
                     notify_url=None,
                     result_url=None,
                     mch_tx_id=None,
                     extra=None):
        """
        申请创建订单
        :return:
        """
        merchant = user.merchant

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

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

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

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

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

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

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

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

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

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

        if not order:
            return None, PreOrderCreateError()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.path = "/user/balance/get"
        response = self.do_request()
        print(response.json)
        self.assertEqual(ResponseUserBalance.code, response.status_code)
        self.assertEqual(ResponseUserBalance.error_code,
                         response.json['error_code'])
예제 #18
0
 def get_config_channels(cls, payment_way: PayTypeEnum, ret_dict=False):
     if payment_way == PayTypeEnum.DEPOSIT:
         return ChannelConfig.get_latest_active_configs(ret_dict)
     else:
         return ProxyChannelConfig.get_latest_active_configs(ret_dict)
예제 #19
0
    def __add_event(self, uid, merchant, channel_enum, order_type):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        stop = 1
예제 #21
0
    def post(self):
        if not EnvironEnum.is_local_evn(current_app.config['FLASK_ENV']):
            # 无论如何都记录一条log
            current_app.logger.info(
                'zhuanyifu deposit callback, ip: %s, data: %s, headers: %s',
                IpKit.get_remote_ip(), request.json, request.headers)
        event = request.headers.get('ChinaRailway-Event')
        signature = request.headers.get('ChinaRailway-Signature')
        form, error = ZhuanYeFuWithdrawForm().request_validate()
        if error:
            current_app.logger.fatal('msg: %s, data: %s', error.message,
                                     request.args)
            return BaseResponse('FAIlURE')

        client_ip = form.client_ip.data
        tx_amount = Decimal(form.amount.data)
        fee = Decimal(form.fee.data)
        channel_tx_id = form.transaction.data

        # if not CallbackZYF.check_ip(client_ip):
        #     current_app.logger.fatal('ip not allow, client_ip: %s, data: %s, body: %s', client_ip, request.args,
        #                              request.json)
        #     return ResponseSuccess(code=500, message='ip not allow').as_response()

        pp = signature.split('.')
        if event != "Charge.Succeeded":
            return ResponseSuccess(code=500).as_response()

        order = DepositTransactionCtl.get_order(form.order.data)
        if not order:
            return ResponseSuccess(
                code=500, message='curr order no found').as_response()

        curr_status = order.state
        if curr_status != OrderStateEnum.INIT:
            return ResponseSuccess(
                code=500,
                message='curr order status must be DEALING').as_response()

        channel_config = ChannelConfig.query_by_channel_id(order.channel_id)
        # 检查通道手续费与系统计算出的手续费
        channel_cost = FeeCalculator.calc_cost(order.amount,
                                               channel_config.fee_type,
                                               channel_config.fee)
        if Decimal(fee) != channel_cost:
            current_app.logger.error(
                "ZYF deposit fee info order_id:{}, channel_fee: {}, channel_cost:{}"
                .format(order.order_id, Decimal(fee), channel_cost))
        flag = CallbackZYF.check_sign(pp=pp, channel_config=channel_config)
        if not flag:
            current_app.logger.fatal(
                'invalid sign, client_ip: %s, data: %s, body: %s', client_ip,
                request.args, request.json)
            return ResponseSuccess(code=500, message='签名错误').as_response()

        status = form.status.data

        if str(status) == '1':
            if not DepositTransactionCtl.success_order_process(
                    order, tx_amount, channel_tx_id, client_ip):
                return ResponseSuccess(code=500,
                                       message='订单状态更新失败').as_response()
            else:
                return ResponseSuccess(code=500, message='签名错误').as_response()

        elif str(status) == '2':
            if not DepositTransactionCtl.failed_order_process(
                    order, tx_amount, channel_tx_id, client_ip):
                return ResponseSuccess(code=500,
                                       message='订单状态更新失败').as_response()

        elif str(status) == '0':
            pass

        return ResponseSuccess(code=204).as_response()