Sage One API 在创建付款发票时返回 500 内部服务错误

Sage One API returning 500 Internal Service Error when creating Payment Invoice

我在 Sage One API 中创建 "Purchase Invoice" 时遇到问题。无论我对传入的数据进行何种更改,我似乎都会收到 500 Internal Service Error,并且没有包含任何有意义信息的详细响应。无论我输入什么数据,响应总是相同的(只有 errorCode 字段中的 GUID 和服务器时间发生变化)。回复如下:

{
"$diagnoses": [
{
  "$severity": "error",
  "$dataCode": "UnexpectedError",
  "$message": "Unexpected error",
  "$source": {
    "serverTime": "2016-04-29T15:48:11.637+00:00",
    "errorCode": "3b83e1b5-164d-42d4-95b3-3479b09c93f1",
    "requestPath": "/api/v2/purchase_invoices",
    "queryString": "",
        "requestMethod": "POST"
      }
     }
  ]
}

我确定这不是授权问题,因为我在此之前获取并创建了其他数据类型。这包括创建采购发票所需的联系人。

我已经按照他们 self-service site. I also started with their bare bones SDK 中提供的信息作为我正在使用的大部分基础流程的基础。从那以后,我重写了大部分底层结构,认为最初它可能是由 SDK 引起的,这让我遇到了同样的情况——我只收到 500 个内部服务错误作为响应。

这让我相信这是参数本身的问题,因为文档在中间列中列出的参数与右列中示例调用中的数据之间存在一些差异。具体来说,该示例有额外的字段,如 "extra_reference",并且在行项目 "product_id" 和 "product_code" 中没有列在中间列中。

这里是调用的一些相关代码,再次记住基本架构是他们的,有一些程序修改以适应我当前的架构,但不影响实际调用:

    protected override List<KeyValuePair<string, string>> GetPostDataValuesForCreate(
        SageOnePurchaseInvoice objectToCreate)
    {
        List<KeyValuePair<string, string>> postData = new List<KeyValuePair<string, string>>();

        postData.Add(new KeyValuePair<string, string>("expense[contact_id]", objectToCreate.ContactId.ToString()));
        postData.Add(new KeyValuePair<string, string>("expense[date]", objectToCreate.Date));
        postData.Add(new KeyValuePair<string, string>("expense[due_date]", objectToCreate.DueDate));

        if (!string.IsNullOrWhiteSpace(objectToCreate.Reference))
        {
            postData.Add(new KeyValuePair<string, string>("expense[reference]", objectToCreate.Reference));
        }

        if (objectToCreate.ProjectId != 0)
        {
            postData.Add(new KeyValuePair<string, string>("expense[project_id]", objectToCreate.ProjectId.ToString()));
        }

        if (!string.IsNullOrWhiteSpace(objectToCreate.Notes))
        {
            postData.Add(new KeyValuePair<string, string>("expense[notes]", objectToCreate.Notes));
        }


        for (int i = 0; i < objectToCreate.LineItems.Length; i++)
        {
            string index = "expense[line_items_attributes][" + i.ToString() + "][";
            postData.Add(new KeyValuePair<string, string>(index + "description]", objectToCreate.LineItems[i].Description));
            postData.Add(new KeyValuePair<string, string>(index + "ledger_account_id]", objectToCreate.LineItems[i].LedgerAccount.Id.ToString()));
            postData.Add(new KeyValuePair<string, string>(index + "quantity]", objectToCreate.LineItems[i].Quantity.ToString()));
            postData.Add(new KeyValuePair<string, string>(index + "unit_price]", objectToCreate.LineItems[i].UnitPrice.ToString()));
        }

        return postData;
    }

下面是创建和执行 Web 请求的实际方法:

public static string Create(Uri baseUrl, List> bodyParams, string token, string signingSecret) { 字符串结果;

        string nonce = GenerateNonce();
        HttpWebRequest sageOneWebRequest = WebRequest.Create(baseUrl) as HttpWebRequest;

        string PostParams = ConvertPostParams(bodyParams);

        string signatureString = GetSignatureString(baseUrl, null, bodyParams, nonce, WebRequestMethods.Http.Post);
        string signingKey = GetSigningKey(token, signingSecret);
        string signature = GenerateHmac(signingKey, signatureString);

        sageOneWebRequest.AllowAutoRedirect = true;
        sageOneWebRequest.Accept = "*/*";
        sageOneWebRequest.UserAgent = "Itemize";
        sageOneWebRequest.Headers.Add("X-Signature", signature);
        sageOneWebRequest.Headers.Add("X-Nonce", nonce);
        sageOneWebRequest.ContentType = "application/x-www-form-urlencoded";
        sageOneWebRequest.Timeout = 100000;
        sageOneWebRequest.Headers.Add("Authorization", "Bearer " + token);
        sageOneWebRequest.Method = WebRequestMethods.Http.Post;

        using (StreamWriter requestWriter = new StreamWriter(sageOneWebRequest.GetRequestStream()))
        {
            try
            {
                requestWriter.Write(PostParams);
            }
            catch(Exception ex)
            {
                throw new Exception("Exception thrown writing Post Params to Body", ex);
            }
        }

        try
        {
            using (WebResponse response = sageOneWebRequest.GetResponse())
            {
                Stream dataStream = response.GetResponseStream();
                using (StreamReader reader = new StreamReader(dataStream))
                {
                    result = reader.ReadToEnd();
                }
            }
        }
        catch (WebException webex)
        {
            //This is where the error is caught
            Logger.Error("Web Exception while processing Sage One Web Request: ", webex);
            string text;

            using (var sr = new StreamReader(webex.Response.GetResponseStream()))
            {
                text = sr.ReadToEnd();
            }

            result = null;
            throw new Exception("Web Exception thrown processing Sage One Request", webex);
        }
        catch (Exception ex)
        {
            Logger.Error("Exception while processing Sage One Web Request: ", ex);
            result = null;
            throw new Exception("Exception thrown processing Sage One Request", ex);
        }

        return result;
    }

非常感谢对此问题的任何帮助!谢谢!

编辑:关于下面的建议,实际遵循的URL路径是"api.sageone.com/accounts/v2/purchase_invoices",而不是收到的错误中指出的请求路径。

根据错误响应,请求路径看起来不正确。表明 "requestPath":“/api/v2/purchase_invoices”

但文档显示 /accounts/v2/purchase_invoices

您要发布到 /purchase_invoices,但您的参数是针对 expense。请使用 purchase_invoice 名称来包装您的参数。