From ee6669253fec8e767815469e1e0133ec82465b9e Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Mon, 14 Mar 2022 10:43:38 -0700 Subject: [PATCH] enforce locked until for payments --- src/clj/auto_ap/graphql/checks.clj | 14 ++++++++++++-- src/clj/auto_ap/graphql/invoices.clj | 19 ++++++++++--------- src/clj/auto_ap/graphql/utils.clj | 17 +++++++++++++++++ src/cljs/auto_ap/views/pages/payments.cljs | 4 +++- 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/clj/auto_ap/graphql/checks.clj b/src/clj/auto_ap/graphql/checks.clj index 38c350f2..544486b7 100644 --- a/src/clj/auto_ap/graphql/checks.clj +++ b/src/clj/auto_ap/graphql/checks.clj @@ -10,7 +10,7 @@ [auto-ap.datomic.transactions :as d-transactions] [auto-ap.datomic.vendors :as d-vendors] [auto-ap.graphql.utils - :refer [->graphql <-graphql assert-admin assert-can-see-client enum->keyword]] + :refer [->graphql <-graphql assert-admin assert-can-see-client enum->keyword assert-not-locked assert-none-locked]] [auto-ap.numeric :refer [num->words]] [auto-ap.time :refer [iso-date local-now parse]] [auto-ap.utils :refer [by dollars-0?]] @@ -376,6 +376,7 @@ (let [message (str "The bank account " (:bank-account/name bank-account) " does not have a starting check number. Please ask the integreat staff to initialize it.")] (throw (ex-info message {:validation-error message})))) + _ (assert-none-locked client-id (map (comp c/to-date :invoice/date) invoices)) checks (->> (for [[[vendor-id invoices] index] (map vector invoices-grouped-by-vendor (range))] (invoices->entities invoices (vendors vendor-id) client bank-account type index invoice-amounts)) (reduce into []) @@ -431,7 +432,10 @@ bank-account (d-bank-accounts/get-by-id bank-account-id) _ (doseq [invoice invoices] (assert-can-see-client (:id context) (:invoice/client invoice))) + client-id (:db/id (:invoice/client (first invoices))) _ (validate-belonging (:db/id (:client/_bank-accounts bank-account)) invoices bank-account) + _ (assert-none-locked client-id (map (comp c/to-date :invoice/date) invoices)) + _ (assert-not-locked client-id (:date args)) invoice-payment-lookup (by :invoice_id :amount (:invoice_payments args)) base-payment (base-payment invoices (:invoice/vendor (first invoices)) @@ -459,6 +463,7 @@ (assert (or (= :payment-status/pending (:payment/status check)) (#{:payment-type/cash :payment-type/debit} (:payment/type check)))) (assert-can-see-client (:id context) (:db/id (:payment/client check))) + (assert-not-locked (:db/id (:payment/client check)) (:payment/date check)) (let [removing-payments (mapcat (fn [x] (let [invoice (:invoice-payment/invoice x) new-balance (+ (:invoice/outstanding-balance invoice) @@ -501,7 +506,12 @@ :in $ [?p ...] :where (not [_ :transaction/payment ?p]) - (not [?p :payment/status :payment-status/voided])] + (not [?p :payment/status :payment-status/voided]) + [?p :payment/client ?c] + [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] + [?p :payment/date ?d] + [(>= ?d ?lu)] + ] (d/db conn)) (mapcat (fn [{:keys [:db/id] invoices :invoice-payment/_payment}] diff --git a/src/clj/auto_ap/graphql/invoices.clj b/src/clj/auto_ap/graphql/invoices.clj index f1d862fc..9bb01aa9 100644 --- a/src/clj/auto_ap/graphql/invoices.clj +++ b/src/clj/auto_ap/graphql/invoices.clj @@ -11,6 +11,7 @@ :as u :refer [<-graphql assert-admin + assert-not-locked assert-can-see-client assert-power-user assert-failure @@ -149,11 +150,8 @@ (when-not (dollars= total expense-account-total) (let [error (str "Expense account total (" expense-account-total ") does not equal invoice total (" total ")")] (throw (ex-info error {:validation-error error})))))) -(defn assert-not-locked [client-id date] - (let [{:client/keys [locked-until]} (d/pull (d/db conn) [:client/locked-until] client-id)] - (when (and locked-until - (>= (compare locked-until (coerce/to-date date)) 0)) - (assert-failure (str "Integreat has locked finances prior to " (-> locked-until coerce/to-date-time (atime/unparse-local atime/normal-date)) "."))))) + + (defn add-invoice [context {{:keys [expense_accounts client_id] :as in} :invoice} _] (assert-no-conflicting in) @@ -252,11 +250,14 @@ (log/info "Voiding " (count all-ids) args) (audit-transact (->> all-ids - (d/q '[:find [(pull ?i [:db/id {:invoice/expense-accounts [:db/id]}]) ...] + (d/q '[:find [(pull ?i [:db/id :invoice/date {:invoice/expense-accounts [:db/id]}]) ...] :in $ [?i ...] - :where (not [_ :invoice-payment/invoice ?i])] - (d/db conn) - ) + :where (not [_ :invoice-payment/invoice ?i]) + [?i :invoice/client ?c] + [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] + [?i :invoice/date ?d] + [(>= ?d ?lu)]] + (d/db conn)) (mapcat (fn [i] (into diff --git a/src/clj/auto_ap/graphql/utils.clj b/src/clj/auto_ap/graphql/utils.clj index 6a13db01..1cf7ddf3 100644 --- a/src/clj/auto_ap/graphql/utils.clj +++ b/src/clj/auto_ap/graphql/utils.clj @@ -1,6 +1,10 @@ (ns auto-ap.graphql.utils (:require [clojure.string :as str] + [auto-ap.datomic :refer [conn]] + [clj-time.coerce :as coerce] + [auto-ap.time :as atime] [buddy.auth :refer [throw-unauthorized]] + [datomic.api :as d] [clojure.walk :as walk] [clojure.tools.logging :as log])) @@ -106,3 +110,16 @@ (defn enum->keyword [e namespace] (some->> e name snake->kebab (keyword namespace))) + +(defn get-locked-until [client-id] + (:client/locked-until (d/pull (d/db conn) [:client/locked-until] client-id))) + +(defn assert-not-locked [client-id date] + (let [locked-until (get-locked-until client-id)] + (when (and locked-until + (>= (compare locked-until (coerce/to-date date)) 0)) + (assert-failure (str "Integreat has locked finances prior to " (-> locked-until coerce/to-date-time (atime/unparse-local atime/normal-date)) "."))))) + +(defn assert-none-locked [client-id dates] + (doseq [d dates] + (assert-not-locked client-id d))) diff --git a/src/cljs/auto_ap/views/pages/payments.cljs b/src/cljs/auto_ap/views/pages/payments.cljs index f6e049ec..457be66e 100644 --- a/src/cljs/auto_ap/views/pages/payments.cljs +++ b/src/cljs/auto_ap/views/pages/payments.cljs @@ -55,8 +55,9 @@ (re-frame/reg-event-fx ::unmounted - (fn [_ _] + (fn [{:keys [db]} _] {:dispatch [::data-page/dispose ::page] + :db (-> db (status/reset-multi ::table/void)) ::track/dispose {:id ::params} ::forward/dispose {:id ::page}})) @@ -148,6 +149,7 @@ [:div [:h1.title "Payments"] [action-buttons] + [status/status-notification {:statuses [[::status/last-multi ::table/void]]}] [table/table {:id :payments :data-page ::page}]])