303 lines
14 KiB
Clojure
303 lines
14 KiB
Clojure
(ns auto-ap.views.pages.ledger.balance-sheet
|
|
(:require
|
|
[auto-ap.forms :as forms]
|
|
[auto-ap.ledger.reports :as l-reports]
|
|
[auto-ap.status :as status]
|
|
[clojure.string :as str]
|
|
[auto-ap.subs :as subs]
|
|
[auto-ap.views.components.modal :as modal]
|
|
[auto-ap.views.components.layouts
|
|
:refer [appearing-side-bar side-bar-layout]]
|
|
[auto-ap.views.components.switch-field :refer [switch-field]]
|
|
[auto-ap.views.pages.data-page :as data-page]
|
|
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
|
|
[auto-ap.views.pages.ledger.table :as ledger-table]
|
|
[auto-ap.views.utils
|
|
:refer [date->str
|
|
date-picker-friendly
|
|
dispatch-event
|
|
local-now
|
|
standard
|
|
with-user]]
|
|
[cljs-time.core :as t]
|
|
[clojure.set :as set]
|
|
[re-frame.core :as re-frame]
|
|
[reagent.core :as reagent]
|
|
[vimsical.re-frame.fx.track :as track]
|
|
[vimsical.re-frame.cofx.inject :as inject]
|
|
[auto-ap.views.pages.ledger.report-table :as rtable]))
|
|
|
|
(defn data-params->query-params [params]
|
|
(when params
|
|
{:start (:start params 0)
|
|
:sort (:sort params)
|
|
:per-page (:per-page params)
|
|
:vendor-id (:id (:vendor params))
|
|
:client-id (:client-id params )
|
|
:from-numeric-code (:from-numeric-code params)
|
|
:to-numeric-code (:to-numeric-code params)
|
|
:date-range (:date-range params)}))
|
|
|
|
(re-frame/reg-sub
|
|
::can-submit
|
|
(fn [_]
|
|
true))
|
|
|
|
|
|
(re-frame/reg-sub
|
|
::ledger-list-active?
|
|
(fn [db]
|
|
(-> db ::ledger-list-active?)))
|
|
|
|
(re-frame/reg-event-db
|
|
::received
|
|
[(forms/in-form ::form)]
|
|
(fn [db [_ data]]
|
|
(-> db
|
|
(assoc :report (:balance-sheet data)))))
|
|
|
|
(re-frame/reg-event-fx
|
|
::change
|
|
[with-user (forms/in-form ::form)]
|
|
(fn [{:keys [db]} [_ & event]]
|
|
{:db (dissoc db :report)
|
|
:dispatch-n [(into [::forms/change ::form] event)
|
|
[::ledger-list-closing]]}))
|
|
|
|
(re-frame/reg-event-db
|
|
::ledger-list-closing
|
|
(fn [db]
|
|
(assoc db ::ledger-list-active? false)))
|
|
|
|
|
|
(re-frame/reg-event-fx
|
|
::report-requested
|
|
[with-user (forms/in-form ::form) (re-frame/inject-cofx ::inject/sub [::subs/client])]
|
|
(fn [{:keys [db user ::subs/client]} [_]]
|
|
{:db (dissoc db :report)
|
|
:graphql {:token user
|
|
:query-obj {:venia/queries [[:balance-sheet
|
|
(-> (:data db)
|
|
(assoc :client-id (:id client))
|
|
(update :date (fnil #(date->str % standard) nil))
|
|
(update :comparison-date (fnil #(date->str % standard) nil)))
|
|
[[:balance-sheet-accounts [:name :amount :account-type :id :numeric-code]]
|
|
[:comparable-balance-sheet-accounts [:name :amount :account-type :id :numeric-code]]]]]}
|
|
|
|
:owns-state {:single ::page}
|
|
:on-success [::received]}}))
|
|
|
|
(defn email-body [report-url]
|
|
(js/encodeURIComponent
|
|
(str
|
|
"Hello,
|
|
Click here (" report-url ") to download your financial reports. We have not finished reviewing and reconciling these numbers with you. Please review and let us know if anything seems missing or in need of correction.
|
|
Click here (http://app.integreatconsult.com/) to login to the Financials app to review the details here.
|
|
Click here (https://share.vidyard.com/watch/MHTo5PyXPxXUpVH93RWFM9?) for a video on how to run a P&L on your own.
|
|
To see a history of past financial reports, click here: https://app.integreatconsult.com/reports/
|
|
|
|
NOTE: Please review the transactions we may have question for you here: https://app.integreatconsult.com/transactions/requires-feedback. You can either edit the transaction to what expense account it should be or email back what it should be.")))
|
|
|
|
(re-frame/reg-event-fx
|
|
::received-pdf
|
|
[(re-frame/inject-cofx ::inject/sub [::subs/client])]
|
|
(fn [{:keys [::subs/client]} [_ result]]
|
|
{:dispatch [::modal/modal-requested {:title "Your report is ready"
|
|
:body [:div
|
|
[:div "Click "
|
|
[:a {:href (-> result :balance-sheet-pdf :url) :target "_new"} "here"] " to view it."]
|
|
(when (seq (:emails client))
|
|
[:div "Once you've confirmed you're happy with it, click "
|
|
[:a {:href (str "mailto:" (str/join ";" (map :email (:emails client))) "?body=" (email-body (-> result :balance-sheet-pdf :url))
|
|
"&subject=" (-> result :balance-sheet-pdf :name) " is ready")}
|
|
"here"] " to open your email client and to send it to " (str/join "," (map (fn [e]
|
|
(str (:email e) " (" (:description e) ")"))
|
|
(:emails client))) "."])]}]}))
|
|
|
|
(re-frame/reg-event-fx
|
|
::export-pdf
|
|
[with-user (forms/in-form ::form) (re-frame/inject-cofx ::inject/sub [::subs/client])]
|
|
(fn [{:keys [db user ::subs/client]} [_]]
|
|
{:db (dissoc db :report)
|
|
:graphql {:token user
|
|
:query-obj {:venia/queries [[:balance-sheet-pdf
|
|
(-> (:data db)
|
|
(assoc :client-id (:id client))
|
|
(update :date (fnil #(date->str % standard) nil))
|
|
(update :comparison-date (fnil #(date->str % standard) nil)))
|
|
[:url :name]]]}
|
|
|
|
:owns-state {:single ::page}
|
|
:on-success [::received-pdf]}}))
|
|
|
|
|
|
(re-frame/reg-event-fx
|
|
::investigate-clicked
|
|
(fn [{:keys [db]} [_ {:keys [from-numeric-code to-numeric-code date-range]}]]
|
|
{:db (-> db (assoc ::ledger-list-active? true))
|
|
:dispatch [::data-page/additional-params-changed ::ledger {:client-id (:id @(re-frame/subscribe [::subs/client]))
|
|
:from-numeric-code from-numeric-code
|
|
:to-numeric-code to-numeric-code
|
|
:date-range {:start "2000-01-01"
|
|
:end (date->str date-range standard)}}]}))
|
|
|
|
(re-frame/reg-event-fx
|
|
::ledger-params-change
|
|
[with-user]
|
|
(fn [{:keys [user]} [_ ledger-params]]
|
|
(when (seq ledger-params)
|
|
{:graphql {:token user
|
|
:owns-state {:single [::data-page/page ::ledger]}
|
|
:query-obj {:venia/queries [[:ledger-page
|
|
{:filters (data-params->query-params ledger-params)}
|
|
[[:journal-entries [:id
|
|
:source
|
|
:original-entity
|
|
:amount
|
|
:alternate-description
|
|
[:vendor
|
|
[:name :id]]
|
|
[:client
|
|
[:name :id]]
|
|
[:line-items
|
|
[:id :debit :credit :location :running-balance
|
|
[:account [:id :name]]]]
|
|
:date]]
|
|
:total
|
|
:start
|
|
:end]]]}
|
|
:on-success (fn [result]
|
|
[::data-page/received ::ledger (set/rename-keys (:ledger-page result)
|
|
{:journal-entries :data})])}})))
|
|
|
|
(re-frame/reg-event-fx
|
|
::unmounted-balance-sheet
|
|
(fn [{:keys [db]} _]
|
|
{
|
|
:db (dissoc db ::ledger-list-active?)
|
|
:dispatch [::data-page/dispose ::ledger]
|
|
::track/dispose {:id ::ledger-params}}))
|
|
|
|
(re-frame/reg-event-fx
|
|
::mounted-balance-sheet
|
|
(fn [{:keys [db]} _]
|
|
{:db (forms/start-form db ::form {:date (local-now)
|
|
:comparison-date (t/minus (local-now) (t/years 1))
|
|
:include-comparison true})
|
|
::track/register {:id ::ledger-params
|
|
:subscription [::data-page/params ::ledger]
|
|
:event-fn (fn [params] [::ledger-params-change params])}}))
|
|
|
|
|
|
(def balance-sheet-form (forms/vertical-form {:can-submit [::can-submit]
|
|
:change-event [::change]
|
|
:submit-event [::report-requested]
|
|
:id ::form}))
|
|
|
|
(defn report-form []
|
|
(let [{:keys [form-inline raw-field]} balance-sheet-form
|
|
{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
|
|
(form-inline {}
|
|
[:div
|
|
[:div.report-controls
|
|
[:div.level
|
|
[:div.level-left
|
|
[:div.level-item
|
|
[:div.control
|
|
[:p.help "Date"]
|
|
(raw-field
|
|
[date-picker-friendly {:cljs-date? true
|
|
:type "date"
|
|
:field [:date]}])]]
|
|
[:div.level-item
|
|
[:div.control
|
|
[:div.mt-3]
|
|
[switch-field {:id "include-comparison"
|
|
:checked (:include-comparison data)
|
|
:on-change (fn [e]
|
|
(re-frame/dispatch [::change [:include-comparison] (.-checked (.-target e))]))
|
|
:label "Include comparison"
|
|
:type "checkbox"}]]]
|
|
[:div.level-item
|
|
|
|
(when (boolean (:include-comparison data))
|
|
[:div.control
|
|
[:p.help "Comparison Date"]
|
|
(raw-field
|
|
[date-picker-friendly {:cljs-date? true
|
|
:type "date"
|
|
:field [:comparison-date]}])])]]
|
|
[:div.level-right
|
|
[:div.buttons
|
|
|
|
(when @(re-frame/subscribe [::subs/is-admin?])
|
|
[:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"])
|
|
[:button.button.is-primary "Run"]]]]]])))
|
|
|
|
(defn balance-sheet-report [{:keys [args report-data]}]
|
|
(let [pnl-data (concat (->> (:balance-sheet-accounts report-data)
|
|
(map (fn [b]
|
|
(assoc b
|
|
:period (:date args)
|
|
:amount (js/parseFloat (:amount b))))))
|
|
(->> (:comparable-balance-sheet-accounts report-data)
|
|
(map (fn [b]
|
|
(assoc b
|
|
:period (:comparison-date args)
|
|
:amount (js/parseFloat (:amount b)))))))
|
|
client-names (->> @(re-frame/subscribe [::subs/clients-by-id])
|
|
(map (fn [[k v]]
|
|
[k (:name v)]))
|
|
(into {}))
|
|
pnl-data (l-reports/->PNLData args pnl-data client-names)
|
|
report (l-reports/summarize-balance-sheet pnl-data)]
|
|
[rtable/table {:widths (cond-> [30 13]
|
|
(:include-comparison args) (into [13 13]))
|
|
:click-event ::investigate-clicked
|
|
:table report}]))
|
|
|
|
(defn balance-sheet-content []
|
|
(let [current-client @(re-frame/subscribe [::subs/client])
|
|
status @(re-frame/subscribe [::status/single ::page])
|
|
{params :data report :report} @(re-frame/subscribe [::forms/form ::form])]
|
|
(if current-client
|
|
[:div.is-inline
|
|
[status/status-notification {:statuses [[::status/single ::page]]}]
|
|
[report-form]
|
|
|
|
[status/big-loader status]
|
|
(when (and (not= :loading (:state status))
|
|
report)
|
|
[balance-sheet-report {:args (assoc params
|
|
:periods (filter identity (cond-> [(:date params)]
|
|
(:include-comparison params) (conj (:comparison-date params)))))
|
|
:report-data report}])]
|
|
[:div
|
|
[:h1.title "Balance sheet"]
|
|
[:h2.subtitle "Please choose a client first"]])))
|
|
|
|
(defn ledger-list [_ ]
|
|
[:div [:a.delete.is-pulled-right {:on-click (dispatch-event [::ledger-list-closing])}]
|
|
[:div
|
|
[:h1.title "Ledger entries"]
|
|
[ledger-table/table {:id :ledger
|
|
:data-page ::ledger}]]])
|
|
|
|
(defn balance-sheet-page []
|
|
(reagent/create-class
|
|
{:display-name "balance-sheet-page"
|
|
:component-did-mount #(re-frame/dispatch [::mounted-balance-sheet])
|
|
:component-will-unmount #(re-frame/dispatch [::unmounted-balance-sheet])
|
|
:reagent-render
|
|
(fn []
|
|
(let [ledger-list-active? @(re-frame/subscribe [::ledger-list-active?])
|
|
user (re-frame/subscribe [::subs/user])]
|
|
(if (not= "manager" (:user/role @user))
|
|
[side-bar-layout
|
|
{:side-bar [ledger-side-bar]
|
|
:main [balance-sheet-content]
|
|
:right-side-bar [appearing-side-bar
|
|
{:visible? ledger-list-active?}
|
|
[ledger-list]]}]
|
|
[:div "Not authorized"])))}))
|