From 17fde0dd1676826037f5dbfa42ea4d567d062213 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Tue, 29 Mar 2022 18:02:13 -0700 Subject: [PATCH] unifying reports even more. --- src/clj/auto_ap/pdf/ledger.clj | 48 ++--- src/cljc/auto_ap/ledger/reports.cljc | 35 +++- .../views/pages/ledger/profit_and_loss.cljs | 187 ++++++++---------- 3 files changed, 131 insertions(+), 139 deletions(-) diff --git a/src/clj/auto_ap/pdf/ledger.clj b/src/clj/auto_ap/pdf/ledger.clj index 54b07f5f..d84420be 100644 --- a/src/clj/auto_ap/pdf/ledger.clj +++ b/src/clj/auto_ap/pdf/ledger.clj @@ -167,31 +167,31 @@ report (l-reports/summarize-pnl pnl-data) output-stream (ByteArrayOutputStream.)] (pdf/pdf - (into - [{:left-margin 10 :right-margin 10 :top-margin 15 :bottom-margin 15 - :size (cond - (and (>= (count (-> pnl-data :args :periods)) 8 ) - (-> pnl-data :args :include-deltas)) - :a2 + (-> [{:left-margin 10 :right-margin 10 :top-margin 15 :bottom-margin 15 + :size (cond + (and (>= (count (-> pnl-data :args :periods)) 8 ) + (-> pnl-data :args :include-deltas)) + :a2 - (>= (count (-> pnl-data :args :periods)) 4 ) - :tabloid - - :else - :letter) - :orientation :landscape - :font {:size 6 - :ttf-name "fonts/calibri-light.ttf"}} - [:heading (str "Profit and Loss - " (str/join ", " (map :client/name clients)))]] - (for [table (concat (:summaries report) - (:details report))] - (table->pdf table - (into [20] (take (dec (cell-count table)) - (mapcat identity - (repeat - (if (-> pnl-data :args :include-deltas) - [13 6 13] - [13 6])))))))) + (>= (count (-> pnl-data :args :periods)) 4 ) + :tabloid + :else + :letter) + :orientation :landscape + :font {:size 6 + :ttf-name "fonts/calibri-light.ttf"}} + [:heading (str "Profit and Loss - " (str/join ", " (map :client/name clients)))]] + (conj [:paragraph {:color [128 0 0] :size 9} (:warning report)]) + (into + (for [table (concat (:summaries report) + (:details report))] + (table->pdf table + (into [20] (take (dec (cell-count table)) + (mapcat identity + (repeat + (if (-> pnl-data :args :include-deltas) + [13 6 13] + [13 6]))))))))) output-stream) (.toByteArray output-stream))) diff --git a/src/cljc/auto_ap/ledger/reports.cljc b/src/cljc/auto_ap/ledger/reports.cljc index 3a12bbd0..1a26bdb1 100644 --- a/src/cljc/auto_ap/ledger/reports.cljc +++ b/src/cljc/auto_ap/ledger/reports.cljc @@ -1,9 +1,15 @@ (ns auto-ap.ledger.reports - (:require - [auto-ap.utils :refer [dollars-0?]] - #?(:cljs [auto-ap.views.utils :as au ] - :clj [auto-ap.time :as atime]))) - + #?@ + (:clj + [(:require + [auto-ap.time :as atime] + [auto-ap.utils :refer [dollars-0?]] + [clojure.string :as str])] + :cljs + [(:require + [auto-ap.utils :refer [dollars-0?]] + [auto-ap.views.utils :as au] + [clojure.string :as str])])) (defn date->str [d] #?(:clj @@ -339,11 +345,26 @@ {:header (headers pnl-data title) :rows (combine-tables pnl-data table percent-of-sales deltas)})) +(defn warning-message [pnl-data] + (let [errors (->> pnl-data + :data + (filter (fn [{:keys [numeric-code]}] + (nil? numeric-code)))) + error-count (count errors)] + (when (> error-count 0) + (str "This report does not include " + (str/join ", " + (map #(str (:count %) " unresolved ledger entries for " (if (str/blank? (:location %)) + " all locations" + (:location %))) + errors)))))) + (defn summarize-pnl [pnl-data] - {:summaries (for [[client-id location] (locations (:data pnl-data))] + {:warning (warning-message pnl-data) + :summaries (for [[client-id location] (locations (:data pnl-data))] (location-summary-table (-> pnl-data (filter-client client-id) - (filter-location location)) + (filter-location location)) (str (-> pnl-data :clients-by-id (get client-id)) " (" location ") Summary"))) :details (for [[client-id location] (locations (:data pnl-data))] (location-detail-table (-> pnl-data diff --git a/src/cljs/auto_ap/views/pages/ledger/profit_and_loss.cljs b/src/cljs/auto_ap/views/pages/ledger/profit_and_loss.cljs index ecedb570..c5b72be3 100644 --- a/src/cljs/auto_ap/views/pages/ledger/profit_and_loss.cljs +++ b/src/cljs/auto_ap/views/pages/ledger/profit_and_loss.cljs @@ -37,9 +37,14 @@ -(defn and-last-year [[from to]] - [[from to] - [(t/minus from (t/years 1)) (t/minus to (t/years 1))]]) +(defn and-last-year [{:keys [start end] :as p1}] + [p1 + {:start (t/minus start (t/years 1)) + :end (t/minus end (t/years 1))}]) + +(defn encode-period [p] + {:start (date->str (:start p) standard) + :end (date->str (:end p) standard)}) ;; SUBS @@ -49,18 +54,6 @@ (fn [db] (-> db ::ledger-list-active?))) -(re-frame/reg-sub - ::uncategorized-accounts - :<- [::forms/form ::form] - (fn [db [_ ]] - - (->> (get-in db [:report :periods ]) - (mapcat :accounts) - (map #(update % :amount js/parseFloat)) - (filter (fn [{:keys [account-type location numeric-code]}] - (nil? numeric-code)))))) - - (re-frame/reg-event-db ::received [(forms/in-form ::form)] @@ -82,14 +75,12 @@ :owns-state {:single ::page} :query-obj {:venia/queries [[:profit-and-loss {:client-ids (map :id (:clients (:data db))) - :periods (mapv (fn [[start end] ] {:start (date->str start standard) :end (date->str end standard)} ) - (:periods (:data db)))} + :periods (mapv encode-period (:periods (:data db)))} [[:periods [[:accounts [:name :amount :client_id :account-type :id :count :numeric-code :location]]]]]]]} :on-success [::received]} - :set-uri-params {:periods (mapv (fn [[start end title]] - [(date->str start standard) - (date->str end standard)]) - (:periods (:data db))) + :set-uri-params {:periods (mapv + encode-period + (:periods (:data db))) :clients (mapv #(select-keys % [:name :id]) (:clients (:data db))) } :db (dissoc db :report)}))) @@ -129,14 +120,10 @@ Please download it by clicking this link: " report-url))) :query-obj {:venia/queries [[:profit-and-loss-pdf {:client-ids (map :id (:clients (:data db))) :include-deltas (:include-deltas (:data db)) - :periods (mapv (fn [[start end] ] {:start (date->str start standard) :end (date->str end standard)} ) - (:periods (:data db)))} + :periods (mapv encode-period (:periods (:data db)))} [:report_url]]]} :on-success [::received-pdf]} - :set-uri-params {:periods (mapv (fn [[start end title]] - [(date->str start standard) - (date->str end standard)]) - (:periods (:data db))) + :set-uri-params {:periods (mapv encode-period (:periods (:data db))) :clients (mapv #(select-keys % [:name :id]) (:clients (:data db))) } :db (dissoc db :report)}))) @@ -368,14 +355,14 @@ Please download it by clicking this link: " report-url))) (let [today (or (some-> (:thirteen-periods-end data) (str->date standard)) (local-today))] (into - [[(t/plus (t/minus today (t/weeks (* 13 4))) - (t/days 1)) - today - "Total"]] + [{:start (t/plus (t/minus today (t/weeks (* 13 4))) + (t/days 1)) + :end today + :title "Total"}] (for [i (range 13)] - [(t/plus (t/minus today (t/weeks (* (inc i) 4))) - (t/days 1)) - (t/minus today (t/weeks (* i 4)))]))) + {:start (t/plus (t/minus today (t/weeks (* (inc i) 4))) + (t/days 1)) + :end (t/minus today (t/weeks (* i 4)))}))) [:selected-period] "13 periods"])} "13 periods"]]]] @@ -385,8 +372,7 @@ Please download it by clicking this link: " report-url))) (raw-field [date-picker-friendly {:placeholder "End date" :type "date" - :field [:twelve-periods-end]}]) - ] + :field [:twelve-periods-end]}])] [:div.control [:a.button {:class (when (= selected-period "12 months") "is-active") @@ -397,17 +383,16 @@ Please download it by clicking this link: " report-url))) (local-today)) this-month (t/local-date (t/year end-date) (t/month end-date) - 1) - ] - (into - [[(t/minus this-month (t/months 11)) - (t/minus (t/plus this-month (t/months 1)) - (t/days 1)) - "Total"]] + 1)] + (into + [{:start (t/minus this-month (t/months 11)) + :end (t/minus (t/plus this-month (t/months 1)) + (t/days 1)) + :title "Total"}] (for [i (range 12)] - [(t/minus this-month (t/months (- 11 i))) - (t/minus (t/minus this-month (t/months (- 10 i))) - (t/days 1))]))) + {:start (t/minus this-month (t/months (- 11 i))) + :end (t/minus (t/minus this-month (t/months (- 10 i))) + (t/days 1))}))) [:selected-period] "12 months"])} "12 months"]]]] @@ -421,21 +406,21 @@ Please download it by clicking this link: " report-url))) (if (= 7 (t/day-of-week current)) current (recur (t/minus current (t/period :days 1)))))] - - (and-last-year [(t/minus last-sunday (t/period :days 6)) last-sunday])) + (and-last-year {:start (t/minus last-sunday (t/period :days 6)) + :end last-sunday})) [:selected-period] "Last week"])} "Last week"]] - [:div.control + [:div.control [:a.button {:class (when (= selected-period "Week to date") "is-active") :on-click (dispatch-event [::change [:periods] - (and-last-year [(loop [current (local-today)] - (if (= 1 (t/day-of-week current)) - current - (recur (t/minus current (t/period :days 1))))) - (local-today)]) + (and-last-year {:start (loop [current (local-today)] + (if (= 1 (t/day-of-week current)) + current + (recur (t/minus current (t/period :days 1))))) + :end (local-today)}) [:selected-period] "Week to date"])} "Week to date"]] [:div.control @@ -445,14 +430,14 @@ Please download it by clicking this link: " report-url))) [::change [:periods] - (and-last-year [(t/minus (t/local-date (t/year (local-today)) - (t/month (local-today)) - 1) - (t/period :months 1)) - (t/minus (t/local-date (t/year (local-today)) - (t/month (local-today)) - 1) - (t/period :days 1))]) + (and-last-year {:start (t/minus (t/local-date (t/year (local-today)) + (t/month (local-today)) + 1) + (t/period :months 1)) + :end (t/minus (t/local-date (t/year (local-today)) + (t/month (local-today)) + 1) + (t/period :days 1))}) [:selected-period] "Last Month"])} "Last Month"]] [:div.control @@ -461,10 +446,10 @@ Please download it by clicking this link: " report-url))) :on-click (dispatch-event [::change [:periods] - (and-last-year [(t/local-date (t/year (local-today)) - (t/month (local-today)) - 1) - (local-today)]) + (and-last-year {:start (t/local-date (t/year (local-today)) + (t/month (local-today)) + 1) + :end (local-today)}) [:selected-period] "Month to date"] )} "Month to date"]] @@ -474,8 +459,9 @@ Please download it by clicking this link: " report-url))) :on-click (dispatch-event [::change [:periods] - (and-last-year [(t/local-date (t/year (local-today)) 1 1) - (local-today)]) + (and-last-year {:start (t/local-date (t/year (local-today)) 1 1) + :end + (local-today)}) [:selected-period] "Year to date"])} "Year to date"]] [:div.control @@ -484,8 +470,8 @@ Please download it by clicking this link: " report-url))) :on-click (dispatch-event [::change [:periods] - [[(t/local-date (dec (t/year (local-today))) 1 1) - (t/local-date (dec (t/year (local-today))) 12 31)]] + [{:start (t/local-date (dec (t/year (local-today))) 1 1) + :end (t/local-date (dec (t/year (local-today))) 12 31)}] [:selected-period] "Last Calendar year"])} "Last calendar year"]] [:div.control @@ -494,15 +480,15 @@ Please download it by clicking this link: " report-url))) :on-click (dispatch-event [::change [:periods] - (and-last-year [(t/plus (t/minus (local-today) (t/period :years 1)) - (t/period :days 1)) - (local-today)]) + (and-last-year {:start (t/plus (t/minus (local-today) (t/period :years 1)) + (t/period :days 1)) + :end (local-today)}) [:selected-period] "Full year"])} "Full year"]]] [:div [:div.field [:label.checkbox - (raw-field + (raw-field [:input {:type "checkbox" :field [:show-advanced?]}]) " Show Advanced"]]] @@ -515,13 +501,13 @@ Please download it by clicking this link: " report-url))) [:p.help "From"] (raw-field [date-picker-friendly {:type "date" - :field [:periods i 0]}])] + :field [:periods i :start]}])] [:div.control [:p.help "To"] (raw-field [date-picker-friendly {:type "date" - :field [:periods i 1]}])]])))]]] + :field [:periods i :end]}])]])))]]] [:div.level-item [:div @@ -545,14 +531,7 @@ Please download it by clicking this link: " report-url))) (reset! !box el)))}]])))) (defn pnl-report [{:keys [args report-data]}] - (let [args (update args :periods - (fn [p] - (mapv (fn [[start end] ] - {:start start - :end end} ) - p))) - - pnl-data (->> report-data + (let [pnl-data (->> report-data :periods (mapcat (fn [p1 p2] (map @@ -562,7 +541,6 @@ Please download it by clicking this link: " report-url))) ) (:accounts p2))) (:periods args))) - unresolved-accounts @(re-frame/subscribe [::uncategorized-accounts]) client-names (->> @(re-frame/subscribe [::subs/clients-by-id]) (map (fn [[k v]] [k (:name v)])) @@ -571,13 +549,9 @@ Please download it by clicking this link: " report-url))) report (l-reports/summarize-pnl pnl-data)] [:div [:h1.title "Profit and Loss - " (str/join ", " (map :name (:clients args)))] - (when (seq unresolved-accounts) + (when (:warning report) [:div.notification.is-warning.is-light - "This report does not include " (str/join ", " - (map #(str (:count %) " unresolved ledger entries for " (if (str/blank? (:location %)) - " all locations" - (:location %))) - unresolved-accounts))]) + (:warning report)]) (for [[index table] (map vector (range) (concat (:summaries report) (:details report)))] ^{:key index} @@ -592,18 +566,18 @@ Please download it by clicking this link: " report-url))) (defn profit-and-loss-content [] (let [status @(re-frame/subscribe [::status/single ::page]) - {:keys [data report active? error id]} @(re-frame/subscribe [::forms/form ::form]) - {:keys [form-inline field raw-field error-notification submit-button ]} pnl-form - ] - (form-inline {} - [:div - [status/status-notification {:statuses [[::status/single ::page]]}] - [report-controls pnl-form] - [status/big-loader status] - (when (and (not= :loading (:state status)) - report) - [pnl-report {:report-data report - :args data}])]))) + {:keys [data report]} @(re-frame/subscribe [::forms/form ::form]) + {:keys [form-inline]} pnl-form] + [:div + (form-inline {} + [:div + [status/status-notification {:statuses [[::status/single ::page]]}] + [report-controls pnl-form]]) + [status/big-loader status] + (when (and (not= :loading (:state status)) + report) + [pnl-report {:report-data report + :args data}])])) (re-frame/reg-event-fx ::unmounted-pnl @@ -617,11 +591,8 @@ Please download it by clicking this link: " report-url))) {:db (forms/start-form db ::form {:periods (->> qp :periods (mapv (fn [period] - (mapv - (fn [dt] - (str->date dt standard)) - period)))) - + {:start (str->date (:start period) standard) + :end (str->date (:end period) standard)}))) :clients (or (:clients qp) [(some-> @(re-frame/subscribe [::subs/client]) (select-keys [:name :id]))]) :include-deltas true})