• Home
  • About TechTalk
  •  

    New API features: Time entries and a lot more…

    16 July 2009

    With our July 14th update to version 1.4.5 of the e-conomic API, a number of new features have been added:

    Time entries may now be created via the API, using the new ITimeEntry class. This will open up a host of new possibilities for integrations (IPhone interface, anyone?). Note that this requires access to the Project Management add-on module. Also note that approval of time entries is not yet available in the API.

    Accruals may now be set on cash book entries, using ICashBookEntry.SetAccrualInformation(). Note that this requires access to the Accruals add-on module.

    Accounting years are now exposed (read-only), via the IAccountingYear class. This is a great help for integrating with e.g. reporting tools, where your calculations of account balances from entries (class IEntry) will depend on which accounting years are already closed.

    The new ISumInterval class allows reading and writing of sum intervals for sum interval accounts (AKA TotalInterval accounts in some language versions of the e-conomic web application). To retrieve all sum intervals for a given sum interval account, you can use IAccount.GetSumIntervals().

    It is now possible to look up invoices by order number, using IInvoiceUtil.FindByOrderNumber(). Note that, since the order number is auto-generated, the recommended way of tracking an invoice all the way through is to set ICurrentInvoice.OtherReference. Both ICurrentInvoiceUtil and IInvoiceUtil contains a FindByOtherReference() method for subsequently looking up your invoice.

    Subscription users can now find all subscribers on a customer using the new IDebtor.GetSubscribers() method.

    The IDebtorEntry and ICreditorEntry classes now expose a SerialNumber property, allowing you to uniquely identify individual debtor/customer and creditor/supplier entries.

    Finally, the new IEntryUtil.GetLastUsedSerialNumber() makes it even easier to synchronize entries between e-conomic and other systems, by allowing you to very quickly determine whether new entries have been created in e-conomic.

    As always, if you wish to utilize some of this new functionality, you need to upgrade to the latest version of Economic.Api.dll – or ‘re-consume’ the web service if you’re not developing on the .NET framework. Pick up the latest version of our SDK here.

    NOTE: The SerialNumber property on debtor/creditor entries seems to have caused some problems for a few people. Long story short: Make sure you’re using at least version 1.4.5.21081 of Economic.Api.dll, and you should be fine.

    For any technical questions on either the new or existing API functions, we are of course still available at api@e-conomic.com.


    New E-conomic API Forum Launched!

    8 June 2009

    Striving to be the best in the business, e-conomic now launches a new API Forum to meet the demands of the growing number of people who want to integrate their system with e-conomic.

    The API Forum is a place where developers who use e-conomic’s API can meet and exchange stories, tips ‘n’ tricks and help other users who need help in using the API.

    The Forum will host a number of categories (subject to change), where users can create topics and discuss challenges faced in the API.

    Starting out, the API Forum will have the following categories:

    • .NET
    • PHP
    • JAVA
    • SOAP
    • Miscellaneous
    • Integration

    A warm welcome to everyone,

    and see you at: http://apiforum.e-conomic.dk


    Planned downtime 18th of May 00:15-06:00 (CET)

    14 May 2009

    Our hosting center are upgrading their high-voltage power supply on May 18th between 00:15 and 06:00 (CET). In this period e-conomic will be unavailable, this means that neither the web site nor the API will be available. So if you have any automatic jobs running within this time interval, they will not be run on May 18th.

    As the system comes online again, we will be monitoring it to make sure that everything is running correctly.


    API: Something new, something faster…

    16 April 2009

    Last night, our latest Market Package with enhancements, fixes and improvements was released. It contains one new API feature, as well as a vast improvement of the speed of another.

    As for the new feature, it is now possible to login (‘Connect‘ in API terms) as an administrator. This facilitates integration with external accounting applications, e.g. reporting tools.

    To utilize this feature, instead of ‘logging in’ by using the Connect() method, you use the ConnectAsAdministrator() method, which takes the administrator user’s credentials (administrator agreement number, user ID and password), as well as the agreement number of a client to which the administrator user has access, as parameters. Note that the client in question of course still needs to have the API add-on module enabled.

    As for optimizations, we were recently made aware of some serious bottlenecks in our GetDataArray() methods when large registers are downloaded. Somewhat embarrassing, since we’re constantly pushing the data array methods as the recommended way of bulk reading/writing of data :-(

    After digging deeper into this, we discovered that the culprit was our ORM tool’s extremely conservative approach to checking for ‘dirty objects’ in its cache. While you’d expect the execution time for a GetDataArray() call to be proportional to the number of objects retrieved, in practice, it turned out to be polynomial instead! Not exactly what you’d want when downloading product registers in the thousands…

    While we could conceivably implement a generic workaround directly in our ORM tool, for the sake of risk minimizing, we have instead opted to implement bespoke optimizations on a per-object level – starting with the objects our logs show us to be the most frequently used.

    Last night’s release includes this optimization for the IProduct object – in practice, the Product_GetDataArray() method, which now handles upwards of a couple of thousand objects in a few seconds. The relative speed improvement increases with the number of objects – we’ve measured the speed increase to a factor of 10+ with 2,000 products.

    Our next Market Package release, due in mid-May, will include similar optimizations for a lot of other objects (IDebtor, ICreditor, IAccount, IInvoice, IInvoiceLine, etc.). As for all these registers, we still recommend ‘paging’ to approximately 500 objects for each call to its GetDataArray() method.

    For more detailed technical API documentation, take a look here.


    Improving API performance beyond data classes

    6 April 2009

    In the e-conomic API, using data classes is a powerful way of optimizing the retrieval, creation or updating of multiple entity properties – or even multiple entities – to use as few round-trips as possible.

    However, many developers are put off by the fact that when using data classes, only simple-type properties are returned – thus still requiring round-trips to retrieve properties of referenced objects.

    Suppose, for example, that we wish to list the product number, product name and product group number of all our products. The following would seem to be the obvious way of achieving this:

    IProduct[] arrP = session.Product.GetAll();
    IProductData[] arrPD = session.ProductData.GetDataArray(arrP);

    foreach (IProductData pd in arrPD)
    {
    Console.WriteLine("Number: " + pd.Number.ToString());
    Console.WriteLine("Name: " + pd.Name);
    Console.WriteLine("Group: " + pd.ProductGroup.Number.ToString());
    Console.WriteLine("");
    }

    This should result in only two round-trips – one for Product.GetAll() and one for ProductData.GetDataArray() – right? Wrong! For each product group, the above code will also generate a round-trip to retrieve the product group number (effectively a call to the SOAP function ProductGroup_GetNumber). The final result is a number of round-trips equalling n+2, with n denoting the number of products. This seems very unnecessary – especially since the number of products is usually several orders of magnitude higher than the number of product groups.

    First of all – why are the data classes designed this way? Why does the IProductData class return IProductGroup object references instead of IProductGroupData objects? While that would seem to be more consistent with the point of data classes, consider the ramifications if all data objects were to include referred objects as other data objects. In the above example:

    IProductData would include IProductGroupData
    • which would include IAccountData
    • which might include IVatAccountData (IAccount.VatAccount is NULLable)
    • which would include IAccountData
    • etc.

    In other words, this could quickly result in massively ‘recursive’ retrievals of data one would in most cases not have any use for.

    Luckily, there is another way of reducing the number of round-trips to an absolute minimum: Retrieve all product groups in one go, and store them in a dictionary with IProductGroup as key:

    IProductGroup[] arrPG = session.ProductGroup.GetAll();
    IProductGroupData[] arrPGD = session.ProductGroupData.GetDataArray(arrPG);

    Dictionary<IProductGroup, IProductGroupData> pgd = new Dictionary<IProductGroup, IProductGroupData>();

    for (int x = 0; x < arrPG.Length; x++)
    {
    pgd[arrPG[x]] = arrPGD[x];
    }

    IProduct[] arrP = session.Product.GetAll();
    IProductData[] arrPD = session.ProductData.GetDataArray(arrP);

    foreach (IProductData pd in arrPD)
    {
    Console.WriteLine("Number: " + pd.Number.ToString());
    Console.WriteLine("Name: " + pd.Name);
    Console.WriteLine("Group: " + pgd[pd.ProductGroup].Number.ToString());
    Console.WriteLine("");
    }

    This generates only four round-trips: ProductGroup.GetAll(), ProductGroupData.GetDataArray(), Product.GetAll() and ProductData.GetDataArray() – irrespective of the number of products or product groups. A similar trick can be used with any data class that includes object references.

    A final, and somewhat related performance tip: Throwing the result of GetAll() at GetDataArray() may of course still lead to massive amounts of data being downloaded. As a general rule, we recommend that you split the GetAll() result into batches of 500 entities for the subsequent data retrieval. While this will of course result in slightly more round-trips, it is much less prone to timeouts in either end.

    Take a look at our API documentation.