def create_new_platform(user_id): # 成为平台属主 user = User.get(user_id=user_id) assert user account = Account.get(user_id=user.user_id, platform_id=user.bind_platform_id) assert account platform = Platform.get(owner_user_id=user.user_id) if not platform: # SELECT `AUTO_INCREMENT` FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'trade' AND table_name = 'platform'; # ALTER TABLE `platform` AUTO_INCREMENT = 3; platform = Platform.create(owner_user_id=user.user_id) platform.platform_id = platform.id qrcode_info = WeClient.create_qrcode(scene_str=str(platform.platform_id), is_permanent=True) log.d(f'qrcode_info: {qrcode_info}') qrcode_content = qrcode_info['url'] log.i( f'create qrcode, platform_id: {platform.platform_id}, qrcode_content: {qrcode_content}' ) platform.update(qrcode_content=qrcode_content, platform_id=platform.id, ssid=f'WIFI-{platform.platform_id}') user.update(bind_platform_id=platform.platform_id) account.update(role=Account.Role.PLATFORM_OWNER.value, platform_id=user.bind_platform_id) return platform
def handle_order_unpaid(cls, order): # 查询订单API文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2 # 关闭订单API文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3 # 下载对账单API文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6 out_trade_no = order.out_trade_no # 商户订单号 attach = order.attach total_fee = order.total_fee # 1. 查询订单API, 获取查询结果 ret_json = WePay.query_order(out_trade_no) # OrderedDict([ # ('return_code', 'SUCCESS'), ('return_msg', 'OK'), ('appid', 'wx54d296959ee50c0b'), ('mch_id', '1517154171'), # ('nonce_str', 'LQ36VyPkbS7tK7Nk'), ('sign', '5182234EB26EBFB718D5FDD1189E6056'), ('result_code', 'SUCCESS'), # ('out_trade_no', '1540519817110XiX6jCKAmXb348V3e'), ('trade_state', 'NOTPAY'), # ('trade_state_desc', '订单未支付') # ]) log.d(f'order query from weixin: {ret_json}') # if ret_json['return_code'] != 'SUCCESS': log.e('order query not success') return # 2. 检查签名 if not WePay.is_right_sign(ret_json): log.e('sign illegal, sign:{}', ret_json['sign']) return if ret_json['result_code'] != 'SUCCESS': log.e('check signature not success') return # 3. 交易状态分支处理 trade_state = ret_json['trade_state'] if trade_state == 'SUCCESS': wx_total_fee = int(ret_json['total_fee']) transaction_id = ret_json['transaction_id'] # 支付成功, 先检查total_fee是否一致, 然后把charge记录状态从0改为1, transaction_id更新为微信返回值 if wx_total_fee != total_fee: log.e( f'total_fee: {wx_total_fee} != order.total_fee:{total_fee}' ) return # 增加用户免费资源 increase_user_resource(total_fee, out_trade_no, transaction_id, attach) elif trade_state in ['NOTPAY', 'CLOSED', 'PAYERROR']: # 超时还未支付或订单已经关闭, 需把charge记录状态从0改为-1 status = Order.Status.EXPIRED.value Order.objects.filter(out_trade_no=out_trade_no).update( status=status) log.i( f"UPDATE orders SET status = '{status}' WHERE out_trade_no = '{out_trade_no}'" )
def release_lock(self): if self.is_released: return self.is_released = True key = self.get_key(process_name=self.process_name, worker_id=self.worker_id) is_success = self.get_and_delete(keys=[key], args=[self.pod_uid]) if not is_success: if not self.worker_id: log.d( f'no need release because not get lock, worker_id: {self.worker_id}' ) return -1 sentry_sdk.capture_message(f'release lock fail. key: {key}') return is_success
def doing(cls, start_time, end_time): # 明天到期的用户 log.d( f'select expire account where start_time > {start_time} and end_time <= {end_time}' ) # accounts = Account.objects.filter( expired_at__gt=start_time, expired_at__lte=end_time, ) for account in accounts: user = User.get(user_id=account.user_id) log.i( f'send wechat template message, openid: {user.openid}, expired_at: {account.expired_at}' ) WePush.notify_account_expire(openid=user.openid, username=account.username, expired_at=account.expired_at)
def doing(cls): if not cls.start_time: cls.start_time = cls.load_start_time() cls.end_time = cls.calculate_end_time() if cls.end_time < cls.start_time: log.w(f'end_time({cls.end_time}) < start_time({cls.start_time})') return log.d( f'select unpaid order where start_time > {cls.start_time} and end_time <= {cls.end_time}' ) # orders = Order.objects.filter(created_at__gt=cls.start_time, created_at__lte=cls.end_time, status=Order.Status.UNPAID.value) for order in orders: cls.handle_order_unpaid(order) # 保存标签 cls.start_time = cls.end_time cls.save_start_time(start_time=cls.start_time)
def post(self, request): log.d(f'we_pay notify. data: {request.body}') try: # request.data: OrderedDict([(u'appid', u'wx7f843ee17bc2a7b7'), (u'attach', u'{"btype": 0}'), (u'bank_type', u'CFT'), (u'cash_fee', 1), (u'fee_type', u'CNY'), (u'is_subscribe', u'Y'), (u'mch_id', u'1480215992'), (u'nonce_str', u'bZhA1HTmIqBFCluKpai32Yj97tvk4DzV'), (u'openid', u'ovj3E0l9vffwBuqz_PNu25yL_is4'), (u'out_trade_no', u'15021710481087kJMqd36CBz9OqFnK'), (u'result_code', u'SUCCESS'), (u'return_code', u'SUCCESS'), (u'time_end', u'20170808134526'), (u'total_fee', 1), (u'trade_type', u'JSAPI'), (u'transaction_id', u'4005762001201708085135613047'), (u'sign', u'F59843FFFAE5E70A9F1B67D755A372E0')]) # (Pdb) request.body # b'<xml><appid><![CDATA[wx54d296959ee50c0b]]></appid>\n<attach><![CDATA[{"tariff_name": "month1"}]]></attach>\n<bank_type><![CDATA[CFT]]></bank_type>\n<cash_fee><![CDATA[1]]></cash_fee>\n<fee_type><![CDATA[CNY]]></fee_type>\n<is_subscribe><![CDATA[Y]]></is_subscribe>\n<mch_id><![CDATA[1517154171]]></mch_id>\n<nonce_str><![CDATA[dJ1t73xXmCrOjn8z5DP6BKyNqgI0cwvS]]></nonce_str>\n<openid><![CDATA[o0FSR0Zh3rotbOog_b2lytxzKrYo]]></openid>\n<out_trade_no><![CDATA[1540483879395x3Oko4Ta9RWamsQCW]]></out_trade_no>\n<result_code><![CDATA[SUCCESS]]></result_code>\n<return_code><![CDATA[SUCCESS]]></return_code>\n<sign><![CDATA[22BE162C29D8558541F04475C379E18B]]></sign>\n<time_end><![CDATA[20181026001122]]></time_end>\n<total_fee>1</total_fee>\n<trade_type><![CDATA[JSAPI]]></trade_type>\n<transaction_id><![CDATA[4200000206201810263667544938]]></transaction_id>\n</xml>' data = WePay.parse_payment_result(request.body) out_trade_no = data['out_trade_no'] attach = data['attach'] return_code = data['return_code'] assert return_code == 'SUCCESS' transaction_id = data['transaction_id'] total_fee = data['total_fee'] # 增加用户免费资源 increase_user_resource(total_fee, out_trade_no, transaction_id, attach) return self.SUCCESS_RESPONSE except (InvalidSignatureException, Exception) as e: log.e(f'we_pay notify error, body: {request.body}') sentry_sdk.capture_exception(e) return self.SUCCESS_RESPONSE
def refresh_lock(self): last = 0 while 1: if SigTerm.is_term or self.is_process_exit: result = self.release_lock() log.d(f'release lock. result: {result}') raise SystemExit() now = int(time.time()) if now - last < (self.expire_time / 2): continue else: last = now key = self.get_key(process_name=self.process_name, worker_id=self.worker_id) is_success = self.get_and_expire( keys=[key], args=[self.pod_uid, self.expire_time]) if not is_success: sentry_sdk.capture_message( f'refresh lock fail. key: {key}, pod_uid: {self.pod_uid}') log.t(f'success refresh lock. key: {key}') time.sleep(1)
def start(self): # 需支持高可用, 多进程互斥, 只有1个进程在处理 log.set_header('timer_processor') lock = RedisLock(max_worker_id=1, expire_time=30, process_name='timer_processor') try: lock.start() log.d(f'jobs: {MetaClass.jobs}') while True: # FIXME SigTerm, PidFile close_old_connections( ) # workaround: https://zhaojames0707.github.io/post/django_mysql_gone_away/ for job_class in MetaClass.jobs: job_class.start() time.sleep(self.sleep_seconds) except Exception as e: log.e(traceback.format_exc()) if not isinstance(e, SystemExit): sentry_sdk.capture_exception(e) finally: lock.stop()