def api_retrieve_shop_info(): """ @api {post} /shop/complex_query/:page [商户]基本信息复杂查询 @apiDescription 查询多条商户详细信息记录(mongodb __raw__). @apiName api_retrieve_shop_info @apiGroup shop @apiParamExample {json} 请求body示例: { "_id": "56c2d708a785c90ab0014d00" } """ kw = ctx.request.input() query = {} if 'query' in kw: query = pickle.loads(kw.query) if '_id' in kw: query['_id'] = ObjectId(kw['_id']) for k in ('tel', 'name'): if k in kw: query[k] = kw[k] page, count = parse_page_count(kw) excludes = (str('password'), ) only = kw.get('only') if only: shops = Shop.objects(__raw__=query).only(*only).skip( (page * count)).limit(count) else: shops = Shop.objects(__raw__=query).exclude(*excludes).skip( (page * count)).limit(count) _count = Shop.objects(__raw__=query).count() ret = [] for s in shops: s_packed = ShopLogic.pack_shop(s, excludes=excludes, only=only) ret.append(s_packed) ctx.response.set_header("X-Resource-Count".encode('utf-8'), _count) return ret[0] if len(ret) == 1 else ret if len(ret) > 1 else {}
def api_get_shop_info_from_token(): # 输入: token <token> params = ctx.request.input() if 'token' not in params: logging.warning( "You are calling /shop/token without [token] key in params%s." % params) token = params.token.split()[1] key = key_shop_token.format(content=token) # 可能值: id who = redis_client.get(key) if not who: ctx.response.status = '401 Unauthorized' return None elif len(who) == 24: s = Shop.objects(id=who).first() # 如果该商户没有定价, 取默认定价 if s.fee and s.fee.get('fh'): pass else: _s = Shop.objects(tel='00000000000').only('fee').first() s.fee = _s.fee return ShopLogic.pack_shop(s)
def api_shop_wap_top_up_as_pay(): # shop_id, cash kw = ctx.request.input() # 记录这次尝试 transact_num = gen_transact_num() s = Shop.objects(id=kw.shop_id).first() # todo 暂时用充值尝试的记录 TopUpLogic.create(transact_num=transact_num, shop_id=kw.shop_id, shop_name=s.name, shop_tel=s.tel, cash=kw.cash) # 创建手机wap转账接口链接 url = gen_wap_transfer_link(transact_num, kw.cash, '商户现金支付') logging.info(url) return {'transact_num': transact_num, 'url': url}
def api_shop_wap_top_up(): # 输入: shop_id, cash kw = ctx.request.input() # 记录这次尝试 transact_num = gen_transact_num() kw.transact_num = transact_num s = Shop.objects(id=kw.shop_id).first() kw.shop_name = s.name kw.shop_tel = s.tel TopUpLogic.create(**kw) # 创建手机wap充值接口链接 url = create_wap_trade(transact_num, kw.cash, '商户充值') logging.info(url) # 返回示例 {'transact_num': transact_num, # 'url': 'http://wappaygw.alipay.com/service/rest.htm?service=alipay.wap.auth.authAndExecute # &format=xml&v=2.0&_input_charset=utf-8 # &req_data=<auth_and_execute_req><request_token>20160226c760e7d843186665408fa6729ee21979</request_token> # </auth_and_execute_req>&sec_id=MD5&partner=2088901729140845&sign=f7d02ce9ece212677a512108687594fb} return {'transact_num': transact_num, 'url': url}
def api_shop_h5_wx_top_up(): kw = Schema({ 'shop_id': schema_unicode, 'cash': schema_float_2, 'code': schema_unicode, # 用于获取用户标识openid }).validate(ctx.request.input()) code = kw.pop('code') # 记录这次尝试 transact_num = gen_transact_num() kw.transact_num = transact_num s = Shop.objects(id=kw.shop_id).first() kw.shop_name = s.name kw.shop_tel = s.tel TopUpLogic.create(**kw) # 创建预支付交易会话, 获取预支付交易会话标识 result = wx_generate_prepay_jsapi(transact_num, kw['cash'], ctx.request.remote_addr, code) if result['result'] == 'success': return { 'prepay_id': result['prepay_id'], } else: raise ValueError('wxPay[JSAPI] Error: %s' % result['msg'])
def api_shop_web_top_up(): # shop_id, cash params = ctx.request.input() # 记录这次尝试 transact_num = gen_transact_num() params.transact_num = transact_num s = Shop.objects(id=params.shop_id).first() params.shop_name = s.name params.shop_tel = s.tel TopUpLogic.create(**params) # 创建PC网页端充值接口链接 url = create_web_trade(transact_num, params.cash) logging.info(url) # 返回示例 { # "transact_num": "20160226117671", # "url": "https://mapi.alipay.com/gateway.do?seller_email=abcx%40123feng.com&seller_id=2088901729140845" # "&total_fee=0.01&service=create_direct_pay_by_user" # "&_input_charset=utf-8&sign=d4ee6f2151e2a0aafce26865b4fb4ad9" # "&out_trade_no=20160226117671&payment_type=1" # "¬ify_url=http%3A%2F%2F123.57.45.209%3A5000%2Fpay%2Falipay%2Fweb%2Fnotify" # "&sign_type=MD5&partner=2088901729140845&subject=charge", # } return {'transact_num': transact_num, 'url': url}
def api_shop_login(): """ @api {get} /shop/login?shop_id=&password= [商户]登录 @apiDescription 风先生商户登录成功则返回token,失败则报错. @apiName api_shop_login @apiGroup shop @apiParam {string(11)} [shop_id] 商户工号, 如 7748657. @apiParam {string(11)} [tel] 商户手机号, 如 150687929321. @apiParam {string(32)} password 商户密码hash(如果是id+密码登录), 验证码(如果是手机号+验证码登录). @apiParamExample {json} 请求url示例: /shop/login?shop_id=17066&password=0192023a7bbd73250516f069df18b500 OR /shop/login?tel=150687929321&password=123456 @apiSuccessExample {json} 手机号验证码登录成功示例: HTTP/1.1 200 OK { "tel": "150687929321", "token": "36dc92e290f334aaa96466d3ee9b9efa" } @apiSuccessExample {json} 工号密码登录成功示例: HTTP/1.1 200 OK { "shop_id": "17066", "token": "36dc92e290f334aaa96466d3ee9b9efa" } @apiErrorExample {json} 失败示例: HTTP/1.1 400 ValueError { "message": "No such shop=[150687929321]." } @apiErrorExample {json} 失败示例: HTTP/1.1 400 ValueError { "message": "Password validation for [17066]=[012023a7bbd73250516f069df18b500] failed." } """ def set_token(inner_who): token = hashlib.md5('%s%s' % (inner_who, utc_8_now())).hexdigest() key = key_shop_token.format(content=token) # 插入token到redis中, 30天有效期: get token:fe11ad907e2fa779ed2f363ef589d3f9 => 7740959 redis_client.setex(key, inner_who, 30 * 24 * 3600) return token params = ctx.request.input() shop_id = str(params.get("id", "")).strip() tel = str(params.get("tel", "")).strip() password_or_sms_code = str(params.get('password', '')).strip() # ==> 首先检查是不是免密码[优先级为: 免密码>手机] who = shop_id if shop_id else tel if tel else None if not who: raise ValueError("Expect either [shop_id] or [tel] in params%s." % params) elif not password_or_sms_code: raise ValueError("Expect [password] in params%s." % params) # 存放: 免密码名单和token(30天) # 登录成功: smembers no_password => set(13245678901,...); sismember(key_login, tel) elif redis_client.sismember(key_no_password, who): if tel: shop = Shop.objects(tel=tel).first() content = set_token(str(shop.pk)) s_packed = ShopLogic.pack_shop(shop) s_packed.update(dict(token=content)) return s_packed # ==> 商户登录: 商户owner手机号+密码 shop = None if shop_id: shop = Shop.objects(id=shop_id).first() elif tel: shop = Shop.objects(tel=tel).first() password_in_db = str(shop.password).strip() if shop else None # 如果此人不存在,直接报错 if not password_in_db: logging.info("No such shop=[%s]." % who) raise ValueError("商户不存在,请注册后登录.") # 登录成功: 密码与数据库中值匹配 if password_or_sms_code == password_in_db: content = set_token(str(shop.pk)) s_packed = ShopLogic.pack_shop(shop) s_packed.update(dict(token=content)) return s_packed # 登录失败 else: logging.info( "Password validation for [%s]=[%s] failed, expected [%s]." % (who, password_or_sms_code, password_in_db)) raise ValueError("用户名或密码错误.")
def api_shop_operation(operation): def set_token(inner_who): token = hashlib.md5('%s%s' % (inner_who, utc_8_now())).hexdigest() key = key_shop_token.format(content=token) # 插入token到redis中, 7天有效期: get shop:token:fe11ad907e2fa779ed2f363ef589d3f9 => 7740959 redis_client.setex(key, inner_who, 7 * 24 * 3600) return token operation = str(operation).upper().strip() kw = ctx.request.input() # ==> 商户注册 if operation == OPERATIONS.REGISTER: kw = Schema({ 'tel': schema_unicode, 'sms_code': schema_unicode, 'password': schema_unicode, Optional('name'): schema_unicode, 'contact': { Optional('name', default=''): schema_unicode_empty, Optional('tel', default=''): schema_unicode_empty }, Optional("loc"): { "address": schema_unicode, "longitude": schema_float, "latitude": schema_float, Optional(object): object }, Optional('recommended_by'): { 'tel': schema_unicode_empty }, }).validate(ctx.request.input()) tel = kw['tel'] sms_code = kw['sms_code'] password = kw['password'] # song.123feng.com/APP注册: 手机号+验证码 if tel: sms_key = key_sms_code.format(tel=tel) # 验证成功: 验证码匹配 get sms:code:15901739717 => 123456 sms_code_in_redis = redis_client.get(sms_key) if sms_code_in_redis == sms_code: shop = Shop.objects(tel=tel).first() if not shop: # 记录商户到mongodb(如无记录): status=STATUS_VALID # 记录商户到mongodb(如无记录): status=STATUS_INFO_YES if 'recommended_by' in kw: kw['recommended_by']['time'] = TimeZone.utc_now() kw_filtered = ShopLogic.filter_shop(kw) shop = Shop(**kw_filtered).save() # ===== 注册风信账户 ===== http_client = HTTPClient() http_client.fetch(account.req_create( account_type=conf.ACCOUNT_TYPE_SHOP, account_id=str(shop.pk)), raise_error=False) else: # 允许重复注册, 改一下密码 shop.password = password shop.save() shop.reload() shop_id = str(shop.pk) content = set_token(shop_id) s_packed = ShopLogic.pack_shop(shop) s_packed.update(dict(token=content)) return s_packed # 登录失败 else: logging.info( "SMS code validation for [%s]=[%s] failed, expected[%s]." % (tel, sms_code, sms_code_in_redis)) raise ValueError("验证码验证失败.") # ==> 商户事件 elif operation in ShopFSM.FE_INSIDE_EVENTS or operation in ShopFSM.OUTSIDE_EVENTS: # 对完善资料特殊添加时间信息 if operation == ShopFSM.EVENT_COMPLETE_INFO and 'recommended_by' in kw: kw['recommended_by']['time'] = TimeZone.utc_now() # 对修改定价特殊处理: 能用tel找商户id if operation == ShopFSM.EVENT_ALTER_INFO: shop = Shop.objects(tel=kw.tel).first() # 其他事件一概用shop_id else: shop = Shop.objects(id=kw.shop_id).first() if shop: operator_type = kw.operator_type kw.pop('operator_type') modified_shop = ShopFSM.update_status(operator_type, shop, operation, **kw) if not modified_shop: raise ValueError( "State transfer for shop[%s][%s][%s] using [%s] failed." % (kw.shop_id, shop.name, shop.status, operation)) return ShopLogic.pack_shop(modified_shop) else: pass