NetSuite 沙盒 RESTlet API 未获取订单数据

问题描述 投票:0回答:1

我已经设置了一个 RESTlet API,用于从 NetSuite 中的“保存的交易搜索”获取订单数据。在生产中,它工作得非常完美。现在我需要根据NetSuite的订单数据完成更多功能。在不影响生产的情况下,我开始在沙盒中设计新的功能。在生产中完美运行的 API 仅在沙箱中返回 []。

我尝试过重做集成,并进行访问,并检查了所有ID,但无法找出问题所在。

这里是打印订单数据的代码:

import time
import uuid
import urllib.parse
import hmac
import hashlib
import base64
import requests

def generate_oauth_signature(method, url, consumer_key, consumer_secret, token_id, token_secret, realm=""):
    params = {
        'oauth_consumer_key': consumer_key,
        'oauth_nonce': uuid.uuid4().hex,
        'oauth_signature_method': 'HMAC-SHA256',
        'oauth_timestamp': str(int(time.time())),
        'oauth_token': token_id,
        'oauth_version': '1.0',
    }

    url_parts = urllib.parse.urlparse(url)
    query_params = urllib.parse.parse_qs(url_parts.query)
    for key, value in query_params.items():
        params[key] = value[0]

    sorted_params = sorted(params.items())


    base_string = method.upper() + '&' + urllib.parse.quote_plus(url_parts.scheme + '://' + url_parts.netloc + url_parts.path) + '&' + urllib.parse.quote_plus('&'.join([urllib.parse.quote_plus(k) + '=' + urllib.parse.quote_plus(v) for k, v in sorted_params]))

    signing_key = urllib.parse.quote_plus(consumer_secret) + '&' + urllib.parse.quote_plus(token_secret)

    signature = hmac.new(signing_key.encode(), base_string.encode(), hashlib.sha256).digest()
    oauth_signature = base64.b64encode(signature).decode()

    auth_header = 'OAuth realm="' + realm + '", '
    auth_header += 'oauth_consumer_key="' + urllib.parse.quote_plus(consumer_key) + '", '
    auth_header += 'oauth_token="' + urllib.parse.quote_plus(token_id) + '", '
    auth_header += 'oauth_signature_method="HMAC-SHA256", '
    auth_header += 'oauth_timestamp="' + params['oauth_timestamp'] + '", '
    auth_header += 'oauth_nonce="' + params['oauth_nonce'] + '", '
    auth_header += 'oauth_version="1.0", '
    auth_header += 'oauth_signature="' + urllib.parse.quote_plus(oauth_signature) + '"'

    return auth_header

def fetch_netsuite_orders():
    #This is for production
    '''  
    netsuite_url = "https://11111111.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=111&deploy=1"
    consumer_key = "11111111"
    consumer_secret = "11111111"
    token_id = "11111111"
    token_secret = "111111111"
    realm = "11111111"
    '''

    #This is for sandbox
    netsuite_url = "https://11111111-sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=111&deploy=1"
    consumer_key = "11111111"
    consumer_secret = "11111111"
    token_id = "11111111"
    token_secret = "11111111"
    realm = "11111111_SB1"
    
    auth_header = generate_oauth_signature("GET", netsuite_url, consumer_key, consumer_secret, token_id, token_secret, realm)
    #print(auth_header)

    headers = {
        'Authorization': auth_header,
        'Content-Type': 'application/json',
    }

    response = requests.get(netsuite_url, headers=headers)

    if response.status_code == 200:
        #print("Success")
        #print(response.json())
        return response.json()
    else:
        print(f"Failed to fetch orders, status code: {response.status_code}")
        print(response.text)
        return []
        

def fetch_orders():
    orders_data = fetch_netsuite_orders()
    return orders_data


if __name__ == "__main__":
    orders_data = fetch_orders()
    print(orders_data)

API 代码如下:

/**
 * @NApiVersion 2.x
 * @NScriptType Restlet
 */

define(['N/search'], function(search) {

    function doGet(requestParams) {
        var searchId = 'customsearch696000';
        var searchResults = [];

        var mySearch = search.load({
            id: searchId
        });

        var resultSet = mySearch.run();
        var searchIndex = 0;
        var result;

        do {
            result = resultSet.getRange({
                start: searchIndex,
                end: searchIndex + 1000
            });

            if (result && result.length > 0) {
                searchResults = searchResults.concat(result);
                searchIndex += result.length;
            }
        } while (result && result.length == 1000);

        return searchResults;
    }

    return {
        'get': doGet
    };
});

netsuite restlet restlet-2.0
1个回答
0
投票

您的问题至少有一部分是由于签名生成不正确...... 仅使用 baseUrl 生成签名:https://11111111-sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl,并在生成“params”时使用查询参数(在按字母顺序排列),因此只需在调用“generate_oauth_signature”函数之前将它们分开即可:

#This is for sandbox
netsuite_url = "https://11111111-sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=111&deploy=1"
baseUrl = "https://11111111-sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl"
scriptId = "111"
deployId = "1"
.
.
.
auth_header = generate_oauth_signature("GET", baseUrl, scriptId, deployId, consumer_key, consumer_secret, token_id, token_secret, realm)



def generate_oauth_signature(method, baseUrl, scriptId, deployId, consumer_key, consumer_secret, 
token_id, token_secret, realm=""):
params = {
    'deploy': deployId,
    'oauth_consumer_key': consumer_key,
    'oauth_nonce': uuid.uuid4().hex,
    'oauth_signature_method': 'HMAC-SHA256',
    'oauth_timestamp': str(int(time.time())),
    'oauth_token': token_id,
    'oauth_version': '1.0',
    'script': scriptId
}

但生成签名后仍使用请求的完整 url。还, 对于某些 Netsuite 调用,需要 Prefer 'transient' 标头:

 headers = {
    'Authorization': auth_header,
    'Prefer', "transient" ,
    'Content-Type': 'application/json',
}

response = requests.get(netsuite_url, headers=headers)

此外,直接在标头中指定 Content-Type 有时可能会导致 Netsuite 出现错误。我主要通过 api 与 c# 进行通信,因此这可能与您的代码有所不同。因为我只指定了 application/json 的内容类型,所以只指定了我发送的有效负载。仅供参考。祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.