From e1298a1f94fde5e75f9615995ef7a1f0c33d1d89 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Thu, 10 Feb 2022 12:40:09 -0800 Subject: [PATCH] added the ability to credit invoices. Also made it so check numbers pop up for intuit even if they're not in the description. --- src/clj/auto_ap/datomic/migrate.clj | 4 +- src/clj/auto_ap/graphql.clj | 117 +------- src/clj/auto_ap/graphql/checks.clj | 279 +++++++++++++----- src/clj/auto_ap/import/intuit.clj | 21 +- .../auto_ap/views/pages/unpaid_invoices.cljs | 77 ++--- 5 files changed, 283 insertions(+), 215 deletions(-) diff --git a/src/clj/auto_ap/datomic/migrate.clj b/src/clj/auto_ap/datomic/migrate.clj index 35eec030..1e090c46 100644 --- a/src/clj/auto_ap/datomic/migrate.clj +++ b/src/clj/auto_ap/datomic/migrate.clj @@ -487,7 +487,9 @@ :auto-ap/add-source-url-admin-only {:txes [[{:db/ident :invoice/source-url-admin-only :db/doc "Can only admins see this invoice?" :db/valueType :db.type/boolean - :db/cardinality :db.cardinality/one}]]}} + :db/cardinality :db.cardinality/one}]]} + :auto-ap/add-payment-type-credit {:txes [[{:db/ident :payment-type/credit + :db/doc "Credit for negative invoices"}]]}} diff --git a/src/clj/auto_ap/graphql.clj b/src/clj/auto_ap/graphql.clj index 10b2ec42..8134081a 100644 --- a/src/clj/auto_ap/graphql.clj +++ b/src/clj/auto_ap/graphql.clj @@ -300,32 +300,8 @@ :charges {:type '(list :charge)} :line_items {:type '(list :order_line_item)}}} - :check {:fields {:id {:type :id} - :type {:type 'String} - :amount {:type 'String} - :vendor {:type :vendor} - :date {:type 'String} - :bank_account {:type :bank_account} - :memo {:type 'String} - :s3_url {:type 'String} - :check_number {:type 'Int} - :status {:type 'String} - :invoices {:type '(list :invoice_payment)}}} - :payment {:fields {:id {:type :id} - :type {:type :payment_type} - :original_id {:type 'Int} - :amount {:type 'String} - :vendor {:type :vendor} - :client {:type :client} - :date {:type 'String} - :bank_account {:type :bank_account} - :memo {:type 'String} - :s3_url {:type 'String} - :check_number {:type 'Int} - :status {:type :ident} - :transaction {:type :transaction} - :invoices {:type '(list :invoice_payment)}}} + :yodlee_merchant {:fields {:id {:type :id} :yodlee_id {:type 'String} @@ -352,13 +328,7 @@ :accounts {:type '(list :percentage_account)} :transaction_approval_status {:type :transaction_approval_status}}} - :invoice_payment - {:fields {:id {:type :id} - :amount {:type 'String} - :invoice_id {:type 'String} - :payment_id {:type 'String} - :payment {:type :payment} - :invoice {:type :invoice}}} + :user {:fields {:id {:type :id} @@ -392,11 +362,7 @@ :start {:type 'Int} :end {:type 'Int}}} - :payment_page {:fields {:payments {:type '(list :payment)} - :count {:type 'Int} - :total {:type 'Int} - :start {:type 'Int} - :end {:type 'Int}}} + :transaction_rule_page {:fields {:transaction_rules {:type '(list :transaction_rule)} :count {:type 'Int} @@ -459,9 +425,7 @@ :potential_transaction_rule_matches {:type '(list :transaction_rule) :args {:transaction_id {:type :id}} :resolve :get-transaction-rule-matches} - :potential_payment_matches {:type '(list :payment) - :args {:transaction_id {:type :id}} - :resolve :get-potential-payments} + :test_transaction_rule {:type '(list :transaction) :args {:transaction_rule {:type :edit_transaction_rule}} @@ -499,12 +463,7 @@ :args {:account_set {:type 'String}} :resolve :get-accounts} - :all_payments {:type '(list :payment) - :args {:client_id {:type :id} - :client_code {:type 'String} - :original_id {:type 'Int} - :statuses {:type '(list String)}} - :resolve :get-all-payments} + :all_sales_orders {:type '(list :sales_order) :args {:client_id {:type :id} @@ -546,20 +505,7 @@ :sort {:type '(list :sort_item)}} :resolve :get-sales-order-page} - :payment_page {:type '(list :payment_page) - :args {:client_id {:type :id} - :vendor_id {:type :id} - :payment_type {:type :payment_type} - :exact_match_id {:type :id} - :date_range {:type :date_range} - :amount_lte {:type :money} - :amount_gte {:type :money} - :check_number_like {:type 'String} - :invoice_number {:type 'String} - :start {:type 'Int} - :per_page {:type 'Int} - :sort {:type '(list :sort_item)}} - :resolve :get-payment-page} + :client {:type '(list :client) :resolve :get-client} @@ -590,8 +536,7 @@ :only_external {:type 'Boolean} :external_id_like {:type 'String} :sort {:type '(list :sort_item)}}} - :invoice_payment_amount {:fields {:invoice_id {:type :id} - :amount {:type :money}}} + :edit_location_match {:fields {:location {:type 'String} :match {:type 'String} :id {:type :id}}} @@ -747,10 +692,7 @@ :name {:type 'String} :client_overrides {:type '(list :edit_account_client_override)}}}} - :enums {:payment_type {:values [{:enum-value :check} - {:enum-value :cash} - {:enum-value :debit}]} - + :enums { :processor {:values [{:enum-value :na} {:enum-value :doordash} {:enum-value :uber_eats} @@ -790,19 +732,6 @@ :to {:type :id}} :resolve :mutation/merge-vendors} - :print_checks {:type :check_result - :args {:invoice_payments {:type '(list :invoice_payment_amount)} - :bank_account_id {:type :id} - :type {:type :payment_type} - :client_id {:type :id}} - :resolve :mutation/print-checks} - - :add_handwritten_check {:type :check_result - :args {:invoice_payments {:type '(list :invoice_payment_amount)} - :date {:type 'String} - :check_number {:type 'Int} - :bank_account_id {:type :id}} - :resolve :mutation/add-handwritten-check} :edit_user {:type :user :args {:edit_user {:type :edit_user}} :resolve :mutation/edit-user} @@ -827,9 +756,7 @@ :args {:account {:type :edit_account}} :resolve :mutation/upsert-account} - :void_payment {:type :payment - :args {:payment_id {:type :id}} - :resolve :mutation/void-payment}}}) + }}) (defn snake->kebab [s] @@ -869,11 +796,7 @@ m)) -(defn get-all-payments [context args value] - (assert-admin (:id context)) - (map - ->graphql - (first (d-checks/get-graphql (assoc (<-graphql args) :count Integer/MAX_VALUE))))) + (defn get-all-sales-orders [context args value] (assert-admin (:id context)) @@ -889,17 +812,7 @@ -(defn print-checks [context args value] - - (assert-can-see-client (:id context) (:client_id args)) - (->graphql - (gq-checks/print-checks (map (fn [i] {:invoice-id (:invoice_id i) - :amount (:amount i)}) - (:invoice_payments args)) - (:client_id args) - (:bank_account_id args) - (:type args) - (:id context)))) + (defn get-expense-account-stats [context {:keys [client_id] } value] (let [result (cond-> {:query {:find ['?account '?account-name '(sum ?amount)] @@ -1058,12 +971,9 @@ (def schema (-> integreat-schema - (attach-resolvers {:mutation/void-payment gq-checks/void-check + (attach-resolvers { :get-yodlee-provider-account-page gq-yodlee2/get-yodlee-provider-account-page - :get-all-payments get-all-payments :get-all-sales-orders get-all-sales-orders - :get-payment-page gq-checks/get-payment-page - :get-potential-payments gq-checks/get-potential-payments :get-accounts gq-accounts/get-accounts :get-ledger-page gq-ledger/get-ledger-page :get-sales-order-page gq-sales-orders/get-sales-orders-page @@ -1078,9 +988,7 @@ :get-intuit-bank-accounts gq-intuit-bank-accounts/get-intuit-bank-accounts :get-client gq-clients/get-client :get-user get-user - :mutation/add-handwritten-check gq-checks/add-handwritten-check :mutation/delete-transaction-rule gq-transaction-rules/delete-transaction-rule - :mutation/print-checks print-checks :mutation/edit-user gq-users/edit-user :mutation/delete-external-ledger gq-ledger/delete-external-ledger :mutation/upsert-transaction-rule gq-transaction-rules/upsert-transaction-rule @@ -1093,6 +1001,7 @@ :mutation/import-ledger gq-ledger/import-ledger :mutation/request-import gq-requests/request-import :get-vendor gq-vendors/get-graphql}) + gq-checks/attach gq-plaid/attach gq-import-batches/attach gq-transactions/attach diff --git a/src/clj/auto_ap/graphql/checks.clj b/src/clj/auto_ap/graphql/checks.clj index 897f5a0f..e59d3b98 100644 --- a/src/clj/auto_ap/graphql/checks.clj +++ b/src/clj/auto_ap/graphql/checks.clj @@ -1,31 +1,32 @@ (ns auto-ap.graphql.checks - (:require [amazonica.aws.s3 :as s3] - [auto-ap.datomic :refer [audit-transact remove-nils]] - [auto-ap.datomic.bank-accounts :as d-bank-accounts] - [auto-ap.datomic.checks :as d-checks] - [auto-ap.datomic.clients :as d-clients] - [auto-ap.datomic.invoices :as d-invoices] - [auto-ap.datomic.transactions :as d-transactions] - [auto-ap.datomic.vendors :as d-vendors] - [auto-ap.graphql.utils - :refer - [->graphql <-graphql assert-can-see-client enum->keyword]] - [auto-ap.numeric :refer [num->words]] - [auto-ap.time :refer [iso-date local-now parse]] - [auto-ap.utils :refer [by dollars-0?]] - [clj-pdf.core :as pdf] - [clj-time.coerce :as c] - [clj-time.core :as time] - [clj-time.format :as f] - [clojure.edn :as edn] - [clojure.java.io :as io] - [clojure.string :as str] - [config.core :refer [env]] - [clojure.tools.logging :as log] - [clojure.set :as set]) - (:import java.io.ByteArrayOutputStream - java.text.DecimalFormat - java.util.UUID)) + (:require + [amazonica.aws.s3 :as s3] + [auto-ap.datomic :refer [audit-transact remove-nils]] + [auto-ap.datomic.bank-accounts :as d-bank-accounts] + [auto-ap.datomic.checks :as d-checks] + [auto-ap.datomic.clients :as d-clients] + [auto-ap.datomic.invoices :as d-invoices] + [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]] + [auto-ap.numeric :refer [num->words]] + [auto-ap.time :refer [iso-date local-now parse]] + [auto-ap.utils :refer [by dollars-0?]] + [clj-pdf.core :as pdf] + [clj-time.coerce :as c] + [clj-time.core :as time] + [clj-time.format :as f] + [clojure.edn :as edn] + [clojure.java.io :as io] + [clojure.set :as set] + [clojure.string :as str] + [com.walmartlabs.lacinia.util :refer [attach-resolvers]] + [config.core :refer [env]]) + (:import + (java.io ByteArrayOutputStream) + (java.text DecimalFormat) + (java.util UUID))) (def parser (f/formatter "MM/dd/YYYY")) (defn date->str [t] @@ -58,12 +59,9 @@ (let [{:keys [bank-account paid-to client check date amount memo] {print-as :vendor/print-as vendor-name :vendor/name :as vendor} :vendor} check df (DecimalFormat. "#,###.00") word-amount (num->words amount) - amount (str "--" (.format df amount) "--")] - [:table {:num-cols 12 :border false :leading 11 :widths (distribute [2 3 3 3 3 3 3 3 3 2 2 2])} - [(let [{:keys [:client/name] {:keys [:address/street1 :address/street2 :address/city :address/state :address/zip]} :client/address} client] - + [(let [{:keys [:client/name] {:keys [:address/street1 :address/city :address/state :address/zip]} :client/address} client] [:cell {:colspan 4 } [:paragraph {:leading 14} name "\n" street1 "\n" (str city ", " state " " zip)] ]) (let [{:keys [:bank-account/bank-name :bank-account/bank-code] } bank-account] [:cell {:colspan 6 :align :center} [:paragraph {:style :bold} bank-name] [:paragraph {:size 8 :leading 8} bank-code]]) @@ -108,9 +106,7 @@ [[:cell {:colspan 2}] [:cell {:colspan 10 :leading 30} [:phrase {:size 18 :ttf-name "public/micrenc.ttf"} (str "c" check "c a" (:bank-account/routing bank-account) "a " (:bank-account/number bank-account) "c")]]] - [[:cell {:colspan 12 :leading 18} [:spacer]]] - [[:cell] (into [:cell {:colspan 9}] @@ -230,8 +226,14 @@ :payment/invoices (map :db/id invoices)}) (defmethod invoices->entities :payment-type/check [invoices vendor client bank-account type index invoice-amounts] - (let [uuid (str (UUID/randomUUID)) - memo (str "Invoice #'s: " + (when (<= (->> invoices + (map (comp invoice-amounts :db/id)) + (reduce + 0.0)) + 0.001) + (throw (ex-info "The selected invoices do not have an outstanding balance." + {:validation-error "The selected invoices do not have an outstanding balance."}))) + (let [uuid (str (UUID/randomUUID)) + memo (str "Invoice #'s: " (str/join ", " (map (fn [i] (str (:invoice/invoice-number i) "(" (invoice-amounts (:db/id i)) ")")) @@ -239,29 +241,29 @@ base-payment (base-payment invoices vendor client bank-account type index invoice-amounts) payment (remove-nils - (assoc base-payment - :payment/s3-uuid (when (> (:payment/amount base-payment) 0) uuid) - :payment/s3-key (when (> (:payment/amount base-payment) 0) (str "checks/" uuid ".pdf")) - :payment/s3-url (when (> (:payment/amount base-payment) 0) (str "http://" (:data-bucket env) ".s3-website-us-east-1.amazonaws.com/checks/" uuid ".pdf")) - :payment/check-number (+ index (:bank-account/check-number bank-account)) - :payment/type :payment-type/check - :payment/memo memo - :payment/status :payment-status/pending - :payment/pdf-data (pr-str {:vendor vendor - :paid-to (or (:vendor/paid-to vendor) (:vendor/name vendor)) - :amount (reduce + 0 (map (comp invoice-amounts :db/id) invoices)) - :check (str (+ index (:bank-account/check-number bank-account))) - :memo memo - :date (date->str (local-now)) - :client (dissoc client :client/bank-accounts) - :bank-account (dissoc bank-account :bank-account/start-date) - #_#_:client {:name (:name client) - :address (:address client) - :signature-file (:signature-file client) - :bank {:name (:bank-account/bank-name bank-account) - :acct (:bank-account/bank-code bank-account) - :routing (:bank-account/routing bank-account) - :acct-number (:bank-account/number bank-account)}}})))] + (assoc base-payment + :payment/s3-uuid (when (> (:payment/amount base-payment) 0) uuid) + :payment/s3-key (when (> (:payment/amount base-payment) 0) (str "checks/" uuid ".pdf")) + :payment/s3-url (when (> (:payment/amount base-payment) 0) (str "http://" (:data-bucket env) ".s3-website-us-east-1.amazonaws.com/checks/" uuid ".pdf")) + :payment/check-number (+ index (:bank-account/check-number bank-account)) + :payment/type :payment-type/check + :payment/memo memo + :payment/status :payment-status/pending + :payment/pdf-data (pr-str {:vendor vendor + :paid-to (or (:vendor/paid-to vendor) (:vendor/name vendor)) + :amount (reduce + 0 (map (comp invoice-amounts :db/id) invoices)) + :check (str (+ index (:bank-account/check-number bank-account))) + :memo memo + :date (date->str (local-now)) + :client (dissoc client :client/bank-accounts) + :bank-account (dissoc bank-account :bank-account/start-date) + #_#_:client {:name (:name client) + :address (:address client) + :signature-file (:signature-file client) + :bank {:name (:bank-account/bank-name bank-account) + :acct (:bank-account/bank-code bank-account) + :routing (:bank-account/routing bank-account) + :acct-number (:bank-account/number bank-account)}}})))] (-> [] (conj payment) @@ -269,6 +271,12 @@ (defmethod invoices->entities :payment-type/debit [invoices vendor client bank-account type index invoice-amounts] + (when (<= (->> invoices + (map (comp invoice-amounts :db/id)) + (reduce + 0.0)) + 0.001) + (throw (ex-info "The selected invoices do not have an outstanding balance." + {:validation-error "The selected invoices do not have an outstanding balance."}))) (let [payment (assoc (base-payment invoices vendor client bank-account type index invoice-amounts) :payment/type :payment-type/debit :payment/memo (str "Debit Invoice #'s: " @@ -281,7 +289,32 @@ (conj payment) (into (invoice-payments invoices invoice-amounts))))) +(defmethod invoices->entities :payment-type/credit [invoices vendor client bank-account type index invoice-amounts] + (when (>= (->> invoices + (map (comp invoice-amounts :db/id)) + (reduce + 0.0)) + 0.001) + (throw (ex-info "The selected invoices do not have an outstanding balance." + {:validation-error "The selected invoices do not have an outstanding balance."}))) + (let [payment (assoc (base-payment invoices vendor client bank-account type index invoice-amounts) + :payment/type :payment-type/credit + :payment/memo (str "Debit Invoice #'s: " + (str/join ", " + (map (fn [i] + (str (:invoice/invoice-number i) "(" (invoice-amounts (:db/id i)) ")")) + invoices))) + :payment/status :payment-status/pending)] + (-> [] + (conj payment) + (into (invoice-payments invoices invoice-amounts))))) + (defmethod invoices->entities :payment-type/cash [invoices vendor client bank-account type index invoice-amounts] + (when (<= (->> invoices + (map (comp invoice-amounts :db/id)) + (reduce + 0.0)) + 0.001) + (throw (ex-info "The selected invoices do not have an outstanding balance." + {:validation-error "The selected invoices do not have an outstanding balance."}))) (let [payment (assoc (base-payment invoices vendor client bank-account type index invoice-amounts) :payment/type :payment-type/cash :payment/memo (str "Cash Invoice #'s: " @@ -307,7 +340,7 @@ :client-id client-id :invoices (map :invoice/invoice-number invoices)})))) -(defn print-checks [invoice-payments client-id bank-account-id type id] +(defn print-checks-internal [invoice-payments client-id bank-account-id type id] (let [type (keyword "payment-type" (name type)) invoices (d-invoices/get-multi (map :invoice-id invoice-payments)) client (d-clients/get-by-id client-id) @@ -321,17 +354,6 @@ (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})))) - - _ (if (->> invoices-grouped-by-vendor - vals - (map (fn [payments] - (->> payments - (map (comp invoice-amounts :db/id)) - (reduce + 0.0)))) - (filter #(<= % 0.0)) - seq) - (throw (ex-info "The selected invoices do not have an outstanding balance." - {:validation-error "The selected invoices do not have an outstanding balance."}))) 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,3 +453,120 @@ (-> (d-checks/get-by-id id) (->graphql)))) + +(defn get-all-payments [context args value] + (assert-admin (:id context)) + (map + ->graphql + (first (d-checks/get-graphql (assoc (<-graphql args) :count Integer/MAX_VALUE))))) + +(defn print-checks [context args value] + + (assert-can-see-client (:id context) (:client_id args)) + (->graphql + (print-checks-internal (map (fn [i] {:invoice-id (:invoice_id i) + :amount (:amount i)}) + (:invoice_payments args)) + (:client_id args) + (:bank_account_id args) + (:type args) + (:id context)))) + +(def objects + {:payment {:fields {:id {:type :id} + :type {:type :payment_type} + :original_id {:type 'Int} + :amount {:type 'String} + :vendor {:type :vendor} + :client {:type :client} + :date {:type 'String} + :bank_account {:type :bank_account} + :memo {:type 'String} + :s3_url {:type 'String} + :check_number {:type 'Int} + :status {:type :ident} + :transaction {:type :transaction} + :invoices {:type '(list :invoice_payment)}}} + :invoice_payment + {:fields {:id {:type :id} + :amount {:type 'String} + :invoice_id {:type 'String} + :payment_id {:type 'String} + :payment {:type :payment} + :invoice {:type :invoice}}} + :payment_page {:fields {:payments {:type '(list :payment)} + :count {:type 'Int} + :total {:type 'Int} + :start {:type 'Int} + :end {:type 'Int}}}}) + +(def queries + {:all_payments {:type '(list :payment) + :args {:client_id {:type :id} + :client_code {:type 'String} + :original_id {:type 'Int} + :statuses {:type '(list String)}} + :resolve :get-all-payments} + :payment_page {:type '(list :payment_page) + :args {:client_id {:type :id} + :vendor_id {:type :id} + :payment_type {:type :payment_type} + :exact_match_id {:type :id} + :date_range {:type :date_range} + :amount_lte {:type :money} + :amount_gte {:type :money} + :check_number_like {:type 'String} + :invoice_number {:type 'String} + :start {:type 'Int} + :per_page {:type 'Int} + :sort {:type '(list :sort_item)}} + :resolve :get-payment-page} + :potential_payment_matches {:type '(list :payment) + :args {:transaction_id {:type :id}} + :resolve :get-potential-payments}}) + +(def mutations + {:print_checks {:type :check_result + :args {:invoice_payments {:type '(list :invoice_payment_amount)} + :bank_account_id {:type :id} + :type {:type :payment_type} + :client_id {:type :id}} + :resolve :mutation/print-checks} + :add_handwritten_check {:type :check_result + :args {:invoice_payments {:type '(list :invoice_payment_amount)} + :date {:type 'String} + :check_number {:type 'Int} + :bank_account_id {:type :id}} + :resolve :mutation/add-handwritten-check} + :void_payment {:type :payment + :args {:payment_id {:type :id}} + :resolve :mutation/void-payment}}) + +(def input-objects + {:invoice_payment_amount {:fields {:invoice_id {:type :id} + :amount {:type :money}}}}) + +(def enums + {:payment_type {:values [{:enum-value :check} + {:enum-value :cash} + {:enum-value :debit} + {:enum-value :credit}]}}) + +(def resolvers + {:get-potential-payments get-potential-payments + :get-payment-page get-payment-page + :get-all-payments get-all-payments + :mutation/void-payment void-check + :mutation/print-checks print-checks + :mutation/add-handwritten-check add-handwritten-check + }) + +(defn attach [schema] + (-> + (merge-with merge schema + {:objects objects + :queries queries + :mutations mutations + :input-objects input-objects + :enums enums}) + (attach-resolvers resolvers))) diff --git a/src/clj/auto_ap/import/intuit.clj b/src/clj/auto_ap/import/intuit.clj index d88e3f55..7af9851d 100644 --- a/src/clj/auto_ap/import/intuit.clj +++ b/src/clj/auto_ap/import/intuit.clj @@ -2,6 +2,7 @@ (:require [auto-ap.datomic :refer [conn]] [auto-ap.import.transactions :as t] + [auto-ap.time :as atime] [auto-ap.intuit.core :as i] [auto-ap.utils :refer [allow-once]] [clj-time.coerce :as coerce] @@ -10,7 +11,9 @@ [datomic.api :as d] [mount.core :as mount] [unilog.context :as lc] - [yang.scheduler :as scheduler])) + [yang.scheduler :as scheduler] + [clojure.string :as str] + [clojure.tools.logging :as log])) (defn get-intuit-bank-accounts [db] (d/q '[:find ?external-id ?ba ?c @@ -22,10 +25,18 @@ db)) (defn intuit->transaction [transaction] - {:transaction/description-original (:Memo/Description transaction) - :transaction/amount (Double/parseDouble (:Amount transaction)) - :transaction/date (coerce/to-date (auto-ap.time/parse (:Date transaction) auto-ap.time/iso-date)) - :transaction/status "POSTED"}) + (let [check-number (when (not (str/blank? (:Num transaction))) + (try + (Integer/parseInt (:Num transaction)) + (catch NumberFormatException e + (log/warn "Got an invalid check number " e) + nil)))] + (cond-> {:transaction/description-original (:Memo/Description transaction) + :transaction/amount (Double/parseDouble (:Amount transaction)) + :transaction/date (coerce/to-date (atime/parse (:Date transaction) atime/iso-date)) + :transaction/status "POSTED"} + check-number (assoc :transaction/check-number check-number)))) + (defn intuits->transactions [transactions bank-account-id client-id] (->> transactions diff --git a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs index 11b91250..ef754577 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -145,42 +145,49 @@ :class "is-primary"}] (when current-client - [drop-down {:header [:button.button.is-primary {:aria-haspopup true - :on-click (dispatch-event [::events/toggle-menu ::print-checks ]) - :disabled (or (status/disabled-for print-checks-status) (not (seq checked-invoices))) - :class (status/class-for @(re-frame/subscribe [::status/single ::print-checks]))} - "Pay " - (when (> (count checked-invoices )) - (str - (count checked-invoices) - " invoices " - "(" (->> checked-invoices - (map (comp js/parseFloat :outstanding-balance)) - (reduce + 0) - (gstring/format "$%.2f" )) - ")")) - [:span " "] - [:span.icon.is-small [:i.fa.fa-angle-down {:aria-hidden "true"}]]] - :id ::print-checks - :is-right? true} - [:div - (list - (for [{:keys [id number name type]} (->> (:bank-accounts current-client) (filter :visible) (sort-by :sort-order))] - (if (= :cash type) - ^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :cash]) - :disabled (status/disabled-for print-checks-status)} "With cash"] - (list - ^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::print-checks id :check]) - :disabled (doto (status/disabled-for print-checks-status) println)} "Print checks from " name] - ^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::print-checks id :debit]) - :disabled (status/disabled-for print-checks-status)} "Debit from " name]))) - ^{:key "advanced-divider"} [:hr.dropdown-divider] + (let [balance (->> checked-invoices + (map (comp js/parseFloat :outstanding-balance)) + (reduce + 0) + )] + [drop-down {:header [:button.button.is-primary {:aria-haspopup true + :on-click (dispatch-event [::events/toggle-menu ::print-checks ]) + :disabled (or (status/disabled-for print-checks-status) (not (seq checked-invoices))) + :class (status/class-for @(re-frame/subscribe [::status/single ::print-checks]))} + "Pay " + (when (> (count checked-invoices ) 0) + (str + (count checked-invoices) + " invoices " + "(" (gstring/format "$%.2f" balance ) ")")) + [:span " "] + [:span.icon.is-small [:i.fa.fa-angle-down {:aria-hidden "true"}]]] + :id ::print-checks + :is-right? true} + [:div + (list + (for [{:keys [id number name type]} (->> (:bank-accounts current-client) (filter :visible) (sort-by :sort-order))] + (if (= :cash type) + ^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :cash]) + :disabled (status/disabled-for print-checks-status)} "With cash"] + (if (> balance 0.001) + (list + ^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::print-checks id :check]) + :disabled (doto (status/disabled-for print-checks-status) println)} "Print checks from " name] + ^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::print-checks id :debit]) + :disabled (status/disabled-for print-checks-status)} "Debit from " name]) + (list + ^{:key (str id "-credit")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::print-checks id :credit]) + :disabled (status/disabled-for print-checks-status)} "Credit from " name])))) + (when (> balance 0.001) + ^{:key "advanced-divider"} [:hr.dropdown-divider]) - (when (= 1 (count (set (map (comp :id :vendor) checked-invoices)))) - ^{:key "handwritten"} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::handwritten-checks/show checked-invoices]) - :disabled (status/disabled-for print-checks-status)} "Handwritten Check..."]) - ^{:key "advanced"} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::advanced-print-checks/show checked-invoices]) - :disabled (status/disabled-for print-checks-status)} "Advanced..."])]])]] + (when (and (= 1 (count (set (map (comp :id :vendor) checked-invoices)))) + (> balance 0.001)) + ^{:key "handwritten"} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::handwritten-checks/show checked-invoices]) + :disabled (status/disabled-for print-checks-status)} "Handwritten Check..."]) + (when (> balance 0.001) + ^{:key "advanced"} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::advanced-print-checks/show checked-invoices]) + :disabled (status/disabled-for print-checks-status)} "Advanced..."]))]]))]] [:div.is-pulled-right {:style {:margin-right "0.5rem"}} (into [:div.tags ] (map (fn [{:keys [id invoice-number]}] [:span.tag.is-medium invoice-number