From de6e6f15729afdf89e7099af003489a8d7988399 Mon Sep 17 00:00:00 2001 From: Bryce Date: Fri, 19 Apr 2024 22:02:25 -0700 Subject: [PATCH] fixes bug, adds CSV template --- src/clj/auto_ap/parse/templates.clj | 55 ++++--- .../auto_ap/ssr/company/reports/expense.clj | 135 ++++++++++++++++++ 2 files changed, 174 insertions(+), 16 deletions(-) create mode 100644 src/clj/auto_ap/ssr/company/reports/expense.clj diff --git a/src/clj/auto_ap/parse/templates.clj b/src/clj/auto_ap/parse/templates.clj index 400b4a4d..5b42634f 100644 --- a/src/clj/auto_ap/parse/templates.clj +++ b/src/clj/auto_ap/parse/templates.clj @@ -657,22 +657,45 @@ :keywords [#"Mama Lu's Foods"] :extract (fn [sheet vendor] (transduce (comp - (drop 5) - (filter - (fn [r] - (and - (seq r) - (->> r second not-empty)))) - (map - (fn [r] - (let [[_ customer-order-number num date name amount] r] - {:customer-identifier (second (re-find #"([^:]*):" name)) - :text name - :full-text name - :date (u/parse-value :clj-time "MM/dd/yyyy" (str/trim date)) - :invoice-number (str customer-order-number "-" (Integer/parseInt num)) - :total (str amount) - :vendor-code vendor})))) + (drop 5) + (filter + (fn [r] + (and + (seq r) + (->> r second not-empty)))) + (map + (fn [r] + (let [[_ customer-order-number num date name amount] r] + {:customer-identifier (second (re-find #"([^:]*):" name)) + :text name + :full-text name + :date (u/parse-value :clj-time "MM/dd/yyyy" (str/trim date)) + :invoice-number (str customer-order-number "-" (Integer/parseInt num)) + :total (str amount) + :vendor-code vendor})))) + conj + [] + sheet))} + + {:vendor "Daylight Foods" + :keywords [#"CUSTNO"] + :extract (fn [sheet vendor] + (transduce (comp + (drop 1) + (filter + (fn [r] + (and + (seq r) + (->> r first not-empty)))) + (map + (fn [[customer-number _ _ _ invoice-number date amount :as row]] + {:customer-identifier customer-number + :text (str/join " " row) + :full-text (str/join " " row) + :date (u/parse-value :clj-time "MM/dd/yyyy" (str/trim date)) + :invoice-number invoice-number + :total (str amount) + :vendor-code vendor}))) conj [] sheet))}]) diff --git a/src/clj/auto_ap/ssr/company/reports/expense.clj b/src/clj/auto_ap/ssr/company/reports/expense.clj new file mode 100644 index 00000000..1d37961d --- /dev/null +++ b/src/clj/auto_ap/ssr/company/reports/expense.clj @@ -0,0 +1,135 @@ +(ns auto-ap.ssr.company.reports.expense + (:require [auto-ap.datomic :refer [conn merge-query]] + [auto-ap.graphql.utils :refer [extract-client-ids]] + [auto-ap.logging :as alog] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.form-cursor :as fc] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.ui :refer [base-page]] + [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers + html-response wrap-schema-enforce]] + [bidi.bidi :as bidi] + [cemerick.url :as url] + [clj-time.coerce :as coerce] + [clj-time.core :as time] + [datomic.api :as dc] + [hiccup2.core :as hiccup])) + +(defn lookup-data [request] + (let [query (cond-> {:query '{:find [?an ?user-date (sum ?amt)] + :in [$ [?clients ?start ?end]] + :where + [[(iol-ion.query/scan-invoices $ ?clients ?start ?end) [[?e _ ?sort-default] ...]] + [?e :invoice/date ?d] + [?e :invoice/expense-accounts ?iea] + [?iea :invoice-expense-account/amount ?amt] + [?iea :invoice-expense-account/account ?a] + [?a :account/name ?an] + [(iol-ion.query/iso-date ?d) ?user-date]]} + :args + [(dc/db conn) + [(extract-client-ids (:clients request) + (:client-id request) + (when (:client-code request) + [:client/code (:client-code request)])) + (some-> (time/plus (time/now) (time/days -14)) coerce/to-date) + (some-> (time/now) coerce/to-date)]]} + + (:vendor-id (:query-params request)) + (merge-query {:query '{:in [?v] + :where [ [?e :invoice/vendor ?v]]} + :args [ (:db/id (:vendor-id (:query-params request)))]}))] + + (dc/query query))) + +(defn card* [request] + (com/content-card {:class "w-full" :id "report"} + [:div {:class "flex flex-col px-8 py-8 space-y-3"} + [:div + [:h1.text-2xl.mb-3.font-bold "Expenses by day, 14 days"] + [:form {:hx-get (bidi.bidi/path-for ssr-routes/only-routes :company-expense-report-card ) + :hx-trigger "change" + :hx-target "#report" + :hx-swap "outerHTML"} + (fc/start-form + (:query-params request) + (:form-errors request) + [:div + (fc/with-field :vendor-id + (com/validated-field {:label "Vendor" + :errors (fc/field-errors)} + (com/typeahead {:name (fc/field-name) + :class "w-64" + :url (bidi/path-for ssr-routes/only-routes :vendor-search) + :value (fc/field-value) + :value-fn :db/id + :content-fn :vendor/name})))])] + [:div + (let [data (lookup-data request) + distinct-accounts (take 5 (->> data + (reduce + (fn [acc [an _ amount]] + (update acc an (fnil + 0.0) amount)) + {}) + (sort-by last) + (reverse) + (map first) + (take 5))) + lookup (->> + (reduce + (fn [acc [a d v]] + (assoc-in acc [a d] v)) + {} + data)) + dates (for [d (range -14 0)] + (iol-ion.query/iso-date (coerce/to-date (time/plus (time/now) (time/days d))))) + series (for [ea distinct-accounts] + (for [d dates] + (get-in lookup [ea d] 0)))] + [:div {:class "w-full h-64" + :id "client-chart" + :x-data (hx/json {:chart {:labels dates + #_["2 years ago" "1 year ago" "today"], + :series (alog/peek ::test series)}}) + :x-init (hiccup/raw "new Chartist.Bar($el, chart, {seriesBarDistance:10}); ")} + [:div.flex.space-x-2.my-4 + (for [[d color] (map vector distinct-accounts ["bg-green-500" "bg-red-500" "bg-blue-500" "bg-yellow-500" "bg-purple-500"])] + [:span.px-2.py-1.rounded.rounded-full.text-sm.text-gray-100 {:class color} d])]])]]])) + +(defn page [request] + (base-page + request + (com/page {:nav com/company-aside-nav + :client-selection (:client-selection request) + :client (:client request) + :clients (:clients request) + :identity (:identity request) + :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :company-expense-report) + :hx-trigger "clientSelected from:body" + :hx-select "#app-contents" + :hx-swap "outerHTML swap:300ms"}} + (com/breadcrumbs {} + [:a {:href (bidi/path-for ssr-routes/only-routes :company)} + "My Company"] + [:a {:href (bidi/path-for ssr-routes/only-routes :company-expense-report)} + "Expense Report"]) + (card* request)) + "My Company")) + +(defn card [request] + (html-response + (card* request) + :headers {"hx-push-url" (str "?" (url/map->query (update (:query-params request) :vendor-id :db/id))) })) + +(def key->handler + (apply-middleware-to-all-handlers + {:company-expense-report page + :company-expense-report-card card} + (fn [h] + (-> h + (wrap-schema-enforce :query-schema + [:map {:default {}} + [:vendor-id {:optional true} + [:maybe + [:entity-map {:pull [:vendor/name :db/id]}]]]] ))))) \ No newline at end of file