Sage One API возвращает 500 Internal Service Error при создании платежного счета

У меня возникла проблема при создании «Счета за покупку» в Sage One API. Независимо от того, какие изменения я вношу в передаваемые данные, я, похоже, получаю 500 Internal Service Error и не получаю подробного ответа, содержащего какую-либо значимую информацию. Ответ всегда один и тот же, независимо от того, какие данные я ввожу (только то, что кажется GUID в поле errorCode и время сервера меняется). Ответ выглядит следующим образом:

{
"$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"
      }
     }
  ]
}

Я уверен, что это не проблема авторизации, так как я получаю и создаю другие типы данных до этого. Сюда входят контакты, необходимые для создания счета-фактуры на покупку.

Я следил за информацией, представленной на их сайте самообслуживания. Я также начал с их базового 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;
    }

Вот фактический метод, который создает и выполняет веб-запрос:

общедоступная статическая строка Create (Uri baseUrl, List> bodyParams, токен строки, string signingSecret) { string result;

        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", а не путь запроса, указанный в полученном сообщении об ошибке.


person Vin B.    schedule 29.04.2016    source источник


Ответы (2)


Вы отправляете сообщение на /purchase_invoices, но ваши параметры предназначены для expense. Пожалуйста, используйте имя purchase_invoice для переноса ваших параметров.

person Christoph Petschnig    schedule 05.12.2016

Путь запроса выглядит неверным в соответствии с ответом об ошибке. Он показывает "requestPath": "/api/v2/purchase_invoices"

но документация показывает /accounts/v2/purchase_invoices

person mfyameen    schedule 03.05.2016
comment
Однако я изменяю свой первоначальный комментарий, чтобы здесь было ясно, фактический URL-адрес называется api. sageone.com/accounts/v2/purchase_invoices, как указано в документации. Я не знаю, почему API возвращает этот URL. - person Vin B.; 04.05.2016