diff --git a/src/clj/auto_ap/pdf/ledger.clj b/src/clj/auto_ap/pdf/ledger.clj index 059238b1..c67215d2 100644 --- a/src/clj/auto_ap/pdf/ledger.clj +++ b/src/clj/auto_ap/pdf/ledger.clj @@ -41,7 +41,8 @@ (= :dollar (:format cell)) (assoc :align :right) (= :percent (:format cell)) (assoc :align :right) (: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 ])) @@ -195,7 +196,7 @@ report (l-reports/summarize-pnl pnl-data) output-stream (ByteArrayOutputStream.)] (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 (and (>= (count (-> pnl-data :args :periods)) 8 ) (-> pnl-data :args :include-deltas)) diff --git a/src/cljc/auto_ap/ledger/reports.cljc b/src/cljc/auto_ap/ledger/reports.cljc index 8099b114..47e11b0c 100644 --- a/src/cljc/auto_ap/ledger/reports.cljc +++ b/src/cljc/auto_ap/ledger/reports.cljc @@ -177,6 +177,11 @@ (update :filters (fn [f] (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] @@ -208,6 +213,7 @@ :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 p) cell-args)) pnl-datas))) @@ -221,10 +227,18 @@ (map (fn [v s] {:border (:border v) - :format :percent + :bg-color (:bg-color v) + :format (if (string? (:value v)) + :text + :percent) :color [128 128 128] - :value (if (dollars-0? s) + :value (cond + (string? (:value v)) + "" + + (dollars-0? s) 0.0 + :else (/ (:value v) s))}) values sales)))))) @@ -234,10 +248,16 @@ (->> values (partition 2 1) (map (fn [[a b]] - {:border (:border b) - :format :dollar - :value (- (:value b) - (:value a))}))))))) + (if (or (string? (:value b)) + (string? (:value a))) + {:value "" + :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 ([[pnl-data] table percent-of-sales deltas] @@ -259,46 +279,53 @@ deltas))) (defn headers [[pnl-data :as pnl-datas] header-title] - (let [ - big-header (into [{:value 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 (cond - (-> pnl-data :args :include-deltas) - 3 + (map-indexed (fn [i p] + (cond-> {:value + (str (date->str (:start p)) + " - " + (date->str (:end p))) + :colspan (cond + (-> pnl-data :args :include-deltas) + 3 - (-> pnl-data :args :column-per-location) - (* 2 (/ (count pnl-datas) - (count (-> pnl-data :args :periods)))) + (-> pnl-data :args :column-per-location) + (* 2 (/ (count pnl-datas) + (count (-> pnl-data :args :periods)))) - :else - 2) - :align :center - :bold true}) + :else + 2) + :align :center + :bold true} + (odd? i) (assoc :bg-color [240 240 240]))) (:periods (:args pnl-data)))) sub-header (into [{:value ""}] (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}))) + (cond-> [(merge {:value (or ( +-> p :filters :location) "Total") + :align :right} + (:cell-args p)) + (merge {:value "%" + :align :right} + (:cell-args p))] + (-> pnl-data :args :include-deltas) (conj (merge {:value "+/-" + :align :right} + (:cell-args p))))) pnl-datas) (mapcat - (fn [_] - (cond-> [{:value "Amt" - :align :right} - {:value "%" - :align :right}] - (-> pnl-data :args :include-deltas) (conj {:value "+/-" - :align :right}))) + (fn [p] + (cond-> [(merge {:value "Amt" + :align :right} + (:cell-args p)) + (merge {:value "%" + :align :right} + (:cell-args p))] + (-> pnl-data :args :include-deltas) (conj (merge {:value "+/-" + :align :right} + (:cell-args p))))) pnl-datas)))] [big-header sub-header])) @@ -343,25 +370,36 @@ pnl-datas) account-codes (used-accounts pnl-datas)] :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 [{:value name}] (map (fn [p] (let [pnl-data (-> p (filter-numeric-code numeric-code numeric-code))] - {:format :dollar - :filters (:filters pnl-data) - :value (aggregate-accounts pnl-data)})) + (merge + {:format :dollar + :filters (:filters pnl-data) + :value (aggregate-accounts pnl-data)} + (:cell-args p)))) pnl-datas)))) (conj (subtotal-by-column-row pnl-datas "" {:border [:top]})))] row)] - (-> [[{:value title - :bold true}]] + (-> [(into [{:value title + :bold true}] + (map + (fn [p] + (assoc (:cell-args p) :value "" :format "")) + pnl-datas))] (into individual-accounts) (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 (-> [] (into (detail-rows pnl-datas :sales @@ -399,11 +437,14 @@ (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"))) + (str prefix " Net Income")))) + table (if (seq client-datas) + (conj table (subtotal-by-column-row (map #(-> % + (filter-categories [:sales :cogs :payroll :controllable :fixed-overhead :ownership-controllable]) + (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) deltas (into [] (calc-deltas table))] {:header (headers pnl-datas title) @@ -427,45 +468,52 @@ {: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"))) + [(location-summary-table (mapcat identity (for [[period i] (map vector (-> pnl-data :args :periods ) (range))] + (concat + (for [location (set (map second (client-locations pnl-data)))] + (-> pnl-data + (filter-location location) + (filter-period period) + (zebra i))) + [(zebra (filter-period pnl-data period) i)]))) + "All location Summary")] (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 (filter-client client-id) (filter-location location) - (filter-period period))) + (filter-period period) + (zebra i))) (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) - (filter-period period))) - (-> pnl-data - (filter-client client-id)) - (str (-> pnl-data :clients-by-id (get client-id)) " Detail") - "")) + [(location-detail-table (mapcat identity (for [[period i] (map vector (-> pnl-data :args :periods ) (range))] + (concat + (for [location (set (map second (client-locations pnl-data)))] + (-> pnl-data + (filter-location location) + (filter-period period) + (zebra i))) + [(-> pnl-data + (filter-period period) + (zebra i))]))) + nil + "All location Detail" + "")] (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 (filter-client client-id) (filter-location location) - (filter-period period))) - (-> pnl-data - (filter-client client-id)) + (filter-period period) + (zebra i))) + (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") - location)))) - }) + location))))}) (defn balance-sheet-headers [pnl-data] @@ -483,8 +531,7 @@ (:value b))})])))) (defn summarize-balance-sheet [pnl-data] - (let [ - pnl-datas (map (fn [p] + (let [pnl-datas (map (fn [p] (filter-period pnl-data p)) (:periods (:args pnl-data))) table (-> [] @@ -502,7 +549,6 @@ (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) diff --git a/src/cljs/auto_ap/views/pages/ledger/report_table.cljs b/src/cljs/auto_ap/views/pages/ledger/report_table.cljs index d90f08b7..f33bbacd 100644 --- a/src/cljs/auto_ap/views/pages/ledger/report_table.cljs +++ b/src/cljs/auto_ap/views/pages/ledger/report_table.cljs @@ -38,6 +38,10 @@ (:color c) (assoc-in [:style :color] (str "rgb(" (str/join "," (:color c)) + ")")) + (:bg-color c) (assoc-in [:style :background-color] (str "rgb(" + (str/join "," + (:bg-color c)) ")"))) cell-contents])) @@ -68,7 +72,14 @@ (for [[i row] (map vector (range) (:rows table))] ^{:key i} [: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} [cell {:click-event click-event} c])])) (conj ^{:key "last"}