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