• yahooM充值接入


    一、接入流程
    ①    App调用opensocial.requestPayment(),生成支付信息
    ②    Mbga向对应App服务器的endpoint URL发送支付确认信息请求
    ③    App服务器验证mbga发送的请求之后返回response给mbga,mbga引导用户去充值页面
    ④    用户同意充值了,就向App服务器发送一个支付确认的request。
    ⑤    App服务器验证request的正确性,处理游戏内部item购买业务,最后返回response给mbga。Mbga在收到正常的response之后,就确定了支付了。
    ⑥    执行最初调用opensocial.requestPayment()的最后一个参数(执行callback 函数)
    ⑦    可选的:在callback函数里面调用gadgets.io.makeRequest()来请求App服务器,用于确认支付是否正确。
    ⑧    App服务器调用Restful Api的Payment API来获取当前支付的状态。
    ⑨    Api服务器返回当前支付状态给App服务器,服务器来确认支付信息
    ⑩    结果处理完毕

    二、前端代码,通过JS调用,如下代码,含游戏接入代码和邀请代码

    View Code
    <?xml version="1.0" encoding="UTF-8"?>
    <Module>
    <ModulePrefs title="bubblefish">
    <Require feature="dynamic-height" />
    <Require feature="opensocial-0.8" />
    <Require feature="flash" />
    <Require feature="opensocial-payment" />
    <Link rel="payment.handler" href="{{ game_server_url }}payment/" />
    </ModulePrefs>

    <Content type="html" view="canvas" >
    <![CDATA[
    <script type="text/javascript">
    function handlePaymentResponse(dataItem) {
    if (dataItem.hadError()) {
    //alert('got an error');
    }
    else {
    var orderId
    = dataItem.getData().getField(opensocial.Payment.Field.ORDER_ID);
    alert(
    'payment request accepted, orderId: ' + orderId);
    }
    }

    function makePayment(sku_id,price) {

    var itemParams
    = {};
    itemParams[opensocial.BillingItem.Field.SKU_ID]
    = sku_id;
    itemParams[opensocial.BillingItem.Field.PRICE]
    = price;
    itemParams[opensocial.BillingItem.Field.COUNT]
    = 1;
    itemParams[mbga.BillingItem.Field.NAME]
    = "パールで";
    itemParams[mbga.BillingItem.Field.IMAGE_URL]
    = "http://60.29.241.40/yahoom_media/img/yabage_tu03.gif";
    itemParams[opensocial.BillingItem.Field.DESCRIPTION]
    = '';

    var item
    = opensocial.newBillingItem(itemParams);

    var params
    = {};
    params[opensocial.Payment.Field.ITEMS]
    = [item];
    params[opensocial.Payment.Field.AMOUNT]
    = price;
    var payment
    = opensocial.newPayment(params);

    opensocial.requestPayment(payment, handlePaymentResponse);
    }

    function paymentPage(){
    var url
    = "{{ game_server_url }}payment/recharge/";
    var params
    ={};
    var post_data
    = {snsId : snsId};
    params[gadgets.io.RequestParameters.POST_DATA]
    = gadgets.io.encodeValues(post_data);
    params[gadgets.io.RequestParameters.AUTHORIZATION]
    = gadgets.io.AuthorizationType.SIGNED;
    params[gadgets.io.RequestParameters.METHOD]
    = gadgets.io.MethodType.POST;
    params[gadgets.io.RequestParameters.CONTENT_TYPE]
    = gadgets.io.ContentType.TEXT;
    gadgets.io.makeRequest(url, commonResponse, params);
    };


    var snsId
    = undefined;
    function sendFeed(title, content){
    var ap
    = {};
    ap[opensocial.Activity.Field.TITLE]
    = title;//21字之内
    ap[opensocial.Activity.Field.BODY]
    = content;//140字之内
    var activity
    = opensocial.newActivity(ap);
    opensocial.requestCreateActivity(activity, opensocial.CreateActivityPriority.LOW, function(response){
    if (response.hadError()) {
    var code
    = response.getErrorCode();
    }
    });
    };
    function invitePage(){
    var url
    = "{{ game_server_url }}invite/isinfo/";
    var params
    ={};
    var post_data
    = {snsId : snsId};
    params[gadgets.io.RequestParameters.POST_DATA]
    = gadgets.io.encodeValues(post_data);
    params[gadgets.io.RequestParameters.AUTHORIZATION]
    = gadgets.io.AuthorizationType.SIGNED;
    params[gadgets.io.RequestParameters.METHOD]
    = gadgets.io.MethodType.POST;
    params[gadgets.io.RequestParameters.CONTENT_TYPE]
    = gadgets.io.ContentType.TEXT;
    gadgets.io.makeRequest(url, commonResponse, params);
    };
    function commonResponse(data){
    document.getElementById(
    'bubblefishcontent').innerHTML=data.text;
    document.getElementById(
    'invite_button').innerHTML="";
    gadgets.window.adjustHeight(
    1080);
    };
    function innerinvite(){
    opensocial.requestShareApp(
    "VIEWER_FRIENDS", null, function(response) {
    if (response.hadError()) {
    var errCode
    = response.getErrorCode();
    }
    else {
    var recipientIds
    = response.getData()["recipientIds"];
    // alert(recipientIds);
    if (recipientIds) {
    var url
    ="{{ game_server_url }}invite/iscallback/";
    var params
    ={};
    var post_data
    = {snsId : snsId, ids : recipientIds };
    params[gadgets.io.RequestParameters.POST_DATA]
    = gadgets.io.encodeValues(post_data);
    params[gadgets.io.RequestParameters.AUTHORIZATION]
    = gadgets.io.AuthorizationType.SIGNED;
    params[gadgets.io.RequestParameters.METHOD]
    = gadgets.io.MethodType.POST;
    params[gadgets.io.RequestParameters.CONTENT_TYPE]
    = gadgets.io.ContentType.JSON;
    gadgets.io.makeRequest(url, function(data){}, params);
    }
    }
    });
    };

    function initRequest() {
    var req
    = opensocial.newDataRequest();
    req.add(req.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER),
    "viewer");
    req.send(function(data) {
    if (!data.hadError()) {
    var item
    = data.get("viewer");
    if (!item.hadError()) {
    var viewer
    = item.getData();
    snsId
    = viewer.getId();
    var nickname
    = viewer.getDisplayName();
    var servletUrl
    ="{{ game_server_url }}";//这是后台的入口,执行完init方法之后,就可以在后台取到当前登录的用户id了
    var params
    ={};
    var post_data
    = {snsId : snsId};
    params[gadgets.io.RequestParameters.POST_DATA]
    = gadgets.io.encodeValues(post_data);
    params[gadgets.io.RequestParameters.AUTHORIZATION]
    = gadgets.io.AuthorizationType.SIGNED;
    params[gadgets.io.RequestParameters.METHOD]
    = gadgets.io.MethodType.POST;
    params[gadgets.io.RequestParameters.CONTENT_TYPE]
    = gadgets.io.ContentType.JSON;
    gadgets.io.makeRequest(servletUrl,initResponse,params);
    var title
    = nickname+"さんがバブル海に潜入しました";
    var content
    = nickname+"さんが可愛いフィッシュ達と共に楽しみました!あなたも行って見ては?";
    sendFeed(title, content);
    }
    }
    });
    };

    function initResponse(resp){
    var skey
    = resp.data.skey;
    var swfUrl
    = "{{ media_url }}swf/v16/gameMain.swf?v=1.0";
    gadgets.flash.embedFlash(swfUrl,
    "bubblefishcontent", Number("10"), {flashVars:"xn_sig_session_key="+skey+"&sns=yahooM", wmode:"window", allowScriptAccess:"always", height:"640px"});
    };
    gadgets.util.registerOnLoadHandler(initRequest);
    gadgets.window.adjustHeight(
    850);
    </script>
    <div>
    <button type="button" onclick="paymentPage();">payment</button>
    </div>
    <div id="invite_button">
    <p style="text-align:right;"><a href="#" onclick="invitePage()"><img src="{{ media_url }}img/invite_yahoom/canvas_invite_btn.gif" /></a></p>
    </div>
    <div id="bubblefishcontent"></div>
    ]]
    >
    </Content>
    </Module>

    三、后台处理代码

    View Code
    def generate_timestamp():
    """Get seconds since epoch (UTC)."""
    return int(time.time())

    def generate_nonce(length=8):
    """Generate pseudorandom number."""
    return ''.join([str(random.randint(0, 9)) for i in range(length)])

    def pay(request):
    viewer_id
    = int(request.GET.get('opensocial_viewer_id','0'))
    owner_id
    = int(request.GET.get('opensocial_owner_id', '1'))
    if viewer_id != owner_id:
    return HttpResponse('invalid')

    member
    = get_member_by_sns_id(viewer_id)
    #生成订单
    if request.method == 'POST':
    order_info
    = None
    for rec in request.POST.keys():
    rec
    = simplejson.loads(rec)
    if rec.has_key('ITEMS'):
    order_info
    = rec
    if not order_info:
    return HttpResponse('invalid-1')

    items
    = order_info.get('ITEMS', [])
    amount
    = order_info.get('AMOUNT', 0)
    payment_id
    = order_info.get('PAYMENT_ID', '')

    #购买的价格就是珍珠数量,购买的数量是固定值1.
    price = items[0].get('PRICE', 0)
    count
    = items[0].get('COUNT', 0)

    if price * count != amount:
    return HttpResponse('invalid-2')

    #rmb = pearls_to_yen(count)
    record = RechargeRecord(member_id=member.id,
    payment_id
    = payment_id,
    pearls
    = price,
    rmb
    = amount,
    status
    = 'UP')
    record.save()
    body
    = {'order_id': str(record.id), 'response_code': 'OK'}
    body_string
    = simplejson.dumps(body, separators=(',',':'))

    #充值成功给用户珍珠
    elif request.method == 'GET':
    order_id
    = int(request.GET.get('order_id', 0))
    if order_id <= 0:
    return HttpResponse('invalid-3')
    record
    = RechargeRecord.objects.get(id=order_id, member_id=member.id)

    result
    = finish_payment(record)

    body
    = {'order_id': str(record.id), 'response_code': 'OK', 'amount': str(record.rmb)}
    body_string
    = simplejson.dumps(body, separators=(',',':'))

    hashed
    = hashlib.sha1(body_string)
    params
    = {
    "timestamp": generate_timestamp(),
    "nonce": generate_nonce(),
    "consumer_key" : consumer_key,
    "body_hash": urllib.quote_plus(base64.b64encode(hashed.digest()).rstrip("=")),
    }

    base_string
    = '&'.join(['%s=%s' % (x, params[x]) for x in sorted(params.keys())])
    hmac_str
    = hmac.new(consumer_secret, base_string, hashlib.sha1).digest()
    sign
    = base64.b64encode(hmac_str).rstrip("=")

    header_sign
    = "%s&signature=%s" % (base_string, urllib.quote(sign))
    response
    = HttpResponse(body_string)
    response[
    'Content-type'] = 'application/json'
    response[
    'X-MBGA-PAYMENT-SIGNATURE'] = header_sign

    return response

    问题:生成的 signature总是不正确

    原因:simplejson.dumps默认生成json数据有空格,需要处理一下

    >>> a = {"one":1, "two":2}
    >>> str_a = simplejson.dumps(a)
    >>> str_a
    '{"two": 2, "one": 1}'

    >>> str_a2 = simplejson.dumps(a, separators=(',',':'))
    >>> str_a2
    '{"two":2,"one":1}'
     
  • 相关阅读:
    缓存更新的套路
    return 和 return false 的区别
    TensorFlow函数:tf.truncated_normal
    TensorFlow随机值:tf.random_normal函数
    TensorFlow函数:tf.lin_space
    TensorFlow函数:tf.ones_like
    TensorFlow函数:tf.ones
    TensorFlow函数:tf.zeros_like
    Tensorflow函数:tf.zeros
    数据分析常用的python工具和SQL语句
  • 原文地址:https://www.cnblogs.com/imouren/p/2019668.html
Copyright © 2020-2023  润新知