(ns auto-ap.graphql.ledger (:require [auto-ap.datomic :refer [uri]] [auto-ap.datomic.ledger :as l] [auto-ap.time :refer [parse iso-date]] [auto-ap.graphql.utils :refer [->graphql <-graphql limited-clients]] [clj-time.coerce :as coerce] [clojure.string :as str] [clj-time.core :as time] [datomic.api :as d] [auto-ap.parse.templates :as t])) (defn get-ledger-page [context args value] (let [args (assoc args :id (:id context)) [journal-entries journal-entries-count] (l/get-graphql (<-graphql args)) journal-entries (map ->graphql journal-entries)] {:journal_entries journal-entries :total journal-entries-count :count (count journal-entries) :start (:start args 0) :end (+ (:start args 0) (count journal-entries))})) ;; TODO a better way to do this might be to accumulate ALL credits and ALL debits, and then just do for credits: balance = credits - debits. and for debits balance = debits - credits (defn credit-account? [account] (or (#{:account-type/liability :account-type/equity :account-type/revenue} (:db/ident (:account/type account))) (#{:bank-account-type/credit} (-> account :bank-account/type :db/ident )))) (defn debit-account? [account] (or (#{:account-type/asset :account-type/dividend :account-type/expense} (:db/ident (:account/type account))) (#{:bank-account-type/check} (-> account :bank-account/type :db/ident )))) (defn expense-account? [account] (= :account-type/expense (:db/ident (:account/type account)))) (defn roll-up [results] (->> results (mapcat :journal-entry/line-items) (group-by :journal-entry-line/account) (reduce-kv (fn [result account line-items] ;; TODO fix (when-not (or (:bank-account/name account) (:account/name account)) (println "WARNING " account line-items)) (conj result {:name (or (:bank-account/name account) (:account/name account)) :id (:db/id account) :numeric-code (or (:account/numeric-code account) (and (:bank-account/type account) 1100)) :account-type (or (:db/ident (:account/type account)) ({:bank-account-type/check :asset :bank-account-type/credit :liability} (:db/ident (:bank-account/type account)))) :amount (reduce + 0 (map (fn [line-item] (cond (and (credit-account? account) (:journal-entry-line/debit line-item)) (- (:journal-entry-line/debit line-item)) (and (credit-account? account) (:journal-entry-line/credit line-item)) (:journal-entry-line/credit line-item) (and (debit-account? account) (:journal-entry-line/debit line-item)) (:journal-entry-line/debit line-item) (and (debit-account? account) (:journal-entry-line/credit line-item)) (- (:journal-entry-line/credit line-item)) :else 0)) line-items))})) []))) (defn get-balance-sheet [context args value] (let [args (assoc args :id (:id context)) [results] (l/get-graphql {:client-id (:client_id args) :date-before (coerce/to-date (:date args)) :count Integer/MAX_VALUE}) [comparable-results] (l/get-graphql {:client-id (:client_id args) :date-before (coerce/to-date (time/minus (parse (:date args) iso-date) (time/months 1))) :count Integer/MAX_VALUE})] (->graphql {:balance-sheet-accounts (roll-up results) :comparable-balance-sheet-accounts (roll-up comparable-results)}))) (defn get-profit-and-loss [context args value] (let [args (assoc args :id (:id context)) [starting-results] (l/get-graphql {:client-id (:client_id args) :date-before (coerce/to-date (:from_date args)) :count Integer/MAX_VALUE}) [ending-results] (l/get-graphql {:client-id (:client_id args) :date-before (coerce/to-date (:to_date args)) :count Integer/MAX_VALUE}) starting-accounts (roll-up starting-results) ending-accounts (roll-up ending-results) accounts (reduce-kv (fn [result account line-item] (update-in result [(cond (expense-account? account) "Expenses" (credit-account? account) "Liabilities" (debit-account? account) "Assets") (if (credit-account? account) "Accounts Payable" "1100 Cash and Bank Accounts" ) ] conj (update line-item :amount #(- % (:amount (starting-accounts account 0) 0)) ) )) {} ending-accounts) ] (->graphql {:balance-sheet-groupings (-> [] (into (->> (get accounts "Expenses") (map (fn [[n accounts]] {:name n :grouping-type "Expenses" :accounts accounts} )))))}))) #_(get-profit-and-loss nil {:client_id [:client/code "CBC"] :from_date "2018-01-01" :to_date "2019-04-01"} nil)