Jump to content

Stuart Eastland

Members
  • Posts

    19
  • Joined

  • Last visited

  • Days Won

    1

Stuart Eastland last won the day on February 24 2021

Stuart Eastland had the most liked content!

Reputation

3 Neutral

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. OK, so I just tried it without specifying ANY attributes. The API documentation states that this will only return the "base attributes (name, path)" however it has returned the full data set including nested data such as contact. Poorly written documentation or am I missing something?
  2. This is all I get: {{ "id": "8057948faa504a7ea77f6399c7ae0408", "displayed_as": "SI-1008542", "$path": "/sales_invoices/8057948faa504a7ea77f6399c7ae0408", "date": "2022-11-30", "reference": "DN 19676", "shipping_net_amount": "51.0", "net_amount": "3242.72", "tax_amount": "12.83", "total_paid": "0.0", "last_paid": "" }} I am using the 32 character guid to retrieve the data. I need to get data for pro-forma which don't have a numeric id assigned.
  3. I am using the endpoint /sales_invoices/{key} to retrieve a sales invoice. I also specify the following parameters: "attributes" = "reference,vendor_reference,date,last_paid,net_amount,shipping_net_amount,tax_amount,total_paid,contact_id" "nested_attributes" = "contact" The API documentation suggests that I should be able to retrieve the nested data for contact, however the returned contact is null. The API documentation showing the sample payload also suggests that the contact_id might be returned as a field in the main body, hence I have added this to my attribute list, however this is also returned as null. The other data is returned as expected. Any suggestions on how to retrieve the contact key for a sales invoice and sales credit note?
  4. I've just gone through the process of getting the oAuth callback to work and have posted simplistic demo code in an earlier thread: Oauth2 Authorisation and IIS - Support - Sage Developer Community You need to have logic in the callback to retrieve the code sent from sage and then request the tokens. I found this easiest to do on a development machine using localhost. If you don't use localhost you need to use https. One thing to note is the token is refreshed without using the callback url, so it may be something that you only need to do initially as long as your refresh token does not expire (30 days?).
  5. Thanks Ben, that works perfectly although it does mean a second request when creating new products/contacts. Also your pointers to the "key concepts" in your help pages should reduce the number of further questions from me 😁 My project to allow our in-house system to push products, contacts and sales invoices directly into Sage went live this week following our migration from sage50 and should result in significant time (and error) savings. However, the json in your previous answer makes me question the best way for me to deal with paginated queries. I understand the principle behind the $total, $page, $items elements, however I have not found an efficient way to de-serialize the "$" prefixed data. I appreciate that this is more of a basic coding question rather than Sage specific, but I wondered if you can give me some hints for use with C#.
  6. I am able to push sales invoices into Sage using the API, however some of these need to be PROFORMA. When creating a new invoice online I can set the dropdown to DRAFT or PROFORMA but I cannot see any such option in the API.
  7. Here is my commented pseudo-code for the callback.Please feel free to peer-review and make suggestions for improvement. public partial class SageCallback : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (Request.Params["code"] == null) { Response.Redirect("Default.aspx?Message=Missing [code] parameter in sage callback request."); } RestClient client = new RestClient("https://oauth.accounting.sage.com/token"); RestRequest request = new RestRequest(Method.POST); request.AddObject(new { code = Request.Params["code"], client_id = < your SageClientId >, client_secret = < your SageClientSecret >, redirect_uri = < your SageCallbackUrl >, grant_type = "authorization_code" }); IRestResponse response = client.Execute(request); if (response.ErrorException != null) { Response.Redirect("Default.aspx?Message=" + response.ErrorException.Message); } if (response.StatusCode.ToString() != "OK") { Response.Redirect("Default.aspx?Message=Unexpected error authenticating Sage"); } User currentUser = < persisted user object >; currentUser.SageAccessToken = GetJsonValue(response.Content, "access_token"); currentUser.SageRefreshToken = GetJsonValue(response.Content, "refresh_token"); long expires = long.Parse(GetJsonValue(response.Content, "expires_in")); // seconds currentUser.SageAccessTokenExpiry = DateTime.UtcNow.AddSeconds(expires); long refreshExpires = long.Parse(GetJsonValue(response.Content, "refresh_token_expires_in")); // seconds currentUser.SageRefreshTokenExpiry = DateTime.UtcNow.AddSeconds(refreshExpires); currentUser.Save(); string url = "Default.aspx?Message=Sage access granted. Please retry Sage update request."; Response.Redirect(url); } }
  8. Here is my commented pseudo-code for getting the token. I'll post the code for the callback separately. Please feel free to peer-review and make suggestions for improvement. private static string GetOAuthToken() { User currentUser = new <persisted user data >; // if the token has not expired, use it if (currentUser.SageAccessTokenExpiry != DateTime.MinValue && currentUser.SageAccessTokenExpiry > DateTime.UtcNow) { return currentUser.SageAccessToken; } // if refresh token has not expired, get a new token if (currentUser.SageRefreshTokenExpiry != DateTime.MinValue && currentUser.SageRefreshTokenExpiry > DateTime.UtcNow) { RestClient client = new RestClient("https://oauth.accounting.sage.com/token"); RestRequest request = new RestRequest(Method.POST); request.AddObject(new { client_id = < your SageClientId >, client_secret = < your SageClientSecret >, refresh_token = currentUser.SageRefreshToken, redirect_uri = < your SageCallbackUrl >, grant_type = "refresh_token" }); IRestResponse response = client.Execute(request); if (response.ErrorException != null) { throw response.ErrorException; } if (response.StatusCode.ToString() != "OK") { if (!response.Content.Contains("refresh_token is invalid")) { throw new ApplicationException(response.Content); } } else { currentUser.SageAccessToken = Common.GetJsonValue(response.Content, "access_token"); currentUser.SageRefreshToken = Common.GetJsonValue(response.Content, "refresh_token"); long expires = long.Parse(Common.GetJsonValue(response.Content, "expires_in")); // seconds currentUser.SageAccessTokenExpiry = DateTime.UtcNow.AddSeconds(expires); long refreshExpires = long.Parse(Common.GetJsonValue(response.Content, "refresh_token_expires_in")); // seconds currentUser.SageRefreshTokenExpiry = DateTime.UtcNow.AddSeconds(refreshExpires); currentUser.Save(); return currentUser.SageAccessToken; } } // otherwise, start the process by requesting a new code HttpContext.Current.Session["SageRequestUrl"] = HttpContext.Current.Request.Url; string url = string.Format("https://www.sageone.com/oauth2/auth/central?filter=apiv3.1&response_type=code&client_id={0}&redirect_uri={1}&scope=full_access", Common.SageClientId, Common.SageCallbackUrl); HttpContext.Current.Response.Redirect(url); return string.Empty; }
  9. Hi Ben, I wonder if you can help me again? Your suggestion to use the links/href in the contact json resolved my requirements for contacts, however the products uses the same dual unique key scenario where the API requires the 32 character key and the pages require a numeric id which I cannot find anywhere in the json returned or a product. This does not have a links section. So, how do I find this numeric id for a product so I can construct a link from our internal website?
  10. In answer to my own question, I clearly need to use an SSL secured url that can be resolved externally so I need to get an SSL certificate installed on the server as my next step.
  11. I have been working on using the API running on a development machine with our website and oAuth callback on localhost. Just installed on our server which is running inside a fire wall and now get www.sageone.com refused to connect when trying to fetch the oauth token. I am using an internal ip address. Is this going to be possible? I figured that localhost was also local so a local ip address should work too.
  12. I started trying to do this in December. There is no API for sage50. We just migrated to Sage Online, far superior and excellent API. Task completed in a couple of days including full integration or products, customers and suppliers.
  13. Thanks. That is perfect. I thought that I had looked through the returned json but maybe missed this. I think the issue with the reference number is that the migration populated the reference number with the original invoice number and the invoice number with a transaction number that previously had not been visible to end users. This means that all our sales invoices now have different numbers to those sent to our customers. I anticipate some frustration when we start getting queries on these! I have not been very impressed by the migration. I don't see why the data above has been transposed as it is clear that I can create new invoices the way I want to, and use the reference number for our internal despatch number and continue to use the previous invoice number sequence in invoice number. Also the migrated data is read only. What happens if we need to change a journal code or reprint a sales order (print is disabled too).
  14. We push sales invoices from our in-house system into sage using the API, a process that also creates customers and suppliers in Sage if required. When I create a Contact (customer or vendor) using the API I get a 32 character "id" and the $path shows as /contacts/abcde where abcde is the 32 character id. When I use Sage online and search for a contact the resulting url looks like /contacts/customers/12345678 where 12345678 is an 8 digit numeric id which I cannot find in the data returned from Sage when I do a Contact GET. I note that the API uses the 32 character id when creating sales invoices, so this is what I am persisting against customers in our in-house system.. So my question is, how can I construct a url to a contact using the 32 character id? If this is not possible, how can I obtain the numeric id that Sage uses in the page url for contacts? As a wider question, why does Sage use so many different identifiers? It is even worse in a sales invoice which has the 32 character id, a SI-nnnnn transaction id and another sequential sales invoice id in the reference field. the SI-nnnnn seems unnecessary. We have just migrated from sage50 where we used to use the reference column to hold a unique identifier to the corresponding despatch data in our own system, but there is no suitable place for this now.
  15. I am using POST to create a new sales order but I get an error saying that "contact cannot be found". I am using a unique reference for all my contacts which matches the database id from our in-house database as a lookup on contacts (customer/supplier), however I am supplying the numeric "id" for a customer which I get from the customer details page url when using the api.
×
×
  • Create New...