building a powerful double entry accounting system
TRANSCRIPT
![Page 1: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/1.jpg)
BUILDING A POWERFUL DOUBLE-ENTRY ACCOUNTING SYSTEMLucas Cavalcanti
![Page 2: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/2.jpg)
DOUBLE-ENTRY ACCOUNTING ANCIENT, UBIQUITOUS TECHNOLOGY
![Page 3: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/3.jpg)
![Page 4: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/4.jpg)
![Page 5: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/5.jpg)
USER BALANCES
Future bills
Open bill
Due bill
Available balance
![Page 6: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/6.jpg)
OPERATIONS
Purchases
Chargebacks
Payments
![Page 7: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/7.jpg)
BALANCE SHEET
![Page 8: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/8.jpg)
DEBIT CREDIT
General Ledger
USEFUL ABSTRACTIONS
Income statement
Cash flow statement
Balance sheet
LIABILITYASSET
EQUITY
Debits Credits
![Page 9: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/9.jpg)
PROPERTY: on each movement
Image © http://chestofbooks.com/business/reference/Home-Cyclopedia-Of-Business/Bill-Book.html
![Page 10: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/10.jpg)
Credits (CR): - $97 on liability payables (we will pay the merchant) - $3 Credit on P&L interchange (our profit)
- $100 on off-balance asset current-limit
EXAMPLE: A purchase of $100
Debits (DR): - $100 on asset settled (we will receive it from the customer)
- $100 on off-balance liability current-limit-cp
![Page 11: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/11.jpg)
EXAMPLE: A payment of $100
Debits (DR): - $100 on asset cash (we received it from the customer)
- $100 on off-balance asset current-limit
Credits (CR): - $100 on asset settled (we paid the purchase)
- $100 on off balance liability current-limit-cp
![Page 12: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/12.jpg)
DOUBLE ENTRY ACCOUNTING
EVENTS TRIGGERING MOVEMENTS • purchases • payments • bills
IMMUTABLE • append-only • entry log • can fix past by compensating
INVARIANTS • movements sums to zero • a book-account balance is sum of credits
and debits
![Page 13: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/13.jpg)
1 MOVEMENT => N ENTRIES
(s/defschema Entry {:entry/id s/Uuid :entry/amount PositiveAmount :entry/debit-account BookAccount :entry/credit-account BookAccount :entry/post-date LocalDate :entry/movement Movement})
So by design,
(ns double-entry.models.entry (:require [schema.core :as s]))
![Page 14: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/14.jpg)
1 BUSINESS EVENT => 1 MOVEMENT + META e.g new-purchase, new-payment, new-bill
(s/defschema Movement {:movement/id s/Uuid :movement/flow-id String :movement/topic Topic :movement/owner-account Account :movement/produced-at LocalDateTime :movement/consumed-at LocalDateTime :movement/user String})
(s/defschema Meta {:meta/id s/Uuid :meta/movement Movement :meta/entity (s/either Payment Purchase Bill ...)})
![Page 15: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/15.jpg)
DECLARATIVE RULES FOR MOVEMENTS
(ns common-schemata.wire)
(s/defschema Purchase {:purchase {:id s/Uuid :merchant String :amount t-money/PositiveAmount :interchange t-money/PositiveAmount :time LocalDateTime …}})
(s/defschema Payment {:payment {:id s/Uuid :amount t-money/PositiveAmount :post-date LocalDate …}})
![Page 16: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/16.jpg)
DECLARATIVE RULES FOR MOVEMENTS
(def new-purchase [{:entry/debit-account :book-account.asset/settled-brazil :entry/credit-account :book-account.liability/payable-brazil :entry/amount (comp :amount :purchase) :entry/post-date (comp time->date :time :purchase)}
{:entry/debit-account :book-account.liability/payable-brazil :entry/credit-account :book-account.profit-and-loss/interchange-brazil :entry/amount (comp :interchange :purchase) :entry/post-date (comp time->date :time :purchase)} {:entry/debit-account :book-account.liability/current-limit-counterparty :entry/credit-account :book-account.asset/current-limit :entry/amount (comp :amount :purchase) :entry/post-date (comp time->date :time :purchase)}])
![Page 17: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/17.jpg)
DECLARATIVE RULES FOR MOVEMENTS
(def new-payment [{:entry/debit-account :book-account.asset/transitory-bank :entry/credit-account :book-account.asset/settled-brazil :entry/amount (comp :amount :payment) :entry/post-date (comp :post-date :payment)} {:entry/debit-account :book-account.asset/current-limit :entry/credit-account :book-account.liability/current-limit-counterparty :entry/amount (comp :amount :payment) :entry/post-date (comp :post-date :purchase)}])
![Page 18: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/18.jpg)
[{:entry/id (uuid) :entry/amount 100.0M :entry/debit-account :book-account.asset/settled-brazil :entry/credit-account :book-account.liability/payable-brazil :entry/post-date #nu/date "2016-12-01" :entry/movement new-purchase} {:entry/id (uuid) :entry/amount 3.0M :entry/debit-account :book-account.liability/payable-brazil :entry/credit-account :book-account.profit-and-loss/interchange-brazil :entry/post-date #nu/date "2016-12-01" :entry/movement new-purchase}
{:entry/id (uuid) :entry/amount 100.0M :entry/debit-account :book-account.liability/current-limit-counterparty :entry/credit-account :book-account.asset/current-limit :entry/post-date #nu/date "2016-12-01" :entry/movement new-purchase}]
{:purchase {:id (uuid) :amount 100.0M :interchange 3.0M :time #nu/time "2016-12-01T13:37:42Z"}}
Rulebook
![Page 19: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/19.jpg)
[{:entry/id (uuid) :entry/amount 100.0M :entry/debit-account :book-account.asset/transitory-bank :entry/credit-account :book-account.asset/settled-brazil :entry/post-date #nu/date "2016-12-01" :entry/movement new-payment}
{:entry/id (uuid) :entry/amount 100.0M :entry/debit-account :book-account.asset/current-limit :entry/credit-account :book-account.liability/current-limit-counterparty :entry/post-date #nu/date "2016-12-01" :entry/movement new-payment}]
{:payment {:id (uuid) :amount 100.0M :post-date #nu/date "2016-12-01"}}
Rulebook
![Page 20: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/20.jpg)
Cumulative cache (balance sheet)
Event (log)
2 LOGS AND A CACHE
ACTUAL TIME audit trail / Datomic log “when did we know”day 0 day 30 day 90
SYSTEM OF RECORD TIME official version of events uses business-relevant “post dates” can correct after the fact
day 90
day 0day 0
day 30
![Page 21: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/21.jpg)
SANITY CHECKS / BUSINESS INVARIANTS
• Balances must be always positive or always negative
• Cannot have a “late” balance there is a “prepaid” balance
• A purchase should “move” exactly the purchase amount on assets and on current limit
![Page 22: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/22.jpg)
(def balances-property (prop/for-all [account (g/generator Account) events (gen/vector (gen/one-of [(g/generator Purchase) (g/generator Payment) ...]))] (->> (empty-db) (save-all! account events) :db-after (balances-are-positive!)))
(fact (tc/quick-check 50 balances-property) => (th/embeds {:result true}))
GENERATIVE TESTING(ns double-entry.controllers.rulebook-test (:require [midje.sweet :refer :all] [clojure.test.check.properties :as prop] [clojure.test.check :as tc] [schema-generators.generators :as g] [clojure.test.check.generators :as gen]))
![Page 23: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/23.jpg)
EVENT STREAM FOR A SINGLE CUSTOMER
![Page 24: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/24.jpg)
1. Business events generate idempotent Kafka messages
2. For each event, apply functions to convert the event data into a movement with 1+ entries • Movements balance by design • Movements associate provenance metadata
3. Pre-check guarantees invariants against db value
4. Eagerly cache resulting balances
debit-account credit-account amount
a/max-limit a/current-limit
l/max-limit-cpl/current-limit-cp
initial-limit
15000.0015000.00
CARD ISSUED
![Page 25: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/25.jpg)
debit-account credit-account amount
new-purchase / settle-brazil
100.00100.00
100.00100.00
CARD ISSUED FIRST PURCHASE
l/current-limit-cpa/unsettled
l/unsettled-cpa/settled-brazil
a/current-limitl/unsettled-cp
a/unsettledl/payable-brazil
![Page 26: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/26.jpg)
debit-account credit-account amount
closed-bill
15.00100.00
CARD ISSUED FIRST PURCHASE
a/minimum-paymenta/closed
l/minimum-payment-cpa/settled-brazil
FIRST BILL CLOSES
![Page 27: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/27.jpg)
debit-account credit-account amount
new-payment
10.0010.0010.00
CARD ISSUED FIRST PURCHASE
a/current-limitl/minimum-payment-cpa/transitory-bank
l/current-limit-cpa/minimum-paymenta/late
FIRST BILL CLOSES PARTIAL PAYMENT
![Page 28: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/28.jpg)
debit-account credit-account amount
new-adjustment
7.007.00
CARD ISSUED FIRST PURCHASE
l/current-limit-cpa/settled-financed
a/current-limite/revolving-interest
FIRST BILL CLOSES PARTIAL PAYMENT INTEREST ASSESSED
![Page 29: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/29.jpg)
debit-account credit-account amount
closed-bill
7.005.0014.557.00
90.005.007.0090.007.007.007.002.557.00
CARD ISSUED FIRST PURCHASE
a/latel/minimum-payment-cpa/minimum-paymenta/closed
a/current-limitl/minimum-payment-cpa/transitory-banka/transitory-bankl/prepaida/current-limitl/minimum-payment-cpl/minimum-payment-cpa/closed
a/closeda/minimum-paymentl/minimum-payment-cpa/settled-financed
l/current-limit-cpa/minimum-paymentl/prepaida/latea/closedl/current-limit-cpa/minimum-paymenta/minimum-paymenta/late
FIRST BILL CLOSES PARTIAL PAYMENT INTEREST ASSESSED PAYMENT IN FULL
![Page 30: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/30.jpg)
ZOOMING OUT
2015-01 2015-04 2015-07 2015-10 2015-01 2016-03
![Page 31: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/31.jpg)
DETECTING OPERATIONAL MISTAKES
USE CASES
MANAGEMENT ACCOUNTING • delinquency tables by cohort and aging
• receivables (domestic, foreign, financed)
• revenue per customer (interchange, interest, fx spread)
REPORTING • covenants
• regulatory
FINANCIAL ACCOUNTING • consolidate to ERP
![Page 32: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/32.jpg)
Declarative rules are extensible for additional financial products (e.g., already extending to rewards, debt financing)
Financial analysis applies at a micro level (negative balances, weird ratios, operational problems)
Business-specific invariants provide safety (declare mutually exclusive and impossible states,alert unexpected situations)
Generative testing finds real bugs
Service is shardable by customer account (no interactions between accounts)
WHAT DO WE LIKE?
![Page 33: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/33.jpg)
33
IF YOU ARE ENTRUSTED WITH A CUSTOMER’S FINANCIAL RELATIONSHIP, CONSIDER BUILDING A DOUBLE-ENTRY SYSTEM FOR YOUR DOMAIN
![Page 34: Building a powerful double entry accounting system](https://reader034.vdocuments.net/reader034/viewer/2022042706/58a2c9d11a28ab217a8b65ab/html5/thumbnails/34.jpg)
Thank you!
Lucas Cavalcanti @lucascs
IF YOU CHOOSE TO DO SO, USE ALL THE POWER FUNCTIONAL PROGRAMMING GIVES YOU