beginning on new journal entry

This commit is contained in:
2024-10-26 20:11:03 -07:00
parent b46c668199
commit bf7e63f7e0
6 changed files with 229 additions and 9 deletions

View File

@@ -23,6 +23,7 @@
[auto-ap.ssr.ledger.common :refer [bank-account-filter default-read
fetch-ids grid-page query-schema]]
[auto-ap.ssr.ledger.investigate :as investigate]
[auto-ap.ssr.ledger.new :as new]
[auto-ap.ssr.ledger.profit-and-loss :as profit-and-loss]
[auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]]
[auto-ap.ssr.svg :as svg]
@@ -732,4 +733,5 @@
balance-sheet/key->handler
profit-and-loss/key->handler
cash-flows/key->handler
investigate/key->handler))
investigate/key->handler
new/key->handler))

View File

@@ -417,13 +417,10 @@
:parse-query-params (fn [p]
(mc/decode query-schema p main-transformer))
:action-buttons (fn [request]
(let [[_ _ outstanding total] (:page-results request)]
[ #_(when (can? (:identity request) {:subject :invoice :activity :bulk-delete})
(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/bulk-delete))
"x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})"
"hx-include" "#ledger-filters"
:color :red}
"Void selected")) ]))
[(com/button {:color :primary
:hx-get (bidi/path-for ssr-routes/only-routes
::route/new)}
"Add journal entry")])
:row-buttons (fn [request entity]
[(when (and (= :invoice-status/unpaid (:invoice/status entity))
(can? (:identity request) {:subject :invoice :activity :delete}))

View File

@@ -0,0 +1,217 @@
(ns auto-ap.ssr.ledger.new
(:require
[auto-ap.datomic :refer [conn pull-attr]]
[auto-ap.datomic.accounts :as d-accounts]
[auto-ap.permissions :refer [wrap-must]]
[auto-ap.routes.ledger :as route]
[auto-ap.routes.utils :refer [wrap-client-redirect-unauthenticated]]
[auto-ap.ssr-routes :as ssr-routes]
[auto-ap.ssr.common-handlers :refer [add-new-entity-handler]]
[auto-ap.ssr.components :as com]
[auto-ap.ssr.form-cursor :as fc]
[auto-ap.ssr.hx :as hx]
[auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]]
[auto-ap.ssr.svg :as svg]
[auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers entity-id
modal-response wrap-schema-enforce]]
[auto-ap.time :as atime]
[bidi.bidi :as bidi]
[datomic.api :as dc]))
(defn- account-typeahead*
[{:keys [name value client-id x-model]}]
[:div.flex.flex-col
(com/typeahead {:name name
:placeholder "Search..."
:url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id)
:id name
:x-model x-model
:value value
:content-fn (fn [value]
(let [a (dc/pull (dc/db conn) d-accounts/default-read value)]
(when value
(str
(:account/numeric-code a)
" - "
(:account/name (d-accounts/clientize a
client-id))))))})])
(defn- location-select*
[{:keys [name account-location client-locations value]}]
(com/select {:options (into [["" ""]]
(cond account-location
[[account-location account-location]]
(seq client-locations)
(into [["Shared" "Shared"]]
(for [cl client-locations]
[cl cl]))
:else
[["Shared" "Shared"]]))
:name name
:value value
:class "w-full"}))
(defn- line-item-row*
[account client-id client-locations]
(com/data-grid-row
(-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account)))
(fc/field-value (:transaction-rule-account/account account)))
:location (fc/field-value (:transaction-rule-account/location account))
:show (boolean (not (fc/field-value (:new? account))))})
:data-key "show"
:x-ref "p"}
hx/alpine-mount-then-appear)
(let [account-name (fc/field-name (:transaction-rule-account/account account))]
(list
(fc/with-field :db/id
(com/hidden {:name (fc/field-name)
:value (fc/field-value)}))
(fc/with-field :transaction-rule-account/account
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)}
[:div {:hx-trigger "changed"
:hx-target "next div"
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', value: event.detail.accountId || ''}" account-name)
:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/account-typeahead))
:x-init "$watch('clientId', cid => $dispatch('changed', $data));"}]
(account-typeahead* {:value (fc/field-value)
:client-id client-id
:name (fc/field-name)
:x-model "accountId"}))))
(fc/with-field :transaction-rule-account/location
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)
:x-data (hx/json {:location (fc/field-value)})}
;; TODO make this thing into a component
[:div {:hx-trigger "changed"
:hx-target "next *"
:hx-swap "outerHTML"
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || '', value: event.detail.location || ''}" (fc/field-name))
:hx-get (bidi/path-for ssr-routes/only-routes ::route/location-select)
:x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data) )"}]
(location-select* {:name (fc/field-name)
:account-location (:account/location (cond->> (:transaction-rule-account/account @account)
(nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn)
'[:account/location])))
:client-locations client-locations
:x-model "location"
:value (fc/field-value)}))))
(fc/with-field :transaction-rule-account/percentage
(com/data-grid-cell
{}
(com/validated-field
{:errors (fc/field-errors)}
(com/money-input {:name (fc/field-name)
:class "w-16"
:value (some-> (fc/field-value)
(* 100)
(long))}))))))
(com/data-grid-cell {:class "align-top"}
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
(defn form* [request]
(fc/start-form (:form-params request)
(:form-errors request)
[:div.flex.gap-4.flex-col
(fc/with-field :journal-entry/client
(com/validated-field
{:label "Client"
:errors (fc/field-errors)}
[:div.w-96
(com/typeahead {:name (fc/field-name)
:error? (fc/error?)
:class "w-96"
:placeholder "Search..."
:url (bidi/path-for ssr-routes/only-routes :company-search)
:value (fc/field-value)
:content-fn (fn [c] (pull-attr (dc/db conn) :client/name c))})]))
(fc/with-field :invoice/date
(com/validated-field
{:label "Date"
:errors (fc/field-errors)}
[:div {:class "w-24"}
(com/date-input {:value (some-> (fc/field-value)
(atime/unparse-local atime/normal-date))
:name (fc/field-name)
:error? (fc/field-errors)
:placeholder "1/1/2024"})]))
(fc/with-field :journal-entry/vendor
(com/validated-field
{:label "Vendor"
:errors (fc/field-errors)}
[:div.w-96
(com/typeahead {:name (fc/field-name)
:error? (fc/error?)
:disabled (boolean (-> request :multi-form-state :snapshot :db/id))
:class "w-96"
:placeholder "Search..."
:url (bidi/path-for ssr-routes/only-routes :vendor-search)
:value (fc/field-value)
:content-fn (fn [c] (pull-attr (dc/db conn) :vendor/name c))})]))
(fc/with-field :invoice/total
(com/validated-field
{:label "Total"
:errors (fc/field-errors)}
[:div {:class "w-16"}
(com/money-input {:value (-> (fc/field-value))
:name (fc/field-name)
:class "w-24"
:error? (fc/field-errors)
:placeholder "212.44"})]))
(fc/with-field :journal-entry/line-items
(com/validated-field
{:errors (fc/field-errors)}
(let [client-locations (some->> (fc/field-value) :transaction-rule/client (pull-attr (dc/db conn) :client/locations))]
(com/data-grid {:headers [(com/data-grid-header {} "Account")
(com/data-grid-header {:class "w-32"} "Location")
(com/data-grid-header {:class "w-16"} "%")
(com/data-grid-header {:class "w-16"})]}
(fc/cursor-map #(line-item-row* % (:transaction-rule/client (fc/field-value)) client-locations))
(com/data-grid-new-row {:colspan 4
:hx-get (bidi/path-for ssr-routes/only-routes
::route/new-line-item)
:index (count (fc/field-value))
:tr-params (hx/bind-alpine-vals {} {"client-id" "clientId"})}
"New account")))))]))
(defn new [request]
(modal-response
(com/modal {}
(com/modal-card {:class ""}
[:div "New ledger entry"]
[:div (form* request)]
[:div (com/button {:color :primary} "Save")]))
#_[:div]))
(def key->handler
(apply-middleware-to-all-handlers
(->
{::route/new (-> new
#_(wrap-schema-enforce :query-schema query-schema)
#_(wrap-form-4xx-2 profit-and-loss))
::route/new-line-item
(-> (add-new-entity-handler [:journal-entry/line-items]
(fn render [cursor request]
(line-item-row*
cursor
(:client-id (:query-params request))
(some->> (:client-id (:query-params request)) (pull-attr (dc/db conn) :client/locations))))
(fn build-new-row [base _]
(assoc base :transaction-rule-account/location "Shared")))
(wrap-schema-enforce :query-schema [:map
[:client-id {:optional true}
[:maybe entity-id]]]))})
(fn [h]
(-> h
#_(wrap-merge-prior-hx)
(wrap-must {:activity :edit :subject :ledger})
(wrap-nested-form-params)
(wrap-client-redirect-unauthenticated)))))

View File

@@ -1,6 +1,9 @@
(ns auto-ap.routes.ledger)
(def routes {"" {:get ::all-page}
"/new" {:get ::new
"/line-item" {:get ::new-line-item}}
"/external-new" ::external-page
"/external-import-new" {"" ::external-import-page
"/parse" ::external-import-parse