diff --git a/src/clj/auto_ap/graphql/ledger.clj b/src/clj/auto_ap/graphql/ledger.clj index 0ace63fe..ef12862c 100644 --- a/src/clj/auto_ap/graphql/ledger.clj +++ b/src/clj/auto_ap/graphql/ledger.clj @@ -598,13 +598,15 @@ :profit_and_loss {:type :profit_and_loss_report :args {:client_id {:type :id} :client_ids {:type '(list :id)} - :periods {:type '(list :date_range)}} + :periods {:type '(list :date_range)} + :include_deltas {:type 'Boolean}} :resolve :get-profit-and-loss} :profit_and_loss_pdf {:type :profit_and_loss_pdf :args {:client_id {:type :id} :client_ids {:type '(list :id)} - :periods {:type '(list :date_range)}} + :periods {:type '(list :date_range)} + :include_deltas {:type 'Boolean}} :resolve :profit-and-loss-pdf} :ledger_page {:type :ledger_page diff --git a/src/clj/auto_ap/pdf/ledger.clj b/src/clj/auto_ap/pdf/ledger.clj index 69f8094d..a269ec99 100644 --- a/src/clj/auto_ap/pdf/ledger.clj +++ b/src/clj/auto_ap/pdf/ledger.clj @@ -15,10 +15,6 @@ (java.text DecimalFormat) (java.util UUID))) -(defn distribute [nums] - (let [sum (reduce + 0 nums)] - (map #(* 100 (/ % sum)) nums))) - (defn date->str [d] (atime/unparse-local d atime/normal-date)) @@ -82,7 +78,7 @@ (->> data (filter (comp in-range? :numeric-code)) (group-by (juxt :client-id :location)) - (filter (fn [[k as]] + (filter (fn [[_ as]] (not (dollars-0? (reduce + 0 (map :amount as)))))) (mapcat second) (map (fn [a] @@ -105,7 +101,7 @@ (defn best-category [a] (->> ranges - (filter (fn [[category [start end]]] + (filter (fn [[_ [start end]]] (<= start (:numeric-code a) end))) first first)) @@ -192,7 +188,9 @@ (into [title] (mapcat (fn [v p d] - [v p d]) + (if (:include-deltas (:args pnl-data)) + [v p d] + [v p])) row percent-of-sales deltas)) @@ -204,27 +202,29 @@ (defn headers [pnl-data 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 3 - :align :center - :bold true}) - (:periods (:args pnl-data)))) + (map (fn [p] + {:value + (str (date->str (:start p)) + " - " + (date->str (:end p))) + :colspan (if (-> pnl-data :args :include-deltas) + 3 + 2) + :align :center + :bold true}) + (:periods (:args pnl-data)))) sub-header (into [{:value ""}] (mapcat (fn [_] - [{:value "Amount" - :align :right - :bold true} - {:value "% Sales" - :align :right - :bold true} - {:value "Change" - :align :right - :bold true}]) + (cond-> [{:value "Amount" + :align :right + :bold true} + {:value "% Sales" + :align :right + :bold true}] + (-> pnl-data :args :include-deltas) (conj {:value "Change" + :align :right + :bold true}))) (:periods (:args pnl-data))))] [big-header sub-header])) @@ -442,9 +442,11 @@ (into [new-table] (split-table remaining n)))))) -(defn break-apart-tables [tables] +(defn break-apart-tables [pnl-data tables] (for [table tables - table (split-table table 10)] + table (split-table table (if (:include-deltas (:args pnl-data)) + 10 + 9))] table)) (defn make-pnl [args data] @@ -462,7 +464,8 @@ (:accounts p2)) ) (:periods args))) - report (summarize-pnl (PNLData. (assoc args :deltas true) data (by :db/id clients))) + pnl-data (PNLData. args data (by :db/id clients)) + report (summarize-pnl pnl-data) output-stream (ByteArrayOutputStream.)] (pdf/pdf (into @@ -470,7 +473,8 @@ :orientation :landscape :font {:size 8}} [:heading (str "Profit and Loss - " (str/join ", " (map :client/name clients)))]] - (for [table (break-apart-tables (concat (:summaries report) + (for [table (break-apart-tables pnl-data + (concat (:summaries report) (:details report)))] (table->pdf table))) output-stream) 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 4de9f5d0..54ea3fa0 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 @@ -169,7 +169,6 @@ (fn [db [_ data]] (-> db (assoc :report (:profit-and-loss data))))) - (re-frame/reg-sub ::period-inputs (fn [db] @@ -211,13 +210,33 @@ :clients (mapv #(select-keys % [:name :id]) (:clients (:data db))) } :db (dissoc db :report)}))) +(defn email-body [report-url] + (js/encodeURIComponent + (str + "Your profit and loss report is now ready. +Please download it by clicking this link: " report-url))) + (re-frame/reg-event-fx ::received-pdf - (fn [_ [_ result]] - (println result) - {:dispatch [::modal/modal-requested {:title "Your report is ready" - :body [:div - [:div "Click " [:a {:href (-> result :profit-and-loss-pdf :report-url) :target "_new"} "here"] " to view it."]]}]})) + [(re-frame/inject-cofx ::inject/sub [::subs/clients-by-id])] + (fn [{:keys [db ::subs/clients-by-id]} [_ result]] + (let [selected-clients (-> db ::forms/forms ::form :data :clients) + single-client? (= (count selected-clients) + 1) + client-email (when single-client? + (-> clients-by-id + (get (:id (first selected-clients))) + :email))] + + + {:dispatch [::modal/modal-requested {:title "Your report is ready" + :body [:div + [:div "Click " + [:a {:href (-> result :profit-and-loss-pdf :report-url) :target "_new"} "here"] " to view it."] + (when single-client? + [:div "Once you've confirmed you're happy with it, click " + [:a {:href (str "mailto:" (or client-email "client@xyz.com") "?body=" (email-body (-> result :profit-and-loss-pdf :report-url)))} + "here"] " to open your email client and to send it to " (str (or client-email "client@xyz.com")) "."])]}]}))) (re-frame/reg-event-fx ::export-pdf [with-user (forms/in-form ::form)] @@ -226,6 +245,7 @@ :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)) :periods (mapv (fn [[start end] ] {:start (date->str start standard) :end (date->str end standard)} ) (:periods (:data db)))} [:report_url]]]} @@ -239,7 +259,7 @@ (re-frame/reg-event-db - ::change + ::change-internal (forms/change-handler ::form (fn [data field value] (cond @@ -260,6 +280,13 @@ :else nil) ))) +(re-frame/reg-event-fx + ::change + [with-user (forms/in-form ::form)] + (fn [{:keys [db]} [_ & event]] + {:db (dissoc db :report) + :dispatch (into [::change-internal] event)})) + (defn data-params->query-params [params client-id] (when params @@ -956,8 +983,7 @@ (re-frame/reg-event-fx ::unmounted-pnl (fn [{:keys [db]} _] - {:dispatch [::data-page/dispose ::ledger] - ::track/dispose {:id ::ledger-params}})) + {::track/dispose {:id ::ledger-params}})) (re-frame/reg-event-fx ::mounted-pnl @@ -974,9 +1000,9 @@ :clients (or (:clients qp) [(some-> @(re-frame/subscribe [::subs/client]) (select-keys [:name :id]))]) :include-deltas true}) - ::track/register {:id ::ledger-params + ::track/register {:id ::ledger-params :subscription [::data-page/params ::ledger] - :event-fn (fn [params] [::ledger-params-change params])}}))) + :event-fn (fn [params] [::ledger-params-change params])}}))) (defn ledger-list [_ ] [:div [:a.delete.is-pulled-right {:on-click (dispatch-event [::ledger-list-closing])}]