Adds a more actionable view
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,15 +1,17 @@
|
|||||||
(ns auto-ap.ssr.pos.sales-summaries
|
(ns auto-ap.ssr.pos.sales-summaries
|
||||||
(:require
|
(:require
|
||||||
[auto-ap.datomic
|
[auto-ap.datomic
|
||||||
:refer [apply-pagination apply-sort-3 conn merge-query pull-many
|
:refer [apply-pagination apply-sort-3 conn merge-query pull-many
|
||||||
query2]]
|
query2]]
|
||||||
[auto-ap.datomic.accounts :as d-accounts]
|
[auto-ap.datomic.accounts :as d-accounts]
|
||||||
[auto-ap.graphql.utils :refer [extract-client-ids]]
|
[auto-ap.graphql.utils :refer [extract-client-ids]]
|
||||||
[auto-ap.query-params :refer [wrap-copy-qp-pqp]]
|
[auto-ap.query-params :refer [wrap-copy-qp-pqp]]
|
||||||
|
[auto-ap.client-routes :as client-routes]
|
||||||
[auto-ap.routes.pos.sales-summaries :as route]
|
[auto-ap.routes.pos.sales-summaries :as route]
|
||||||
[auto-ap.ssr-routes :as ssr-routes]
|
[auto-ap.ssr-routes :as ssr-routes]
|
||||||
[auto-ap.ssr.common-handlers :refer [add-new-entity-handler]]
|
[auto-ap.ssr.common-handlers :refer [add-new-entity-handler]]
|
||||||
[auto-ap.ssr.components :as com]
|
[auto-ap.ssr.components :as com]
|
||||||
|
[auto-ap.ssr.components.link-dropdown :refer [link-dropdown]]
|
||||||
[auto-ap.ssr.components.multi-modal :as mm]
|
[auto-ap.ssr.components.multi-modal :as mm]
|
||||||
[auto-ap.ssr.form-cursor :as fc]
|
[auto-ap.ssr.form-cursor :as fc]
|
||||||
[auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]]
|
[auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]]
|
||||||
@@ -18,35 +20,35 @@
|
|||||||
:refer [date-range-field*]]
|
:refer [date-range-field*]]
|
||||||
[auto-ap.ssr.svg :as svg]
|
[auto-ap.ssr.svg :as svg]
|
||||||
[auto-ap.ssr.utils
|
[auto-ap.ssr.utils
|
||||||
:refer [apply-middleware-to-all-handlers clj-date-schema
|
:refer [apply-middleware-to-all-handlers clj-date-schema
|
||||||
default-grid-fields-schema entity-id html-response money
|
default-grid-fields-schema entity-id html-response money
|
||||||
strip temp-id wrap-merge-prior-hx wrap-schema-enforce]]
|
strip temp-id wrap-merge-prior-hx wrap-schema-enforce]]
|
||||||
[auto-ap.time :as atime]
|
[auto-ap.time :as atime]
|
||||||
[bidi.bidi :as bidi]
|
[bidi.bidi :as bidi]
|
||||||
[clj-time.coerce :as c]
|
[clj-time.coerce :as c]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[datomic.api :as dc]
|
[datomic.api :as dc]
|
||||||
[hiccup.util :as hu]
|
[hiccup.util :as hu]
|
||||||
[iol-ion.query :refer [dollars=]]
|
[iol-ion.query :refer [dollars= dollars-0?]]
|
||||||
[malli.core :as mc]
|
[malli.core :as mc]
|
||||||
[malli.util :as mut]))
|
[malli.util :as mut]))
|
||||||
|
|
||||||
(def query-schema (mc/schema
|
(def query-schema (mc/schema
|
||||||
[:maybe
|
[:maybe
|
||||||
(into [:map {:date-range [:date-range :start-date :end-date]}
|
(into [:map {:date-range [:date-range :start-date :end-date]}
|
||||||
|
|
||||||
[:start-date {:optional true}
|
[:start-date {:optional true}
|
||||||
[:maybe clj-date-schema]]
|
[:maybe clj-date-schema]]
|
||||||
[:end-date {:optional true}
|
[:end-date {:optional true}
|
||||||
[:maybe clj-date-schema]] ]
|
[:maybe clj-date-schema]]]
|
||||||
default-grid-fields-schema)]))
|
default-grid-fields-schema)]))
|
||||||
|
|
||||||
(defn filters [request]
|
(defn filters [request]
|
||||||
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
|
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
|
||||||
"hx-get" (bidi/path-for ssr-routes/only-routes
|
"hx-get" (bidi/path-for ssr-routes/only-routes
|
||||||
::route/table)
|
::route/table)
|
||||||
"hx-target" "#entity-table"
|
"hx-target" "#entity-table"
|
||||||
"hx-indicator" "#entity-table"}
|
"hx-indicator" "#entity-table"}
|
||||||
|
|
||||||
[:fieldset.space-y-6
|
[:fieldset.space-y-6
|
||||||
(date-range-field* request)]])
|
(date-range-field* request)]])
|
||||||
@@ -55,15 +57,14 @@
|
|||||||
*
|
*
|
||||||
[:sales-summary/date :xform clj-time.coerce/from-date]
|
[:sales-summary/date :xform clj-time.coerce/from-date]
|
||||||
{:sales-summary/client [:client/code :client/name :db/id]}
|
{:sales-summary/client [:client/code :client/name :db/id]}
|
||||||
{:sales-summary/items [{[:ledger-mapped/ledger-side :xform iol-ion.query/ident] [:db/ident]
|
{:sales-summary/items [{[:ledger-mapped/ledger-side :xform iol-ion.query/ident] [:db/ident]}
|
||||||
}
|
:ledger-mapped/account
|
||||||
:ledger-mapped/account
|
:ledger-mapped/amount
|
||||||
:ledger-mapped/amount
|
:sales-summary-item/category
|
||||||
:sales-summary-item/category
|
:sales-summary-item/sort-order
|
||||||
:sales-summary-item/sort-order
|
:db/id
|
||||||
:db/id
|
:sales-summary-item/manual?]}
|
||||||
:sales-summary-item/manual?]
|
{:journal-entry/original-entity [:db/id]}])
|
||||||
} ])
|
|
||||||
|
|
||||||
(defn fetch-ids [db request]
|
(defn fetch-ids [db request]
|
||||||
(let [query-params (:query-params request)
|
(let [query-params (:query-params request)
|
||||||
@@ -72,27 +73,26 @@
|
|||||||
(:client-id query-params)
|
(:client-id query-params)
|
||||||
(when (:client-code query-params)
|
(when (:client-code query-params)
|
||||||
[:client/code (:client-code query-params)]))
|
[:client/code (:client-code query-params)]))
|
||||||
query (cond-> {:query {:find []
|
query (cond-> {:query {:find []
|
||||||
:in '[$ [?client ...]]
|
:in '[$ [?client ...]]
|
||||||
:where '[[?e :sales-summary/client ?client]]}
|
:where '[[?e :sales-summary/client ?client]]}
|
||||||
:args [db valid-clients]}
|
:args [db valid-clients]}
|
||||||
(or (:start-date query-params)
|
(or (:start-date query-params)
|
||||||
(:end-date query-params))
|
(:end-date query-params))
|
||||||
(merge-query {:query '{:where [[?e :sales-summary/date ?d]]}})
|
(merge-query {:query '{:where [[?e :sales-summary/date ?d]]}})
|
||||||
|
|
||||||
(:start-date query-params)
|
(:start-date query-params)
|
||||||
(merge-query {:query '{:in [?start-date]
|
(merge-query {:query '{:in [?start-date]
|
||||||
:where [[(>= ?d ?start-date)]]}
|
:where [[(>= ?d ?start-date)]]}
|
||||||
:args [(-> query-params :start-date c/to-date)]})
|
:args [(-> query-params :start-date c/to-date)]})
|
||||||
|
|
||||||
(:end-date query-params)
|
(:end-date query-params)
|
||||||
(merge-query {:query '{:in [?end-date]
|
(merge-query {:query '{:in [?end-date]
|
||||||
:where [[(< ?d ?end-date)]]}
|
:where [[(< ?d ?end-date)]]}
|
||||||
:args [(-> query-params :end-date c/to-date)]})
|
:args [(-> query-params :end-date c/to-date)]})
|
||||||
|
|
||||||
|
|
||||||
true
|
true
|
||||||
(merge-query {:query {:find ['?sort-default '?e]
|
(merge-query {:query {:find ['?sort-default '?e]
|
||||||
:where ['[?e :sales-summary/date ?sort-default]]}}))]
|
:where ['[?e :sales-summary/date ?sort-default]]}}))]
|
||||||
(cond->> (query2 query)
|
(cond->> (query2 query)
|
||||||
true (apply-sort-3 query-params)
|
true (apply-sort-3 query-params)
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
refunds))
|
refunds))
|
||||||
|
|
||||||
(defn fetch-page [request]
|
(defn fetch-page [request]
|
||||||
(let [db (dc/db conn)
|
(let [db (dc/db conn)
|
||||||
{ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]
|
{ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]
|
||||||
|
|
||||||
[(->> (hydrate-results ids-to-retrieve db request))
|
[(->> (hydrate-results ids-to-retrieve db request))
|
||||||
@@ -116,27 +116,29 @@
|
|||||||
(defn sort-items [ss]
|
(defn sort-items [ss]
|
||||||
(sort-by (juxt :ledger-mapped/ledger-side :sales-summary-item/sort-order :sales-summary-item/category) ss))
|
(sort-by (juxt :ledger-mapped/ledger-side :sales-summary-item/sort-order :sales-summary-item/category) ss))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn total-debits [items]
|
(defn total-debits [items]
|
||||||
(->> items
|
(->> items
|
||||||
(filter #(= :ledger-side/debit (:ledger-mapped/ledger-side %)))
|
(filter #(= :ledger-side/debit (:ledger-mapped/ledger-side %)))
|
||||||
(map #(:ledger-mapped/amount % 0.0))
|
(map #(:ledger-mapped/amount % 0.0))
|
||||||
(reduce + 0.0)))
|
(reduce + 0.0)))
|
||||||
|
|
||||||
(defn total-credits [items]
|
(defn total-credits [items]
|
||||||
(->> items
|
(->> items
|
||||||
(filter #(= :ledger-side/credit (:ledger-mapped/ledger-side %)))
|
(filter #(= :ledger-side/credit (:ledger-mapped/ledger-side %)))
|
||||||
(map #(:ledger-mapped/amount % 0.0))
|
(map #(:ledger-mapped/amount % 0.0))
|
||||||
(reduce + 0.0)))
|
(reduce + 0.0)))
|
||||||
|
|
||||||
|
(defn truncate [s max-len]
|
||||||
|
(if (> (count s) max-len)
|
||||||
|
(str (subs s 0 (- max-len 3)) "...")
|
||||||
|
s))
|
||||||
|
|
||||||
(def grid-page
|
(def grid-page
|
||||||
(helper/build {:id "entity-table"
|
(helper/build {:id "entity-table"
|
||||||
:id-fn :db/id
|
:id-fn :db/id
|
||||||
:nav com/main-aside-nav
|
:nav com/main-aside-nav
|
||||||
:fetch-page fetch-page
|
:fetch-page fetch-page
|
||||||
:page-specific-nav filters
|
:page-specific-nav filters
|
||||||
:query-schema query-schema
|
:query-schema query-schema
|
||||||
:row-buttons (fn [_ entity]
|
:row-buttons (fn [_ entity]
|
||||||
[(com/icon-button {:hx-get (bidi/path-for ssr-routes/only-routes
|
[(com/icon-button {:hx-get (bidi/path-for ssr-routes/only-routes
|
||||||
@@ -144,84 +146,145 @@
|
|||||||
:db/id (:db/id entity))}
|
:db/id (:db/id entity))}
|
||||||
svg/pencil)])
|
svg/pencil)])
|
||||||
:oob-render
|
:oob-render
|
||||||
(fn [request]
|
(fn [request]
|
||||||
[(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)])
|
[(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)])
|
||||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||||
:company)}
|
:company)}
|
||||||
"POS"]
|
"POS"]
|
||||||
|
|
||||||
[:a {:href (bidi/path-for ssr-routes/only-routes
|
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||||
::route/page)}
|
::route/page)}
|
||||||
"Sales Summaries"]]
|
"Sales Summaries"]]
|
||||||
:title "Sales Summaries"
|
:title "Sales Summaries"
|
||||||
:entity-name "Daily Summary"
|
:entity-name "Daily Summary"
|
||||||
:route ::route/table
|
:route ::route/table
|
||||||
:headers [{:key "client"
|
:headers [{:key "client"
|
||||||
:name "Client"
|
:name "Client"
|
||||||
:sort-key "client"
|
:sort-key "client"
|
||||||
:hide? (fn [args]
|
:hide? (fn [args]
|
||||||
(= (count (:clients args)) 1))
|
(= (count (:clients args)) 1))
|
||||||
:render #(-> % :sales-summary/client :client/code)}
|
:render #(-> % :sales-summary/client :client/code)}
|
||||||
|
|
||||||
|
{:key "date"
|
||||||
|
:name "Date"
|
||||||
|
:sort-key "date"
|
||||||
|
:render #(some-> % :sales-summary/date (atime/unparse-local atime/normal-date))}
|
||||||
|
|
||||||
{:key "date"
|
{:key "debits"
|
||||||
:name "Date"
|
:name "Debits"
|
||||||
:sort-key "date"
|
:sort-key "debits"
|
||||||
:render #(some-> % :sales-summary/date (atime/unparse-local atime/normal-date))}
|
:class "w-64 align-top"
|
||||||
|
:render (fn [ss]
|
||||||
|
(let [items (:sales-summary/items ss)
|
||||||
|
debit-items (filter #(= :ledger-side/debit (:ledger-mapped/ledger-side %)) (sort-items items))
|
||||||
|
credit-count (count (filter #(= :ledger-side/credit (:ledger-mapped/ledger-side %)) items))
|
||||||
|
total-debits (total-debits items)
|
||||||
|
total-credits (total-credits items)
|
||||||
|
delta (- total-debits total-credits)]
|
||||||
|
[:div.flex.flex-col.h-full
|
||||||
|
[:div.font-semibold.text-sm "Debits"]
|
||||||
|
[:ul.space-y-0.5.flex-grow
|
||||||
|
(for [si debit-items]
|
||||||
|
[:li.text-sm.text-gray-700
|
||||||
|
[:span.text-gray-500 (truncate (:sales-summary-item/category si) 30)]
|
||||||
|
[:span.ml-2 "→"]
|
||||||
|
[:span.ml-2.font-mono (format "$%,.2f" (:ledger-mapped/amount si))]
|
||||||
|
(when-not (:ledger-mapped/account si)
|
||||||
|
[:span.ml-2 (com/pill {:color :red} "?")])])
|
||||||
|
(for [_ (range (max 0 (- credit-count (count debit-items))))]
|
||||||
|
[:li "\u00a0"])]
|
||||||
|
[:div.border-t.mt-1.pt-1.flex.justify-between.items-center.w-full
|
||||||
|
[:span.font-semibold "Total"]
|
||||||
|
[:span.font-mono.font-semibold (format "$%,.2f" total-debits)]]
|
||||||
|
(when-not (dollars-0? delta)
|
||||||
|
[:div.text-xs.text-red-600.flex.justify-between.w-full.mt-1
|
||||||
|
[:span "Delta:"]
|
||||||
|
[:span.font-mono (format "$%,.2f" delta)]])]))}
|
||||||
|
|
||||||
|
{:key "credits"
|
||||||
|
:name "Credits"
|
||||||
|
:sort-key "credits"
|
||||||
|
:class "w-64 align-top"
|
||||||
|
:render (fn [ss]
|
||||||
|
(let [items (:sales-summary/items ss)
|
||||||
|
credit-items (filter #(= :ledger-side/credit (:ledger-mapped/ledger-side %)) (sort-items items))
|
||||||
|
debit-count (count (filter #(= :ledger-side/debit (:ledger-mapped/ledger-side %)) items))
|
||||||
|
total-debits (total-debits items)
|
||||||
|
total-credits (total-credits items)
|
||||||
|
delta (- total-credits total-debits)]
|
||||||
|
[:div.flex.flex-col.h-full
|
||||||
|
[:div.font-semibold.text-sm "Credits"]
|
||||||
|
[:ul.space-y-0.5.flex-grow
|
||||||
|
(for [si credit-items]
|
||||||
|
[:li.text-sm.text-gray-700
|
||||||
|
[:span.text-gray-500 (truncate (:sales-summary-item/category si) 30)]
|
||||||
|
[:span.ml-2 "→"]
|
||||||
|
[:span.ml-2.font-mono (format "$%,.2f" (:ledger-mapped/amount si))]
|
||||||
|
(when-not (:ledger-mapped/account si)
|
||||||
|
[:span.ml-2 (com/pill {:color :red} "?")])])
|
||||||
|
(for [_ (range (max 0 (- debit-count (count credit-items))))]
|
||||||
|
[:li "\u00a0"])]
|
||||||
|
[:div.border-t.mt-1.pt-1.flex.justify-between.items-center.w-full
|
||||||
|
[:span.font-semibold "Total"]
|
||||||
|
[:span.font-mono.font-semibold (format "$%,.2f" total-credits)]]
|
||||||
|
(when-not (dollars-0? delta)
|
||||||
|
[:div.text-xs.text-green-600.flex.justify-between.w-full.mt-1
|
||||||
|
[:span "Delta:"]
|
||||||
|
[:span.font-mono (format "$%,.2f" delta)]])]))}
|
||||||
|
|
||||||
{:key "debits"
|
{:key "balance"
|
||||||
:name "debits"
|
:name "Balance"
|
||||||
:sort-key "debits"
|
:sort-key "balance"
|
||||||
:render (fn [ss]
|
:class "w-24"
|
||||||
(let [total-debits (total-debits (:sales-summary/items ss))
|
:render (fn [ss]
|
||||||
total-credits (total-credits (:sales-summary/items ss))]
|
(let [items (:sales-summary/items ss)
|
||||||
[:ul
|
total-debits (total-debits items)
|
||||||
(for [si (sort-items (:sales-summary/items ss))
|
total-credits (total-credits items)
|
||||||
:when (= :ledger-side/debit (:ledger-mapped/ledger-side si))]
|
delta (- total-debits total-credits)
|
||||||
[:li (:sales-summary-item/category si) ": " (format "$%,.2f" (:ledger-mapped/amount si))
|
balanced? (dollars= total-debits total-credits)
|
||||||
(when-not (:ledger-mapped/account si)
|
missing-account? (some #(not (:ledger-mapped/account %)) items)]
|
||||||
[:span.pl-4 (com/pill {:color :red}
|
[:div.flex.flex-col.items-center.pt-2
|
||||||
"missing account")])]
|
(when missing-account?
|
||||||
)
|
[:span.text-red-600.font-bold.text-xs "Missing acct"])
|
||||||
[:li (com/pill {:color (if (dollars= total-debits total-credits)
|
(if balanced?
|
||||||
:primary
|
(when-not missing-account?
|
||||||
:red)} "Total: " (format "$%,.2f" total-debits))]]))}
|
[:span.text-green-600.font-bold "✓ Balanced"])
|
||||||
{:key "credits"
|
(list
|
||||||
:name "credits"
|
[:span.text-red-600.font-mono (format "$%,.2f" (Math/abs delta))]
|
||||||
:sort-key "credits"
|
[:span.text-xs.text-gray-500.mt-1
|
||||||
:render (fn [ss]
|
(if (> total-debits total-credits) "Debit over" "Credit over")]))]))}
|
||||||
(let [total-debits (total-debits (:sales-summary/items ss))
|
|
||||||
total-credits (total-credits (:sales-summary/items ss))]
|
{:key "links"
|
||||||
[:ul
|
:name "Links"
|
||||||
(for [si (sort-items (:sales-summary/items ss))
|
:show-starting "lg"
|
||||||
:when (= :ledger-side/credit (:ledger-mapped/ledger-side si))]
|
:class "w-8"
|
||||||
[:li (:sales-summary-item/category si) ": " (format "$%,.2f" (:ledger-mapped/amount si))
|
:render (fn [ss]
|
||||||
(when-not (:ledger-mapped/account si)
|
(let [ledger-entry (:journal-entry/original-entity ss)]
|
||||||
[:span.pl-4 (com/pill {:color :red}
|
(when (seq ledger-entry)
|
||||||
"missing account")])])
|
(link-dropdown
|
||||||
[:li (com/pill {:color (if (dollars= total-debits total-credits)
|
[{:link (hu/url (bidi/path-for client-routes/routes :ledger)
|
||||||
:primary
|
{:exact-match-id (:db/id (first ledger-entry))})
|
||||||
:red)} "Total: " (format "$%,.2f" total-credits))]]))}]}))
|
:color :yellow
|
||||||
|
:content "Ledger entry"}]))))}]}))
|
||||||
|
|
||||||
(def row* (partial helper/row* grid-page))
|
(def row* (partial helper/row* grid-page))
|
||||||
(def table* (partial helper/table* grid-page))
|
(def table* (partial helper/table* grid-page))
|
||||||
|
|
||||||
(def edit-schema
|
(def edit-schema
|
||||||
[:map
|
[:map
|
||||||
[:db/id entity-id]
|
[:db/id entity-id]
|
||||||
[:sales-summary/client [:map [:db/id entity-id]]]
|
[:sales-summary/client [:map [:db/id entity-id]]]
|
||||||
[:sales-summary/items
|
[:sales-summary/items
|
||||||
[:vector {:coerce? true}
|
[:vector {:coerce? true}
|
||||||
[:and
|
[:and
|
||||||
[:map
|
[:map
|
||||||
[:db/id [:or entity-id temp-id]]
|
[:db/id [:or entity-id temp-id]]
|
||||||
[:sales-summary-item/category [:string {:decode/string strip}]]
|
[:sales-summary-item/category [:string {:decode/string strip}]]
|
||||||
[:sales-summary-item/manual? {:default false :decode/arbitrary (fn [x] (cond
|
[:sales-summary-item/manual? {:default false :decode/arbitrary (fn [x] (cond
|
||||||
(boolean? x)
|
(boolean? x)
|
||||||
x
|
x
|
||||||
(nil? x)
|
(nil? x)
|
||||||
false
|
false
|
||||||
(str/blank? x)
|
(str/blank? x)
|
||||||
false
|
false
|
||||||
:else
|
:else
|
||||||
@@ -230,11 +293,10 @@
|
|||||||
[:credit {:optional true} [:maybe money]]
|
[:credit {:optional true} [:maybe money]]
|
||||||
[:debit {:optional true} [:maybe money]]]
|
[:debit {:optional true} [:maybe money]]]
|
||||||
[:fn {:error/message "Must choose one of credit/debit"
|
[:fn {:error/message "Must choose one of credit/debit"
|
||||||
:error/path [:credit]}
|
:error/path [:credit]}
|
||||||
(fn [x]
|
(fn [x]
|
||||||
(not (and (:credit x)
|
(not (and (:credit x)
|
||||||
(:debit x))))]]]] ])
|
(:debit x))))]]]]])
|
||||||
|
|
||||||
|
|
||||||
(defn summary-total-row* [request]
|
(defn summary-total-row* [request]
|
||||||
(let [total-credits (-> request
|
(let [total-credits (-> request
|
||||||
@@ -293,21 +355,21 @@
|
|||||||
(defn- account-typeahead*
|
(defn- account-typeahead*
|
||||||
[{:keys [name value client-id]}]
|
[{:keys [name value client-id]}]
|
||||||
[:div.flex.flex-col
|
[:div.flex.flex-col
|
||||||
(com/typeahead {:name name
|
(com/typeahead {:name name
|
||||||
:placeholder "Search..."
|
:placeholder "Search..."
|
||||||
:url (hu/url (bidi/path-for ssr-routes/only-routes :account-search)
|
:url (hu/url (bidi/path-for ssr-routes/only-routes :account-search)
|
||||||
{:client-id client-id
|
{:client-id client-id
|
||||||
:purpose "invoice"})
|
:purpose "invoice"})
|
||||||
:value value
|
:value value
|
||||||
:content-fn (fn [value]
|
:content-fn (fn [value]
|
||||||
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
|
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
|
||||||
client-id)))})])
|
client-id)))})])
|
||||||
|
|
||||||
(defn sales-summary-item-row* [{:keys [value client-id]}]
|
(defn sales-summary-item-row* [{:keys [value client-id]}]
|
||||||
(let [manual? (fc/field-value (:sales-summary-item/manual? value))]
|
(let [manual? (fc/field-value (:sales-summary-item/manual? value))]
|
||||||
(com/data-grid-row (cond-> {:x-ref "p"
|
(com/data-grid-row (cond-> {:x-ref "p"
|
||||||
:x-data (hx/json {})}
|
:x-data (hx/json {})}
|
||||||
(fc/field-value (:new? value)) (hx/htmx-transition-appear ))
|
(fc/field-value (:new? value)) (hx/htmx-transition-appear))
|
||||||
(fc/with-field :db/id
|
(fc/with-field :db/id
|
||||||
(com/hidden {:name (fc/field-name)
|
(com/hidden {:name (fc/field-name)
|
||||||
:value (fc/field-value)}))
|
:value (fc/field-value)}))
|
||||||
@@ -319,9 +381,9 @@
|
|||||||
(fc/with-field :sales-summary-item/category
|
(fc/with-field :sales-summary-item/category
|
||||||
(if manual?
|
(if manual?
|
||||||
(com/validated-field {:errors (fc/field-errors)}
|
(com/validated-field {:errors (fc/field-errors)}
|
||||||
(com/text-input {:placeholder "Category/Explanation"
|
(com/text-input {:placeholder "Category/Explanation"
|
||||||
:name (fc/field-name)
|
:name (fc/field-name)
|
||||||
:value (fc/field-value)}))
|
:value (fc/field-value)}))
|
||||||
|
|
||||||
(list
|
(list
|
||||||
(com/hidden {:name (fc/field-name)
|
(com/hidden {:name (fc/field-name)
|
||||||
@@ -330,9 +392,9 @@
|
|||||||
(com/data-grid-cell {}
|
(com/data-grid-cell {}
|
||||||
(fc/with-field :ledger-mapped/account
|
(fc/with-field :ledger-mapped/account
|
||||||
(com/validated-field {:errors (fc/field-errors)}
|
(com/validated-field {:errors (fc/field-errors)}
|
||||||
(account-typeahead* {:value (fc/field-value)
|
(account-typeahead* {:value (fc/field-value)
|
||||||
:client-id client-id
|
:client-id client-id
|
||||||
:name (fc/field-name)}))))
|
:name (fc/field-name)}))))
|
||||||
(com/data-grid-cell {:class "text-right"}
|
(com/data-grid-cell {:class "text-right"}
|
||||||
|
|
||||||
(if manual?
|
(if manual?
|
||||||
@@ -356,7 +418,7 @@
|
|||||||
:ledger-side/credit)
|
:ledger-side/credit)
|
||||||
(format "$%,.2f" (fc/field-value (:ledger-mapped/amount value))))))
|
(format "$%,.2f" (fc/field-value (:ledger-mapped/amount value))))))
|
||||||
(com/data-grid-cell {:class "align-top"}
|
(com/data-grid-cell {:class "align-top"}
|
||||||
(when manual?
|
(when manual?
|
||||||
(com/a-icon-button {"@click.prevent.stop" "$refs.p.remove()"} svg/x))))))
|
(com/a-icon-button {"@click.prevent.stop" "$refs.p.remove()"} svg/x))))))
|
||||||
|
|
||||||
(defrecord MainStep [linear-wizard]
|
(defrecord MainStep [linear-wizard]
|
||||||
@@ -370,45 +432,45 @@
|
|||||||
[])
|
[])
|
||||||
|
|
||||||
(step-schema [_]
|
(step-schema [_]
|
||||||
(mut/select-keys (mm/form-schema linear-wizard) #{:db/id :sales-summary/items}))
|
(mut/select-keys (mm/form-schema linear-wizard) #{:db/id :sales-summary/items}))
|
||||||
|
|
||||||
(render-step
|
(render-step
|
||||||
[this {:keys [multi-form-state] :as request}]
|
[this {:keys [multi-form-state] :as request}]
|
||||||
(mm/default-render-step
|
(mm/default-render-step
|
||||||
linear-wizard this
|
linear-wizard this
|
||||||
:head [:div.p-2 "New invoice"]
|
:head [:div.p-2 "New invoice"]
|
||||||
:body (mm/default-step-body
|
:body (mm/default-step-body
|
||||||
{}
|
{}
|
||||||
[:div
|
[:div
|
||||||
(fc/with-field :db/id
|
(fc/with-field :db/id
|
||||||
(com/hidden {:name (fc/field-name)
|
(com/hidden {:name (fc/field-name)
|
||||||
:value (fc/field-value)}))
|
:value (fc/field-value)}))
|
||||||
(com/data-grid {:headers
|
(com/data-grid {:headers
|
||||||
[(com/data-grid-header {} "Category")
|
[(com/data-grid-header {} "Category")
|
||||||
(com/data-grid-header {} "Account")
|
(com/data-grid-header {} "Account")
|
||||||
(com/data-grid-header {} "Debits")
|
(com/data-grid-header {} "Debits")
|
||||||
(com/data-grid-header {} "Credits")
|
(com/data-grid-header {} "Credits")
|
||||||
(com/data-grid-header {} "")]}
|
(com/data-grid-header {} "")]}
|
||||||
(fc/with-field :sales-summary/items
|
(fc/with-field :sales-summary/items
|
||||||
(list
|
(list
|
||||||
(fc/cursor-map #(sales-summary-item-row* {:value %
|
(fc/cursor-map #(sales-summary-item-row* {:value %
|
||||||
:client-id (:db/id (:sales-summary/client (:snapshot multi-form-state))) }))
|
:client-id (:db/id (:sales-summary/client (:snapshot multi-form-state)))}))
|
||||||
(com/data-grid-new-row {:colspan 5
|
(com/data-grid-new-row {:colspan 5
|
||||||
:hx-get (bidi/path-for ssr-routes/only-routes ::route/new-summary-item)
|
:hx-get (bidi/path-for ssr-routes/only-routes ::route/new-summary-item)
|
||||||
:row-offset 0
|
:row-offset 0
|
||||||
:index (count (fc/field-value))
|
:index (count (fc/field-value))
|
||||||
:tr-params {:hx-vals (hx/json {:client-id (:db/id (:sales-summary/client (:snapshot multi-form-state)))})}}
|
:tr-params {:hx-vals (hx/json {:client-id (:db/id (:sales-summary/client (:snapshot multi-form-state)))})}}
|
||||||
"New Summary Item")))
|
"New Summary Item")))
|
||||||
(summary-total-row* request)
|
(summary-total-row* request)
|
||||||
(unbalanced-row* request)) ])
|
(unbalanced-row* request))])
|
||||||
|
|
||||||
:footer
|
:footer
|
||||||
(mm/default-step-footer linear-wizard this :validation-route ::route/edit-wizard-navigate)
|
(mm/default-step-footer linear-wizard this :validation-route ::route/edit-wizard-navigate)
|
||||||
:validation-route ::route/edit-wizard-navigate
|
:validation-route ::route/edit-wizard-navigate
|
||||||
:width-height-class "lg:w-[850px] lg:h-[900px]")))
|
:width-height-class "lg:w-[850px] lg:h-[900px]")))
|
||||||
|
|
||||||
(defn attach-ledger [i]
|
(defn attach-ledger [i]
|
||||||
(cond-> i
|
(cond-> i
|
||||||
(:credit i) (assoc :ledger-mapped/ledger-side :ledger-side/credit
|
(:credit i) (assoc :ledger-mapped/ledger-side :ledger-side/credit
|
||||||
:ledger-mapped/amount (:credit i))
|
:ledger-mapped/amount (:credit i))
|
||||||
(:debit i) (assoc :ledger-mapped/ledger-side :ledger-side/debit
|
(:debit i) (assoc :ledger-mapped/ledger-side :ledger-side/debit
|
||||||
@@ -424,8 +486,8 @@
|
|||||||
(navigate [this step-key]
|
(navigate [this step-key]
|
||||||
(assoc this :current-step step-key))
|
(assoc this :current-step step-key))
|
||||||
(get-current-step
|
(get-current-step
|
||||||
[this]
|
[this]
|
||||||
(mm/get-step this :main))
|
(mm/get-step this :main))
|
||||||
(render-wizard [this {:keys [multi-form-state] :as request}]
|
(render-wizard [this {:keys [multi-form-state] :as request}]
|
||||||
(mm/default-render-wizard
|
(mm/default-render-wizard
|
||||||
this request
|
this request
|
||||||
@@ -437,29 +499,28 @@
|
|||||||
(steps [_]
|
(steps [_]
|
||||||
[:main])
|
[:main])
|
||||||
(get-step [this step-key]
|
(get-step [this step-key]
|
||||||
(let [step-key-result (mc/parse mm/step-key-schema step-key)
|
(let [step-key-result (mc/parse mm/step-key-schema step-key)
|
||||||
[step-key-type step-key] step-key-result]
|
[step-key-type step-key] step-key-result]
|
||||||
(->MainStep this)))
|
(->MainStep this)))
|
||||||
(form-schema [_]
|
(form-schema [_]
|
||||||
edit-schema)
|
edit-schema)
|
||||||
(submit [this {:keys [multi-form-state request-method identity] :as request}]
|
(submit [this {:keys [multi-form-state request-method identity] :as request}]
|
||||||
(let [result (:snapshot multi-form-state )
|
(let [result (:snapshot multi-form-state)
|
||||||
transaction [:upsert-sales-summary {:db/id (:db/id result)
|
transaction [:upsert-sales-summary {:db/id (:db/id result)
|
||||||
:sales-summary/items (map
|
:sales-summary/items (map
|
||||||
(fn [i]
|
(fn [i]
|
||||||
(if (:sales-summary-item/manual? i)
|
(if (:sales-summary-item/manual? i)
|
||||||
(attach-ledger i)
|
(attach-ledger i)
|
||||||
{:db/id (:db/id i)
|
{:db/id (:db/id i)
|
||||||
:ledger-mapped/account (:ledger-mapped/account i)
|
:ledger-mapped/account (:ledger-mapped/account i)}))
|
||||||
}))
|
(:sales-summary/items result))}]]
|
||||||
(:sales-summary/items result))}]]
|
|
||||||
(clojure.pprint/pprint (:sales-summary/items result))
|
(clojure.pprint/pprint (:sales-summary/items result))
|
||||||
@(dc/transact conn [ transaction])
|
@(dc/transact conn [transaction])
|
||||||
(html-response
|
(html-response
|
||||||
(row* identity (dc/pull (dc/db conn) default-read (:db/id result))
|
(row* identity (dc/pull (dc/db conn) default-read (:db/id result))
|
||||||
{:flash? true
|
{:flash? true
|
||||||
:request request})
|
:request request})
|
||||||
:headers (cond-> {"hx-trigger" "modalclose"
|
:headers (cond-> {"hx-trigger" "modalclose"
|
||||||
"hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id result))
|
"hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id result))
|
||||||
"hx-reswap" "outerHTML"})))))
|
"hx-reswap" "outerHTML"})))))
|
||||||
|
|
||||||
@@ -479,8 +540,8 @@
|
|||||||
(def key->handler
|
(def key->handler
|
||||||
(apply-middleware-to-all-handlers
|
(apply-middleware-to-all-handlers
|
||||||
(->>
|
(->>
|
||||||
{::route/page (helper/page-route grid-page)
|
{::route/page (helper/page-route grid-page)
|
||||||
::route/table (helper/table-route grid-page)
|
::route/table (helper/table-route grid-page)
|
||||||
::route/edit-wizard (-> mm/open-wizard-handler
|
::route/edit-wizard (-> mm/open-wizard-handler
|
||||||
(mm/wrap-wizard edit-wizard)
|
(mm/wrap-wizard edit-wizard)
|
||||||
(mm/wrap-init-multi-form-state initial-edit-wizard-state)
|
(mm/wrap-init-multi-form-state initial-edit-wizard-state)
|
||||||
@@ -498,9 +559,9 @@
|
|||||||
(wrap-schema-enforce :query-schema [:map
|
(wrap-schema-enforce :query-schema [:map
|
||||||
[:client-id {:optional true}
|
[:client-id {:optional true}
|
||||||
[:maybe entity-id]]]))
|
[:maybe entity-id]]]))
|
||||||
::route/edit-wizard-submit (-> mm/submit-handler
|
::route/edit-wizard-submit (-> mm/submit-handler
|
||||||
(mm/wrap-wizard edit-wizard)
|
(mm/wrap-wizard edit-wizard)
|
||||||
(mm/wrap-decode-multi-form-state))})
|
(mm/wrap-decode-multi-form-state))})
|
||||||
(fn [h]
|
(fn [h]
|
||||||
(-> h
|
(-> h
|
||||||
(wrap-copy-qp-pqp)
|
(wrap-copy-qp-pqp)
|
||||||
|
|||||||
Reference in New Issue
Block a user