Ejemplo n.º 1
0
def current(user_id=None):

    json_dict = {
        "ret": 0,
        "message": "",
        "data": {
            "pay_channel": pay_config['pay_channel'],
            "user_info": {},
            "user_id": user_id
        }
    }

    if user_id == 'DEFAULT' or user_id is None or len(str(user_id)) == 0:
        json_dict['message'] = "未登录用户"
        json_dict['user_id'] = user_id
        return display_json(json_dict)
    rels = RedEnvelopeSql()

    # 是支付宝支付的,返回支付宝绑定
    if pay_config['pay_channel'] == 'alipay':
        user_info = rels.get_user_pay_alipay_account(user_id=user_id)
        if user_info['id'] is None:
            json_dict['message'] = "该用户未绑定支付宝"
            return display_json(json_dict)
        else:
            del user_info['id']
    json_dict['ret'] = 1
    json_dict['data']['user_info'] = user_info
    return display_json(json_dict)
Ejemplo n.º 2
0
    def __init__(self, **params):
        self._rels = RedEnvelopeSql()
        # order_list 表的相关字段
        self._table_fields = [
            "id", "order_type", "pay_channel", "pay_account", "credit",
            "remain_credit", "refund_credit", "order_no", "order_line",
            "refund_order_line", "pay_order_no", "pay_order_line", "state",
            "order_comments", "create_time", "pay_time", "cancel_time",
            "refund_time", "aid"
        ]
        # 初始化 将本地的字段 置空
        self.aid = None
        names = self.__dict__
        for k in self._table_fields:
            if k in params.keys():
                names[k] = params[k]
            else:
                names[k] = ""
        # 订单初始化必须剩余金额一至
        names['remain_credit'] = names['credit']
        if str(self.state) == "":
            self.state = "unpay"
        # 处理id 预处理变量 放最后处理, 会覆盖变量
        if "id" in params.keys():
            if type(params['id']) is not int or params['id'] <= 0:
                # id的格式错误
                self.write_info_log(
                    "订单id%s:2001:%s" %
                    (str(params['id']), str(self.error_code['2001'])))
                raise Exception("2001")
            self.write_info_log("订单id%s:初始化" % str(params['id']))
            info = self.get_order_info(order_id=params['id'])

            if 'id' not in info.keys() or str(info['id']) != str(params['id']):
                # 订单不存在
                self.write_info_log(
                    "订单id%s:2001:%s" %
                    (str(params['id']), self.error_code['2001']))
                raise Exception("2001")
            # 重写 所有的变量值
            names = self.__dict__
            for k in info:
                names[k] = info[k]

            self.write_info_log(
                "订单id%s:所有订单信息:%s" %
                (str(params['id']), json.dumps(info, ensure_ascii=False)))
Ejemplo n.º 3
0
def current(user_id=None):

    json_dict = {"ret": 0, "message": "", "error_ext": "", "data": {}}
    if user_id == 'DEFAULT' or user_id is None or len(str(user_id)) == 0:
        json_dict['message'] = "未登录用户"
        json_dict['user_id'] = user_id
        return display_json(json_dict)

    if pay_config['pay_channel'] != 'alipay':
        json_dict['message'] = "用户不能绑定支付宝"
        json_dict['data']['ext'] = pay_config['pay_channel']
        return display_json(json_dict)

    # 本页面 必要参数
    current_params = {"account": None}
    # 获取本页面必要参数
    current_params = get_request_need_args(**current_params)

    current_params['account'] = current_params['account'].strip()

    # 授权的用户id
    if len(current_params['account']) < 4:
        json_dict['message'] = "支付宝uid错误"
        return display_json(json_dict)

    rels = RedEnvelopeSql()
    # 如果可以,判断 帐户是否是已被使用

    if rels.get_alipay_account_is_bind(
            user_id=user_id, alipay_login_account=current_params['account']):
        json_dict['message'] = "该支付帐户已绑定其他用户"
        return display_json(json_dict)

    # 如果未被使用入库 返回结果
    res = rels.bind_pay_alipay_account(
        user_id=user_id, alipay_login_account=current_params['account'])
    if res is True:
        json_dict['ret'] = 1
        json_dict['message'] = "绑定成功"
    else:
        json_dict['message'] = "绑定失功"

    return display_json(json_dict)
def current(user_id=None):
    json_dict = {"ret": 0, "message": "", "error_code": 0, "error_ext": "",  "data": {'list': [], 'count': {}}}
    # rels.host_id
    rels = RedEnvelopeSql()

    current_params = {
        # 当前页数
        "page": 1,
        # 每页显示数
        "pagesize": 5,
        # 要获取的年份
        "year": time.strftime("%Y"),
        # 是否获取汇总
        "get_count": 0
    }
    # 获取本页面必要参数
    current_params = get_request_need_args(**current_params)
    current_params['page'] = int(current_params['page'])
    current_params['pagesize'] = int(current_params['pagesize'])
    current_params['year'] = int(current_params['year'])
    current_params['get_count'] = int(current_params['get_count'])

    if current_params['page'] == 0:
        current_params['page'] = 1

    offset = (current_params['page'] - 1)*current_params['pagesize']

    sql_where = {
                 'user_id': user_id,
                 'year': current_params['year'],
                 'next_year': current_params['year']+1,
                 'offset': offset,
                 'pagesize': current_params['pagesize']
                 }

    if current_params['get_count']:
        json_dict['data']['count'] = rels.get_my_send_red_envelope_count(sql_where)

    json_dict['data']['list'] = rels.get_my_send_red_envelope(sql_where)
    json_dict['ret'] = 1
    json_dict['error_code'] = 200
    return display_json(json_dict)
Ejemplo n.º 5
0
class PayOrder:
    error_code = {
        "2001": "订单不存在",
        "2002": "该AA收款订单已存在,请到我的账单里查看",
        "2003": "未找到用户手机号信息",
        "2004": "order表插入失败",
        "2005": "该订单不能进行取消操作",
        "2006": "数据库操作失败",
        "2007": "初始化参数错误",
        "2008": "合并订单至少为2个订单",
        "2009": "合并的订单非订单类实例",
        "2010": "订单不是未支付状态,不能进行合单支付",
        "2011": "不是一个活动的订单不能进行合单支付",
        "2012": "不同类型的订单不能进行合单支付",
        "2013": "不同帐号的订单不能进行合单支付",
        "2100": "支付帐号发生问题",
        "2101": "支付成功后重复回调",
        "2102": "订单已支付",
        "2103": "订单金额出现问题",
        "2104": "订单不能退款",
        "2105": "订单金额超过限额",
        "2106": "不是合单支付不能进行合单退款",
        "2201": "子订单由父订单更新订单状态"
    }
    """
    order_type red_envelope=发红包,return_balance=退款,aa=AA
    pay_channel
    pay_account 支付的帐户 可传可不传, 红包打款需要用到 payee_login_id
    """
    def __init__(self, **params):
        self._rels = RedEnvelopeSql()
        # order_list 表的相关字段
        self._table_fields = [
            "id", "order_type", "pay_channel", "pay_account", "credit",
            "remain_credit", "refund_credit", "order_no", "order_line",
            "refund_order_line", "pay_order_no", "pay_order_line", "state",
            "order_comments", "create_time", "pay_time", "cancel_time",
            "refund_time", "aid"
        ]
        # 初始化 将本地的字段 置空
        self.aid = None
        names = self.__dict__
        for k in self._table_fields:
            if k in params.keys():
                names[k] = params[k]
            else:
                names[k] = ""
        # 订单初始化必须剩余金额一至
        names['remain_credit'] = names['credit']
        if str(self.state) == "":
            self.state = "unpay"
        # 处理id 预处理变量 放最后处理, 会覆盖变量
        if "id" in params.keys():
            if type(params['id']) is not int or params['id'] <= 0:
                # id的格式错误
                self.write_info_log(
                    "订单id%s:2001:%s" %
                    (str(params['id']), str(self.error_code['2001'])))
                raise Exception("2001")
            self.write_info_log("订单id%s:初始化" % str(params['id']))
            info = self.get_order_info(order_id=params['id'])

            if 'id' not in info.keys() or str(info['id']) != str(params['id']):
                # 订单不存在
                self.write_info_log(
                    "订单id%s:2001:%s" %
                    (str(params['id']), self.error_code['2001']))
                raise Exception("2001")
            # 重写 所有的变量值
            names = self.__dict__
            for k in info:
                names[k] = info[k]

            self.write_info_log(
                "订单id%s:所有订单信息:%s" %
                (str(params['id']), json.dumps(info, ensure_ascii=False)))

    """
    获取当日 用户所有发出的红包额度
    """

    def get_user_today_pay_red_envelope(self,
                                        pay_channel=None,
                                        pay_account=None):

        if pay_channel is None:
            pay_channel = self.pay_channel
            pay_account = self.pay_account
        pg_cursor = self._rels.get_pg_dict_cursor()

        sql = """SELECT  coalesce(sum(credit),0.0) as sum FROM public.order_list 
                    where pay_channel =%(pay_channel)s and  pay_account = %(pay_account)s
                    and state = 'pay'  and  order_type = 'red_envelope'  and pay_time::date = current_date
               """
        self.write_info_log("sql:" + sql)
        try:
            pg_cursor.execute(sql, {
                'pay_channel': pay_channel,
                'pay_account': pay_account
            })
            row = pg_cursor.fetchone()
        except Exception as e:
            row = None
            sql_error = str(pg_cursor.query) + " error: " + str(
                e) + ",trace:" + traceback.format_exc()
            self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": self.id
                    },
                    "error_code": 4003,
                    "id": 0,
                    "error_msg": "数据库执行失败",
                    "sql_error": sql_error
                })
        pg_cursor.close()
        return float(row['sum'])

    """
    根据id获取一条订单信息
    """

    def get_order_info(self, order_id):
        pg_cursor = self._rels.get_pg_dict_cursor()
        sql = "select * from public.order_list where id=%(id)s"

        try:
            pg_cursor.execute(sql, {'id': int(order_id)})
            row = pg_cursor.fetchone()
        except Exception as e:
            row = None
            sql_error = str(pg_cursor.query) + " error: " + str(
                e) + ",trace:" + traceback.format_exc()
            self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": self.id
                    },
                    "error_code": 4003,
                    "id": 0,
                    "error_msg": "数据库执行失败",
                    "sql_error": sql_error
                })
        pg_cursor.close()

        info = {}
        for k in self._table_fields:
            info[k] = ""
        if row is not None:
            for k in info:
                if k in [
                        'create_time', 'pay_time', 'cancel_time', 'refund_time'
                ]:
                    # timestamp 格式出来的是date time (Mon, 03 Jun 2019 11:02:24 GMT)需要转换一下格式用于显示
                    if row[k] is not None:
                        info[k] = row[k].strftime("%Y-%m-%d %H:%M:%S")
                elif k in ['credit', 'remain_credit', 'refund_credit']:
                    info[k] = float(row[k])
                else:
                    info[k] = row[k]

        return info

    """
    生成支付订单no
    """

    def generate_order_no(self):
        return "%s_%s_%s" % ("qt", str(
            time.strftime("%Y%m%d%H%M%S")), str(self.get_id()))

    """
    生成订单流水
    """

    def generate_order_line(self):
        return "%s_%s_%s" % ("qtl", str(
            time.strftime("%Y%m%d%H%M%S")), str(self.get_id()))

    """
    生成转帐的订单号
    qts_父订单id_子红包的draw_record_id_抢红包时间
    """

    def generate_sub_red_envelope_order_no(self, sub_red_envelope_id,
                                           draw_time_str):
        return "%s_%s_%s_%s" % ("qts", str(
            self.get_id()), str(sub_red_envelope_id), str(draw_time_str))

    """
        生成退款订单流水号 一个订单 只有一个流水号
    """

    def generate_refund_order_no(self, create_time_str):
        return "%s_%s_%s" % ("qtr", str(self.get_id()), str(create_time_str))

    """
    获取 order_list 表 自增id
    """

    def get_new_order_id(self):
        sql = "select nextval('order_list_id_seq'::regclass) as id"
        pg_cursor = self._rels.get_pg_dict_cursor()

        sql_error = ""
        try:
            pg_cursor.execute(sql)
            row = pg_cursor.fetchone()
        except Exception as e:
            row = None
            sql_error = str(pg_cursor.query) + " error: " + str(
                e) + ",trace:" + traceback.format_exc()
            self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": self.id
                    },
                    "error_code": 4003,
                    "error_msg": "数据库执行失败",
                    "sql_error": sql_error
                })

        pg_cursor.close()
        return row['id'] if row is not None else 0

    def get_id(self):
        return self.id

    def get_credit(self):
        return self.credit

    def get_remain_credit(self):
        return self.remain_credit

    def get_refund_credit(self):
        return self.refund_credit

    def get_pay_time(self):
        return self.pay_time

    def get_order_type(self):
        return self.order_type

    def get_state(self):
        return self.state

    def get_order_no(self):
        return self.order_no

    def get_pay_channel(self):
        return self.pay_channel

    def get_pay_account(self):
        return self.pay_account

    def get_pay_order_no(self):
        return self.pay_order_no

    def get_pay_order_line(self):
        return self.pay_order_line

    """
    创建订单
    """

    def create(self):
        # 获取order表自增id
        order_id = self.get_new_order_id()

        self.write_info_log("订单id%s:创建订单开始:" % (order_id))

        if order_id <= 0:
            return self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": 0
                    },
                    "error_code": 4003,
                    "error_msg": "数据库执行失败",
                    "sql_error": ""
                })
        self_id_tmp = self.id
        self.id = order_id

        order_no = self.generate_order_no()

        sql = """insert into public.order_list (id,order_type,pay_channel,pay_account,credit,remain_credit,order_no,state,order_comments)
                 values (%(id)s,%(order_type)s,%(pay_channel)s,%(pay_account)s,%(credit)s,%(remain_credit)s,%(order_no)s,%(state)s,%(order_comments)s)
              """
        params = {
            "id": order_id,
            "order_type": self.order_type,
            "pay_channel": self.pay_channel,
            "pay_account": self.pay_account,
            "credit": self.credit,
            "remain_credit": self.credit,
            "order_no": order_no,
            "state": self.state,
            "order_comments": self.order_comments
        }

        self.write_info_log("订单id%s:获取参数:%s" %
                            (order_id, json.dumps(params, ensure_ascii=False)))
        pg_cursor = self._rels.get_pg_dict_cursor()

        sql_error = ""
        # execute sql语句只要有错误 就会触发异常
        try:
            pg_cursor.execute(sql, params)
            if self.aid:
                sql = """UPDATE public.order_list SET aid = %(aid)s where id = %(order_id)s"""
                pg_cursor.execute(sql, {"aid": self.aid, "order_id": order_id})
            result = parse_psycopg2_statusmessage(pg_cursor.statusmessage)
            self.write_info_log("订单id%s:生成新订单成功" % order_id)
        except Exception as e:
            self.write_info_log("订单id%s:生成新语句,%s" %
                                (order_id, str(pg_cursor.query)))
            result = str(e)
            sql_error = " error: " + result + ",trace:" + str(
                traceback.format_exc())
        pg_cursor.close()
        # 插入成功返回的是 INSERT 0 1
        # pg_cursor.query 是插入的sql 语句
        if str(result) == "1":
            self.order_no = str(order_no)
            return self.return_result(
                **{
                    "ret": 1,
                    "data": {
                        "id": self.id
                    },
                    "error_code": 200,
                    "error_msg": "",
                    "sql_error": sql_error
                })
        else:
            self.id = self_id_tmp
            return self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": 0
                    },
                    "error_code": 4003,
                    "error_msg": "数据库执行失败",
                    "sql_error": sql_error
                })

    """
    插入订单流水, 用于刚建红包时|红包打款,红包退款 等流水使用
    默认参数使用红包对应订单的,即建红包
    
    op 包含 pay|refund|return_balance
    """

    def insert_order_trace(self, **params):

        if type(params) is not dict:
            params = {}
        params['order_id'] = params['order_id'] if "order_id" in params.keys(
        ) else self.get_id()
        # 订单流水每次都 要生成新的, 回传的时候更新 流水状态
        params['order_line'] = params[
            'order_line'] if "order_line" in params.keys(
            ) else self.generate_order_line()
        params['pay_channel'] = params[
            'pay_channel'] if "pay_channel" in params.keys(
            ) else self.get_pay_channel()
        params['pay_account'] = params[
            'pay_account'] if "pay_account" in params.keys(
            ) else self.get_pay_account()
        params['pay_status'] = params[
            'pay_status'] if "pay_status" in params.keys() else self.get_state(
            )
        params['credit'] = params['credit'] if "credit" in params.keys(
        ) else self.get_credit()
        params['pay_order_no'] = params[
            'pay_order_no'] if "pay_order_no" in params.keys(
            ) else self.get_pay_order_no()
        params['pay_order_line'] = params[
            'pay_order_line'] if "pay_order_line" in params.keys(
            ) else self.get_pay_order_line()

        params['op'] = str(params['op']) if "op" in params.keys() else "pay"
        params['trace_comments'] = params['trace_comments'] if "trace_comments" in params.keys() \
                                                               and type(params['trace_comments']) is dict else {}

        sql = "insert into public.order_trace ("

        # 插入 如果为空的 则会插入失败, 由其是pay_time 一些特殊字段
        for k in params:
            if params[k] is None:
                continue
            sql = sql + k + ","

        sql = sql.strip(",")
        sql = sql + ") values ("

        for k in params:
            if params[k] is None:
                continue
            sql = sql + "%(" + k + ")s,"
        sql = sql.strip(",")
        sql = sql + ")"

        print("插入订单失误 {}".format(params))
        self.write_info_log("订单id{}:插入订单流水:{}".format(
            self.id, json.dumps(params, ensure_ascii=False)))
        pg_cursor = self._rels.get_pg_dict_cursor()

        sql_error = ""
        # execute sql语句只要有错误 就会触发异常
        try:
            pg_cursor.execute(sql, params)
            result = parse_psycopg2_statusmessage(pg_cursor.statusmessage)
            self.write_info_log("订单id%s:生成订单流水成功" % self.id)
        except Exception as e:
            self.write_info_log("订单id%s:生成订单流水失败语句,%s" %
                                (self.id, str(pg_cursor.query)))
            result = str(e)
            sql_error = " error: " + result + ",trace:" + str(
                traceback.format_exc())
        pg_cursor.close()
        # 插入成功返回的是 INSERT 0 1
        # pg_cursor.query 是插入的sql 语句
        if str(result) == "1":
            return self.return_result(
                **{
                    "ret": 1,
                    "data": {
                        "order_line": params['order_line']
                    },
                    "error_code": 200,
                    "error_msg": "",
                    "sql_error": sql_error
                })
        else:
            return self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "order_line": 0
                    },
                    "error_code": 4003,
                    "error_msg": "数据库执行失败",
                    "sql_error": sql_error
                })

    """
    根据流水号获取 order_trace 信息,只获取一条
    """

    def get_order_trace(self, order_line=None):
        if not order_line:
            return False

        sql = """select id, order_id, order_line, pay_channel, pay_account, pay_status, 
       pay_order_no, pay_order_line, credit, op, op_time, trace_comments FROM public.order_trace
                       where order_line=%(order_line)s"""

        pg_cursor = self._rels.get_pg_dict_cursor()
        try:
            pg_cursor.execute(sql, {'order_line': str(order_line)})
            row = pg_cursor.fetchone()
        except Exception as e:
            row = None
            sql_error = str(pg_cursor.query) + " error: " + str(
                e) + ",trace:" + traceback.format_exc()
            self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": self.id
                    },
                    "error_code": 4003,
                    "id": 0,
                    "error_msg": "数据库执行失败",
                    "sql_error": sql_error
                })
        pg_cursor.close()

        if row is None:
            return False

        info = {
            "id": row['id'],
            "order_id": row['order_id'],
            "order_line": row['order_line'],
            "pay_channel": row['pay_channel'],
            "pay_account": row['pay_account'],
            "pay_status": row['pay_status'],
            "pay_order_no": row['pay_order_no'],
            "pay_order_line": row['pay_order_line'],
            "credit": float(row['credit']),
            "op": row['op'],
            "op_time": row['op_time'].strftime("%Y-%m-%d %H:%M:%S"),
            "trace_comments": json.loads(row['trace_comments'])
        }

        return info

    """
    更新流水表支付状态,用于,支付回调, 红包打款,红包退款,打款回调,退款回调
    order_line 支付流水号
    trace_comments 可以是调用支付宝的倾向于部 dict 
    pay_order_no  支付订单号即支付宝的 auth_no
    pay_order_line 支付流水号 即支付宝的 operation_id
    pay_status unpay|pay|return_balance_ing|re_balance_ok|refund_ing|refund_ok
    """

    def update_order_trace(self, order_line, pay_status, pay_order_no,
                           pay_order_line, trace_comments):

        sql = """UPDATE public.order_trace 
                        SET pay_status = %(pay_status)s, 
                        trace_comments = trace_comments || %(trace_comments)s ,
                        pay_order_line=%(pay_order_line)s, pay_order_no=%(pay_order_no)s
                        WHERE order_line = %(order_line)s 
                    """

        if not isinstance(trace_comments, dict):
            trace_comments = {}

        pg_cursor = self._rels.get_pg_dict_cursor()
        try:
            pg_cursor.execute(
                sql, {
                    "order_line": order_line,
                    "pay_status": pay_status,
                    "trace_comments": trace_comments,
                    "pay_order_no": pay_order_no,
                    "pay_order_line": pay_order_line
                })
            result = parse_psycopg2_statusmessage(pg_cursor.statusmessage)
            self.write_info_log("order_line%s:更新订单流水成功" % order_line)
        except Exception as e:

            self.write_info_log("order_line%s:更新订单流水失败语句,%s,error:%s" %
                                (self.id, str(pg_cursor.query), str(e)))

        pg_cursor.close()
        return True if str(result) == "1" else False

    """
    返回结果格式化的结果
    """

    def return_result(self, **params):
        if type(params) is not dict:
            params = dict()
        ret = int(params['ret']) if 'ret' in params.keys() else 0
        data = params['data'] if 'data' in params.keys() else dict()
        error_code = int(
            params['error_code']) if 'error_code' in params.keys() else 0
        error_msg = params['error_msg'] if 'error_msg' in params.keys() else ""
        sql_error = params['sql_error'] if 'sql_error' in params.keys() else ""

        if len(sql_error) > 0:
            self._rels.write_error_log(
                log_type="order_list",
                message=
                """ret:%s,data:%s,error_code:%s,error_msg:%s,sql_error:%s""" %
                (str(ret), str(data), str(error_code), str(error_msg),
                 str(sql_error)))
        else:
            self.write_info_log(json.dumps(params, ensure_ascii=False))
        return {
            "ret": ret,
            "data": data,
            "error_code": error_code,
            "error_msg": error_msg
        }

    """
    写日志
    """

    def write_info_log(self, message):
        self._rels.write_info_log(log_type="order_list", message=message)
Ejemplo n.º 6
0
def pay_success():
    current_args = RequestUtil.get_request_args(request)
    logger = configure_logger("pay_success")
    logger.info("支付回调接口参数:" + json.dumps(current_args))

    # 测试的时候暂不验签
    pa = PayAlipay()
    status = pa.check_sign(**current_args)
    if not status:
        logger.info("验签失败")
        return "fail"

    # 商家的appid
    app_id = current_args['app_id']

    if app_id != pay_config['appId']:
        logger.info("appid校验失败")
        return "fail"
    # 如果不是支付回调  直接返回fail
    if current_args['msg_method'] != 'alipay.fund.trans.order.changed':
        logger.info("msg_method 不是 alipay.fund.trans.order.changed")
        return "fail"

    current_args = json.loads(current_args['biz_content'])
    '''
        {
        "action_type": "FINISH",
        "biz_scene": "PERSONAL_PAY",
        "order_id": "20190912110075000006740023648562", #支付宝系统的单据唯一ID
        "origin_interface": "alipay.fund.trans.app.pay", #支付的接口
        "out_biz_no": "qt_20190912162507_298",#商户端的唯一订单号
        "pay_date": "2019-09-12 16:25:15", 
        "pay_fund_order_id": "20190912110075001506740023416000",#支付宝支付资金流水号(转账成功时才返回)
        "product_code": "STD_RED_PACKET",
        "status": "SUCCESS",
        "trans_amount": "0.01"
    }
    '''
    # 只有成功的 才进行下一部
    if current_args['status'] != 'SUCCESS':
        logger.info("本次status:%s ,直接返回success" % current_args['status'])
        return "success"

    # 支付宝交易号
    pay_order_no = current_args['order_id']
    pay_order_line = current_args['pay_fund_order_id']
    # 商家唯一订单号
    out_order_no = current_args['out_biz_no']

    # 支付金额
    amount = float(current_args['trans_amount'])

    # 付款时间
    gmt_payment = current_args['pay_date']

    red_instance = RedEnvelopeSql()
    conn = red_instance.get_pg_conn()
    pg_cursor = red_instance.get_pg_dict_cursor()
    sql = "Select id,state,order_type,credit from public.order_list where order_no=%s"
    try:
        pg_cursor.execute(sql, (out_order_no,))
        row = pg_cursor.fetchone()
        conn.commit()
    except Exception as e:
        pg_cursor.close()
        logger.info("订单号order_no为:%s,数据库执行失败" % out_order_no)
        return "fail"

    if not row:
        pg_cursor.close()
        logger.info("订单未查找成功,订单号order_no为%s" % out_order_no)
        return "fail"

    if row['state'] != 'unpay':
        pg_cursor.close()
        logger.info("订单未查找成功,订单号order_no为%s;订单状态为%s,不在进行操作" % (out_order_no, row['state']))

        if row['state'] == 'pay':
            return "success"
        return "fail"

    if row['order_type'] != 'red_envelope' and row['order_type'] != 'all_average':
        pg_cursor.close()
        logger.info("订单未查找成功,订单号order_no为%s;订单状态为%s,order_type:%s;直接退出" % (out_order_no, row['order_type']))
        return "fail"

    if amount != float(row['credit']):
        pg_cursor.close()
        logger.info("支付金额与订单金额不符,支付金额 %s  VS  订单金额 %s" % (amount, row['credit']))
        return "fail"

    # 修改订单状态
    # auth_no:pay_order_no
    # out_order_no:order_no
    # operation_id:pay_order_line
    # out_request_no:order_line
    # 插入订单流水

    try:
        order_sql = """Update public.order_list set state='pay', pay_order_no=%(pay_order_no)s,pay_order_line=%(pay_order_line)s, pay_time=%(gmt_payment)s
        where order_no=%(out_order_no)s and state='unpay'"""

        pg_cursor.execute(order_sql,
                          {"pay_order_no": pay_order_no, "pay_order_line": pay_order_line, "gmt_payment": gmt_payment,
                           "out_order_no": out_order_no})
        if 0 == parse_psycopg2_statusmessage(pg_cursor.statusmessage):
            pg_cursor.close()
            logger.info("订单未查找成功,订单号order_no为%s;更新失败" % out_order_no)
            return "fail"
        conn.commit()
    except Exception as e:
        pg_cursor.close()
        logger.info("订单号order_no为%s;更新成为pay状态失败" % out_order_no)
        return "fail"

    pay_order = PayOrder(id=row['id'])
    order_trace_result = pay_order.insert_order_trace(order_line=out_order_no)

    # 生成小红包
    if row['order_type'] == 'red_envelope':
        try:
            rel = RedEnvelope(order_id=row['id'])
        except Exception as e:
            logger.info("订单号order_no为%s;红包不存在;error_code:%s" % (out_order_no, str(e)))
            return "fail"

        ret = rel.generate_sub_redenv()
        if not ret['ret']:
            return jsonify({"ret": False, "error_msg": "红包生成失败"})

        # 发送红包消息
        params = {"msg_type": "pay_success", "id": rel.id, "group_id": rel.group_chat_id[0]}
        rel.add_qtalk_message_queue(**params)
    elif row['order_type'] == 'all_average':
        try:
            aas = AllAverageSql()
            ret = aas.pay_success_callback(order_no=out_order_no, )
            if not ret:
                print("aa状态数据库更新失败")
                return 'failed'

            pa = PayAlipay()
            payee_info = aas.get_aa_payee(order_no=out_order_no)
            print("获取 支付者信息 {}".format(payee_info))
            order_line = order_trace_result['data']['order_line']
            print("准备支付")
            print("...original order id: {}".format(pay_order.get_pay_order_no()))
            print("...order_no: {}".format(order_line))
            print("...payee_info: {}".format(payee_info))

            disburse_result = pa.disburse(
                order_no=str(order_line),
                original_order_id=str(pay_order.get_pay_order_no()),
                amount=float(row['credit']),
                payee_logon_id=str(payee_info),
                title=pay_config['all_average']['grab_bill_title']
            )
            print("支付返回 {}".format(disburse_result))
            if not disburse_result['ret']:
                print("支付失败, 没有拿到返回, 结果 {}".format(disburse_result))
                # pg_cursor_normal.execute("rollback")
                # message = message_prefix + "\n红包领取转账失败;\n返回结果:%s" % (json.dumps(disburse_result, ensure_ascii=False))
                # 更新order_trace表

                order_trace_result = pay_order.insert_order_trace(**{
                    "order_line": order_line,
                    "op": "return_balance",
                    "credit": float(row['credit']),
                    "pay_order_no": "",
                    "pay_status": "re_balance_faild",
                    'trace_comments': disburse_result
                })
            else:
                order_trace_result = pay_order.insert_order_trace(**{
                    "order_line": order_line,
                    "op": "return_balance",
                    "credit": float(row['credit']),
                    "pay_order_no": disburse_result['order_id'],
                    "pay_status": "re_balance_ok",
                    'trace_comments': disburse_result
                })
            if order_trace_result['ret'] != 1:
                print("插入失败")
                print("\n红包调用支付宝成功,插入order_trace失败,order_line:%s;请检order_list日志" % order_line)
        except Exception as e:
            print(e)
            print(traceback.print_exc())
            print("aa状态更新失败")
            return "failed"
    return "success"
Ejemplo n.º 7
0
def current(user_id=None):
    json_dict = {
        "ret": 0,
        "message": "",
        "error_code": 0,
        "error_ext": "",
        "data": {}
    }

    if user_id == 'DEFAULT' or user_id is None or len(str(user_id)) == 0:
        json_dict['message'] = "未登录用户"
        json_dict['user_id'] = user_id
        return display_json(json_dict)

    # 本页面 必要参数
    """
    公共参数
    action 必须是 open_red_envelope
    group_id 红包所在群id [email protected] 特殊可选 group_id 与user_id 必选其1
    user_id 收红包的人 suozhu.li@ejabhost1

    rid 红包id
    """

    current_params = {
        # 公共参数
        "action": None,
        "group_id": "",
        "user_id": "",
        # 必要参数
        "rid": 0
    }
    # 获取本页面必要参数
    current_params = get_request_need_args(**current_params)

    if current_params['action'] != 'open_red_envelope':
        json_dict['message'] = "参数错误"
        json_dict['error_ext'] = "action"
        return display_json(json_dict)
    if len(current_params['group_id']) < 5 and len(
            current_params['user_id']) < 3:
        json_dict['message'] = "参数错误"
        json_dict['error_ext'] = "group_id|user_id特殊可选"
        return display_json(json_dict)

    # 验权用
    group_id = current_params['group_id'] if len(
        current_params['group_id']) > 0 else current_params['user_id']

    if not is_int(current_params['rid']):
        # 红包不存在
        json_dict['error_code'] = 4002
        json_dict['error_ext'] = "id"
        json_dict['message'] = "参数错误"
        return display_json(json_dict)

    current_params['rid'] = int(current_params['rid'])
    rels = RedEnvelopeSql()

    user_info = rels.get_user_pay_alipay_account(user_id=user_id)
    if user_info['id'] is None:
        # 红包不存在
        json_dict['error_code'] = 4300
        json_dict['error_ext'] = "user"
        json_dict['message'] = "用户未绑定支付宝"
        return display_json(json_dict)

    try:
        rel = RedEnvelope()
        red_info = rel.get_red_info_from_cacheordb(current_params['rid'])

        if red_info is None:
            # 红包不存在
            json_dict['error_code'] = 4002
            json_dict['message'] = rel.error_code['4002']
            return display_json(json_dict)
        """
            是否有权拆红包 has_power
            是否已过期 is_expired
            是否抢光 is_out
            自已是否抢过 is_grab

            是否能拆 
        """
        if not rel.check_power(group_id, red_info['group_chat_id']):
            # 无权抢红包
            json_dict['error_code'] = 4022
            json_dict['message'] = rel.error_code['4022']
            return display_json(json_dict)

        grab_count = rel.get_day_grab_count(
            host_id=red_info['host_id'],
            send_user_id=red_info['user_id'],
            grab_user_id=current_params['user_id'])

        red_info['status'] = {}
        red_info['status']['today_has_power'] = False
        if grab_count < pay_config['red_envelope']['grab_c2c_day_max_number']:
            red_info['status']['today_has_power'] = True
        red_info['status']['is_expired'] = rel.check_expired(
            red_info['expire_time'])
        red_info['status']['is_out'] = rel.check_is_out(current_params['rid'])
        red_info['status']['is_grab'] = rel.check_is_grab(
            rels.host_id, user_id, current_params['rid'])
        red_info['status']['has_power'] = False

        if red_info['status']['today_has_power'] and not red_info['status']['is_expired'] \
                and not red_info['status']['is_out'] and not red_info['status']['is_grab']:
            red_info['status']['has_power'] = True
        json_dict['data'] = red_info

        # 不能返回红包的群id,防止窃取 支付信息
        del json_dict['data']['group_chat_id']
        del json_dict['data']['id']
        del json_dict['data']['order_id']

        json_dict['ret'] = 1
        return display_json(json_dict)
    except Exception as e:
        json_dict['error_code'] = str(e)

        if not is_int(json_dict['error_code']):
            rels.write_error_log(
                "red_envelope", "红包id:%s出错%s" %
                (current_params['rid'], json_dict['error_code']))
            json_dict['error_code'] = 0

        json_dict['message'] = "获取红包信息失败"
        json_dict['error_ext'] = ""
        return display_json(json_dict)
Ejemplo n.º 8
0
        user.append({"user": i, "host": r_domain[0]})

    params = {
        "from": "crontab_refund_red_env",
        "fromhost": r_domain[0],
        "to": user,
        "content": msg,
        "extendinfo": ""
    }
    return QtalkMessage.send(1, **params)


r_log.info("开始执行退红包剩余金额脚本~")

pa = PayAlipay()
rels = RedEnvelopeSql()

re = RedEnvelope()
pg_cursor = rels.get_pg_dict_cursor()
redis_cli = rels.get_redis_conn()

# 红包过期时间+5分钟

sql = """SELECT re.id as red_id, re.order_id, re.balance,re.expire_time
            ,to_char(re.create_time,'YYYYMMDDHH24MISS') as create_time_str
            ,ol.pay_channel,ol.pay_account
        FROM public.red_envelope as re
        JOIN public.order_list as ol on re.order_id=ol.id 
        WHERE  re.expire_time < current_timestamp+'-5m'
        and re.draw_number < re.red_number 
        and re.balance>0 
Ejemplo n.º 9
0
def current(user_id=None):
    json_dict = {"ret": 0, "message": "", "error_code": 0, "error_ext": "",
                 "data": {"pay_channel": "", "pay_parmas": "", "rid": 0}}

    if user_id == 'DEFAULT' or user_id is None or len(str(user_id)) == 0:
        json_dict['message'] = "未登录用户"
        json_dict['user_id'] = user_id
        return display_json(json_dict)

    # 本页面 必要参数
    """
    公共参数
    action 必须是 create_red_envelope
    group_id 红包所在群id [email protected] 特殊可选 group_id 与user_id 必选其1
    user_id 收红包的人 suozhu.li@ejabhost1
    红包参数
    number 红包数量
    rtype 红包类型 normal=普通红包|lucky=拼手气红包
    content 红包显示的内容
    """

    current_params = {
            # 公共参数
            "action": None, "group_id": "", "user_id": "",
            # 红包参数
            "number": 0, "credit": 0.00, "rtype": 'normal', "content": ""
            }
    # 获取本页面必要参数
    current_params = get_request_need_args(**current_params)
    if '@' in user_id:
        current_params['host_domain'] = user_id.split('@')[1]
        user_id = user_id.split('@')[0]
    # 创建红包 current_params['user_id'] 会被覆盖成当前登录用户
    rels = RedEnvelopeSql()
    rels.write_error_log("red_envelope", "建红包原始参数:%s" % (json.dumps(current_params)))

    if not is_int(current_params['number']):
        json_dict['error_ext'] = "id"
        json_dict['message'] = "参数错误"
        return display_json(json_dict)

    if not is_float(current_params['credit']):
        json_dict['error_ext'] = "credit"
        json_dict['message'] = "参数错误"
        return display_json(json_dict)

    current_params['number'] = int(current_params['number'])

    current_params['credit'] = decimal_2_float(float(current_params['credit']))

    if current_params['action'] != 'create_red_envelope':
        json_dict['message'] = "参数错误"
        json_dict['error_ext'] = "action"
        return display_json(json_dict)
    if len(current_params['group_id']) < 5 and len(current_params['user_id']) < 3:
        json_dict['message'] = "参数错误"
        json_dict['error_ext'] = "group_id|user_id特殊可选"
        return display_json(json_dict)

    if current_params['number'] < 1 or current_params['number'] > pay_config['red_envelope']['max_number']:
        json_dict['message'] = "红包数量不合法"
        json_dict['error_ext'] = "number"
        return display_json(json_dict)

    if current_params['rtype'] == 'normal':
        current_params['credit'] = decimal_2_float(current_params['number'] * current_params['credit'])
    else:
        current_params['rtype'] == 'lucky'

    if current_params['credit'] < 0.01:
        json_dict['message'] = "红包金额不能小于0.01元"
        json_dict['error_ext'] = "credit"
        return display_json(current_params)

    if current_params['credit'] > pay_config['red_envelope']['max_credit']:
        json_dict['message'] = "单个红包金额不可超过%s元" % (pay_config['red_envelope']['max_credit'])
        json_dict['error_ext'] = "credit"
        json_dict['error_code'] = 4010
        return display_json(json_dict)

    if decimal_2_float(current_params['credit'] / current_params['number']) < 0.01:
        json_dict['message'] = "单个红包金额不可小于0.01元"
        json_dict['error_ext'] = "credit"
        return display_json(json_dict)

    if decimal_2_float(current_params['credit'] / current_params['number']) < 0.01:
        json_dict['message'] = "单个红包金额不可小于0.01元"
        json_dict['error_ext'] = "credit"
        return display_json(json_dict)

    if decimal_2_float(current_params['credit'] / current_params['number']) > pay_config['red_envelope']['single_max_credit']:
        json_dict['message'] = "单个红包金额最大%s 元" % pay_config['red_envelope']['single_max_credit']
        json_dict['error_ext'] = "credit"
        return display_json(json_dict)

    if len(str(current_params['content'])) == 0:
        current_params['content'] = "恭喜发财,大吉大利!"

    if len(str(current_params['content'])) > 30:
        current_params['content'] = str(current_params['content'])[0:30]

    current_params['group_chat_id'] = []
    if len(current_params['group_id']) > 0:
        current_params['group_chat_id'].append(current_params['group_id'])
    if len(current_params['user_id']) > 0:
        current_params['group_chat_id'].append(current_params['user_id'])


    try:
        # 如果是支付宝的取支付宝帐户
        if pay_config['pay_channel'] == "alipay":
            user_pay_info = rels.get_user_pay_alipay_account(user_id)
            pay_account = user_pay_info['alipay_login_account']
            if len(pay_account) == 0:
                json_dict['message'] = "用户没有绑定支付宝帐户"
                json_dict['error_ext'] = "alipay_login_account"
                return display_json(json_dict)
        else:
            # 其他支付方式 在取
            user_pay_info = {""}
            pay_account = ""
            pass

        # 创建订单
        format_order_params = {
            "order_type": "red_envelope",
            "pay_channel": pay_config['pay_channel'],
            "pay_account": pay_account,
            "credit": current_params['credit'],
            "remain_credit": current_params['credit'],
            "create_time": time.strftime("%Y-%m-%d %H:%M:%S"),
            "order_comments": {}
        }
        po = PayOrder(**format_order_params)
        today_pay = po.get_user_today_pay_red_envelope()

        if (today_pay + current_params['credit']) > pay_config['red_envelope']['day_pay_credit_limit']:
            json_dict['message'] = "已达到单日支付限额"
            json_dict['error_ext'] = "credit"
            return display_json(json_dict)

        order_result = po.create()
        if order_result['ret'] != 1:
            json_dict['error_code'] = order_result['error_code']
            json_dict['message'] = "创建红包失败"
            return display_json(order_result)

        # 创建红包
        order_id = order_result["data"]['id']
        order_no = po.get_order_no()
        format_params = {
            "host_id": rels.host_id,
            "user_id": user_id,
            "order_id": order_id,
            "number": current_params['number'],
            "credit": current_params['credit'],
            "balance": current_params['credit'],
            "red_type": current_params['rtype'],
            "red_number": current_params['number'],
            "draw_number": 0,
            "red_content": current_params['content'],
            "group_chat_id": current_params['group_chat_id'],
            "create_time": time.strftime("%Y-%m-%d %H:%M:%S"),
            "expire_time": time.strftime("%Y-%m-%d %H:%M:%S",
                                         time.localtime(time.time() + pay_config['red_envelope']['expiry_time'])),
        }

        rel = RedEnvelope(**format_params)
        red_result = rel.create()

        if red_result['ret'] != 1:
            json_dict['error_code'] = red_result['error_code']
            json_dict['message'] = "创建红包失败"
            return display_json(json_dict)

        red_id = red_result["data"]['id']

        # 缓存红包信息
        rel.cache_red_info(red_id)
        # 有红包id了, 有订单id ,生成订单流水

        trace_result = po.insert_order_trace()

        if trace_result['ret'] != 1:
            json_dict['error_code'] = trace_result['error_code']
            json_dict['message'] = "创建红包失败"
            return display_json(json_dict)
        order_line = trace_result['data']['order_line']
        # 订单流水用于 生成支付链接参数

        # 创建红包成功后 生成支付信息, 订单流水
        if pay_config['pay_channel'] == "alipay":
            pa = PayAlipay()
            pay_params = pa.get_app_pay(order_no=order_no, amount=current_params['credit'],
                                        alipay_uid=pay_account,
                                        title=pay_config['red_envelope']['bill_title'])

            json_dict['ret'] = 1
            json_dict['error_code'] = 200
            json_dict['message'] = "初始化红包成功"
            json_dict['data']['pay_channel'] = pay_config['pay_channel']
            json_dict['data']['pay_parmas'] = pay_params
            json_dict['data']['rid'] = red_id
            return display_json(json_dict)
        else:
            # 其他支付方式 在取
            json_dict['error_code'] = 4023
            json_dict['message'] = "不支持的支付方式"
            return display_json(json_dict)

    except Exception as e:
        json_dict['error_code'] = e
        if not is_int(json_dict['error_code']):
            rels.write_error_log("red_envelope", "红包id:%s出错%s" % (0, json_dict['error_code']))
            json_dict['error_code'] = 0

        json_dict['message'] = "创建红包失败!"
        json_dict['error_ext'] = ""
        return display_json(json_dict)
Ejemplo n.º 10
0
from service.red_envelope.crontab_common import RedEnvCrontab

r_log = configure_logger("red_envelope_transfer")

# 判断程序是否正在运行,没有运行打上pid标记
is_run = RedEnvCrontab.crontab_run_begin(__file__)

if is_run:
    r_log.info("is_run")
    sys.exit("程序正在执行")

r_log.info("开始执行红包转账脚本~")

pa = PayAlipay()
rels = RedEnvelopeSql()
pg_cursor = rels.get_pg_dict_cursor()
"""
发送qtalk 消息
"""


def send_error_message(msg):
    user = []
    for i in pay_config['alert_user_id']:
        user.append({"user": i, "host": r_domain[0]})

    params = {
        "from": "crontab_transfer_red_env",
        "fromhost": r_domain[0],
        "to": user,
Ejemplo n.º 11
0
    def __init__(self, **params):
        self._rels = RedEnvelopeSql()
        self._table_fields = [
            "id", "host_id", "user_id", "red_type", "credit", "balance",
            "red_number", "draw_number", "red_content", "order_id",
            "expire_time", "group_chat_id", "create_time", "update_time"
        ]

        self.redis_cli = self._rels.get_redis_conn()
        names = self.__dict__
        for k in self._table_fields:
            names[k] = ""

        # 必须是个字典
        if type(params) is not dict:
            # 传参错误
            self.write_info_log(
                "红包id%s:4009:%s" %
                (str(params['id']), str(self.error_code['4009'])))
            raise Exception('4009')

        # 覆盖传进来的所有充数量值 上边定义的
        names = self.__dict__
        for k in names:
            if k in params.keys():
                names[k] = params[k]

        # 处理id 预处理变量 放最后处理, 会覆盖变量
        id_key = ""
        if "id" in params.keys() and 'user_id' not in params.keys():
            id_key = "id"
        elif "order_id" in params.keys() and 'user_id' not in params.keys():
            id_key = "order_id"

        if id_key:

            if type(params[id_key]) is not int or params[id_key] <= 0:
                # id的格式错误
                self.write_info_log(
                    "红包%s%s:4001:%s" % (id_key, str(
                        params[id_key]), str(self.error_code['4001'])))
                raise Exception("4001")
            self.write_info_log("红包%s%s:初始化" % (id_key, str(params[id_key])))
            if id_key == 'id':
                res = self.get_info(red_id=params['id'])
            else:
                res = self.get_info(order_id=params['order_id'])

            info = res['data']
            if not res['ret'] or not info or info[id_key] != params[id_key]:
                # 红包不存在
                self.write_info_log(
                    "红包%s%s:4002:%s" % (id_key, str(
                        params[id_key]), str(self.error_code['4002'])))
                raise Exception("4002")
            # 重写 所有的变量值
            names = self.__dict__
            for k in info:
                names[k] = info[k]
            self.write_info_log("红包%s%s:所有信息:%s" % (id_key, str(
                params[id_key]), json.dumps(info, ensure_ascii=False)))
Ejemplo n.º 12
0
class RedEnvelope:

    # 错误码
    error_code = {
        "4001": "id的格式错误",
        "4002": "红包不存在",
        "4003": "数据库执行失败",
        "4004": "缓存失败",
        "4005": "红包已过期",
        "4006": "你已领取该红包",
        "4007": "红包已抢光",
        "4008": "未登录",
        "4009": "参数出错",
        "4010": "红包金额不能超过99999",
        "4011": "订单红包已存在",
        "4021": "鉴权失败",
        "4022": "非法访问",
        "4023": "不支持的支付方式",
        "4030": "今日抢同一发送用户红包超限",
        "4300": "用户未绑定支付宝",
    }

    def __init__(self, **params):
        self._rels = RedEnvelopeSql()
        self._table_fields = [
            "id", "host_id", "user_id", "red_type", "credit", "balance",
            "red_number", "draw_number", "red_content", "order_id",
            "expire_time", "group_chat_id", "create_time", "update_time"
        ]

        self.redis_cli = self._rels.get_redis_conn()
        names = self.__dict__
        for k in self._table_fields:
            names[k] = ""

        # 必须是个字典
        if type(params) is not dict:
            # 传参错误
            self.write_info_log(
                "红包id%s:4009:%s" %
                (str(params['id']), str(self.error_code['4009'])))
            raise Exception('4009')

        # 覆盖传进来的所有充数量值 上边定义的
        names = self.__dict__
        for k in names:
            if k in params.keys():
                names[k] = params[k]

        # 处理id 预处理变量 放最后处理, 会覆盖变量
        id_key = ""
        if "id" in params.keys() and 'user_id' not in params.keys():
            id_key = "id"
        elif "order_id" in params.keys() and 'user_id' not in params.keys():
            id_key = "order_id"

        if id_key:

            if type(params[id_key]) is not int or params[id_key] <= 0:
                # id的格式错误
                self.write_info_log(
                    "红包%s%s:4001:%s" % (id_key, str(
                        params[id_key]), str(self.error_code['4001'])))
                raise Exception("4001")
            self.write_info_log("红包%s%s:初始化" % (id_key, str(params[id_key])))
            if id_key == 'id':
                res = self.get_info(red_id=params['id'])
            else:
                res = self.get_info(order_id=params['order_id'])

            info = res['data']
            if not res['ret'] or not info or info[id_key] != params[id_key]:
                # 红包不存在
                self.write_info_log(
                    "红包%s%s:4002:%s" % (id_key, str(
                        params[id_key]), str(self.error_code['4002'])))
                raise Exception("4002")
            # 重写 所有的变量值
            names = self.__dict__
            for k in info:
                names[k] = info[k]
            self.write_info_log("红包%s%s:所有信息:%s" % (id_key, str(
                params[id_key]), json.dumps(info, ensure_ascii=False)))

    """
    获取当天 某用户 抢同一用户的 红包数
    """

    def get_day_grab_count(self, host_id, send_user_id, grab_user_id):

        sql = """SELECT count(1)
                  FROM public.red_envelope_draw_record redr
                       join public.red_envelope as re on redr.red_envelope_id = re.id 
                 where re.host_id = '%s' and re.user_id ='%s' and redr.user_id = '%s' and redr.draw_time::date = current_date
            """ % (host_id, send_user_id, grab_user_id)
        cursor = self._rels.get_pg_dict_cursor()
        try:
            cursor.execute(sql)
            row = cursor.fetchone()
        except Exception as e:
            row = None
            sql_error = str(cursor.query) + " error: " + str(
                e) + ",trace:" + traceback.format_exc()
            return self.return_result(ret=False,
                                      data={"id": self.id},
                                      error_code=4003,
                                      error_msg="数据库执行失败",
                                      sql_error=sql_error)
        finally:
            cursor.close()

        return int(row['count'])

    """
    根据id | order_id 获取一条红包信息
    """

    def get_info(self, red_id: int = None, order_id: int = None):
        cursor = self._rels.get_pg_dict_cursor()

        condition = ' 1=1 '
        if red_id:
            condition += " AND re.id='%d'" % red_id
        elif order_id:
            condition += " AND re.order_id='%d'" % order_id
        else:
            # 直接false 即可
            condition += " AND 1=2 "
        sql = """select 
                    re.*,hu.user_name ,re.user_id || '@' || hi.host as host_user_id,hi.host
                    ,case when re.expire_time< current_timestamp then 1 else 0 end as is_expire
                  ,case when re.red_number= re.draw_number then 1 else 0 end as is_grab_over
                from public.red_envelope as re
                 join public.host_info as hi on hi.id = re.host_id
                left join public.host_users as hu on re.host_id = hu.host_id and re.user_id = hu.user_id
               where %s""" % condition

        try:
            cursor.execute(sql)
            row = cursor.fetchone()
        except Exception as e:
            row = None
            sql_error = str(cursor.query) + " error: " + str(
                e) + ",trace:" + traceback.format_exc()
            return self.return_result(ret=False,
                                      data={"id": self.id},
                                      error_code=4003,
                                      error_msg="数据库执行失败",
                                      sql_error=sql_error)
        finally:
            cursor.close()

        info = {}
        for k in self._table_fields:
            info[k] = ""
        info['host'] = ""
        info['user_name'] = ""
        info['is_expire'] = 0
        info['is_grab_over'] = 0
        info['host_user_id'] = ""

        if row is not None:
            for k in info:
                if k in ['create_time', 'update_time', 'expire_time']:
                    # timestamp 格式出来的是date time (Mon, 03 Jun 2019 11:02:24 GMT)需要转换一下格式用于显示
                    if type(row[k]) is not None:
                        info[k] = row[k].strftime("%Y-%m-%d %H:%M:%S")
                elif k in ["credit", "balance"]:
                    info[k] = float(row[k])
                elif k in [
                        "red_number", "draw_number", "order_id", "id",
                        "host_id"
                ]:
                    info[k] = int(row[k])
                else:
                    info[k] = row[k]

        return self.return_result(ret=True, data=info)

    def generate_sub_redenv(self):
        """生成小红包,以及redis缓存队列"""

        cursor = self._rels.get_pg_dict_cursor()

        balance = Decimal(self.credit)
        # data = []
        ext_sql = ""

        for i in range(self.red_number):
            info = {
                'red_type': self.red_type,
                'red_number': self.red_number,
                'draw_number': i,
                'balance': balance,
                'credit': self.credit
            }
            current_credit = self.get_current_draw_credit(**info)
            balance -= current_credit
            # data.append((self.host_id, self.id, decimal_2_float(current_credit,2)))
            ext_sql += "(%s,%s,%s)," % (self.host_id, self.id,
                                        decimal_2_float(current_credit, 2))

        ext_sql = ext_sql.rstrip(",")
        sql = "Insert into public.red_envelope_draw_record(host_id, red_envelope_id, credit) values " + ext_sql + " Returning id;"
        try:
            cursor.execute(sql)
            result_list = cursor.fetchall()
        except Exception as e:
            sql_error = str(cursor.query) + " error: " + str(
                e) + ",trace:" + traceback.format_exc()
            self.write_info_log("数据库执行失败,详细信息:%s" % (sql_error, ))
            return {"ret": False, "error_msg": "数据库执行失败"}
        finally:
            cursor.close()

        rkey = self.get_redis_key(self.id, "remain_queue")
        pipe = self.redis_cli.pipeline()
        pipe.multi()
        if result_list:
            for sub_rid in result_list:
                pipe.rpush(rkey, sub_rid['id'])
            expire_time = datetime.datetime.strptime(self.expire_time,
                                                     '%Y-%m-%d %H:%M:%S')
            pipe.expireat(rkey, expire_time)
        result = pipe.execute()
        if not result:
            self.write_info_log("生成小红包redis队列失败,红包id为%s" % (self.id, ))
            return {"ret": False, "error_msg": "红包生成失败"}

        return {"ret": True}

    def get_current_draw_credit(self, **kwargs):
        """检查参数合法行"""

        balance = kwargs['balance']
        if isinstance(balance, float):
            balance = Decimal(balance)
        credit = kwargs['credit']
        if isinstance(credit, float):
            credit = Decimal(credit)

        if kwargs['red_number'] <= kwargs['draw_number']:
            return Decimal(0.00)
        else:
            if kwargs['red_type'] == 'lucky':
                remain_number = kwargs['red_number'] - kwargs['draw_number']
                if remain_number == 1:
                    amount = balance
                else:
                    aver = math.floor(balance * 100 / remain_number)
                    amount = random.randint(1, aver * 2 - 1) / 100
            else:
                amount = round(credit / kwargs['red_number'], 2)

            return Decimal(amount)

    """
    获取 redis 缓存的key 主键 
    *命名规范:表名+":"+ 主键值 + "列名"
    red_id = 红包的id
    
    已知子key 
    获取红包相关的 redis key 值
    remain_number  # 剩余红包数 用于发送已领红包消息用 计数器,初始值同 red_number 红包个数, 当抢完发送完qtalk消息时 执行 redis.decr 减1操作
    grab_record  # 抢红包已抢的列表 用于判断自已是否抢了
    remain_queue  # 等抢的小红包队列
    info   # 红包 整体信息 json格式
    
    已知redis key 如下:
    红包组合的 redis key 
    red_envelope:101:info 红包基本信息 
    red_envelope:101:remain_number 红包剩余数量
    red_envelope:101:remain_queue  红包待抢小红包列表
    red_envelope:101:grab_record  红包已抢记录 存储 host_id user_id 
    
    红包相关qtalk 发消息队列
    red_envelope:qtalk_message_queue 消息value json 格式,取出需 json.loads(x, ensure_ascii=False)
     
    """

    def get_redis_key(self, red_id, column=None):
        if not column:
            # 整体红包的key 值
            return "red_envelope:%s" % red_id
        else:
            # 红包下某key 的值
            return "red_envelope:%s:%s" % (red_id, column)

    """
    缓存红包信息
    只有创建红包时才初始化一次
    red_id 红包id
    only_info  是否只更新info信息, 如果为True 则只更新info , 否则更新 剩余红包 
    """

    def cache_red_info(self, red_id: int, only_info=False):
        res = self.get_info(red_id)
        info = res['data']
        if not res['ret'] or not info or str(info['id']) != str(red_id):
            return False

        # 红包基本信息
        red_info_key = self.get_redis_key(red_id=red_id, column="info")

        self.redis_cli.set(red_info_key, json.dumps(info, ensure_ascii=False))

        if not only_info:
            # 剩余红包数 用于发送已领红包消息用
            red_remain_number_key = self.get_redis_key(red_id=red_id,
                                                       column="remain_number")
            self.redis_cli.set(red_remain_number_key, info['red_number'])

            self.redis_cli.expireat(
                red_remain_number_key,
                datetime.datetime.strptime(info['expire_time'],
                                           "%Y-%m-%d %H:%M:%S"))

        # 此处过期时间使用 红包的 过期时间,而不使用 pay_config['red_envelope']['expiry_time']
        self.redis_cli.expireat(
            red_info_key,
            datetime.datetime.strptime(info['expire_time'],
                                       "%Y-%m-%d %H:%M:%S"))

        return True

    """
    获取 红包信息
    """

    def get_red_info_from_cacheordb(self, red_id: int):
        red_cache_key = self.get_redis_key(red_id)
        info = self.redis_cli.hget(red_cache_key, "info")
        if info is not None:
            info = json.loads(info)
        else:
            res = self.get_info(red_id=red_id)
            info = res['data']
            if not res['ret'] or not res['data']:
                return None

        if str(info['id']) != str(red_id):
            return None
        return info

    """
    发红包 ,只生成红包记录
    """

    def create(self):
        self.write_info_log("红包id%s:创建红包初始化;" % self.id)

        if len(str(self.id)) > 0 and str(self.id) != "0":
            # 红包已经存在
            return self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": self.id
                    },
                    "error_code": 4011,
                    "error_msg": self.error_code['4011'],
                    "sql_error": ""
                })

        self_id_tmp = self.id
        # 根据order_id 查找红包是否存在
        red_info_res = self.get_info(order_id=self.order_id)
        red_info = red_info_res['data']
        if red_info_res['ret'] and red_info and str(red_info['id']) != "":
            # 红包已经存在
            return self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": 0
                    },
                    "error_code": 4011,
                    "error_msg": self.error_code['4011'],
                    "sql_error": ""
                })

        sql = """insert into public.red_envelope 
                        (host_id,user_id,red_type,credit,balance,red_number,draw_number,red_content,order_id,expire_time,group_chat_id,create_time)
                         values (%(host_id)s,%(user_id)s,%(red_type)s,%(credit)s,%(balance)s,%(red_number)s,
                         %(draw_number)s,%(red_content)s,%(order_id)s,%(expire_time)s,%(group_chat_id)s,%(create_time)s)
                  RETURNING id
              """
        params = {
            "host_id": self.host_id,
            "user_id": self.user_id,
            "red_type": self.red_type,
            "credit": self.credit,
            "balance": self.balance,
            "red_number": self.red_number,
            "draw_number": self.draw_number,
            "order_id": self.order_id,
            "red_content": self.red_content,
            "expire_time": self.expire_time,
            "group_chat_id": self.group_chat_id,
            "create_time": self.create_time
        }

        self.write_info_log("红包id%s:获取参数:%s" %
                            (self.id, json.dumps(params, ensure_ascii=False)))
        pg_cursor = self._rels.get_pg_dict_cursor()

        sql_error = ""
        # execute sql语句只要有错误 就会触发异常
        try:
            pg_cursor.execute(sql, params)
            row = pg_cursor.fetchone()
            if row is not None:
                self.id = row['id']
            self.write_info_log("红包id%s:生成新红包成功" % (self.id))
        except Exception as e:
            self.write_info_log("订单id%s:生成新语句,%s" %
                                (self.id, str(pg_cursor.query)))
            result = str(e)
            sql_error = " error: " + result + ",trace:" + str(
                traceback.format_exc())
        pg_cursor.close()

        # pg_cursor.query 是插入的sql 语句
        if str(self.id) != "":
            return self.return_result(
                **{
                    "ret": 1,
                    "data": {
                        "id": self.id
                    },
                    "error_code": 200,
                    "error_msg": "",
                    "sql_error": sql_error
                })
        else:
            self.id = self_id_tmp
            return self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": self.id
                    },
                    "error_code": 4003,
                    "error_msg": "数据库执行失败",
                    "sql_error": sql_error
                })

    """
    返回结果格式化的结果
    """

    def return_result(self, **params):
        if type(params) is not dict:
            params = dict()
        ret = int(params['ret']) if 'ret' in params.keys() else 0
        data = params['data'] if 'data' in params.keys() else dict()
        error_code = int(
            params['error_code']) if 'error_code' in params.keys() else 0
        error_msg = params['error_msg'] if 'error_msg' in params.keys() else ""
        sql_error = params['sql_error'] if 'sql_error' in params.keys() else ""

        if len(sql_error) > 0:
            self._rels.write_error_log(
                log_type="red_envelope",
                message=
                """"ret:%s,data:%s,error_code:%s,error_msg:%s,sql_error:%s""" %
                (str(ret), str(data), str(error_code), str(error_msg),
                 str(sql_error)))
        else:
            self.write_info_log(json.dumps(params, ensure_ascii=False))
        return {
            "ret": ret,
            "data": data,
            "error_code": error_code,
            "error_msg": error_msg
        }

    """
    写日志
    """

    def write_info_log(self, message):
        self._rels.write_info_log(log_type="red_envelope", message=message)

    """
    检测 是否有抢红包的权限
    group_id 用户参数 传过来的
    group_chat_id 红包的group_chat_id
    """

    def check_power(self, group_id, group_chat_id):
        if not isinstance(group_chat_id, list):
            return False
        return group_id in group_chat_id

    """
    检测 红包的过期时间是否过期
    expire_time 红包的过期时间 字符串型式
    """

    def check_expired(self, expire_time):
        try:
            et = time.mktime(time.strptime(expire_time, "%Y-%m-%d %H:%M:%S"))
        except Exception as e:
            return True

        return True if et < time.time() else False

    """
    检测 红包是否已抢光
    red_number 红包的数量
    draw_number 已抢的红包数量
    
    写小红包操作
    lkey = rel.get_redis_key("101", "remain_queue")
    redis_cli.rpush(lkey, srid) # srid 即小红包id
    """

    def check_is_out(self, red_id: int):
        #  待抢红包队列
        lkey = self.get_redis_key(red_id, "remain_queue")

        return True if self.redis_cli.llen(lkey) == 0 else False

    """
    自已是否抢过 只有在红包未过期时 才会有, 抢红包时 自动写到缓存中去
    host_id 域id
    user_id 用户id
    red_id 红包id
    """

    def check_is_grab(self, host_id: int, user_id, red_id: int):
        red_cache_key = self.get_redis_key(red_id, column="grab_record")
        cache_column = "%s:%s" % (host_id, user_id)
        info = self.redis_cli.hget(red_cache_key, cache_column)

        return True if info else False

    """
    抢红包成功时 要设置 已抢过的缓存
    host_id 域id
    user_id 用户id
    red_id 抢红包id
    """

    def set_grab_cache(self, host_id: int, user_id, red_id: int):

        red_cache_key = self.get_redis_key(red_id, column="grab_record")
        cache_column = "%s:%s" % (host_id, user_id)
        self.redis_cli.hset(red_cache_key, cache_column,
                            time.strftime("%Y-%m-%d %H:%M:%S"))
        self.redis_cli.expire(red_cache_key,
                              pay_config['red_envelope']['expiry_time'])

    """
    抢红包
    host_id 域id
    user_id 用户id
    red_id 抢红包id
    group_id 当前的群id
    """

    def grab(self, host_id: int, user_id, red_id: int, group_id):

        # 待抢的小红包队列
        lkey = self.get_redis_key(red_id, column="remain_queue")
        log_prefer = "grab:red_id:%s,host_id:%s,user_id:%s,action:" % (
            red_id, host_id, user_id)

        self.write_info_log(log_prefer + "open:begin")
        """
        拆过红包
        """
        if self.check_is_grab(host_id, user_id, red_id):
            self.write_info_log(log_prefer + "open:已经抢过:4006")
            return self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": red_id
                    },
                    "error_code": 4006,
                    "error_msg": self.error_code["4006"],
                    "sql_error": ""
                })

        # 取出未抢小红包队列
        srid = self.redis_cli.lpop(lkey)
        if not srid:
            self.write_info_log(log_prefer + "open:红包已抢光:4007")
            # 红包已抢光
            return self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": red_id
                    },
                    "error_code": 4007,
                    "error_msg": self.error_code["4007"],
                    "sql_error": ""
                })

        # 更新小红包记录 返回id ,以及领取的金额
        sql = """update public.red_envelope_draw_record set
                     host_id = %(host_id)s , user_id = %(user_id)s , draw_time=now()
                 where id = %(srid)s and  red_envelope_id = %(red_envelope_id)s and user_id is null
                 RETURNING id,credit
                 """
        # 更新红包余额, 以及领取数
        re_sql = """ update public.red_envelope re 
                         set draw_number = dr.draw_number ,balance = dr.balance 
                        from (select 
                            sum(case when (user_id is not null)  then 1 else 0 end) as draw_number,
                            sum(case when (user_id is null) then credit else 0.0 end) as balance
                            from public.red_envelope_draw_record
                            where red_envelope_id=%(red_envelope_id)s
                          )as dr
                         where re.id = %(red_envelope_id)s
                """

        # 更新红包余额, 以及领取数

        pg_cursor = self._rels.get_pg_dict_cursor()
        pg_cursor.execute('begin')

        try:

            pg_cursor.execute(
                sql, {
                    "host_id": host_id,
                    "user_id": user_id,
                    "srid": srid,
                    'red_envelope_id': red_id
                })
            draw_record_row = pg_cursor.fetchone()
            # 判断 是否更新成功
            if not draw_record_row or str(draw_record_row['id']) != str(srid):
                # 没有更新,还原小红包,提示报错
                pg_cursor.execute("rollback")

                self.write_info_log(log_prefer +
                                    ("open:更新数据库失败:4003,1恢复小红包队列id:%s" % srid))
                self.redis_cli.rpush(lkey, srid)
                return self.return_result(
                    **{
                        "ret": 0,
                        "data": {
                            "id": red_id
                        },
                        "error_code": 4003,
                        "error_msg": "服务器开小差啦…",
                        "sql_error": ""
                    })

            draw_record_row['credit'] = float(draw_record_row['credit'])

            pg_cursor.execute(re_sql, {'red_envelope_id': red_id})

            if 0 == parse_psycopg2_statusmessage(pg_cursor.statusmessage):
                # 没有更新,还原小红包,提示报错
                pg_cursor.execute("rollback")
                self.write_info_log(log_prefer +
                                    ("open:更新数据库失败:4003,2恢复小红包队列id:%s" % srid))
                self.redis_cli.rpush(lkey, srid)
                return self.return_result(
                    **{
                        "ret": 0,
                        "data": {
                            "id": red_id
                        },
                        "error_code": 4003,
                        "error_msg": "服务器开小差啦……",
                        "sql_error": ""
                    })
            # 主动提交事务
            pg_cursor.execute("commit")
            pg_cursor.close()

            # 加入已抢红包的的列表
            self.set_grab_cache(host_id=host_id,
                                user_id=user_id,
                                red_id=red_id)
            # 更新红包缓存 只更新info表
            self.cache_red_info(red_id=red_id, only_info=True)
            # 加入红包发消息队列
            params = {
                "msg_type": "open_success",
                "id": srid,
                "group_id": group_id
            }
            self.add_qtalk_message_queue(**params)

            return self.return_result(
                **{
                    "ret": 1,
                    "data": {
                        "id": red_id,
                        "srid": int(srid),
                        "credit": draw_record_row['credit']
                    },
                    "error_code": 200,
                    "error_msg": "拆红包成功",
                    "sql_error": ""
                })
        except Exception as e:
            pg_cursor.execute("rollback")
            pg_cursor.close()
            # 没有更新,还原小红包,提示报错
            self.write_info_log(log_prefer +
                                ("open:数据库操作失败:4003,3恢复小红包队列id:%s" % srid))
            self.redis_cli.rpush(lkey, srid)
            return self.return_result(
                **{
                    "ret": 0,
                    "data": {
                        "id": red_id,
                        "srid": int(srid)
                    },
                    "error_code": 4003,
                    "error_msg": "服务器开小差啦~",
                    "sql_error": traceback.format_exc()
                })

    """
    获取红包qtalk 消息队列 redis key 
    """

    def get_qtalk_message_queue_redis_key(self):
        return self.get_redis_key(red_id="qtalk_message_queue")

    """
    红包 填加一条qtalk 消息列表
    msg_type = open_success| pay_success
    id  open_success? red_envelope_draw_record.id 
        pay_success ? red_envelope.id
    group_id 接收方所在的群或用户
    params  = {"group_id": "abcdefff", "id": "5", "msg_type": "open_success"}
    add_qtalk_message_queue(**params)
    """

    def add_qtalk_message_queue(self, **kwargs):
        queue_key = self.get_qtalk_message_queue_redis_key()
        self.redis_cli.rpush(queue_key, json.dumps(kwargs, ensure_ascii=False))

    """
    获取单独抢红包记录
    """

    def get_draw_record_info(self, srid: int):
        sql = """select redr.*,hu.user_name ,hi.host
                            from public.red_envelope_draw_record as redr
                            join public.host_info as hi on hi.id = redr.host_id
                            left join public.host_users as hu on redr.host_id = hu.host_id and redr.user_id = hu.user_id
                         where redr.id = %(id)s order by draw_time desc 
                        """

        pg_cursor = self._rels.get_pg_dict_cursor()

        pg_cursor.execute(sql, {'id': srid})

        row = pg_cursor.fetchone()
        pg_cursor.close()
        if row is None:
            return None

        draw_record = {
            'id': int(row['id']),  # id
            'host': str(row['host']),  # 抢的人域,主要用于发消息
            'host_id': int(row['host_id']),  # 抢的人所在的域
            'user_id': str(row['user_id']),  # 抢的人用户id
            'red_envelope_id': int(row['red_envelope_id']),  # 红包id
            'user_name': str(row['user_name']),  # 抢的人姓名
            'user_img': str(row['user_img']),  # 抢红包的头像
            'credit': decimal_2_float(row['credit'], 2),  # 抢的金额
            'has_transfer': int(row['has_transfer']),  # 是否已转帐
            'draw_time':
            row['draw_time'].strftime("%Y-%m-%d %H:%M:%S"),  # 抢的时间
        }
        return draw_record

    """
    获取红包已抢列表
    """

    def get_draw_record_list(self, red_id: int):

        sql = """select redr.*,redr.user_id || '@' || hi.host as host_user_id,hu.user_name 
                    ,RANK() OVER (ORDER BY credit DESC,redr.id asc ) as rank
                    ,max(draw_time) over() as last_draw_time
                    from public.red_envelope_draw_record as redr
                    join public.host_info as hi on hi.id = redr.host_id
                    left join public.host_users as hu on redr.host_id = hu.host_id and redr.user_id = hu.user_id
                 where redr.red_envelope_id = %(red_envelope_id)s and redr.user_id is not null order by draw_time desc 
                """

        pg_cursor = self._rels.get_pg_dict_cursor()

        pg_cursor.execute(sql, {'red_envelope_id': red_id})

        draw_record = []
        while True:
            row = pg_cursor.fetchone()
            if row is None:
                break

            draw_record.append({
                'id':
                int(row['id']),  # id
                'rank':
                1 if int(row['rank']) == 1 else 0,  # 是否最佳
                'user_id':
                str(row['user_id']),  # 抢的人用户id
                'host_user_id':
                str(row['host_user_id']),  # 抢的人用户id
                'user_name':
                str(row['user_name']),  # 抢的人姓名
                'credit':
                decimal_2_float(row['credit'], 2),  # 抢的金额
                'has_transfer':
                int(row['has_transfer']),  # 是否已转帐
                'last_draw_time':
                row['last_draw_time'].strftime("%Y-%m-%d %H:%M:%S"),  # 最后抢的时间
                'draw_time':
                row['draw_time'].strftime("%Y-%m-%d %H:%M:%S"),  # 抢的时间
            })
        pg_cursor.close()

        return draw_record