added the ability to credit invoices. Also made it so check numbers pop up for intuit even if they're not in the description.
This commit is contained in:
@@ -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)))
|
||||
|
||||
Reference in New Issue
Block a user