From 7739c18bc2e9f5d0a932d911ec6648fe98566528 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Sun, 3 Apr 2022 07:46:15 -0700 Subject: [PATCH] Adds the ability to do a column per location --- src/clj/auto_ap/graphql/ledger.clj | 9 +- src/cljc/auto_ap/ledger/reports.cljc | 306 +++++++++++------- .../views/pages/ledger/profit_and_loss.cljs | 247 +++++++------- 3 files changed, 303 insertions(+), 259 deletions(-) diff --git a/src/clj/auto_ap/graphql/ledger.clj b/src/clj/auto_ap/graphql/ledger.clj index ea2a9a7d..1e4d107d 100644 --- a/src/clj/auto_ap/graphql/ledger.clj +++ b/src/clj/auto_ap/graphql/ledger.clj @@ -192,6 +192,9 @@ (throw (ex-info "Please select a client." {:validation-error "Please select a client."}))) _ (doseq [client-id client-ids] (assert-can-see-client (:id context) client-id)) + _ (when (and (:include_deltas args) + (:column_per_location args)) + (throw (ex-info "Please select one of 'Include deltas' or 'Column per location'" {:validation-error "Please select one of 'Include deltas' or 'Column per location'"}))) all-ledger-entries (->> client-ids (map (fn [client-id] [client-id (full-ledger-for-client client-id)])) @@ -584,14 +587,16 @@ :args {:client_id {:type :id} :client_ids {:type '(list :id)} :periods {:type '(list :date_range)} - :include_deltas {:type 'Boolean}} + :include_deltas {:type 'Boolean} + :column_per_location {:type 'Boolean}} :resolve :get-profit-and-loss} :profit_and_loss_pdf {:type :report_pdf :args {:client_id {:type :id} :client_ids {:type '(list :id)} :periods {:type '(list :date_range)} - :include_deltas {:type 'Boolean}} + :include_deltas {:type 'Boolean} + :column_per_location {:type 'Boolean}} :resolve :profit-and-loss-pdf} :balance_sheet_pdf {:type :report_pdf diff --git a/src/cljc/auto_ap/ledger/reports.cljc b/src/cljc/auto_ap/ledger/reports.cljc index 169578f4..8099b114 100644 --- a/src/cljc/auto_ap/ledger/reports.cljc +++ b/src/cljc/auto_ap/ledger/reports.cljc @@ -90,9 +90,11 @@ (vals ranges)) false)) -(defn locations [data] - (->> data +(defn client-locations [pnl-data] + (->> pnl-data + :data (filter (comp in-range? :numeric-code)) + (filter #(not= "A" (:location %))) (group-by (juxt :client-id :location)) (filter (fn [[_ as]] (not (dollars-0? (reduce + 0 (map :amount as)))))) @@ -112,6 +114,15 @@ "ZZZZZZ" (:location x))])))) +(defn locations [pnl-data] + (->> (client-locations pnl-data) + (map second) + set + (sort-by (fn [x] + (if (= x "HQ" ) + "ZZZZZZ" + x))))) + (defn aggregate-accounts [pnl-data] (reduce (fnil + 0.0) 0.0 (map :amount (:data pnl-data)))) @@ -179,34 +190,32 @@ accounts)))) -(defn used-accounts [pnl-data] - (->> (:data pnl-data) - (map #(select-keys % [:numeric-code :name])) - (set) - (sort-by :numeric-code))) +(defn used-accounts [pnl-datas] + (->> + pnl-datas + (mapcat :data) + (map #(select-keys % [:numeric-code :name])) + (set) + (sort-by :numeric-code))) -(defn subtotal-row [pnl-data title & [cell-args]] - (into [{:value title - :bold true - :filters (when (:from-numeric-code (:filters pnl-data)) ;; don't allow filtering when you don't at least filter numeric codes - (:filters pnl-data))}] +(defn subtotal-by-column-row [pnl-datas title & [cell-args]] + (into [{:value title + :bold true}] (map (fn [p] - (let [data (filter-period pnl-data p)] - (merge - {:format :dollar - :value (aggregate-accounts data) - :filters (when (:from-numeric-code (:filters data)) ;; don't allow filtering when you don't at least filter numeric codes - (:filters data))} - cell-args))) - (-> pnl-data :args :periods)))) + (merge + {:format :dollar + :value (aggregate-accounts p) + :filters (when (:from-numeric-code (:filters p)) ;; don't allow filtering when you don't at least filter numeric codes + (:filters p))} + cell-args)) + pnl-datas))) -(defn calc-percent-of-sales [table pnl-data] - (let [sales-pnl-data (filter-categories pnl-data [:sales]) - sales (map +(defn calc-percent-of-sales [table pnl-datas] + (let [sales (map (fn [p] - (aggregate-accounts (filter-period sales-pnl-data p))) - (-> pnl-data :args :periods))] + (aggregate-accounts (filter-categories p [:sales]))) + pnl-datas)] (->> table (map (fn [[_ & values]] (map @@ -231,7 +240,7 @@ (:value a))}))))))) (defn combine-tables - ([pnl-data table percent-of-sales deltas] + ([[pnl-data] table percent-of-sales deltas] (map (fn [[title & row] percent-of-sales deltas ] (let [deltas (cons {:value 0.0 :format :dollar @@ -249,130 +258,156 @@ percent-of-sales deltas))) -(defn headers [pnl-data header-title] - (let [big-header (into [{:value header-title +(defn headers [[pnl-data :as pnl-datas] header-title] + (let [ + big-header (into [{:value header-title :bold true}] (map (fn [p] {:value (str (date->str (:start p)) " - " (date->str (:end p))) - :colspan (if (-> pnl-data :args :include-deltas) + :colspan (cond + (-> pnl-data :args :include-deltas) 3 + + (-> pnl-data :args :column-per-location) + (* 2 (/ (count pnl-datas) + (count (-> pnl-data :args :periods)))) + + :else 2) :align :center :bold true}) (:periods (:args pnl-data)))) sub-header (into [{:value ""}] - (mapcat - (fn [_] - (cond-> [{:value "Amt" - :align :right} - {:value "%" - :align :right}] - (-> pnl-data :args :include-deltas) (conj {:value "+/-" - :align :right}))) - (:periods (:args pnl-data))))] + (if (-> pnl-data :args :column-per-location) + (mapcat + (fn [p] + (cond-> [{:value (-> p :filters :location) + :align :right} + {:value "%" + :align :right}] + (-> pnl-data :args :include-deltas) (conj {:value "+/-" + :align :right}))) + pnl-datas) + (mapcat + (fn [_] + (cond-> [{:value "Amt" + :align :right} + {:value "%" + :align :right}] + (-> pnl-data :args :include-deltas) (conj {:value "+/-" + :align :right}))) + pnl-datas)))] [big-header sub-header])) -(defn location-summary-table [pnl-data title] - (let [table [(subtotal-row (filter-categories pnl-data [:sales]) "Sales") - (subtotal-row (filter-categories pnl-data [:cogs ]) "Cogs") +(defn location-summary-table [pnl-datas title] + (let [table [(subtotal-by-column-row (map #(filter-categories % [:sales]) + pnl-datas) + "Sales") + (subtotal-by-column-row (map #(filter-categories % [:cogs ]) pnl-datas) + "Cogs") - (subtotal-row (filter-categories pnl-data [:payroll ]) "Payroll") + (subtotal-by-column-row (map #(filter-categories % [:payroll ]) pnl-datas) + "Payroll") - (subtotal-row (-> pnl-data - (filter-categories [:sales :payroll :cogs]) - (negate #{:payroll :cogs})) - "Gross Profits") + (subtotal-by-column-row (map #(-> % + (filter-categories [:sales :payroll :cogs]) + (negate #{:payroll :cogs})) + pnl-datas) + "Gross Profits") - (subtotal-row (filter-categories pnl-data [:controllable :fixed-overhead :ownership-controllable]) - "Overhead") + (subtotal-by-column-row (map #(filter-categories % [:controllable :fixed-overhead :ownership-controllable]) + pnl-datas) + "Overhead") - (subtotal-row (-> pnl-data - (filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable]) - (negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable})) - "Net Income")] - percent-of-sales (calc-percent-of-sales table pnl-data) + (subtotal-by-column-row (map #(-> % + (filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable]) + (negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable})) + pnl-datas) + "Net Income")] + percent-of-sales (calc-percent-of-sales table pnl-datas) deltas (calc-deltas table)] - {:header (headers pnl-data title) - :rows (combine-tables pnl-data table percent-of-sales deltas)})) + {:header (headers pnl-datas title) + :rows (combine-tables pnl-datas table percent-of-sales deltas)})) -(defn detail-rows [pnl-data grouping title] - (let [pnl-data (filter-categories pnl-data [grouping]) +(defn detail-rows [pnl-datas grouping title] + (let [pnl-datas (map #(filter-categories % [grouping]) + pnl-datas) individual-accounts (for [[grouping-name from to] (groupings grouping) - :let [pnl-data (filter-numeric-code pnl-data from to) - account-codes (used-accounts pnl-data)] + :let [pnl-datas (map #(filter-numeric-code % from to) + pnl-datas) + account-codes (used-accounts pnl-datas)] :when (seq account-codes) row (-> [[{:value (str "---" grouping-name "---")}]] (into (for [{:keys [numeric-code name]} account-codes] (into [{:value name}] (map (fn [p] - (let [pnl-data (-> pnl-data - (filter-numeric-code numeric-code numeric-code) - (filter-period p) - )] + (let [pnl-data (-> p (filter-numeric-code numeric-code numeric-code))] {:format :dollar :filters (:filters pnl-data) :value (aggregate-accounts pnl-data)})) - (-> pnl-data :args :periods))))) - (conj (subtotal-row pnl-data "" {:border [:top]})))] + pnl-datas)))) + (conj (subtotal-by-column-row pnl-datas "" {:border [:top]})))] row)] (-> [[{:value title :bold true}]] (into individual-accounts) - (conj (subtotal-row pnl-data title))))) + (conj (subtotal-by-column-row pnl-datas title))))) -(defn location-detail-table [pnl-data client-data title] +(defn location-detail-table [pnl-datas client-data title prefix] (let [table (-> [] - (into (detail-rows pnl-data + (into (detail-rows pnl-datas :sales - (str (:prefix pnl-data) " Sales"))) - (into (detail-rows pnl-data + (str prefix " Sales"))) + (into (detail-rows pnl-datas :cogs - (str (:prefix pnl-data) " COGS"))) + (str prefix " COGS"))) (into (detail-rows - pnl-data + pnl-datas :payroll - (str (:prefix pnl-data) " Payroll"))) - (conj (subtotal-row (filter-categories pnl-data [:payroll :cogs]) - (str (:prefix pnl-data) " Prime Costs"))) - (conj (subtotal-row (-> pnl-data - (filter-categories [:sales :payroll :cogs]) - (negate #{:payroll :cogs})) - (str (:prefix pnl-data) " Gross Profits"))) + (str prefix " Payroll"))) + (conj (subtotal-by-column-row (map #(filter-categories % [:payroll :cogs]) + pnl-datas) + (str prefix " Prime Costs"))) + (conj (subtotal-by-column-row (map #(-> % + (filter-categories [:sales :payroll :cogs]) + (negate #{:payroll :cogs})) + pnl-datas) + (str prefix " Gross Profits"))) (into (detail-rows - pnl-data + pnl-datas :controllable - (str (:prefix pnl-data) " Controllable Expenses"))) + (str prefix " Controllable Expenses"))) (into (detail-rows - pnl-data + pnl-datas :fixed-overhead - (str (:prefix pnl-data) " Fixed Overhead"))) + (str prefix " Fixed Overhead"))) (into (detail-rows - pnl-data + pnl-datas :ownership-controllable - (str (:prefix pnl-data) " Ownership Controllable"))) - (conj (subtotal-row (-> pnl-data - (filter-categories [:controllable :fixed-overhead :ownership-controllable])) - (str (:prefix pnl-data) " Overhead"))) - (conj (subtotal-row (-> pnl-data - (filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable]) - (negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable})) - (str (:prefix pnl-data) " Net Income"))) - (conj (subtotal-row (-> client-data - (filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable]) - (negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable})) - "All Location Net Income"))) - percent-of-sales (calc-percent-of-sales table pnl-data) + (str prefix " Ownership Controllable"))) + (conj (subtotal-by-column-row (map #(filter-categories % [:controllable :fixed-overhead :ownership-controllable]) pnl-datas) + (str prefix " Overhead"))) + (conj (subtotal-by-column-row (map #(-> % + (filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable]) + (negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable})) + pnl-datas) + (str prefix " Net Income"))) + (conj (subtotal-by-column-row (-> client-data + (filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable]) + (negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable})) + "All Location Net Income"))) + percent-of-sales (calc-percent-of-sales table pnl-datas) deltas (into [] (calc-deltas table))] - {:header (headers pnl-data title) - :rows (combine-tables pnl-data table percent-of-sales deltas)})) + {:header (headers pnl-datas title) + :rows (combine-tables pnl-datas table percent-of-sales deltas)})) (defn warning-message [pnl-data] (let [errors (->> pnl-data @@ -389,20 +424,48 @@ errors)))))) (defn summarize-pnl [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)) - (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 + {:warning (warning-message pnl-data) + :summaries + (if (-> pnl-data :args :column-per-location) + (for [client-id (set (map first (client-locations pnl-data)))] + (location-summary-table (for [period (-> pnl-data :args :periods ) + location (locations pnl-data)] + (-> pnl-data + (filter-client client-id) + (filter-location location) + (filter-period period))) + (str (-> pnl-data :clients-by-id (get client-id)) " Summary"))) + (for [[client-id location] (client-locations pnl-data)] + (location-summary-table (for [period (-> pnl-data :args :periods )] + (-> pnl-data + (filter-client client-id) + (filter-location location) + (filter-period period))) + (str (-> pnl-data :clients-by-id (get client-id)) " (" location ") Summary")))) + :details + (doall (if (-> pnl-data :args :column-per-location) + (for [client-id (set (map first (client-locations pnl-data)))] + (location-detail-table (for [period (-> pnl-data :args :periods ) + location (locations pnl-data)] + (-> pnl-data (filter-client client-id) (filter-location location) - (assoc :prefix location)) + (filter-period period))) + (-> pnl-data + (filter-client client-id)) + (str (-> pnl-data :clients-by-id (get client-id)) " Detail") + "")) + (for [[client-id location] (client-locations pnl-data)] + (location-detail-table (for [period (-> pnl-data :args :periods )] (-> pnl-data - (filter-client client-id)) - (str (-> pnl-data :clients-by-id (get client-id)) " (" location ") Detail")))}) + (filter-client client-id) + (filter-location location) + (filter-period period))) + (-> pnl-data + (filter-client client-id)) + (str (-> pnl-data :clients-by-id (get client-id)) " (" location ") Detail") + location)))) + }) (defn balance-sheet-headers [pnl-data] @@ -420,20 +483,27 @@ (:value b))})])))) (defn summarize-balance-sheet [pnl-data] - (let [table (-> [] - (into (detail-rows pnl-data + (let [ + pnl-datas (map (fn [p] + (filter-period pnl-data p)) + (:periods (:args pnl-data))) + table (-> [] + (into (detail-rows pnl-datas :assets "Assets")) - (into (detail-rows pnl-data + (into (detail-rows pnl-datas :liabilities "Liabilities")) - (into (detail-rows pnl-data + (into (detail-rows pnl-datas :equities "Owner's Equity")) - (conj (subtotal-row (-> pnl-data - (filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable]) - (negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable})) - "Retained Earnings"))) + (conj (subtotal-by-column-row + (map #(-> % + (filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable]) + (negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable})) + pnl-datas) + + "Retained Earnings"))) table (if (:include-comparison (:args pnl-data)) (append-deltas table) table)] 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 d10f686c..9035f08d 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 @@ -73,7 +73,9 @@ :owns-state {:single ::page} :query-obj {:venia/queries [[:profit-and-loss {:client-ids (map :id (:clients (:data db))) - :periods (mapv encode-period (:periods (:data db)))} + :periods (mapv encode-period (:periods (:data db))) + :include-deltas (:include-deltas (:data db)) + :column-per-location (:column-per-location (:data db))} [[:periods [[:accounts [:name :amount :client_id :account-type :id :count :numeric-code :location]]]]]]]} :on-success [::received]} :set-uri-params {:periods (mapv @@ -123,7 +125,8 @@ NOTE: Please review the transactions we may have question for you here: https:// :owns-state {:single ::page} :query-obj {:venia/queries [[:profit-and-loss-pdf {:client-ids (map :id (:clients (:data db))) - :include-deltas (:include-deltas (:data db)) + :include-deltas (:include-deltas (:data db)) + :column-per-location (:column-per-location (:data db)) :periods (mapv encode-period (:periods (:data db)))} [:url :name]]]} :on-success [::received-pdf]} @@ -144,7 +147,7 @@ NOTE: Please review the transactions we may have question for you here: https:// (= 2 (count field))) [field value] ;;already serialized - (= :periods (first field)) [field (str->date value standard) ] + (= :periods (first field)) [field value ] :else nil) ))) @@ -233,13 +236,25 @@ NOTE: Please review the transactions we may have question for you here: https:// ]) @box))) +(defn period-preset-button [{:keys [title periods]}] + (let [{{:keys [selected-preset]} :data} @(re-frame/subscribe [::forms/form ::form])] + [:div.control + [:a.button + {:class (when (= selected-preset title) "is-active") + :on-click (dispatch-event + [::change + [:periods] + periods + [:selected-preset] title])} + title]])) + (defn report-controls [_] - (let [!box (reagent/atom nil) + (let [!box (reagent/atom nil) active (reagent/atom nil)] (fn [pnl-form] - (let [{:keys [raw-field]} pnl-form - {:keys [data]} @(re-frame/subscribe [::forms/form ::form]) - {:keys [periods selected-period include-deltas]} data] + (let [{:keys [raw-field]} pnl-form + {:keys [data]} @(re-frame/subscribe [::forms/form ::form]) + {:keys [periods selected-preset include-deltas column-per-location]} data] [:div.report-controls [:div.level.mb-2 [:div.level-left @@ -261,8 +276,8 @@ NOTE: Please review the transactions we may have question for you here: https:// [:div.level-item [buttons/dropdown {:on-click (fn [] (reset! active :range))} [:span (str "Range" - (when selected-period - (str " (" selected-period ")")))]] + (when selected-preset + (str " (" selected-preset ")")))]] [report-control-detail {:active active :box !box :which :range} [:div [:h4.subtitle "Range"] @@ -273,146 +288,89 @@ NOTE: Please review the transactions we may have question for you here: https:// (raw-field [date-picker-friendly {:placeholder "End date" :type "date" + :cljs-date? true :field [:thirteen-periods-end]}])] - [:div.control - [:a.button - {:class (when (= selected-period "13 periods") "is-active") - :on-click (dispatch-event - [::change - [:periods] - (let [today (or (some-> (:thirteen-periods-end data) (str->date standard)) - (local-today))] - (into - [{:start (t/plus (t/minus today (t/weeks (* 13 4))) - (t/days 1)) - :end today - :title "Total"}] - (for [i (range 13)] - {: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"]]]] + [period-preset-button {:title "13 periods" + :periods (let [today (or (some-> (:thirteen-periods-end data)) + (local-today))] + (into + [{:start (t/plus (t/minus today (t/weeks (* 13 4))) + (t/days 1)) + :end today + :title "Total"}] + (for [i (range 13)] + {:start (t/plus (t/minus today (t/weeks (* (inc i) 4))) + (t/days 1)) + :end (t/minus today (t/weeks (* i 4)))})))}]]] [:div.control [:div.field.has-addons [:div.control (raw-field [date-picker-friendly {:placeholder "End date" + :cljs-date? true :type "date" :field [:twelve-periods-end]}])] - [:div.control - [:a.button - {:class (when (= selected-period "12 months") "is-active") - :on-click (dispatch-event - [::change - [:periods] - (let [end-date (or (some-> (:twelve-periods-end data) (str->date standard)) - (local-today)) - this-month (t/local-date (t/year end-date) - (t/month end-date) - 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)] - {: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"]]]] + [period-preset-button {:title "12 months" + :periods (let [end-date (or (some-> (:twelve-periods-end data)) + (local-today)) + this-month (t/local-date (t/year end-date) + (t/month end-date) + 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)] + {:start (t/minus this-month (t/months (- 11 i))) + :end (t/minus (t/minus this-month (t/months (- 10 i))) + (t/days 1))})))}]]] - [:div.control - [:a.button - {:class (when (= selected-period "Last week") "is-active") - :on-click (dispatch-event - [::change - [:periods] - (let [last-sunday (loop [current (local-today)] - (if (= 7 (t/day-of-week current)) - current - (recur (t/minus current (t/period :days 1)))))] - (and-last-year {:start (t/minus last-sunday (t/period :days 6)) - :end last-sunday})) - [:selected-period] "Last week"])} - "Last week"]] - [:div.control - [:a.button - {:class (when (= selected-period "Week to date") "is-active") - :on-click (dispatch-event - [::change - [:periods] - (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 - [:a.button - {:class (when (= selected-period "Last Month") "is-active") - :on-click (dispatch-event + [period-preset-button {:periods (let [last-sunday (loop [current (local-today)] + (if (= 7 (t/day-of-week current)) + current + (recur (t/minus current (t/period :days 1)))))] + (and-last-year {:start (t/minus last-sunday (t/period :days 6)) + :end last-sunday})) + :title "Last week"}] - [::change - [:periods] - (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 - [:a.button - {:class (when (= selected-period "Month to date") "is-active") - :on-click (dispatch-event - [::change - [:periods] - (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"]] - [:div.control - [:a.button - {:class (when (= selected-period "Year to date") "is-active") - :on-click (dispatch-event - [::change - [:periods] - (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 - [:a.button - {:class (when (= selected-period "Full year") "is-active") - :on-click (dispatch-event - [::change - [:periods] - [{: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 - [:a.button - {:class (when (= selected-period "Full year") "is-active") - :on-click (dispatch-event - [::change - [:periods] - (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"]]] + [period-preset-button {:periods (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)}) + :title "Week to date"}] + + [period-preset-button {:periods (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))}) + :title "Last month"}] + + [period-preset-button {:periods (and-last-year {:start (t/local-date (t/year (local-today)) + (t/month (local-today)) + 1) + :end (local-today)}) + :title "Month to date"}] + + [period-preset-button {:periods (and-last-year {:start (t/local-date (t/year (local-today)) 1 1) + :end + (local-today)}) + :title "Year to date"}] + + [period-preset-button {:periods [{:start (t/local-date (dec (t/year (local-today))) 1 1) + :end (t/local-date (dec (t/year (local-today))) 12 31)}] + :title "Last calendar year"}] + + [period-preset-button {:periods (and-last-year {:start (t/plus (t/minus (local-today) (t/period :years 1)) + (t/period :days 1)) + :end (local-today)}) + :title "Full year"}]] [:div [:div.field [:label.checkbox @@ -429,12 +387,14 @@ NOTE: Please review the transactions we may have question for you here: https:// [:p.help "From"] (raw-field [date-picker-friendly {:type "date" + :cljs-date? true :field [:periods i :start]}])] [:div.control [:p.help "To"] (raw-field [date-picker-friendly {:type "date" + :cljs-date? true :field [:periods i :end]}])]])))]]] [:div.level-item @@ -445,7 +405,16 @@ NOTE: Please review the transactions we may have question for you here: https:// (re-frame/dispatch [::change [:include-deltas] (.-checked (.-target e))])) :label "Include deltas" - :type "checkbox"}]]]] + :type "checkbox"}]]] + [:div.level-item + [:div + [switch-field {:id "column-per-location" + :checked (boolean column-per-location) + :on-change (fn [e] + (re-frame/dispatch [::change + [:column-per-location] (.-checked (.-target e))])) + :label "Column per location" + :type "checkbox"}]]]] [:div.level-right [:div.buttons