zebra striping + single table for column-per-location
This commit is contained in:
@@ -41,7 +41,8 @@
|
|||||||
(= :dollar (:format cell)) (assoc :align :right)
|
(= :dollar (:format cell)) (assoc :align :right)
|
||||||
(= :percent (:format cell)) (assoc :align :right)
|
(= :percent (:format cell)) (assoc :align :right)
|
||||||
(:bold cell) (assoc-in [:ttf-name] "fonts/calibri-bold.ttf")
|
(:bold cell) (assoc-in [:ttf-name] "fonts/calibri-bold.ttf")
|
||||||
(:color cell) (assoc :color (:color cell)))
|
(:color cell) (assoc :color (:color cell))
|
||||||
|
(:bg-color cell) (assoc :background-color (:bg-color cell)))
|
||||||
|
|
||||||
cell-contents
|
cell-contents
|
||||||
]))
|
]))
|
||||||
@@ -195,7 +196,7 @@
|
|||||||
report (l-reports/summarize-pnl pnl-data)
|
report (l-reports/summarize-pnl pnl-data)
|
||||||
output-stream (ByteArrayOutputStream.)]
|
output-stream (ByteArrayOutputStream.)]
|
||||||
(pdf/pdf
|
(pdf/pdf
|
||||||
(-> [{:left-margin 10 :right-margin 10 :top-margin 15 :bottom-margin 15
|
(-> [{:left-margin 10 :right-margin 10 :top-margin 5 :bottom-margin 15
|
||||||
:size (cond
|
:size (cond
|
||||||
(and (>= (count (-> pnl-data :args :periods)) 8 )
|
(and (>= (count (-> pnl-data :args :periods)) 8 )
|
||||||
(-> pnl-data :args :include-deltas))
|
(-> pnl-data :args :include-deltas))
|
||||||
|
|||||||
@@ -177,6 +177,11 @@
|
|||||||
(update :filters (fn [f]
|
(update :filters (fn [f]
|
||||||
(assoc f :date-range period)))))
|
(assoc f :date-range period)))))
|
||||||
|
|
||||||
|
(defn zebra [pnl-data i]
|
||||||
|
(if (odd? i)
|
||||||
|
(assoc-in pnl-data [:cell-args :bg-color] [240 240 240])
|
||||||
|
pnl-data))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn negate [pnl-data types]
|
(defn negate [pnl-data types]
|
||||||
@@ -208,6 +213,7 @@
|
|||||||
:value (aggregate-accounts p)
|
: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 (when (:from-numeric-code (:filters p)) ;; don't allow filtering when you don't at least filter numeric codes
|
||||||
(:filters p))}
|
(:filters p))}
|
||||||
|
(:cell-args p)
|
||||||
cell-args))
|
cell-args))
|
||||||
pnl-datas)))
|
pnl-datas)))
|
||||||
|
|
||||||
@@ -221,10 +227,18 @@
|
|||||||
(map
|
(map
|
||||||
(fn [v s]
|
(fn [v s]
|
||||||
{:border (:border v)
|
{:border (:border v)
|
||||||
:format :percent
|
:bg-color (:bg-color v)
|
||||||
|
:format (if (string? (:value v))
|
||||||
|
:text
|
||||||
|
:percent)
|
||||||
:color [128 128 128]
|
:color [128 128 128]
|
||||||
:value (if (dollars-0? s)
|
:value (cond
|
||||||
|
(string? (:value v))
|
||||||
|
""
|
||||||
|
|
||||||
|
(dollars-0? s)
|
||||||
0.0
|
0.0
|
||||||
|
:else
|
||||||
(/ (:value v) s))})
|
(/ (:value v) s))})
|
||||||
values sales))))))
|
values sales))))))
|
||||||
|
|
||||||
@@ -234,10 +248,16 @@
|
|||||||
(->> values
|
(->> values
|
||||||
(partition 2 1)
|
(partition 2 1)
|
||||||
(map (fn [[a b]]
|
(map (fn [[a b]]
|
||||||
{:border (:border b)
|
(if (or (string? (:value b))
|
||||||
:format :dollar
|
(string? (:value a)))
|
||||||
:value (- (:value b)
|
{:value ""
|
||||||
(:value a))})))))))
|
:format :text
|
||||||
|
:bg-color (:bg-color b)}
|
||||||
|
{:border (:border b)
|
||||||
|
:format :dollar
|
||||||
|
:value (- (:value b)
|
||||||
|
(:value a))
|
||||||
|
:bg-color (:bg-color b)}))))))))
|
||||||
|
|
||||||
(defn combine-tables
|
(defn combine-tables
|
||||||
([[pnl-data] table percent-of-sales deltas]
|
([[pnl-data] table percent-of-sales deltas]
|
||||||
@@ -259,46 +279,53 @@
|
|||||||
deltas)))
|
deltas)))
|
||||||
|
|
||||||
(defn headers [[pnl-data :as pnl-datas] header-title]
|
(defn headers [[pnl-data :as pnl-datas] header-title]
|
||||||
(let [
|
(let [big-header (into [{:value header-title
|
||||||
big-header (into [{:value header-title
|
|
||||||
:bold true}]
|
:bold true}]
|
||||||
(map (fn [p]
|
(map-indexed (fn [i p]
|
||||||
{:value
|
(cond-> {:value
|
||||||
(str (date->str (:start p))
|
(str (date->str (:start p))
|
||||||
" - "
|
" - "
|
||||||
(date->str (:end p)))
|
(date->str (:end p)))
|
||||||
:colspan (cond
|
:colspan (cond
|
||||||
(-> pnl-data :args :include-deltas)
|
(-> pnl-data :args :include-deltas)
|
||||||
3
|
3
|
||||||
|
|
||||||
(-> pnl-data :args :column-per-location)
|
(-> pnl-data :args :column-per-location)
|
||||||
(* 2 (/ (count pnl-datas)
|
(* 2 (/ (count pnl-datas)
|
||||||
(count (-> pnl-data :args :periods))))
|
(count (-> pnl-data :args :periods))))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
2)
|
2)
|
||||||
:align :center
|
:align :center
|
||||||
:bold true})
|
:bold true}
|
||||||
|
(odd? i) (assoc :bg-color [240 240 240])))
|
||||||
(:periods (:args pnl-data))))
|
(:periods (:args pnl-data))))
|
||||||
sub-header (into [{:value ""}]
|
sub-header (into [{:value ""}]
|
||||||
(if (-> pnl-data :args :column-per-location)
|
(if (-> pnl-data :args :column-per-location)
|
||||||
(mapcat
|
(mapcat
|
||||||
(fn [p]
|
(fn [p]
|
||||||
(cond-> [{:value (-> p :filters :location)
|
(cond-> [(merge {:value (or (
|
||||||
:align :right}
|
-> p :filters :location) "Total")
|
||||||
{:value "%"
|
:align :right}
|
||||||
:align :right}]
|
(:cell-args p))
|
||||||
(-> pnl-data :args :include-deltas) (conj {:value "+/-"
|
(merge {:value "%"
|
||||||
:align :right})))
|
:align :right}
|
||||||
|
(:cell-args p))]
|
||||||
|
(-> pnl-data :args :include-deltas) (conj (merge {:value "+/-"
|
||||||
|
:align :right}
|
||||||
|
(:cell-args p)))))
|
||||||
pnl-datas)
|
pnl-datas)
|
||||||
(mapcat
|
(mapcat
|
||||||
(fn [_]
|
(fn [p]
|
||||||
(cond-> [{:value "Amt"
|
(cond-> [(merge {:value "Amt"
|
||||||
:align :right}
|
:align :right}
|
||||||
{:value "%"
|
(:cell-args p))
|
||||||
:align :right}]
|
(merge {:value "%"
|
||||||
(-> pnl-data :args :include-deltas) (conj {:value "+/-"
|
:align :right}
|
||||||
:align :right})))
|
(:cell-args p))]
|
||||||
|
(-> pnl-data :args :include-deltas) (conj (merge {:value "+/-"
|
||||||
|
:align :right}
|
||||||
|
(:cell-args p)))))
|
||||||
pnl-datas)))]
|
pnl-datas)))]
|
||||||
[big-header
|
[big-header
|
||||||
sub-header]))
|
sub-header]))
|
||||||
@@ -343,25 +370,36 @@
|
|||||||
pnl-datas)
|
pnl-datas)
|
||||||
account-codes (used-accounts pnl-datas)]
|
account-codes (used-accounts pnl-datas)]
|
||||||
:when (seq account-codes)
|
:when (seq account-codes)
|
||||||
row (-> [[{:value (str "---" grouping-name "---")}]]
|
row (-> [(into [{:value (str "---" grouping-name "---")}]
|
||||||
|
(map
|
||||||
|
(fn [p]
|
||||||
|
(assoc (:cell-args p) :value "" :format ""))
|
||||||
|
pnl-datas)
|
||||||
|
)]
|
||||||
(into (for [{:keys [numeric-code name]} account-codes]
|
(into (for [{:keys [numeric-code name]} account-codes]
|
||||||
(into [{:value name}]
|
(into [{:value name}]
|
||||||
(map
|
(map
|
||||||
(fn [p]
|
(fn [p]
|
||||||
(let [pnl-data (-> p (filter-numeric-code numeric-code numeric-code))]
|
(let [pnl-data (-> p (filter-numeric-code numeric-code numeric-code))]
|
||||||
{:format :dollar
|
(merge
|
||||||
:filters (:filters pnl-data)
|
{:format :dollar
|
||||||
:value (aggregate-accounts pnl-data)}))
|
:filters (:filters pnl-data)
|
||||||
|
:value (aggregate-accounts pnl-data)}
|
||||||
|
(:cell-args p))))
|
||||||
|
|
||||||
pnl-datas))))
|
pnl-datas))))
|
||||||
(conj (subtotal-by-column-row pnl-datas "" {:border [:top]})))]
|
(conj (subtotal-by-column-row pnl-datas "" {:border [:top]})))]
|
||||||
row)]
|
row)]
|
||||||
(-> [[{:value title
|
(-> [(into [{:value title
|
||||||
:bold true}]]
|
:bold true}]
|
||||||
|
(map
|
||||||
|
(fn [p]
|
||||||
|
(assoc (:cell-args p) :value "" :format ""))
|
||||||
|
pnl-datas))]
|
||||||
(into individual-accounts)
|
(into individual-accounts)
|
||||||
(conj (subtotal-by-column-row pnl-datas title)))))
|
(conj (subtotal-by-column-row pnl-datas title)))))
|
||||||
|
|
||||||
(defn location-detail-table [pnl-datas client-data title prefix]
|
(defn location-detail-table [pnl-datas client-datas title prefix]
|
||||||
(let [table (-> []
|
(let [table (-> []
|
||||||
(into (detail-rows pnl-datas
|
(into (detail-rows pnl-datas
|
||||||
:sales
|
:sales
|
||||||
@@ -399,11 +437,14 @@
|
|||||||
(filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable])
|
(filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable])
|
||||||
(negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable}))
|
(negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable}))
|
||||||
pnl-datas)
|
pnl-datas)
|
||||||
(str prefix " Net Income")))
|
(str prefix " Net Income"))))
|
||||||
(conj (subtotal-by-column-row (-> client-data
|
table (if (seq client-datas)
|
||||||
(filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable])
|
(conj table (subtotal-by-column-row (map #(-> %
|
||||||
(negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable}))
|
(filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable])
|
||||||
"All Location Net Income")))
|
(negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable}))
|
||||||
|
client-datas)
|
||||||
|
"All Location Net Income"))
|
||||||
|
table)
|
||||||
percent-of-sales (calc-percent-of-sales table pnl-datas)
|
percent-of-sales (calc-percent-of-sales table pnl-datas)
|
||||||
deltas (into [] (calc-deltas table))]
|
deltas (into [] (calc-deltas table))]
|
||||||
{:header (headers pnl-datas title)
|
{:header (headers pnl-datas title)
|
||||||
@@ -427,45 +468,52 @@
|
|||||||
{:warning (warning-message pnl-data)
|
{:warning (warning-message pnl-data)
|
||||||
:summaries
|
:summaries
|
||||||
(if (-> pnl-data :args :column-per-location)
|
(if (-> pnl-data :args :column-per-location)
|
||||||
(for [client-id (set (map first (client-locations pnl-data)))]
|
[(location-summary-table (mapcat identity (for [[period i] (map vector (-> pnl-data :args :periods ) (range))]
|
||||||
(location-summary-table (for [period (-> pnl-data :args :periods )
|
(concat
|
||||||
location (locations pnl-data)]
|
(for [location (set (map second (client-locations pnl-data)))]
|
||||||
(-> pnl-data
|
(-> pnl-data
|
||||||
(filter-client client-id)
|
(filter-location location)
|
||||||
(filter-location location)
|
(filter-period period)
|
||||||
(filter-period period)))
|
(zebra i)))
|
||||||
(str (-> pnl-data :clients-by-id (get client-id)) " Summary")))
|
[(zebra (filter-period pnl-data period) i)])))
|
||||||
|
"All location Summary")]
|
||||||
(for [[client-id location] (client-locations pnl-data)]
|
(for [[client-id location] (client-locations pnl-data)]
|
||||||
(location-summary-table (for [period (-> pnl-data :args :periods )]
|
(location-summary-table (for [[period i] (map vector (-> pnl-data :args :periods ) (range))]
|
||||||
(-> pnl-data
|
(-> pnl-data
|
||||||
(filter-client client-id)
|
(filter-client client-id)
|
||||||
(filter-location location)
|
(filter-location location)
|
||||||
(filter-period period)))
|
(filter-period period)
|
||||||
|
(zebra i)))
|
||||||
(str (-> pnl-data :clients-by-id (get client-id)) " (" location ") Summary"))))
|
(str (-> pnl-data :clients-by-id (get client-id)) " (" location ") Summary"))))
|
||||||
:details
|
:details
|
||||||
(doall (if (-> pnl-data :args :column-per-location)
|
(doall (if (-> pnl-data :args :column-per-location)
|
||||||
(for [client-id (set (map first (client-locations pnl-data)))]
|
[(location-detail-table (mapcat identity (for [[period i] (map vector (-> pnl-data :args :periods ) (range))]
|
||||||
(location-detail-table (for [period (-> pnl-data :args :periods )
|
(concat
|
||||||
location (locations pnl-data)]
|
(for [location (set (map second (client-locations pnl-data)))]
|
||||||
(-> pnl-data
|
(-> pnl-data
|
||||||
(filter-client client-id)
|
(filter-location location)
|
||||||
(filter-location location)
|
(filter-period period)
|
||||||
(filter-period period)))
|
(zebra i)))
|
||||||
(-> pnl-data
|
[(-> pnl-data
|
||||||
(filter-client client-id))
|
(filter-period period)
|
||||||
(str (-> pnl-data :clients-by-id (get client-id)) " Detail")
|
(zebra i))])))
|
||||||
""))
|
nil
|
||||||
|
"All location Detail"
|
||||||
|
"")]
|
||||||
(for [[client-id location] (client-locations pnl-data)]
|
(for [[client-id location] (client-locations pnl-data)]
|
||||||
(location-detail-table (for [period (-> pnl-data :args :periods )]
|
(location-detail-table (for [[period i] (map vector (-> pnl-data :args :periods ) (range))]
|
||||||
(-> pnl-data
|
(-> pnl-data
|
||||||
(filter-client client-id)
|
(filter-client client-id)
|
||||||
(filter-location location)
|
(filter-location location)
|
||||||
(filter-period period)))
|
(filter-period period)
|
||||||
(-> pnl-data
|
(zebra i)))
|
||||||
(filter-client client-id))
|
(for [[period i] (map vector (-> pnl-data :args :periods ) (range))]
|
||||||
|
(-> pnl-data
|
||||||
|
(filter-client client-id)
|
||||||
|
(filter-period period)
|
||||||
|
(zebra i)))
|
||||||
(str (-> pnl-data :clients-by-id (get client-id)) " (" location ") Detail")
|
(str (-> pnl-data :clients-by-id (get client-id)) " (" location ") Detail")
|
||||||
location))))
|
location))))})
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
(defn balance-sheet-headers [pnl-data]
|
(defn balance-sheet-headers [pnl-data]
|
||||||
@@ -483,8 +531,7 @@
|
|||||||
(:value b))})]))))
|
(:value b))})]))))
|
||||||
|
|
||||||
(defn summarize-balance-sheet [pnl-data]
|
(defn summarize-balance-sheet [pnl-data]
|
||||||
(let [
|
(let [pnl-datas (map (fn [p]
|
||||||
pnl-datas (map (fn [p]
|
|
||||||
(filter-period pnl-data p))
|
(filter-period pnl-data p))
|
||||||
(:periods (:args pnl-data)))
|
(:periods (:args pnl-data)))
|
||||||
table (-> []
|
table (-> []
|
||||||
@@ -502,7 +549,6 @@
|
|||||||
(filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable])
|
(filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable])
|
||||||
(negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable}))
|
(negate #{:cogs :payroll :controllable :fixed-overhead :ownership-controllable}))
|
||||||
pnl-datas)
|
pnl-datas)
|
||||||
|
|
||||||
"Retained Earnings")))
|
"Retained Earnings")))
|
||||||
table (if (:include-comparison (:args pnl-data))
|
table (if (:include-comparison (:args pnl-data))
|
||||||
(append-deltas table)
|
(append-deltas table)
|
||||||
|
|||||||
@@ -38,6 +38,10 @@
|
|||||||
(:color c) (assoc-in [:style :color] (str "rgb("
|
(:color c) (assoc-in [:style :color] (str "rgb("
|
||||||
(str/join ","
|
(str/join ","
|
||||||
(:color c))
|
(:color c))
|
||||||
|
")"))
|
||||||
|
(:bg-color c) (assoc-in [:style :background-color] (str "rgb("
|
||||||
|
(str/join ","
|
||||||
|
(:bg-color c))
|
||||||
")")))
|
")")))
|
||||||
|
|
||||||
cell-contents]))
|
cell-contents]))
|
||||||
@@ -68,7 +72,14 @@
|
|||||||
(for [[i row] (map vector (range) (:rows table))]
|
(for [[i row] (map vector (range) (:rows table))]
|
||||||
^{:key i}
|
^{:key i}
|
||||||
[:tr
|
[:tr
|
||||||
(for [[i c] (map vector (range) (take cell-count (concat row (repeat nil))))]
|
(for [[i c] (map vector (range) (take cell-count
|
||||||
|
(reduce
|
||||||
|
(fn [[acc cnt] cur]
|
||||||
|
(if (>= (+ cnt (:colspan cur 1)) cell-count)
|
||||||
|
(reduced (conj acc cur))
|
||||||
|
[(conj acc cur) (+ cnt (:colspan cur 1))]))
|
||||||
|
[[] 0]
|
||||||
|
(concat row (repeat nil)))))]
|
||||||
^{:key i}
|
^{:key i}
|
||||||
[cell {:click-event click-event} c])]))
|
[cell {:click-event click-event} c])]))
|
||||||
(conj ^{:key "last"}
|
(conj ^{:key "last"}
|
||||||
|
|||||||
Reference in New Issue
Block a user