Amatino Swift 0.0.10 Released

A new version of Amatino Swift has been released. 0.0.10 adds some Custom Unit capabilities, slims some method signatures, and various smaller bits and pieces.

Note that release 0.0.9 was skipped for reasons of… science. 0.0.8 is the previously released Swift library version.

  • Big breaking change: Session is no longer required as an argument for Performance, Position, Transaction, Balance, and RecursiveBalance
  • Build out the previously useless CustomUnit, including .retrieve().create(), .createMany(), and update() methods
  • Added unit tests for new CustomUnit methods.
  • Simplify internal AmatinoObject protocol (no change to public API)
  • Entity now conforms to Equatable protocol
  • Add Entity.delete() method
  • Add EntityList object
  • Fixed a bug causing Ledger and RecursiveLedger iterators to skip the first row in the Ledger

Amatino Python 0.0.7 Released

Amatino Python 0.0.7 has been released! This is a major new release, introducing a vast array of capabilities. It is not backwards compatible with 0.0.6. You can install Amatino via PyPi:

$ pip install amatino

Or, if you already have Amatino Python installed, upgrade:

$ pip install --upgrade amatino

Here’s the full list of changes:

  • Added Entity class including .create(), .retrieve()
  • Added Account class including .create(), .retrieve(), .update()
  • Added Transaction class including .create(), .retrieve(), .update(), .delete()
  • Added Entry class including various convenience initialisers
  • Added GlobalUnit class including .retrieve()
  • Added CustomUnit class including .create(), .retrieve()
  • Added User class including .retrieve()
  • Added Ledger & RecursiveLedger classes
  • Added internal Denomination abstract class
  • Added internal enumeration HTTPMethod
  • Added internal interface Encodable
  • Added some internal error types to provide more robust error explanations
  • Added tests for new classes
  • Removed AmatinoAlpha class & attendant tests

The high level

0.0.7 is the first Amatino Python release to include expressive, object-oriented syntax. Previous releases required manual composition of requests using the AmatinoAlpha object.

Documentation

So many new goodies. But how do we use them? Documentation to the rescue! All the new classes included in 0.0.7 are documented in Amatino Python’s GitHub Wiki. For example, you can check out the Transaction page to see all the Transaction class’s properties and methods.

The future

The most glaring omissions are 0.0.7 are probably Balance, Position, and Performance. Expect 0.0.8 to add those bad boys in the near future.

Enjoy!

– Hugh

Amatino JS 0.0.12 Released

Amatino’s Node.js library has receive a big ‘ol update. 0.0.12 lifts Amatino JS out of bare-bones alpha territory. New classes allow you to build accounting & finance functions into Node.js applications.

0.0.12 is by no means a ‘feature complete’ or beta release. Most Amatino services still lack dedicated classes. However, it is a major step towards such a release. To see plans for 0.0.13 and beyond, check out the newly populated GitHub issue tracker, and Projects page within which future work is organised into planned releases.

New capabilities

Amatino JS now offers the following classes:

Allowing you to easily access and manipulate the `Primary Objects’ discussed in Amatino’s HTTP documentation.

Amatino Javascript Documentation

This release includes the first version of Amatino’s Javascript documentation. The docs are hosted on the Amatino JS GitHub wiki. They provide comprehensive reference for all properties and methods, and example code.

Screenshot from the Amatino JS docs Account page

Installation & Usage

You can install Amatino JS via NPM. For more information about NPM, check out npmjs.com.

$ npm install amatino

Amatino classes may then be accessed by requiring Amatino:

const Amatino = require('Amatino');
Amatino.Transaction.create(...);

The Amatino JS Readme has been updated with a getting-started guide, including example code showing you how to start utilising Amatino services. Check it out on the Amatino JS GitHub page.

What’s next?

Check out the Amatino JS Projects page to see the roadmap for future releases. These plans are totally in flux: Feel free to contact me via Twitter (@hugh_jeremy), email (hugh@amatino.io), or on the Amatino discussion forums, and tell me what you would like to see next.

Special thanks must go to James Robb (jamesrobb.co.uk). Over the past few weeks, James has provided substantial and invaluable advice about how to move the Amatino JS project forward. Thank you James!

– Hugh

 

 

On Prices

The upcoming API 0.0.8 release targets Global Units, Custom Units, and a new Price object that bridges them. It is forcing me to consider some difficult questions.

Amatino’s double-entry data model adopts a ‘quantum mechanics’ approach:  Transactions are the atomic units of all financial information, but they themselves are composed of the more fundamental Entry object, with which we never directly interact. This approach allows financial data to be stored as arbitrary precision numbers in their native denomination.

It also means that the data model does not inherently satisfy the double-entry accounting equation. If external constraints are not applied, it would be possible to store an unbalanced Transaction: The composing Entries may not add up to zero, and the equation would not hold.

Obviously, Amatino is designed with stringent constraints. Attempt to insert an unbalanced Transaction and the digits ‘400’ will present themselves quick smart. But what if a Transaction balance is changed after it is inserted?

How could this happen? It is a matter of relativity. Say you create a Transaction (TX) worth 1 U.S. Dollar (USD) with Entries party to two Accounts: One denominated in USD, and one denominated in Woozlewozzles (WZL). WZL being some Custom Unit you have fed to Amatino.

Perhaps TX is created on 1 Jan 2018, dated at 1 Jan 2018, and at that time, the last WZL / USD price you provided was for 31 Dec 2017, at 2 WZL = 1 USD. Amatino will eat TX and store one Entry for 1 USD, and one Entry for 2 WZL.

Now suppose that on 2 Jan 2018, you have access to new price data. You supply Amatino with a 1 Jan 2018 WZL / USD price of 1 WZL = 1 USD. Ceteris paribus, TX is now unbalanced: Attempt to retrieve TX and Amatino will compute output using the price with time closest-to-but-less-than TX time: 1 Jan 2018.

That yields a WZL entry with double the value that it had at Transaction entry. The double-entry equation is violated and the universe (presumably) implodes.

What’s the solution? The two I am working with right now are:

1. Anchors

When creating a Transaction, a client may specify some (but not all) constituent Entries as being ‘anchors’. When a new Price is inserted, Amatino looks for any Transactions with Entries party to an Account denominated in the Priced unit, with an effective time less than the next most recent Price, and greater-than-or-equal to the new Price.

Amatino then calculates the difference between the old balance and the new balance based on the new Price. That difference is distributed proportionally across any (or the only) Entry that is not marked as being an anchor.

One advantage of Anchors is that they would be compatible with future-dated Transactions with heterogeneous Global Unit denominations.

2. Blind Repair

Similarly to solution (1), Blind Repair would look for any Transactions affected by a new Price. Instead of applying the difference in balance to specially identified Entries, Amatino applies the difference to any Entry in the Priced unit.

One advantage of Blind Repair is that it does not add new complexity to the Transaction model. Anchors would require implicit or explicit decision making on every Transaction entry.

Blind Repair would not be compatible with future-dated Transactions with heterogenous Global Unit denominations. Global Unit prices are updated metronomically at ~1800 UTC each trading day. If a Transaction contained Entries party to say, USD and Euros, how would Blind Repair choose which Entries to adjust? I don’t see a way to make the process deterministic.

What to do?

Right now, I am leaning towards choosing Blind Repair. I would combine it with a new restriction: Transactions cannot be future-dated when they are denominated in heterogenous units where one of those units is a Global Unit.

It will be frustrating to be unable to conveniently future-date known upcoming or recurring Transactions with such denominations. However, I think the increased complexity of Anchors means they are not a viable alternative.

Have thoughts on a third way? Let me know in the comments!

– Hugh

 

Amatino Swift 0.0.8 Released

A new version of Amatino Swift has been released. 0.0.8 makes Amatino Swift CocoaPods compatible. You can now install Amatino by adding it to your Podfile:

pod 'Amatino', '>= 0.0.8'

The underlying library is unchanged. Here’s the full changelog:

  • Added Amatino.podspec
  • Changed macOS target to 10.10 (arbitrary at this point)
  • Changed iOS target to 10.3 (arbitrary at this point)
  • Added MIT license
  • Updated readme.md to reflect latest development of the library

– Hugh

Amatino Swift v0.0.7 Released

Amatino Swift 0.0.7 is now available! You can install it via Carthage or get the source code from GitHub. 0.0.7 is a major new release that adds significant capability. The powerful Tree, Position, and Performance objects are now available. Here’s the full change-log:

    • Remove InternalLibraryError, which sneakily survived the error consolidation purge in 0.0.6
    • Add Account.update() method
    • Add Account.delete() method
    • Add Account.deleteRecursively() method
    • Add Tree class
    • Add Position class
    • Add Performance class
    • Add Node protocol
    • Add Node conforming TreeNode and PlaceholderNode classes (used by Tree, Position, and Performance)
  • Consolidate SessionCreateArguments & SessionAttributes into Session
  • Consolidate BalanceRetrieveArguments into Balance
  • Drastically simplified and empowered the internal EntityObject protocol, reducing code complexity and duplication (does not affect public API)
  • Added unit tests for new features

Plant some Trees

Trees present the entire chart of accounts of an Entity as a hierarchical object. Each node in the Tree summarises an Account, including an individual and recursive balances.

Each node is represented by an instance of a class conforming to the Node protocol. Two such classes existing: TreeNode and PlaceholderNode.

TreeNodes present summarised account data, including individual and recursive balances. PlaceholderNodes stand in for TreeNodes where the requesting User does not have read permissions for the Account in question. A PlaceholderNode still includes children, which may include TreeNodes if the User has permission to read from accounts further down the hierarchy.

Determine Position

Positions are generic representations of the accounting construct variously known as a balance sheet, statement of financial position, or something else depending on your jurisdiction. They include hierarchical representations of all asset, liability, and equity Accounts inside an Entity.

Like the Tree, each Account is represented by an instance of an object conforming to the Node protocol.

Measure Performance

Performances are generic representations of the accounting construct variously known as an income statement, statement of financial performance, or comprehensive income statement, depending on your jurisdiction. They include hierarchical representations of all income and expense accounts inside an Entity.

Like the Tree and Position objects, each Account is represented by an instance of an object conforming to the Node protocol.

Updating & Deleting Accounts

Account instances now feature .update() and delete() methods, which do what it says on the tin. Here’s an example of an update operation:

Delete operations require a bit of thought. Deleting an Account does not delete any Transactions with Entries party to that Account. As such, you must supply an Account you wish to transfer any Entries to upon deletion. Here’s an example:

What next…

0.0.8 will probably focus on units of account, i.e. GlobalUnits & CustomUnits. In particular, loading CustomUnits into an Entity so that you can denominate Transactions in whatever unit suits you.

– Hugh

Amatino Swift v0.0.6 Released

Amatino Swift 0.0.6 has arrived! 0.0.6 makes lots of under the hood changes, the most important being to the error types emitted by the library. Here’s the changelog:

  • Added Transaction.update() method
  • Added Transaction.delete() method
  • Added session and entity properties to Transaction(A side-effect of the addition of .update() and .delete())
  • Consolidated all errors emitted by Amatino Swift under a single error type, AmatinoError
  • Potential API response errors (e.g. server errors) are now gracefully & descriptively emitted by instances of AmatinoError.
  • Consolidated creation, update, and retrieval argument structs into Transaction, e.g. TransactionCreateArguments -> Transaction.CreateArguments
  • Consolidated AccountCreateArguments struct into Account as Account.CreateArguments
  • Replaced overloaded Account.create() & .retrieve() with Account.createMany() & .retrieveMany()
  • Internally re-plumbed Transaction to conform to a new internal EntityObject protocol, reducing code duplication (causes no changes to API)
  • Renamed UrlParameters(:Entity:[UrlTarget]) entity label from entityWithTargets to entity
  • Removed defunct ObjectCore, AmatinoObjectError, and ConstraintError types
  • Consolidated EntityCreateArguments struct into Entity.CreateArguments
  • New unit tests for new features

New Error Handling

Before 0.0.6, errors thrown by Amatino Swift were an absolute mess. There was AmatinoObjectError, ConstraintError, ResponseError, and even just plain old Error. Now, you can be sure that any error thrown by Amatino Swift will be of type AmatinoError.

AmatinoError provides an enum, Kind, off of which you can switch via AmatinoError.kind. For example, a Transaction.retrieve() request might yield a .notFound case when the Amatino API returns 404. You can get a verbose String description of an error by examining the AmatinoError.message property.

Some objects, such as Transaction, provide a superclass of AmatinoError called ConstraintError, which provides more detailed information about input constraint violations. For example, when you supply  Transaction.create() with a description that is too long.

You can still handled these more verbose ConstraintError cases with a plain AmatinoError handler, as AmatinoError will flag them with the .constraintViolated case.

Transaction Update & Deletion

Sometimes you might which to change a Transaction after storing it. Perhaps an error was made, or underlying facts have changed. You can now do so using the update() instance method. Here’s an example:

You may also flat out delete a Transaction using the delete() instance method. Example:

Consolidation of ancillary structs

Many Amatino Swift classes depend on a variety of ancillary structs to perform their work. For example, Transaction uses CreateArguments and UpdateArguments, as well as several internal types. These types were previously in their own files.

This arrangement was causing the Amatino Swift project to be a bit jumbled. Code completion when typing the start of an object name was also getting crowded. So, as a matter of preference, I’ve been moving all ancillary types into their relevant classes. For example, TransactionCreateArguments has become Transaction.CreateArguments.

This process started in 0.0.5, and is ongoing in 0.0.6. There are a few cases of the old style left, which I’ll probably get to in 0.0.7.

Enjoy!

– Hugh

Amatino Swift v0.0.5 Released

Amatino is a double entry accounting API, and Amatino Swift allows macOS & iOS developers to utilise Amatino in a Swift application. v0.0.5 is a major new Alpha release introducing the Ledger class, and some attendant smaller changes.

  • Added new Ledger class
  • Added new RecursiveLedger class
  • Added new LedgerPage class, a low level class underpinning Ledger and RecursiveLedger
  • Added new LedgerRow struct, used by Ledgers
  • parentAccount renamed to parent in AccountCreateArguments initialisers
  • AccountType is now inferred by AccountCreateArguments when a parent is supplied
  • Added new Account.create() async initialisers for various attribute mixes
  • Transaction will now throw ConstraintError if debits & credits do not balance on creation
  • Fixed a bug whereby all times sent to the Amatino API were in local system timezone rather than UTC
  • Added new Ledger-related unit tests

Retrieving a Ledger

Multiple Ledger.retrieve() overloads are available, allowing you to tailor the Ledger to your needs. For example, you might want to retrieve a specific timeframe or denominate the ledger in a particular unit (e.g. a non-native currency). You can also reverse-order the Ledger such that the first pages retrieves the most recent transactions.

RecursiveLedger syntax is identical to Ledger, but delivers every Transaction in the target Account and all of its children.

Installation

Amatino Swift may be installed via Carthage. Add github "amatino-code/amatino-swift"to your Cartfile.

Enjoy, and be sure to tell me what you think!

– Hugh