diff --git a/scratch-sessions/find_bad_expense_accounts.clj b/scratch-sessions/find_bad_expense_accounts.clj new file mode 100644 index 00000000..6617dbe3 --- /dev/null +++ b/scratch-sessions/find_bad_expense_accounts.clj @@ -0,0 +1,19 @@ +(ns find-bad-expense-accounts) + +(require '[auto-ap.expense-accounts :as ea]) + +(let [accounts (-> (set (filter #(= 0 (mod % 100)) (keys ea/expense-accounts))) + (disj 2200) + (disj 2300) + (disj 3100) + (disj 3200) + (disj 3400))] + + (doseq [x accounts + :let [c (d/query {:query {:find ['(pull ?e [*])] + :in ['$ '?x] + :where ['[?e :invoice-expense-account/expense-account-id ?x]]} + :args [(d/db (d/connect uri)) x]})]] + + (if (> (count c ) 0) + (clojure.pprint/pprint [x c])))) diff --git a/src/clj/auto_ap/datomic/migrate.clj b/src/clj/auto_ap/datomic/migrate.clj index 2be04772..9c20b1ae 100644 --- a/src/clj/auto_ap/datomic/migrate.clj +++ b/src/clj/auto_ap/datomic/migrate.clj @@ -128,8 +128,8 @@ :requires [:auto-ap/convert-invoices]} :auto-ap/add-yodlee-merchant2 {:txes add-general-ledger/add-yodlee-merchant :requires [:auto-ap/convert-transactions]} - #_#_:auto-ap/bulk-load-invoice-ledger3 {:txes-fn `add-general-ledger/bulk-load-invoice-ledger :requires [:auto-ap/convert-transactions]} - #_#_:auto-ap/bulk-load-transaction-ledger3 {:txes-fn `add-general-ledger/bulk-load-transaction-ledger :requires [:auto-ap/convert-transactions]} + :auto-ap/bulk-load-invoice-ledger3 {:txes-fn `add-general-ledger/bulk-load-invoice-ledger :requires [:auto-ap/convert-transactions]} + :auto-ap/bulk-load-transaction-ledger3 {:txes-fn `add-general-ledger/bulk-load-transaction-ledger :requires [:auto-ap/convert-transactions]} }] (println "Conforming database...") diff --git a/src/clj/auto_ap/datomic/migrate/add_general_ledger.clj b/src/clj/auto_ap/datomic/migrate/add_general_ledger.clj index 3738e992..1fdf6b33 100644 --- a/src/clj/auto_ap/datomic/migrate/add_general_ledger.clj +++ b/src/clj/auto_ap/datomic/migrate/add_general_ledger.clj @@ -153,16 +153,19 @@ {:db/ident :account-type/asset} {:db/ident :account-type/equity}] - (mapv - (fn [[numeric {:keys [name location]}]] - (remove-nils - {:account/type :account-type/expense - :account/numeric-code numeric - :account/code (str numeric) - :account/name name - :account/location location - :account/account-set "default"})) - expense-accounts/chooseable-expense-accounts)]) + (->> expense-accounts/chooseable-expense-accounts + (filter (fn [[numeric]] + (not (#{0 2100 5800 9600 1300 8200 7400 8500 2400 8800 1400 2500 7200 1200 1600 1500 3300 9800 9200 2800 1100 5700 2600 9300 9500 8100 7500 7100 2700} numeric)))) + + (mapv + (fn [[numeric {:keys [name location]}]] + (remove-nils + {:account/type :account-type/expense + :account/numeric-code numeric + :account/code (str numeric) + :account/name name + :account/location location + :account/account-set "default"}))))]) (defn add-general-ledger-fns [conn] [[{:db/ident :replace-general-ledger @@ -248,18 +251,21 @@ invoice-expense-accounts)])) (defn convert-transactions [conn] - (let [matched-transactions (d/query {:query {:find '[?transaction ?v] + (let [matched-transactions (d/query {:query {:find '[?transaction ?v ?amount] :in '[$] :where ['[?transaction :transaction/payment ?payment] + '[?transaction :transaction/amount ?amount] '[?payment :payment/invoices ?i] '[?i :invoice/vendor ?v]]} :args [(d/db (d/connect auto-ap.datomic/uri))]})] [(mapv - (fn [[transaction-id vendor-id]] + (fn [[transaction-id vendor-id amount]] (remove-nils {:db/id transaction-id :transaction/vendor vendor-id :transaction/location "A" - :transaction/account (:db/id (accounts/get-account-by-numeric-code-and-sets 2110 ["default"])) + :transaction/accounts [#:transaction-account {:account (:db/id (accounts/get-account-by-numeric-code-and-sets 2110 ["default"])) + :location "A" + :amount (Math/abs amount)}] })) matched-transactions)])) diff --git a/src/clj/auto_ap/graphql.clj b/src/clj/auto_ap/graphql.clj index 733558bd..52f98c63 100644 --- a/src/clj/auto_ap/graphql.clj +++ b/src/clj/auto_ap/graphql.clj @@ -66,17 +66,15 @@ :bank_name {:type 'String} :yodlee_account_id {:type 'Int}}} :balance_sheet_account - {:fields { + {:fields {:id {:type 'String} :amount {:type 'String} + :numeric_code {:type 'Int} + :account_type {:type :account_type} :name {:type 'String}}} - :balance_sheet_grouping - {:fields {:accounts {:type '(list :balance_sheet_account)} - :name {:type 'String} - :grouping_type {:type 'String}}} - :balance_sheet - {:fields {:balance_sheet_groupings {:type '(list :balance_sheet_grouping)}}} + {:fields {:balance_sheet_accounts {:type '(list :balance_sheet_account)} + :comparable_balance_sheet_accounts {:type '(list :balance_sheet_account)}}} :address {:fields {:street1 {:type 'String} diff --git a/src/clj/auto_ap/graphql/ledger.clj b/src/clj/auto_ap/graphql/ledger.clj index c61ec750..0a75694c 100644 --- a/src/clj/auto_ap/graphql/ledger.clj +++ b/src/clj/auto_ap/graphql/ledger.clj @@ -1,10 +1,13 @@ (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] - [datomic.api :as d])) + [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)) @@ -15,6 +18,8 @@ :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 @@ -41,72 +46,51 @@ (mapcat :journal-entry/line-items) (group-by :journal-entry-line/account) (reduce-kv (fn [result account line-items] - (assoc result - account - {:name (or (:bank-account/name account) (:account/name 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)) + ;; 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 (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/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)) + (and (debit-account? account) (:journal-entry-line/credit line-item)) + (- (:journal-entry-line/credit line-item)) - :else - 0)) - line-items))})) - {}))) + :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}) - accounts (roll-up 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 - line-item - )) - {} - accounts) - ] + [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-groupings - (-> [] - (into (->> (get accounts "Assets") - (map (fn [[n accounts]] - {:name n - :grouping-type "Assets" - :accounts accounts} - )))) - (into (->> (get accounts "Liabilities") - (map (fn [[n accounts]] - {:name n - :grouping-type "Liabilities" - :accounts accounts} - )))))}))) + {:balance-sheet-accounts (roll-up results) + :comparable-balance-sheet-accounts (roll-up comparable-results)}))) (defn get-profit-and-loss [context args value] diff --git a/src/clj/auto_ap/ledger.clj b/src/clj/auto_ap/ledger.clj index b625cb63..028011b1 100644 --- a/src/clj/auto_ap/ledger.clj +++ b/src/clj/auto_ap/ledger.clj @@ -68,7 +68,7 @@ decreasing? (< (:transaction/amount entity) 0.0) credit-from-bank? decreasing? debit-from-bank? (not decreasing?)] - (println "processing entity" entity) + (when (:transaction/vendor entity) (remove-nils {:journal-entry/source "transaction" diff --git a/src/cljs/auto_ap/views/pages/ledger/balance_sheet.cljs b/src/cljs/auto_ap/views/pages/ledger/balance_sheet.cljs index e0478bcf..12750225 100644 --- a/src/cljs/auto_ap/views/pages/ledger/balance_sheet.cljs +++ b/src/cljs/auto_ap/views/pages/ledger/balance_sheet.cljs @@ -2,8 +2,9 @@ (:require [auto-ap.subs :as subs] [auto-ap.views.components.layouts :refer [side-bar-layout]] [goog.string :as gstring] + [auto-ap.utils :refer [by]] [auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]] - [auto-ap.views.utils :refer [date->str date-picker bind-field]] + [auto-ap.views.utils :refer [date->str date-picker bind-field local-now standard]] [cljs-time.core :as t] [re-frame.core :as re-frame])) @@ -13,14 +14,59 @@ (-> db ::report))) (re-frame/reg-sub - ::assets - (fn [db] - (->> db ::report :balance-sheet-groupings (filter (fn [{:keys [grouping-type]}] (= "Assets" grouping-type)))))) + ::accounts + (fn [db [_ type]] + (->> db + ::report + :balance-sheet-accounts + (map #(update % :amount js/parseFloat)) + (filter (fn [{:keys [account-type]}] + (= type account-type))) + (sort-by :numeric-code)))) (re-frame/reg-sub + ::accounts-by-id + (fn [db [_ type]] + (->> db + ::report + :balance-sheet-accounts + (map #(update % :amount js/parseFloat)) + (filter (fn [{:keys [account-type]}] + (= type account-type))) + (by :id)))) + +(re-frame/reg-sub + ::comparable-accounts-by-id + (fn [db [_ type]] + (->> db + ::report + :comparable-balance-sheet-accounts + (map #(update % :amount js/parseFloat)) + (filter (fn [{:keys [account-type]}] + (= type account-type))) + (by :id)))) + + +(def groupings + {:asset + [["1100 Cash and Bank Accounts" 1100 1199] + ["1200 Accounts Receivable" 1200 1299] + ["1300 Inventory" 1300 1399] + ["1400 Prepaid Expenses" 1400 1499] + ["1500 Property and Equipment" 1500 1599] + ["1600 Intangible Assets" 1600 1699]] + :liability + [["2100 Accounts Payable" 2100 2399] + ["2400 Accrued Expenses" 2400 2499] + ["2500 Other Liabilities" 2500 2599] + ["2600 Split Accounts" 2600 2699] + ["2700 Current Portion of Long-Term Debt" 2700 2799] + ["2800 Notes Payable" 2800 3000]]}) + +#_(re-frame/reg-sub ::liabilities (fn [db] - (->> db ::report :balance-sheet-groupings (filter (fn [{:keys [grouping-type]}] (= "Liabilities" grouping-type)))))) + (->> db ::report :balance-sheet-accounts (filter (fn [{:keys [account-type]}] :liability))))) (re-frame/reg-event-db ::received @@ -44,40 +90,46 @@ :query-obj {:venia/queries [[:balance-sheet (assoc params :client-id (:id @(re-frame/subscribe [::subs/client]))) - [[:balance-sheet-groupings [:grouping-type :name [:accounts [:name :amount]]]]]]]} + [[:balance-sheet-accounts [:name :amount :account-type :id :numeric-code]] + [:comparable-balance-sheet-accounts [:name :amount :account-type :id :numeric-code]]]]]} :on-success [::received]}})) (re-frame/reg-event-fx ::date-picked (fn [cofx [_ _ date]] - (println "DATE" date) - {:dispatch [::params-change (assoc @(re-frame/subscribe [::params]) :date date)]})) -(defn grouping [groupings] +(defn grouping [{:keys [header accounts comparable-accounts groupings]}] - [:table.table - (for [grouping groupings] - (list - [:tr [:td {:col-span "2"} "----" (:name grouping) "----"]] - (for [account (:accounts grouping)] - - [:tr - [:td (:name account) ] - [:td.has-text-right (gstring/format "$%.2f" (:amount account))]] - - ) - - [:tr [:td "----" (:name grouping) "----"] - [:td.has-text-right - (->> grouping - :accounts - (map :amount) - (map #(js/parseFloat %)) - (reduce + 0) - (gstring/format "$%.2f" ))]]))]) + (for [[grouping-name from to] groupings + :let [matching-accounts (filter + #(<= from (:numeric-code %) to) + accounts)] + :when (seq matching-accounts) + ] + (list + [:tr [:td "---" grouping-name "---"] + [:td] + [:td] + [:td] + ] + (for [account matching-accounts] + [:tr [:td (:name account)] + [:td.has-text-right (gstring/format "$%.2f" (:amount account))] + [:td.has-text-right (gstring/format "$%.2f" (:amount (get comparable-accounts (:id account)) 0))] + [:td.has-text-right (gstring/format "$%.2f" (- (:amount account ) (:amount (get comparable-accounts (:id account)) 0)))]]) + [:tr [:td "---" grouping-name "---"] + [:td.has-text-right (gstring/format "$%.2f" (reduce + 0 (map :amount + matching-accounts))) ] + [:td.has-text-right (gstring/format "$%.2f" (reduce + 0 (map #(:amount (get comparable-accounts (:id %)) 0) + matching-accounts)))] + [:td.has-text-right (gstring/format "$%.2f" (reduce + 0 + (map #(- (:amount % ) (:amount (get comparable-accounts (:id %)) 0)) + matching-accounts)))] + [:td] + ]))) (def balance-sheet-content (with-meta @@ -100,12 +152,28 @@ :event [::date-picked] :popper-props (clj->js {:placement "right"}) :subscription params}]] - [:h2.title "Assets"] - [grouping @(re-frame/subscribe [::assets])] - [:h2.title "Liabilities"] - [grouping @(re-frame/subscribe [::liabilities])] + [:table.table + (list + [:tr [:td "Assets"] + [:td] + [:td] + [:td]] + (grouping {:accounts @(re-frame/subscribe [::accounts :asset]) + :groupings (:asset groupings) + :comparable-accounts @(re-frame/subscribe [::comparable-accounts-by-id :asset]) + :header "Assets"}) + [:tr [:td "Liabilities"] + [:td] + [:td] + [:td]] + (grouping {:accounts @(re-frame/subscribe [::accounts :liability]) + :groupings (:liability groupings) + :comparable-accounts @(re-frame/subscribe [::comparable-accounts-by-id :liability]) + :header "Liabilities"}))] + #_[:h2.title "Liabilities"] + #_[grouping @(re-frame/subscribe [::liabilities])] ])) - {:component-will-mount #(re-frame/dispatch-sync [::params-change {}]) })) + {:component-will-mount #(re-frame/dispatch-sync [::params-change {:date (date->str (local-now) standard)}]) })) (defn balance-sheet-page [] [side-bar-layout