예제 #1
0
    def create_order(cls):
        merchant = MerchantEnum.TEST
        order_id = OrderTstGid.generate_order_id()
        create_time = DateTimeKit.get_cur_datetime()

        fields = dict(
            uid=0,
            create_time=create_time,
            update_time=create_time,
            order_id=order_id,
            amount=Decimal("234142.33"),
            mch_tx_id=OrderUtils.generate_mch_tx_id(order_id),
            sys_tx_id=OrderUtils.generate_sys_tx_id(order_id),
            source=OrderSourceEnum.MANUALLY,
            state=OrderStateEnum.INIT,
            op_account='test',
            pay_method=PayMethodEnum.ZHIFUBAO_SAOMA,
            notify_url="https://google.com",
            result_url="https://google.com",
            extra=json.dumps(dict(x=1, y=2, z=3)),
        )

        rst = cls.add_model(fields,
                            merchant=merchant,
                            date=create_time,
                            commit=True)
        return rst
예제 #2
0
    def create_order_event(
            cls,
            uid,
            amount,
            merchant: MerchantEnum,
            source: OrderSourceEnum,  # 订单来源
            order_type: PayTypeEnum,  # 订单类型
            in_type: InterfaceTypeEnum,  # 商户接入类型
            pay_method: PayMethodEnum = None,  # 支付方法
            create_time=None,
            bank_id=None,  # 用户提现银行卡ID
            ref_id=None,  # 票据ID
            op_account=None,  # 后台管理员账号,后台人工修改数据时必填
            comment=None,  # 管理后台修改备注,后台人工修改数据时必填
            mch_tx_id=None,  # 商户交易ID,当in_type为API时必填,其它时候选填
            channel_id: int = None,  # 通道费率ID,ABSChannelConfig 表中的主键ID,充值必填,提款不填
            mch_fee_id: int = None,  # 商户费率配置ID,MerchantFeeConfig 表的主键ID,充值必填,提款不填
            ip=None,
            fee=None,  # 提现订单,创建的时候就扣了手续费
            notify_url=None,
            result_url=None,
            extra=None,
            bank_info=None,  # 银行卡信息,用于API商户
            cost_type=None,
            commit=True,  # 是否立即提交事务
    ):
        if source == OrderSourceEnum.MANUALLY and not (op_account and comment):
            raise RuntimeError("人工修改订单必填管理员账号和备注")

        if in_type == InterfaceTypeEnum.API and not mch_tx_id:
            raise RuntimeError("开放API必须提供商户交易ID")

        if order_type == PayTypeEnum.DEPOSIT and not (channel_id and mch_fee_id):
            raise RuntimeError("充值必须填写channel_id/mch_fee_id/bank_id")

        if order_type == PayTypeEnum.WITHDRAW:
            if not (fee and mch_fee_id):
                raise RuntimeError("提现必须填写 fee/mch_fee_id")
            if not (bank_info or bank_id):
                raise RuntimeError("提现必须填写 bank_info 或 bank_id")

        create_time = create_time or DateTimeKit.get_cur_datetime()
        order_id = GlobalOrderId.generate_order_id(uid, order_type, create_time, merchant)
        sys_tx_id = OrderUtils.generate_sys_tx_id(order_id)

        if not mch_tx_id:
            mch_tx_id = OrderUtils.generate_mch_tx_id(order_id)

        params = copy.deepcopy(locals())
        params.pop('cls')

        if not ref_id:
            ref_id = OrderConstraint.apply_ref_id(order_id, order_type, OrderStateEnum.INIT)
            if not ref_id:
                return None, ''
            params['ref_id'] = ref_id

        try:
            # 订单模型
            rst, fields = cls.__create_order(**params)
            if rst['code'] != 0:
                OrderConstraint.revoke_order_state(order_id, OrderStateEnum.INIT)
                current_app.logger.error('failed to create order model, rst: %s, params: %s', rst, params)
                return None, ref_id

            models = list(rst['model'].values())
            order = rst['model']['hot']

            # 订单详情
            rst, fields = cls.__create_order_detail(**params)
            if rst['code'] != 0:
                OrderConstraint.revoke_order_state(order_id, OrderStateEnum.INIT)
                current_app.logger.error('failed to create order detail model, rst: %s, params: %s', rst, params)
                return None, ref_id

            models.extend(rst['model'].values())
            order_detail = rst['model']['hot']

            # 订单修改事件
            rst = cls.__create_event(**params)
            order_event = rst['model']
            order_event.data_after = [order.get_after_fields(), order_detail.get_after_fields()]
            models.append(order_event)

            # 提交事务
            assert len(models) == 5
            ModelOpMix.commit_models(models=models, commit=commit)

        except IntegrityError as e:
            OrderConstraint.revoke_order_state(order_id, OrderStateEnum.INIT)
            # sqlalchemy.exc.IntegrityError: (pymysql.err.IntegrityError) (1062, "Duplicate entry '4155' for key 'mch_tx_id'")
            msg = str(e)
            if 'Duplicate' in msg and 'mch_tx_id' in msg:
                # 订单号重复时不能重置订单状态
                msg = "商户订单号重复"
            current_app.logger.error(str(msg), exc_info=True)
            raise Exception(msg)

        except Exception as e:
            # 任何非期望的异常都要回滚状态
            OrderConstraint.revoke_order_state(order_id, OrderStateEnum.INIT)
            current_app.logger.error(str(e), exc_info=True)
            raise e

        return order, ref_id
예제 #3
0
파일: demo.py 프로젝트: LyanJin/check-pay
    def post(self):

        merchant = MerchantEnum.TEST_API
        amount = Decimal(request.form['amount'])

        domain = MerchantDomainConfig.get_latest_domain(merchant)

        # 模拟商户发起支付请求
        scheme_host = UrlKit.get_scheme_host(host=domain)
        url = scheme_host + url_for('gateway_deposit_request')

        if not request.form['payment_type']:
            return redirect(
                scheme_host +
                url_for('gateway_demo_merchant_deposit', error="请选择支付类型"))

        payment_type = PaymentTypeEnum.from_name(request.form['payment_type'])

        # 模拟商户的回调URL
        notify_url = UrlKit.join_host_path(url_for('gateway_demo_notify'),
                                           host=domain)

        post_data = dict(
            merchant_id=merchant.value,
            amount=str(amount),
            mch_tx_id=OrderUtils.generate_mch_tx_id(
                DateTimeKit.get_cur_timestamp()),
            payment_type=payment_type.name,
            notify_url=notify_url,
            user_ip=IpKit.get_remote_ip(),
        )
        print('post_data:', post_data)

        post_data['sign'] = GatewaySign(merchant).generate_sign(post_data)
        post_data['redirect_url'] = "https://google.com"
        post_data['extra'] = json.dumps(dict(x=1, y=2))
        post_data['user_id'] = "100"

        print('post_data:', post_data)

        rsp = requests.post(url, json=post_data)
        if rsp.status_code != 200:
            return redirect(scheme_host +
                            url_for('gateway_demo_merchant_deposit',
                                    error="http请求失败,状态码:%s, url: %s" %
                                    (rsp.status_code, url)))

        if rsp.json()['error_code'] != 200:
            return redirect(scheme_host + url_for(
                'gateway_demo_merchant_deposit', error=rsp.json()['message']))

        sys_tx_id = rsp.json()['data']['sys_tx_id']

        return redirect(scheme_host + url_for(
            'gateway_demo_merchant_deposit',
            success=True,
            post_data=json.dumps(post_data),
            notify_url=scheme_host +
            url_for('demo_deposit_notify', tx_id=sys_tx_id),
            redirect_url=rsp.json()['data']['redirect_url'],
            sys_tx_id=sys_tx_id,
            mch_tx_id=rsp.json()['data']['mch_tx_id'],
            valid_time=rsp.json()['data']['valid_time'],
        ))
예제 #4
0
파일: demo.py 프로젝트: LyanJin/check-pay
    def post(self):

        merchant = MerchantEnum.TEST_API
        amount = Decimal(request.form['amount'])

        domain = MerchantDomainConfig.get_latest_domain(merchant)
        # 模拟商户发起支付请求
        scheme_host = UrlKit.get_scheme_host(host=domain)
        url = scheme_host + url_for('gateway_withdraw_request')

        if not request.form['bank_type']:
            return redirect(
                scheme_host +
                url_for('gateway_demo_merchant_withdraw', error="必选选择银行类型"))

        bank_type = PaymentBankEnum.from_name(request.form['bank_type'])

        # 模拟商户的回调URL
        notify_url = UrlKit.join_host_path(url_for('gateway_demo_notify'),
                                           host=domain)

        post_data = dict(
            merchant_id=merchant.value,
            amount=str(amount),
            mch_tx_id=OrderUtils.generate_mch_tx_id(
                DateTimeKit.get_cur_timestamp()),
            bank_type=bank_type.name,
            notify_url=notify_url,
            card_no=request.form['card_no'],
            account_name=request.form['account_name'],
            province=request.form['province'],
            city=request.form['city'],
            user_ip=IpKit.get_remote_ip(),
        )
        print('post_data:', post_data)

        post_data['sign'] = GatewaySign(merchant).generate_sign(post_data)
        post_data['extra'] = json.dumps(dict(x=1, y=2))
        post_data['user_id'] = "100"
        post_data['branch'] = request.form['branch']

        print('post_data:', post_data)

        rsp = requests.post(url, json=post_data)
        if rsp.status_code != 200:
            return redirect(scheme_host +
                            url_for('gateway_demo_merchant_withdraw',
                                    error="http请求失败,状态码:%s, url: %s" %
                                    (rsp.status_code, url)))

        if rsp.json()['error_code'] != 200:
            return redirect(scheme_host + url_for(
                'gateway_demo_merchant_withdraw', error=rsp.json()['message']))

        sys_tx_id = rsp.json()['data']['sys_tx_id']

        return redirect(scheme_host + url_for(
            'gateway_demo_merchant_withdraw',
            success=True,
            post_data=json.dumps(post_data),
            notify_url=scheme_host +
            url_for('demo_withdraw_notify', tx_id=sys_tx_id),
            sys_tx_id=sys_tx_id,
            mch_tx_id=rsp.json()['data']['mch_tx_id'],
        ))