Intent/Audience
It is a mostly platform-agnostic description of the architecture and API for the Mutual Credit module for Drupal. It is of interest to drupal site builders and developers, as well as prospective users wondering how powerful this module is.
Introduction
This architecture supports mutual credit systems such as LETS, Timebanks other monetary-currency models in that every transaction is a debit from one account and a credit to another account. Mutual credit accounting can be used for fiat or backed currencies alike, by designating an account for issuance; the total balances of all accounts will always be zero. Much CC software is designed to promote a particular unused currency model, but this software seeks to foster a culture of monetary experimentation, especially as the skills to build and manage multi user web applications increase in ubiquity.
Mutual credit accounting is not suited to the gift economy or higher scapes of metacurrency. It is not intended to connect with national currencies, but of course virtual (unbacked) dollars, such as those which denominate B2B systems are fine. There is no integration with the banking system, and no special security suitable for national currencies. It does not support any anti-forgery notions related to issuance of physical exchange media, such as notes with serial numbers.
By designating an account for cash issuance, it is possible to issue notes or tokens, but not to track them. The system does not (yet) make payments to accounts outside of the system.
The Drupal implementation bridges the gap between hardcore accounting systems such as Cyclos which have a poor front end and poor integration with other web technologies, and the newer culture of web site 'assembly' in frameworks using contributed 'modules'. The structures, relationships and default settings described herein allow a high degree of configuration without scripting.
In particular, this architecture meets the following requirements.
- An accounting system to plug into online social networks
- An API to connect to other accounting systems.
- Highly configurable payment forms
- Optional 'signing' of exchanges by 2nd (or subsequent) parties.
- Credit/Debit limits, which can be controlled by code, with presets
- An arbitrary number of currencies, with extensible properties
- Scope for new trading tools and transaction types, such as demurrage, auctions, loans, gift tokens, interaction with the rest of the web
Data structure
The heart of the system is the transaction object.- TxID: unique identification
- Description (translatable)
- Payer ID or payer numbered account id
- Payee ID or payee numbered account id
- Amount - a multi-part multivalue field consisting of currency ID and quantity to two decimal places
- State (enumerated value allowing a modicum of workflow)
- Transaction Type: general purpose text identifier which could be useful later
- Created by user ID
- Created time
- Updated by user ID
- Updated time
Many of these fields can be left blank as long as the transaction state isn't 'finished'. This leaves the possibility later on to store not only pending transactions, but also transactions with incomplete data all in the same table.
Currencies are exportable, and consist of the following fields.
- unique currency name - 8 character
- Name
- Creator
- Description and intention
- subdivisions (using internal format)
- display format (using tokens)
- Accounting standards
- delete mode (none, delete, mark deleted)
- update mode (none, edit, replace)
- access control per transaction state
- view callback
- edit callback
- erase callback
- Balance limits
- limit callback
- limit callback options
Permissions work on both the global level and on the per-currency level. Global permissions are:
- Transact
- Manage all Transactions
- configure all currencies
- Declare currency
- Manage currency
However these concern only the management of the system. A multiple currency system needs fine-grained control over viewing and modifying transactions because different currencies may have different privacy requirements and accounting standards, and transactions exist in different workflow states. By storing access callbacks in the currency definition for every transaction state, and operation, modules can define richer access controls. so to update transactions in Hours in the 'pending' state, you might select 'access_transaction_creator', or 'access_transaction_participant'
The transaction controller
Drupal 7 introduces the notion of extensible 'entities' which can have their own combinations of field added, and which can have their own controllers. This means transactions need not be written to a drupal database at all. Rather than being validated and versioned as if it were an item of content, it can be handled more like a financial transaction. By initiating 2 database connections, transactions can be written to 2 databases (but read from only one!). More work can be done on this when it is asked for!
Flexible exchange forms
Modern frameworks can be expected to provide forms for editing data structures, but building a payment system requires very precise control over forms, to remove ambiguities and optimise usability.
Full control of form layout means writing the html of the form, preferably using tokens for the form elements themselves. Forms are, like currencies, exportable objects. In addition developers might want to create any number of forms for different purposes or currencies, perhaps utilising presets and/or hiding fields. Forms are also intrinsically wrapped up in transaction workflow. So the form building interface is quite complex. The following default forms are provided, all constructed using the same tool.
- Third person transaction where payee and payer are identified
- First person form which specifies the user's trading partner, and the direction of the transaction
- Mass Transactions, which have many payers or payees, and save them as one transaction for each
- Edit form, to present the user with a nicely formatted or limited transaction edit form
The form introduces the concept of 'perspective', which refers to whether it is for a user designating another user to trade with (1st party), or whether the payer and payee are entered directly (3rd party).
It only accepts transactions in a certain state, and it saves them to a specified state. This is as close as we get to workflow. When building the form, each of the mandatory transaction fields - payer, payee, currency, quantity, type, and any of the other fields adjoined to transactions using the Field API, such as 'description' or 'date', can be prefilled and disabled or hidden. The payer and payee fields are controlled by another module I created called 'user chooser' which has its own callback to determine valid users, and offers the form builder a choice of drop-down or autocomplete widgets.
Once the fields are prepared they are inserted as tokens into textarea where the form html can be composed by the administrator or usability professional!. Tokens not included become hidden fields. The optional second stage of the form allows an 'are you sure' page, in which the tokens are evaluated not as form elements but as text. Another module adds the opportunity here also to compose the notification email which accompanies the form, allowing the notifications can be as specific as the forms themselves, and to use the same token sub-system
Each form has its own url path, and can produce a block as well. Other modules can modify the form as it is built at runtime, using drupals hook_alter API. Finally there is be an address to redirect to after the form is processed.
Signatures
The signatures module saves a list of required user signatures and put the transaction into a new state, 'pending' before the transaction enters the finished state.. It provides a new webform for 'signing' a transaction, and when the form is submitted it checks if any more signatures are needed before moving the transaction to finished state.
Display elements
The Drupal 'views' module is a query builder and display engine for showing lists. Much work has been done with the storage formats, which views likes to read directly, and with virtual fields, and custom filters and arguments, to utilise the power of views to the site builder. The important but diverse requirements are to be able to present periodic summaries of the activity on the site, to produce activity summaries per user like bank statements, including running balances if possible. Care had to be taken over transaction visibility, since each currency and transaction state has its own 'view' permissions. Performance or at least scalability (or at least caching) is also a consideration.
The main transaction table is exposed to views, but every query is altered to exclude transactions in currencies and states that the user isn't supposed to see. That way the Drupal pager still works.
The solution involved a new transaction index table which makes two rows for each transaction, one from the perspective of each user. (If this could be done as a MySQL 'view' it would put a lot of load on the database instead of less efficient php, and reduce opportunities for data corruption). One row contains the following fields:
- First user
- Second user
- quantity, (column is added to calculate trade volume)
- income (column is added to calculate gross income)
- expenditure (column is added to calculate gross expenditure)
- diff (column is added to calculate user balance)
- currency
- created date
- running balance (if a transaction is edited this whole column needs to be recalculated)
Queries on this table are almost all grouped, so privacy of individual transactions needs to be done by design only. Account balances, promiscuity rates, trade volume, total income other data can be derived FOR ANY PERIOD. Only finished transactions are written to this table. This dynamic approach means that the database is efficiently doing most of the work. but it can be combined with caching of the whole displays if the load needs to be lightened
External APIs (no use case yet)
While accounting systems can live anywhere, they should also be controllable from anywhere using the same API. The Drupal services module enables CRUD and other definable operations on entities. This is incomplete, but remote applications should be able to log in to Drupal, create transactions, retrieve balances and listings. In short, to treat this application as an accounting service. A basic set of methods would be
- transaction.create(object)
- transaction.delete(xid)
- transaction.save(object)
- account.getbalance(accountID, CurrencyID)
- account.statement(accountID, sinceDate)
Future plans
Everyone is asking for the ability to coordinate transactions between mutual credit systems (intertrading); Opentransact has been identified as the appropriate protocol for this, but more work needs to be done on server2server authentication before this is useful.
I have built an experimental transaction controller for Openmoney which enables users of one currency to login to drupal and make transactions which are written and read from the central Openmoney database. This will soon enable a cleaner experience for Community Way projects.
The module now really deserves a B2B application and I am actively seeking partners to build an open source B2B drupal installation.
Comments1
I am interested to learn of
I am interested to learn of your Drupal project . . . have been working to set up a mutual credit network here in the Hudson Valley. Right now we have a test installation of Cyclos for Communities. A major limitation of that is the inability to assess transaction fees. Does your Drupal system do that? I did not see any mention of such a function. This seems to be a serious need for such a system, since the long term viability of such networks depends on some kind of funding. Our beta users seem comfortable with having a percentage deducted in the transaction, giving the network a positive balance in our unit of currency, The Current.
Interested to communicate with you about this and related matters. I am also doing a time bank project for a creative community in development.
With thanks, David McCarthy