Splits out multiple tables when too wide
This commit is contained in:
@@ -188,73 +188,65 @@
|
||||
|
||||
(defn combine-tables [pnl-data table percent-of-sales deltas]
|
||||
(map (fn [[title & row] percent-of-sales deltas ]
|
||||
(let [deltas (cons nil deltas)]
|
||||
(let [deltas (cons "-" deltas)]
|
||||
(into [title]
|
||||
(filter identity
|
||||
(mapcat
|
||||
(fn [v p d]
|
||||
[v p d])
|
||||
row
|
||||
percent-of-sales
|
||||
deltas)))
|
||||
(mapcat
|
||||
(fn [v p d]
|
||||
[v p d])
|
||||
row
|
||||
percent-of-sales
|
||||
deltas))
|
||||
))
|
||||
table
|
||||
percent-of-sales
|
||||
deltas))
|
||||
|
||||
(defn headers [pnl-data header-title]
|
||||
(let [deltas (cons nil (repeat "Change"))
|
||||
big-header (into [{:value header-title
|
||||
(let [big-header (into [{:value header-title
|
||||
:bold true}]
|
||||
(map-indexed (fn [i p]
|
||||
{:value
|
||||
(str (date->str (:start p))
|
||||
" - "
|
||||
(date->str (:end p)))
|
||||
:colspan (if (= 0 i)
|
||||
2
|
||||
3)
|
||||
:colspan 3
|
||||
:align :center
|
||||
:bold true})
|
||||
(:periods (:args pnl-data))))
|
||||
sub-header (into [{:value ""}]
|
||||
(filter identity
|
||||
(mapcat
|
||||
(fn [v p d]
|
||||
[{:value "Amount"
|
||||
:align :right
|
||||
:bold true}
|
||||
{:value "% Sales"
|
||||
:align :right
|
||||
:bold true}
|
||||
(when d
|
||||
{:value d
|
||||
:align :right
|
||||
:bold true})])
|
||||
(:periods (:args pnl-data))
|
||||
(:periods (:args pnl-data))
|
||||
deltas)))]
|
||||
(mapcat
|
||||
(fn [_]
|
||||
[{:value "Amount"
|
||||
:align :right
|
||||
:bold true}
|
||||
{:value "% Sales"
|
||||
:align :right
|
||||
:bold true}
|
||||
{:value "Change"
|
||||
:align :right
|
||||
:bold true}])
|
||||
(:periods (:args pnl-data))))]
|
||||
[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")
|
||||
(let [table [(subtotal-row (filter-categories pnl-data [:sales]) "Sales")
|
||||
(subtotal-row (filter-categories pnl-data [:cogs ]) "Cogs")
|
||||
|
||||
(subtotal-row (filter-categories pnl-data [:payroll ]) "Payroll")
|
||||
(subtotal-row (filter-categories pnl-data [:payroll ]) "Payroll")
|
||||
|
||||
(subtotal-row (-> pnl-data
|
||||
(filter-categories [:sales :payroll :cogs])
|
||||
(negate #{:payroll :cogs}))
|
||||
"Gross Profits")
|
||||
(subtotal-row (-> pnl-data
|
||||
(filter-categories [:sales :payroll :cogs])
|
||||
(negate #{:payroll :cogs}))
|
||||
"Gross Profits")
|
||||
|
||||
(subtotal-row (filter-categories pnl-data [:controllable :fixed-overhead :ownership-controllable])
|
||||
"Overhead")
|
||||
(subtotal-row (filter-categories pnl-data [:controllable :fixed-overhead :ownership-controllable])
|
||||
"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")]
|
||||
(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)
|
||||
deltas (calc-deltas table)]
|
||||
{:header (headers pnl-data title)
|
||||
@@ -317,9 +309,6 @@
|
||||
(conj (subtotal-row (-> pnl-data
|
||||
(filter-categories [:controllable :fixed-overhead :ownership-controllable]))
|
||||
(str (:prefix pnl-data) " Overhead")))
|
||||
(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}))
|
||||
@@ -357,7 +346,7 @@
|
||||
(:colspan cell) (assoc :colspan (:colspan cell)))
|
||||
|
||||
(cond (= :dollar (:format cell))
|
||||
(.format (DecimalFormat. "$###,###.00") (:value cell))
|
||||
(.format (DecimalFormat. "$###,##0.00") (:value cell))
|
||||
|
||||
(= :percent (:format cell))
|
||||
(.format (DecimalFormat. "0%") (:value cell))
|
||||
@@ -365,14 +354,34 @@
|
||||
:else
|
||||
(str (:value cell)))])
|
||||
|
||||
(defn cell-count [table]
|
||||
(let [counts (map count (:rows table))]
|
||||
(if (seq counts)
|
||||
(apply max counts)
|
||||
0)))
|
||||
|
||||
(defn table->pdf [table]
|
||||
(let [cell-count (apply max (map count (:rows table)))]
|
||||
(-> [:pdf-table {:header (mapv
|
||||
(fn [header]
|
||||
(map cell->pdf header))
|
||||
(:header table))
|
||||
:cell-border false}
|
||||
(into [70] (take (dec cell-count) (repeat 20)))]
|
||||
(let [cell-count (cell-count table)]
|
||||
(-> [:pdf-table {:header (mapv
|
||||
(fn [header]
|
||||
(map cell->pdf header))
|
||||
(:header table))
|
||||
:cell-border false
|
||||
:width-percent (cond (= 5 cell-count)
|
||||
50
|
||||
|
||||
(= 6 cell-count)
|
||||
60
|
||||
|
||||
(= 7 cell-count)
|
||||
70
|
||||
|
||||
(= 8 cell-count)
|
||||
80
|
||||
|
||||
:else
|
||||
100)}
|
||||
(into [20] (take (dec cell-count) (repeat 10)))]
|
||||
|
||||
(into
|
||||
(for [row (:rows table)]
|
||||
@@ -381,6 +390,63 @@
|
||||
(cell->pdf cell)
|
||||
))))
|
||||
(conj (take cell-count (repeat (cell->pdf {:value " "})))))))
|
||||
|
||||
(defn split-table [table n]
|
||||
(let [cell-count (cell-count table)]
|
||||
(if (<= cell-count n)
|
||||
[table]
|
||||
(let [new-table (-> table
|
||||
(update :rows (fn [rows]
|
||||
(map
|
||||
(fn [[header & rest]]
|
||||
(into [header]
|
||||
(take (dec n) rest)))
|
||||
rows)))
|
||||
(update :header (fn [headers]
|
||||
(map
|
||||
(fn [[title & header]]
|
||||
(first
|
||||
(reduce
|
||||
(fn [[so-far a] next]
|
||||
(let [new-a (+ a (or (:colspan next)
|
||||
1))]
|
||||
(if (<= new-a n)
|
||||
[(conj so-far next) new-a]
|
||||
[so-far new-a])))
|
||||
|
||||
[[title] 1]
|
||||
header)))
|
||||
headers))))
|
||||
remaining (-> table
|
||||
(update :rows (fn [rows]
|
||||
(map
|
||||
(fn [[header & rest]]
|
||||
(into [header]
|
||||
(drop (dec n) rest)))
|
||||
rows)))
|
||||
(update :header (fn [headers]
|
||||
(map
|
||||
(fn [[title & header]]
|
||||
(first
|
||||
(reduce
|
||||
(fn [[so-far a] next]
|
||||
(let [new-a (+ a (or (:colspan next)
|
||||
1))]
|
||||
(if (> new-a n)
|
||||
[(conj so-far next) new-a]
|
||||
[so-far new-a])))
|
||||
|
||||
[[title] 1]
|
||||
header)))
|
||||
headers))))]
|
||||
(into [new-table]
|
||||
(split-table remaining n))))))
|
||||
|
||||
(defn break-apart-tables [tables]
|
||||
(for [table tables
|
||||
table (split-table table 10)]
|
||||
table))
|
||||
|
||||
(defn make-pnl [args data]
|
||||
|
||||
(let [data (<-graphql data)
|
||||
@@ -399,13 +465,14 @@
|
||||
report (summarize-pnl (PNLData. (assoc args :deltas true) data (by :db/id clients)))
|
||||
output-stream (ByteArrayOutputStream.)]
|
||||
(pdf/pdf
|
||||
[{:left-margin 15 :right-margin 15 :top-margin 15 :bottom-margin 15 :size :letter
|
||||
:font {:size 8}}
|
||||
[:heading (str "Profit and Loss - " (str/join ", " (map :client/name clients)))]
|
||||
(into [:paragraph]
|
||||
(map table->pdf (:summaries report)))
|
||||
(into [:paragraph]
|
||||
(map table->pdf (:details report)))]
|
||||
(into
|
||||
[{:left-margin 10 :right-margin 10 :top-margin 15 :bottom-margin 15 :size :letter
|
||||
:orientation :landscape
|
||||
:font {:size 8}}
|
||||
[:heading (str "Profit and Loss - " (str/join ", " (map :client/name clients)))]]
|
||||
(for [table (break-apart-tables (concat (:summaries report)
|
||||
(:details report)))]
|
||||
(table->pdf table)))
|
||||
output-stream)
|
||||
(.toByteArray output-stream)))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user