Adds bank reconciliation report
This commit is contained in:
36
resources/dolce-examples/payroll.csv
Normal file
36
resources/dolce-examples/payroll.csv
Normal file
@@ -0,0 +1,36 @@
|
||||
Payroll Type,Employee GL,Employee,Location,Role,Role GL,Base / OT,Rate,Total Hours,Overtime Hours,SOH,Wages,Break Issues,Cash Tips,CC Tips,AutoGrat,TipFees,Total Tips,Effective Wage,Supplemental Wage,Pay Period Start,Pay Period End
|
||||
hourly,146905#43,"Ancira, Marcus",NTG Roseville,Cashier,,Base,$20.00,39.45,,,$789.00,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#43,"Ancira, Marcus",NTG Roseville,Cashier,,Overtime,$10.00,0.1,,,$1.00,,,,,,,,,2024-04-01,2024-04-16
|
||||
hourly,146905#43,"Ancira, Marcus",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$196.26,,,196.26,,,2024-04-01,2024-04-16
|
||||
hourly,146905#355,"Arauz, Kevin",NTG Roseville,Line cook,,Base,$20.00,70.92,,,"$1,418.40",0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#355,"Arauz, Kevin",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$242.69,,,242.69,,,2024-04-01,2024-04-16
|
||||
hourly,146905#426,"Beddingfield, Megan",NTG Roseville,Cashier,,Base,$20.00,30.19,,,$603.80,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#426,"Beddingfield, Megan",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$159.68,,,159.68,,,2024-04-01,2024-04-16
|
||||
hourly,146905#46,"Carrillo, Ana",NTG Roseville,Cashier,,Base,$20.00,40.42,,,$808.40,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#46,"Carrillo, Ana",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$191.59,,,191.59,,,2024-04-01,2024-04-16
|
||||
hourly,146905#213,"Chanchavac, Rogelio",NTG Roseville,Line cook,,Base,$23.00,111.85,,,"$2,572.55",0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#213,"Chanchavac, Rogelio",NTG Roseville,Line cook,,Overtime,$11.50,22.41,,,$257.72,,,,,,,,,2024-04-01,2024-04-16
|
||||
hourly,146905#213,"Chanchavac, Rogelio",NTG Roseville,Line cook,,DT Overtime,$23.00,0.28,,,$6.44,,,,,,,,,2024-04-01,2024-04-16
|
||||
hourly,146905#213,"Chanchavac, Rogelio",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$362.75,,,362.75,,,2024-04-01,2024-04-16
|
||||
hourly,146905#405,"Craig, Devan",NTG Roseville,Cashier,,Base,$20.00,29.64,,,$592.80,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#405,"Craig, Devan",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$171.56,,,171.56,,,2024-04-01,2024-04-16
|
||||
hourly,146905#410,"Garcia, Gerber",NTG Roseville,Line cook,,Base,$20.00,47.07,,,$941.40,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#410,"Garcia, Gerber",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$164.49,,,164.49,,,2024-04-01,2024-04-16
|
||||
hourly,146905#440,"Guzman, Nicholas",NTG Roseville,Cashier,,Base,$20.00,11.64,,,$232.80,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#440,"Guzman, Nicholas",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$48.77,,,48.77,,,2024-04-01,2024-04-16
|
||||
hourly,146905#8,"Hoang, Jennifer",NTG Roseville,Cashier,,Base,$20.50,18.9,,,$387.45,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#8,"Hoang, Jennifer",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$81.87,,,81.87,,,2024-04-01,2024-04-16
|
||||
hourly,146905#451,"Mckenna-Tyron, Jacqueline",NTG Roseville,Cashier,,Base,$20.00,45.2,,,$904.00,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#451,"Mckenna-Tyron, Jacqueline",NTG Roseville,Cashier,,Overtime,$10.00,0.5,,,$5.00,,,,,,,,,2024-04-01,2024-04-16
|
||||
hourly,146905#451,"Mckenna-Tyron, Jacqueline",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$237.17,,,237.17,,,2024-04-01,2024-04-16
|
||||
hourly,146905#477,"Morgan, Wayne",NTG Roseville,Cashier,,Base,$20.00,4.57,,,$91.40,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#477,"Morgan, Wayne",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$23.21,,,23.21,,,2024-04-01,2024-04-16
|
||||
hourly,146905#369,"Poz, Henry",NTG Roseville,Line cook,,Base,$20.00,42.14,,,$842.80,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#369,"Poz, Henry",NTG Roseville,Line cook,,Overtime,$10.00,0.57,,,$5.70,,,,,,,,,2024-04-01,2024-04-16
|
||||
hourly,146905#369,"Poz, Henry",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$140.79,,,140.79,,,2024-04-01,2024-04-16
|
||||
hourly,146905#394,"Ramirez Garcia, Juan Ernesto",NTG Roseville,Line cook,,Base,$20.00,41.65,,,$833.00,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#394,"Ramirez Garcia, Juan Ernesto",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$137.95,,,137.95,,,2024-04-01,2024-04-16
|
||||
hourly,146905#216,"Robles, Angel",NTG Roseville,Line cook,,Base,$20.00,60.33,,,"$1,206.60",0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#216,"Robles, Angel",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$210.65,,,210.65,,,2024-04-01,2024-04-16
|
||||
hourly,146905#359,"Velez, Jack",NTG Roseville,Cashier,,Base,$20.00,30.47,,,$609.40,0,,,,,0,,,2024-04-01,2024-04-16
|
||||
hourly,146905#359,"Velez, Jack",NTG Roseville,,,Base,$0.00,0,,,$0.00,0,,$149.21,,,149.21,,,2024-04-01,2024-04-16
|
||||
|
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
(ns auto-ap.import.intuit
|
||||
(:require
|
||||
[auto-ap.datomic :refer [conn]]
|
||||
[auto-ap.datomic :refer [conn pull-attr]]
|
||||
[auto-ap.import.common :refer [wrap-integration]]
|
||||
[auto-ap.import.transactions :as t]
|
||||
[auto-ap.intuit.core :as i]
|
||||
@@ -12,14 +12,26 @@
|
||||
[com.unbounce.dogstatsd.core :as statsd]
|
||||
[datomic.api :as dc]))
|
||||
|
||||
(defn get-intuit-bank-accounts [db]
|
||||
(dc/q '[:find ?external-id ?ba ?c
|
||||
:in $
|
||||
:where
|
||||
[?c :client/bank-accounts ?ba]
|
||||
[?ba :bank-account/intuit-bank-account ?iab]
|
||||
[?iab :intuit-bank-account/external-id ?external-id]]
|
||||
db))
|
||||
(defn get-intuit-bank-accounts
|
||||
( [db]
|
||||
(dc/q '[:find ?external-id ?ba ?c
|
||||
:in $
|
||||
:where
|
||||
[?c :client/bank-accounts ?ba]
|
||||
[?ba :bank-account/intuit-bank-account ?iab]
|
||||
[?iab :intuit-bank-account/external-id ?external-id]]
|
||||
db))
|
||||
([db & client-codes]
|
||||
(dc/q '[:find ?external-id ?ba ?c
|
||||
:in $ [?cc ...]
|
||||
:where
|
||||
[?c :client/code ?cc]
|
||||
[?c :client/bank-accounts ?ba]
|
||||
[?ba :bank-account/intuit-bank-account ?iab]
|
||||
[?iab :intuit-bank-account/external-id ?external-id]]
|
||||
db
|
||||
client-codes)))
|
||||
|
||||
|
||||
(defn intuit->transaction [transaction]
|
||||
(let [check-number (when (not (str/blank? (:Num transaction)))
|
||||
|
||||
@@ -10,10 +10,64 @@
|
||||
[clj-time.core :as time]
|
||||
[clojure.string :as str]
|
||||
[com.unbounce.dogstatsd.core :as statsd]
|
||||
[datomic.api :as dc]))
|
||||
[datomic.api :as dc]
|
||||
[clj-http.client :as client]))
|
||||
|
||||
(for [[e] (take 5 (get-intuit-bank-accounts (dc/db conn)))]
|
||||
|
||||
(i/get-transactions "2023-02-01"
|
||||
"2023-02-05"
|
||||
e))
|
||||
(defn get-bank-accounts [token]
|
||||
|
||||
(defn get-bank-accounts [token]
|
||||
(->> (:body (client/get (str i/prod-base-url "/company/" i/prod-company-id "/query")
|
||||
{:headers
|
||||
(i/with-auth i/prod-base-headers token)
|
||||
:as :json
|
||||
:query-params {"query" "SELECT * From Account maxresults 1000"}}))
|
||||
:QueryResponse
|
||||
:Account
|
||||
#_(filter
|
||||
#(#{"Bank" "Credit Card"} (:AccountType %))))))
|
||||
|
||||
|
||||
|
||||
(require 'auto-ap.time_reader)
|
||||
|
||||
(let [start #clj-time/date-time "2024-02-01"
|
||||
end #clj-time/date-time "2024-04-01"]
|
||||
(for [[ib ba c] (seq (get-intuit-bank-accounts (dc/db conn) "BCFM"))
|
||||
:let [raw-transactions (i/get-transactions (atime/unparse-local start atime/iso-date)
|
||||
(atime/unparse-local end atime/iso-date)
|
||||
ib)
|
||||
ideal-transactions (intuits->transactions raw-transactions ba c)
|
||||
|
||||
found-transactions (when (seq ideal-transactions)
|
||||
(into {} (dc/q '[:find ?si (count ?t)
|
||||
:in $ [?eid ...]
|
||||
:where
|
||||
[?t :transaction/id ?eid]
|
||||
[?t :transaction/approval-status ?s]
|
||||
[?s :db/ident ?si]]
|
||||
(dc/db conn)
|
||||
(map :transaction/id ideal-transactions))))
|
||||
|
||||
missing-transaction-ids (when (seq ideal-transactions)
|
||||
(->>
|
||||
(dc/q '[:find ?eid
|
||||
:in $ [?eid ...]
|
||||
:where (not [_ :transaction/id ?eid])]
|
||||
(dc/db conn)
|
||||
(map :transaction/id ideal-transactions))
|
||||
(map first)
|
||||
(into #{})))
|
||||
missing-transactions (filter (comp missing-transaction-ids :transaction/id) ideal-transactions)]]
|
||||
{:bank-account/name (pull-attr (dc/db conn) :bank-account/name ba)
|
||||
:external-transaction-count (count raw-transactions)
|
||||
:integreat-transaction-count (reduce + 0 (vals found-transactions))
|
||||
:approved-count (:transaction-approval-status/approved found-transactions 0)
|
||||
:unapproved-count (:transaction-approval-status/unapproved found-transactions 0)
|
||||
:requires-feedback-count (:transaction-approval-status/requires-feedback found-transactions 0)
|
||||
:missing-transactions missing-transactions}))
|
||||
|
||||
|
||||
@@ -16,16 +16,29 @@
|
||||
[manifold.executor :as ex]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn get-plaid-accounts [db]
|
||||
(-> (dc/q '[:find ?ba ?c ?external-id ?t
|
||||
:in $
|
||||
:where
|
||||
[?c :client/bank-accounts ?ba]
|
||||
[?ba :bank-account/plaid-account ?pa]
|
||||
[?pa :plaid-account/external-id ?external-id]
|
||||
[?pi :plaid-item/accounts ?pa]
|
||||
[?pi :plaid-item/access-token ?t]]
|
||||
db )))
|
||||
(defn get-plaid-accounts
|
||||
([db]
|
||||
(-> (dc/q '[:find ?ba ?c ?external-id ?t
|
||||
:in $
|
||||
:where
|
||||
[?c :client/bank-accounts ?ba]
|
||||
[?ba :bank-account/plaid-account ?pa]
|
||||
[?pa :plaid-account/external-id ?external-id]
|
||||
[?pi :plaid-item/accounts ?pa]
|
||||
[?pi :plaid-item/access-token ?t]]
|
||||
db)))
|
||||
([db & client-codes]
|
||||
(-> (dc/q '[:find ?ba ?c ?external-id ?t
|
||||
:in $ [?cc ...]
|
||||
:where
|
||||
[?c :client/code ?cc]
|
||||
[?c :client/bank-accounts ?ba]
|
||||
[?ba :bank-account/plaid-account ?pa]
|
||||
[?pa :plaid-account/external-id ?external-id]
|
||||
[?pi :plaid-item/accounts ?pa]
|
||||
[?pi :plaid-item/access-token ?t]]
|
||||
db
|
||||
client-codes))))
|
||||
|
||||
|
||||
(defn plaid->transaction [t plaid-merchant->vendor-id]
|
||||
|
||||
30
src/clj/auto_ap/import/plaid.fiddle
Normal file
30
src/clj/auto_ap/import/plaid.fiddle
Normal file
@@ -0,0 +1,30 @@
|
||||
(ns auto-ap.import.plaid)
|
||||
|
||||
(let [end (atime/local-now)
|
||||
start (time/plus end (time/days -30))
|
||||
[_ _ external-id access-token] (first (get-plaid-accounts (dc/db conn) "BCFM"))]
|
||||
(p/get-balance access-token))
|
||||
|
||||
(def g *1)
|
||||
|
||||
(take 5 (:transactions g))
|
||||
|
||||
;; => ({:account_id "Dpj0d9yKmXsOxBd0eaL4UONyEJYomNIX7kba3",
|
||||
;; :balances
|
||||
;; {:available nil,
|
||||
;; :current 17764.42,
|
||||
;; :iso_currency_code "USD",
|
||||
;; :limit nil,
|
||||
;; :unofficial_currency_code nil},
|
||||
;; :mask "1006",
|
||||
;; :name "NICHOLAS TAPTELIS -91006",
|
||||
;; :official_name "Business Gold Rewards Card",
|
||||
;; :subtype "credit card",
|
||||
;; :type "credit"})
|
||||
|
||||
|
||||
|
||||
|
||||
(user/init-repl)
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(ns auto-ap.plaid.core
|
||||
(:require
|
||||
[clj-http.client :as client]
|
||||
[clojure.data.json :as json]
|
||||
[auto-ap.logging :as alog]
|
||||
[config.core :as cfg :refer [env]]
|
||||
[auto-ap.time :as atime]))
|
||||
(:require [auto-ap.logging :as alog]
|
||||
[auto-ap.time :as atime]
|
||||
[cemerick.url :as url]
|
||||
[clj-http.client :as client]
|
||||
[clojure.data.json :as json]
|
||||
[config.core :as cfg :refer [env]]))
|
||||
|
||||
(def base-url (-> env :plaid :base-url))
|
||||
|
||||
@@ -61,6 +61,15 @@
|
||||
"access_token" access-token})})
|
||||
:body))
|
||||
|
||||
(defn get-balance [access-token ]
|
||||
(-> (client/post (str base-url "/accounts/balance/get")
|
||||
{:as :json
|
||||
:headers {"Content-Type" "application/json"}
|
||||
:body (json/write-str {"access_token" access-token
|
||||
"secret" secret-key
|
||||
"client_id" client-id})})
|
||||
:body))
|
||||
|
||||
(defn get-transactions [access-token account-id start end]
|
||||
(alog/info ::searching
|
||||
:start (str start)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
wrap-secure]]
|
||||
[auto-ap.ssr-routes :as ssr-routes]
|
||||
[auto-ap.ssr.company.reports.expense :as company-expense-report]
|
||||
[auto-ap.ssr.company.reports.reconciliation :as company-reconciliation-report]
|
||||
[auto-ap.ssr.components :as com]
|
||||
[auto-ap.ssr.grid-page-helper :as helper]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
@@ -138,7 +139,8 @@
|
||||
{:company-reports page
|
||||
:company-reports-table table
|
||||
:company-reports-delete delete-report}
|
||||
company-expense-report/key->handler))
|
||||
company-expense-report/key->handler)
|
||||
(into company-reconciliation-report/key->handler))
|
||||
(fn [h]
|
||||
(-> h
|
||||
(wrap-secure)
|
||||
|
||||
204
src/clj/auto_ap/ssr/company/reports/reconciliation.clj
Normal file
204
src/clj/auto_ap/ssr/company/reports/reconciliation.clj
Normal file
@@ -0,0 +1,204 @@
|
||||
(ns auto-ap.ssr.company.reports.reconciliation
|
||||
(:require [auto-ap.datomic :refer [conn pull-attr]]
|
||||
[auto-ap.graphql.utils :refer [extract-client-ids]]
|
||||
[auto-ap.import.intuit :refer [get-intuit-bank-accounts
|
||||
intuits->transactions]]
|
||||
[auto-ap.intuit.core :refer [get-transactions]]
|
||||
[auto-ap.ssr-routes :as ssr-routes]
|
||||
[auto-ap.ssr.components :as com]
|
||||
[auto-ap.ssr.form-cursor :as fc]
|
||||
[auto-ap.ssr.hx :as hx]
|
||||
[auto-ap.ssr.ui :refer [base-page]]
|
||||
[auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers
|
||||
clj-date-schema html-response
|
||||
wrap-schema-enforce]]
|
||||
[auto-ap.time :as atime]
|
||||
[bidi.bidi :as bidi]
|
||||
[cemerick.url :as url]
|
||||
[clj-time.coerce :as coerce]
|
||||
[datomic.api :as dc]
|
||||
[auto-ap.ssr.svg :as svg]))
|
||||
|
||||
(defn report* [{:keys [request report]}]
|
||||
[:div #_{:class "overflow-scroll min-w-full max-h-[700px]"}
|
||||
(com/data-grid
|
||||
{:headers (into
|
||||
[(com/data-grid-header {:class "" #_"sticky left-0 z-60 bg-gray-100"} "Bank Account")
|
||||
(com/data-grid-header {:class "" #_"sticky left-0 z-60 bg-gray-100"} "Source count")
|
||||
(com/data-grid-header {:class "" #_"sticky left-0 z-60 bg-gray-100"} "Synced count")
|
||||
(com/data-grid-header {:class "" #_"sticky left-0 z-60 bg-gray-100"} "Approved transactions")
|
||||
(com/data-grid-header {:class "" #_"sticky left-0 z-60 bg-gray-100"} "Unapproved transactions")
|
||||
(com/data-grid-header {:class "" #_"sticky left-0 z-60 bg-gray-100"} "Requires feedback transactions")
|
||||
(com/data-grid-header {:class "" #_"sticky left-0 z-60 bg-gray-100"} "Missing transactions")])
|
||||
#_#_:thead-params {:class "sticky top-0 z-50"}}
|
||||
(for [row report]
|
||||
(let [matches? (= (:external-transaction-count row)
|
||||
(:integreat-transaction-count row))
|
||||
class (if matches? "bg-primary-200 text-primary-900"
|
||||
"bg-red-200 text-red-900")]
|
||||
(com/data-grid-row
|
||||
{}
|
||||
(com/data-grid-cell {:class class}
|
||||
(:bank-account/name row))
|
||||
(com/data-grid-cell {:class class}
|
||||
(:external-transaction-count row))
|
||||
(com/data-grid-cell {:class class}
|
||||
(:integreat-transaction-count row))
|
||||
(com/data-grid-cell {:class class}
|
||||
(:approved-count row))
|
||||
(com/data-grid-cell {:class class}
|
||||
(:unapproved-count row))
|
||||
(com/data-grid-cell {:class class}
|
||||
(:requires-feedback-count row))
|
||||
(com/data-grid-cell {:class class}
|
||||
[:div { :x-data (hx/json {:popper nil
|
||||
:hovering false})
|
||||
"x-init" "popper = Popper.createPopper($refs.hover_target, $refs.tooltip, {placement: 'bottom', strategy:'fixed', modifiers: [{name: 'preventOverflow'}, {name: 'offset', options: {offset: [0, 10]}}]});"}
|
||||
(com/button {"x-ref" "hover_target"
|
||||
"@click.prevent" "hovering=!hovering; $nextTick(() => popper.update())"}
|
||||
[:div.flex.gap-2.items-center
|
||||
(count (:missing-transactions row))
|
||||
[:div.w-4.h-4 svg/question]
|
||||
|
||||
])
|
||||
[:div (hx/alpine-appear {:x-ref "tooltip"
|
||||
:x-show "hovering"
|
||||
:class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 p-4"})
|
||||
(com/data-grid {:headers [(com/data-grid-header {} "Date")
|
||||
(com/data-grid-header {} "Amount")]}
|
||||
(for [r (:missing-transactions row)]
|
||||
(com/data-grid-row {}
|
||||
(com/data-grid-cell {}
|
||||
(atime/unparse-local (coerce/to-date-time (:transaction/date r)) atime/normal-date))
|
||||
(com/data-grid-cell {}
|
||||
(format "$%,.2f" (:transaction/amount r))))))
|
||||
]
|
||||
|
||||
|
||||
])))))])
|
||||
|
||||
|
||||
(defn reconciliation-card* [{:keys [request report]}]
|
||||
(com/content-card {:class "w-full" :id "reconciliation-report"}
|
||||
[:div {:class "flex flex-col px-8 py-8 space-y-3"}
|
||||
[:div
|
||||
[:h1.text-2xl.mb-3.font-bold "Bank Reconciliation Report"]
|
||||
|
||||
[:form {:hx-get (bidi.bidi/path-for ssr-routes/only-routes :company-reconciliation-report-card)
|
||||
:hx-target "#reconciliation-report"
|
||||
:hx-swap "outerHTML"}
|
||||
(fc/start-form
|
||||
(:query-params request)
|
||||
(:form-errors request)
|
||||
[:div.flex.gap-2
|
||||
(fc/with-field :start-date
|
||||
(com/validated-field {:label "Start"
|
||||
:errors (fc/field-errors)}
|
||||
[:div {:class "w-64"}
|
||||
(com/date-input {:name (fc/field-name)
|
||||
:class "w-64"
|
||||
:value (some-> (fc/field-value)
|
||||
(atime/unparse-local atime/normal-date)) })]))
|
||||
(fc/with-field :end-date
|
||||
(com/validated-field {:label "End"
|
||||
:errors (fc/field-errors)}
|
||||
[:div {:class "w-64"}
|
||||
(com/date-input {:name (fc/field-name)
|
||||
:class "w-64"
|
||||
:value (some-> (fc/field-value)
|
||||
(atime/unparse-local atime/normal-date)) })]))
|
||||
(com/button {:color :primary :class "self-center w-24"} "Run")])]
|
||||
(if report
|
||||
(report* {:request request :report report})
|
||||
[:div "Please choose a time range to run the report"])
|
||||
]]))
|
||||
|
||||
(defn page [request]
|
||||
(base-page
|
||||
request
|
||||
(com/page {:nav com/company-aside-nav
|
||||
:client-selection (:client-selection request)
|
||||
:client (:client request)
|
||||
:clients (:clients request)
|
||||
:identity (:identity request)
|
||||
:app-params {:hx-get (bidi/path-for ssr-routes/only-routes :company-reconciliation-report)
|
||||
:hx-trigger "clientSelected from:body"
|
||||
:hx-select "#app-contents"
|
||||
:hx-swap "outerHTML swap:300ms"}}
|
||||
(com/breadcrumbs {}
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes :company)}
|
||||
"My Company"]
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes :company-reconciliation-report)}
|
||||
"Reconciliation Report"])
|
||||
(reconciliation-card* {:request request :report nil}))
|
||||
"My Company"))
|
||||
|
||||
(defn normalize-query-params [request]
|
||||
(-> request
|
||||
:query-params
|
||||
(update :vendor-id :db/id)
|
||||
(update :account-id :db/id)
|
||||
(update :start-date #(atime/unparse-local % atime/normal-date))
|
||||
(update :end-date #(atime/unparse-local % atime/normal-date))
|
||||
|
||||
url/map->query))
|
||||
|
||||
(defn get-report-data [start-date end-date client-ids]
|
||||
(let [client-codes (map first (dc/q '[:find ?cc :in $ [?c ...] :where [?c :client/code ?cc]] (dc/db conn ) client-ids))]
|
||||
(for [[ib ba c] (seq (apply get-intuit-bank-accounts (dc/db conn) client-codes))
|
||||
:let [raw-transactions (get-transactions (atime/unparse-local start-date atime/iso-date)
|
||||
(atime/unparse-local end-date atime/iso-date)
|
||||
ib)
|
||||
ideal-transactions (intuits->transactions raw-transactions ba c)
|
||||
|
||||
found-transactions (when (seq ideal-transactions)
|
||||
(into {} (dc/q '[:find ?si (count ?t)
|
||||
:in $ [?eid ...]
|
||||
:where
|
||||
[?t :transaction/id ?eid]
|
||||
[?t :transaction/approval-status ?s]
|
||||
[?s :db/ident ?si]]
|
||||
(dc/db conn)
|
||||
(map :transaction/id ideal-transactions))))
|
||||
|
||||
missing-transaction-ids (when (seq ideal-transactions)
|
||||
(->>
|
||||
(dc/q '[:find ?eid
|
||||
:in $ [?eid ...]
|
||||
:where (not [_ :transaction/id ?eid])]
|
||||
(dc/db conn)
|
||||
(map :transaction/id ideal-transactions))
|
||||
(map first)
|
||||
(into #{})))
|
||||
missing-transactions (filter (comp missing-transaction-ids :transaction/id) ideal-transactions)]]
|
||||
{:bank-account/name (pull-attr (dc/db conn) :bank-account/name ba)
|
||||
:external-transaction-count (count raw-transactions)
|
||||
:integreat-transaction-count (reduce + 0 (vals found-transactions))
|
||||
:approved-count (:transaction-approval-status/approved found-transactions 0)
|
||||
:unapproved-count (:transaction-approval-status/unapproved found-transactions 0)
|
||||
:requires-feedback-count (:transaction-approval-status/requires-feedback found-transactions 0)
|
||||
:missing-transactions missing-transactions})))
|
||||
|
||||
(defn card [{ {:keys [start-date end-date]} :query-params :as request}]
|
||||
(let [client-ids (extract-client-ids (:clients request)
|
||||
(:client-id request)
|
||||
(when (:client-code request)
|
||||
[:client/code (:client-code request)]))
|
||||
report (get-report-data start-date end-date client-ids)]
|
||||
(html-response
|
||||
(reconciliation-card* {:request request
|
||||
:report report})
|
||||
:headers {"hx-push-url" (str "?" (normalize-query-params request))})))
|
||||
|
||||
(def key->handler
|
||||
(apply-middleware-to-all-handlers
|
||||
{:company-reconciliation-report page
|
||||
:company-reconciliation-report-card card}
|
||||
(fn [h]
|
||||
(-> h
|
||||
(wrap-schema-enforce :query-schema
|
||||
[:map {:default {}}
|
||||
[:start-date {:optional true}
|
||||
[:maybe clj-date-schema]]
|
||||
[:end-date {:optional true}
|
||||
[:maybe clj-date-schema]] ])))))
|
||||
@@ -294,6 +294,15 @@
|
||||
:company-expense-report)
|
||||
:hx-boost true}
|
||||
"Expense Report")]
|
||||
(when (can? (:identity request)
|
||||
{:subject :reconciliation-report}))
|
||||
[:li
|
||||
(menu-button- {:icon svg/report
|
||||
:active? (= :company-reconciliation-report (:matched-route request))
|
||||
:href (bidi/path-for ssr-routes/only-routes
|
||||
:company-reconciliation-report)
|
||||
:hx-boost true}
|
||||
"Reconciliation Report")]
|
||||
[:li
|
||||
(menu-button- {:icon svg/bank
|
||||
:active? (= :company-plaid (:matched-route request))
|
||||
|
||||
@@ -87,7 +87,10 @@
|
||||
"/table" :company-reports-table
|
||||
"/expense" {:get :company-expense-report
|
||||
"/card" :company-expense-report-breakdown-card
|
||||
"/invoice-total-card" :company-expense-report-invoice-total-card}}
|
||||
"/invoice-total-card" :company-expense-report-invoice-total-card}
|
||||
"/reconciliation"
|
||||
{:get :company-reconciliation-report
|
||||
"/card" :company-reconciliation-report-card}}
|
||||
"/yodlee" {"" {:get :company-yodlee}
|
||||
"/table" {:get :company-yodlee-table}
|
||||
"/fastlink" {:get :company-yodlee-fastlink-dialog}
|
||||
|
||||
Reference in New Issue
Block a user