302 lines
16 KiB
Clojure
302 lines
16 KiB
Clojure
(ns user
|
|
(:require [auto-ap.datomic :refer [uri]]
|
|
|
|
[auto-ap.utils :refer [by]]
|
|
[datomic.api :as d]
|
|
[clojure.data.csv :as csv]
|
|
[clj-time.coerce :as c]
|
|
[clj-time.core :as t]
|
|
[clojure.java.io :as io]
|
|
[clojure.string :as str])
|
|
(:import [org.apache.commons.io.input BOMInputStream]))
|
|
|
|
(defn mark-until-date [client end]
|
|
(let [conn (d/connect uri)]
|
|
(doseq [p (->>
|
|
(d/query {:query {:find '[?e]
|
|
:in '[$ ?client ?end ]
|
|
:where [
|
|
'[?e :invoice/client ?c]
|
|
'[?c :client/code ?client]
|
|
'[?e :invoice/date ?d ]
|
|
'[(<= ?d ?end) ]]}
|
|
:args [(d/db conn)
|
|
client
|
|
(c/to-date end)]})
|
|
(mapv first)
|
|
(mapv (fn [i]
|
|
{:db/id i
|
|
:invoice/exclude-from-ledger true}))
|
|
(partition-all 100))]
|
|
|
|
@(d/transact conn p)
|
|
(println "process 100"))
|
|
|
|
(doseq [p (->>
|
|
(d/query {:query {:find '[?e]
|
|
:in '[$ ?client ?end ]
|
|
:where [
|
|
'[?e :transaction/client ?c]
|
|
'[?c :client/code ?client]
|
|
'[?e :transaction/date ?d ]
|
|
'[(<= ?d ?end) ]]}
|
|
:args [(d/db conn)
|
|
client
|
|
(c/to-date end)]})
|
|
(mapv first)
|
|
(mapv (fn [i]
|
|
{:db/id i
|
|
:transaction/approval-status :transaction-approval-status/excluded}))
|
|
(partition-all 100))]
|
|
|
|
@(d/transact conn p) (println "process 100"))))
|
|
|
|
(defn unapprove-all []
|
|
(let [conn (d/connect uri)]
|
|
(doseq [p (->>
|
|
(d/query {:query {:find '[?e]
|
|
:in '[$ ]
|
|
:where ['[?e :transaction/date ?d ]]}
|
|
:args [(d/db conn)]})
|
|
(mapv first)
|
|
(mapv (fn [i]
|
|
{:db/id i
|
|
:transaction/approval-status :transaction-approval-status/unapproved}))
|
|
(partition-all 100))]
|
|
|
|
@(d/transact conn p)
|
|
(println "process 100"))))
|
|
|
|
|
|
|
|
|
|
(defn load-accounts [conn]
|
|
(let [[header & rows] (-> "master-account-list.csv" (io/resource) io/input-stream (BOMInputStream.) (io/reader) csv/read-csv)
|
|
headers (map read-string header)
|
|
code->existing-account (by :account/numeric-code (map first (d/query {:query {:find ['(pull ?e [:account/numeric-code
|
|
:db/id])]
|
|
:in ['$]
|
|
:where ['[?e :account/name]]}
|
|
:args [(d/db conn)]})))
|
|
|
|
also-merge-txes (fn [also-merge old-account-id]
|
|
(if old-account-id
|
|
(let [[sunset-account]
|
|
(first (d/query {:query {:find ['?a ]
|
|
:in ['$ '?ac ]
|
|
:where ['[?a :account/numeric-code ?ac]]}
|
|
:args [(d/db conn) also-merge ]}))]
|
|
(into (mapv
|
|
(fn [[entity id sunset-account]]
|
|
[:db/add entity id old-account-id])
|
|
(d/query {:query {:find ['?e '?id '?a ]
|
|
:in ['$ '?ac ]
|
|
:where ['[?a :account/numeric-code ?ac]
|
|
'[?e ?at ?a]
|
|
'[?at :db/ident ?id]]}
|
|
:args [(d/db conn) also-merge ]}))
|
|
[[:db/retractEntity sunset-account]]))
|
|
[]))
|
|
|
|
txes (transduce
|
|
(comp
|
|
(map (fn ->map [r]
|
|
(into {} (map vector header r))))
|
|
(map (fn parse-map [r]
|
|
{:old-account-id (:db/id (code->existing-account
|
|
(or
|
|
(if (= (get r "IOL Account #")
|
|
"NEW")
|
|
nil
|
|
(Integer/parseInt (get r "IOL Account #")))
|
|
(Integer/parseInt (get r "Account #")))))
|
|
:new-account-number (Integer/parseInt (get r "Account #"))
|
|
:name (get r "Default Name")
|
|
:location (when-not (str/blank? (get r "Forced Location"))
|
|
(get r "Forced Location"))
|
|
:also-merge (when-not (str/blank? (get r "IOL # additional"))
|
|
(Integer/parseInt (get r "IOL # additional")))
|
|
:account-type (keyword "account-type"
|
|
(str/lower-case (get r "Account Type")))
|
|
:applicability (keyword "account-applicability"
|
|
(condp = (get r "Visiblity (Per-customer, Visible by default, hidden by default)")
|
|
"Visible by default"
|
|
"global"
|
|
|
|
"Hidden by default"
|
|
"optional"
|
|
|
|
"Per Customer"
|
|
"customized"))}))
|
|
(mapcat (fn ->tx [{:keys [old-account-id new-account-number name location also-merge account-type applicability]}]
|
|
(let [tx [(cond-> {:account/name name
|
|
:account/type account-type
|
|
:account/account-set "default"
|
|
:account/applicability applicability
|
|
:account/numeric-code new-account-number}
|
|
old-account-id (assoc :db/id old-account-id)
|
|
location (assoc :account/location location))]]
|
|
(if also-merge
|
|
(into tx
|
|
(also-merge-txes also-merge old-account-id))
|
|
tx)
|
|
))))
|
|
|
|
|
|
conj
|
|
[]
|
|
rows)]
|
|
@(d/transact conn txes)))
|
|
|
|
(defn find-bad-accounts []
|
|
(set (map second (d/query {:query {:find ['(pull ?x [*]) '?z]
|
|
:in ['$]
|
|
:where ['[?e :account/numeric-code ?z]
|
|
'[(<= ?z 9999)]
|
|
'[?x ?a ?e]]}
|
|
:args [(d/db (d/connect uri))]}))))
|
|
|
|
(defn delete-4-digit-accounts []
|
|
@(d/transact (d/connect uri)
|
|
(transduce
|
|
(comp
|
|
(map first)
|
|
(map (fn [old-account-id]
|
|
[:db/retractEntity old-account-id])))
|
|
conj
|
|
[]
|
|
(d/query {:query {:find ['?e]
|
|
:in ['$]
|
|
:where ['[?e :account/numeric-code ?z]
|
|
'[(<= ?z 9999)]]}
|
|
:args [(d/db (d/connect uri))]})))
|
|
)
|
|
|
|
|
|
(defn find-conflicting-accounts []
|
|
(filter
|
|
(fn [[k v]]
|
|
(> (count v) 1))
|
|
(reduce
|
|
(fn [acc [e z]]
|
|
(update acc z conj e))
|
|
{}
|
|
(d/query {:query {:find ['?e '?z]
|
|
:in ['$]
|
|
:where ['[?e :account/numeric-code ?z]]}
|
|
:args [(d/db (d/connect uri))]}))))
|
|
|
|
(defn customize-accounts [customer filename]
|
|
(let [conn (d/connect uri)
|
|
[header & rows] (-> filename (io/resource) io/input-stream (BOMInputStream.) (io/reader) csv/read-csv)
|
|
[client-id] (first (d/query (-> {:query {:find ['?e]
|
|
:in ['$ '?z]
|
|
:where [['?e :client/code '?z]]}
|
|
:args [(d/db (d/connect uri)) customer]})))
|
|
_ (println client-id)
|
|
headers (map read-string header)
|
|
code->existing-account (by :account/numeric-code (map first (d/query {:query {:find ['(pull ?e [:account/numeric-code
|
|
:db/id])]
|
|
:in ['$]
|
|
:where ['[?e :account/name]]}
|
|
:args [(d/db conn)]})))
|
|
|
|
txes (transduce
|
|
(comp
|
|
|
|
(filter (fn [[_ account _ override-name]]
|
|
(and
|
|
(not (str/blank? override-name))
|
|
(not (str/blank? account)))))
|
|
(map (fn parse-map [[_ account account-name override-name _ type]]
|
|
(let [code (Integer/parseInt account)
|
|
existing-id (:db/id (code->existing-account code))]
|
|
(cond-> {:account/client-overrides [{:account-client-override/client client-id
|
|
:account-client-override/name override-name}]}
|
|
existing-id (assoc :db/id existing-id)
|
|
(not existing-id) (assoc :account/applicability :account-applicability/customized
|
|
:account/name account-name
|
|
:account/account-set "default"
|
|
:account/numeric-code code
|
|
:account/code (str code)
|
|
:account/type (keyword "account-type" (str/lower-case type))))))))
|
|
|
|
conj
|
|
[]
|
|
rows)]
|
|
@(d/transact conn txes)))
|
|
|
|
(defn cash-flow-simple []
|
|
(let [total-cash (reduce
|
|
(fn [total [credit debit]]
|
|
(- (+ total credit)
|
|
debit))
|
|
0.0
|
|
(d/query {:query {:find '[?debit ?credit]
|
|
:in '[$ ?client]
|
|
:where ['[?j :journal-entry/client ?c]
|
|
'[?c :client/code ?client]
|
|
'[?j :journal-entry/line-items ?je]
|
|
'[?je :journal-entry-line/account ?ba]
|
|
'[?ba :bank-account/type :bank-account-type/check]
|
|
'[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit]
|
|
'[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]]}
|
|
:args [(d/db (d/connect uri)) "CBC"]}))
|
|
bills-due-soon (d/query {:query {:find '[?due ?outstanding]
|
|
:in '[$ ?client ?due-before]
|
|
:where ['[?i :invoice/client ?c]
|
|
'[?c :client/code ?client]
|
|
'[?i :invoice/status :invoice-status/unpaid]
|
|
'[?i :invoice/due ?due]
|
|
'[(<= ?due ?due-before)]
|
|
'[?i :invoice/outstanding-balance ?outstanding]]}
|
|
:args [(d/db (d/connect uri)) "CBC" (c/to-date (t/plus (auto-ap.time/local-now) (t/days 7)))]})
|
|
outstanding-checks (reduce
|
|
+
|
|
0.0
|
|
(map first (d/query {:query {:find '[?amount]
|
|
:in '[$ ?client ?due-before]
|
|
:where ['[?p :payment/client ?c]
|
|
'[?c :client/code ?client]
|
|
'[?p :payment/status :payment-status/pending]
|
|
'[?p :payment/amount ?amount]
|
|
'(or
|
|
[?p :payment/type :payment-type/debit]
|
|
[?p :payment/type :payment-type/check])]}
|
|
:args [(d/db (d/connect uri)) "CBC" (c/to-date (t/plus (auto-ap.time/local-now) (t/days 7)))]})))]
|
|
[total-cash bills-due-soon outstanding-checks])
|
|
|
|
|
|
#_(->> (d/query {:query {:find '[?account-type-ident ?date ?debit ?credit]
|
|
:in '[$ ?client]
|
|
:where ['[?j :journal-entry/line-items ?je]
|
|
'[?j :journal-entry/date ?date]
|
|
'[?je :journal-entry-line/account ?a]
|
|
'[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit]
|
|
'[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]
|
|
'[?a :account/type ?account-type]
|
|
'[?account-type :db/ident ?account-type-ident]]}
|
|
:args [(d/db (d/connect uri)) "CBC"]})
|
|
|
|
(reduce
|
|
(fn [result [account-type date debit credit]]
|
|
(let [date (clj-time.coerce/from-date date)]
|
|
(let [year-month (str (clj-time.core/year date) "-" (clj-time.core/month date))]
|
|
(-> result
|
|
(update-in [year-month account-type :debit]
|
|
(fn [existing-debit]
|
|
(+ (or existing-debit 0.0)
|
|
debit)))
|
|
(update-in [year-month account-type :credit]
|
|
(fn [existing-credit]
|
|
(+ (or existing-credit 0.0)
|
|
credit)))
|
|
(update-in [year-month account-type :count] #(inc (or % 0)))))))
|
|
{})))
|
|
|
|
(defn attach-signature [client-code filename]
|
|
@(d/transact (d/connect uri)
|
|
[{:db/id [:client/code client-code]
|
|
:client/signature-file (str "https://s3.amazonaws.com/integreat-signature-images/" filename)}]))
|
|
|