now all payments can go through datomic, but pdfs need work.
This commit is contained in:
@@ -34,6 +34,24 @@
|
||||
result
|
||||
nil)))
|
||||
|
||||
(def functions
|
||||
[{:db/ident :pay
|
||||
:db/doc "Data function that increments value of attribute a by amount."
|
||||
:db/fn #db/fn {:lang "clojure"
|
||||
:params [db e amount]
|
||||
:code (let [current-outstanding-balance (-> (d/entity db e) :invoice/outstanding-balance)
|
||||
new-outstanding-balance (- current-outstanding-balance amount)]
|
||||
[[:db/add e :invoice/outstanding-balance new-outstanding-balance]
|
||||
[:db/add e :invoice/status (if (> new-outstanding-balance 0)
|
||||
:invoice-status/unpaid
|
||||
:invoice-status/paid)]])}}
|
||||
{:db/ident :inc
|
||||
:db/doc "Data function that increments value of attribute a by amount."
|
||||
:db/fn #db/fn {:lang "clojure"
|
||||
:params [db e a amount]
|
||||
:code [[:db/add e a
|
||||
(-> (d/entity db e) a (+ amount))]]}}] )
|
||||
|
||||
(def vendor-schema
|
||||
[{:db/ident :vendor/original-id
|
||||
:db/valueType :db.type/long
|
||||
@@ -512,7 +530,7 @@
|
||||
|
||||
(defn create-schema []
|
||||
(->>
|
||||
(concat address-schema contact-schema vendor-schema client-schema bank-account-schema invoice-schema invoice-expense-account-schema payment-schema invoice-payment-schema transaction-schema user-schema)
|
||||
(concat address-schema contact-schema vendor-schema client-schema bank-account-schema invoice-schema invoice-expense-account-schema payment-schema invoice-payment-schema transaction-schema user-schema functions)
|
||||
|
||||
(d/transact (d/connect uri))))
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
(map first)
|
||||
(map #(update % :payment/date c/from-date))
|
||||
(map #(update % :payment/status :db/ident))
|
||||
(map #(update % :payment/type :db/ident))
|
||||
(map #(rename-keys % {:invoice-payment/_payment :payment/invoices}))))
|
||||
|
||||
(defn add-arg [query name value where & rest]
|
||||
@@ -22,12 +23,13 @@
|
||||
{:invoice-payment/_payment [* {:invoice-payment/invoice [*]}]}
|
||||
{:payment/client [:client/name :db/id]}
|
||||
{:payment/vendor [:vendor/name :db/id]}
|
||||
{:payment/status [:db/ident]}]))
|
||||
{:payment/status [:db/ident]}
|
||||
{:payment/type [:db/ident]}]))
|
||||
|
||||
(defn raw-graphql [args]
|
||||
(let [query (cond-> {:query {:find [default-read]
|
||||
:in ['$]
|
||||
:where ['[?e :payment/original-id]]}
|
||||
:where ['[?e :payment/client]]}
|
||||
:args [(d/db (d/connect uri))]}
|
||||
|
||||
(:client-id args) (add-arg '?client-id (cond-> (:client-id args) (string? (:client-id args)) Long/parseLong )
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
:bank_account
|
||||
{:fields {:id {:type 'String}
|
||||
:type {:type 'String}
|
||||
:type {:type :bank_account_type}
|
||||
:number {:type 'String}
|
||||
:check_number {:type 'Int}
|
||||
:name {:type 'String}
|
||||
@@ -110,7 +110,7 @@
|
||||
}}
|
||||
|
||||
:payment {:fields {:id {:type 'String}
|
||||
:type {:type 'String}
|
||||
:type {:type :payment_type}
|
||||
:amount {:type 'String}
|
||||
:vendor {:type :vendor}
|
||||
:client {:type :client}
|
||||
@@ -287,11 +287,16 @@
|
||||
:date {:type 'String}
|
||||
:total {:type 'Float}}}}
|
||||
|
||||
:enums {:payment_type {:values [{:enum-value :check}
|
||||
{:enum-value :cash}
|
||||
{:enum-value :debit}]}
|
||||
:bank_account_type {:values [{:enum-value :check}
|
||||
{:enum-value :cash}]}}
|
||||
:mutations
|
||||
{:print_checks {:type :check_result
|
||||
:args {:invoice_payments {:type '(list :invoice_payment_amount)}
|
||||
:bank_account_id {:type 'String}
|
||||
:type {:type 'String}
|
||||
:type {:type :payment_type}
|
||||
:client_id {:type 'String}}
|
||||
:resolve :mutation/print-checks}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns auto-ap.graphql.checks
|
||||
(:require [auto-ap.graphql.utils :refer [->graphql <-graphql assert-can-see-company]]
|
||||
[datomic.api :as d]
|
||||
[clojure.edn :as edn]
|
||||
|
||||
[com.walmartlabs.lacinia :refer [execute]]
|
||||
[com.walmartlabs.lacinia.executor :as executor]
|
||||
@@ -26,6 +27,7 @@
|
||||
[clojure.string :as str]
|
||||
[clj-pdf.core :as pdf]
|
||||
[clj-time.format :as f]
|
||||
[clj-time.coerce :as c]
|
||||
[clj-time.core :as time]
|
||||
[clojure.java.io :as io])
|
||||
(:import [java.text DecimalFormat]
|
||||
@@ -61,16 +63,17 @@
|
||||
(let [output-stream (ByteArrayOutputStream.)]
|
||||
(pdf/pdf
|
||||
[{:left-margin 25 :right-margin 0 :top-margin 0 :bottom-margin 0 :size :letter}
|
||||
(let [{:keys [paid-to company check date amount memo] {print-as :print-as vendor-name :name :as vendor} :vendor} check
|
||||
(let [{:keys [paid-to client check date amount memo] {print-as :vendor/print-as vendor-name :vendor/name :as vendor} :vendor} check
|
||||
_ (println "VENDOR" vendor)
|
||||
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 [name bank] {:keys [street1 street2 city state zip ]} :address} company]
|
||||
[(let [{:keys [name bank] {:keys [street1 street2 city state zip ]} :address} client]
|
||||
[:cell {:colspan 3 } [:paragraph {:leading 14} name "\n" street1 "\n" (str city ", " state " " zip)] ])
|
||||
(let [{{:keys [name acct]} :bank} company]
|
||||
(let [{{:keys [name acct]} :bank} client]
|
||||
[:cell {:colspan 7 :align :center} [:paragraph {:style :bold} name] [:paragraph {:size 8 :leading 8} acct]])
|
||||
[:cell {:colspan 2 :size 13}
|
||||
check]]
|
||||
@@ -100,10 +103,10 @@
|
||||
[[:cell {:size 9 :leading 11.5} "\n\n\n\n\nMEMO"]
|
||||
[:cell {:colspan 5 :leading 11.5} (split-memo memo)
|
||||
[:line {:line-width 0.15 :color [50 50 50]}]]
|
||||
[:cell {:colspan 6 } (if (:signature-file company)
|
||||
[:cell {:colspan 6 } (if (:signature-file client)
|
||||
[:image { :top-margin 90 :xscale 0.30 :yscale 0.30 :align :center}
|
||||
|
||||
(:signature-file company)]
|
||||
(:signature-file client)]
|
||||
[:spacer])]]
|
||||
|
||||
#_[
|
||||
@@ -112,7 +115,7 @@
|
||||
|
||||
[[:cell {:colspan 2}]
|
||||
[:cell {:colspan 10 :leading 30}
|
||||
[:phrase {:size 18 :ttf-name "public/micrenc.ttf"} (str "c" check "c a" (:routing (:bank company)) "a " (:acct-number (:bank company)) "c")]]]
|
||||
[:phrase {:size 18 :ttf-name "public/micrenc.ttf"} (str "c" check "c a" (:routing (:bank client)) "a " (:acct-number (:bank client)) "c")]]]
|
||||
|
||||
[[:cell {:colspan 12 :leading 18} [:spacer]]]
|
||||
|
||||
@@ -120,7 +123,7 @@
|
||||
(into
|
||||
[:cell {:colspan 9}]
|
||||
(let [{:keys [name]
|
||||
{:keys [street1 city state zip bank]} :address} company]
|
||||
{:keys [street1 city state zip bank]} :address} client]
|
||||
(list
|
||||
[:paragraph " " name]
|
||||
[:paragraph " " street1]
|
||||
@@ -134,8 +137,8 @@
|
||||
[[:cell]
|
||||
[:cell {:colspan 5} [:paragraph
|
||||
" " vendor-name "\n"
|
||||
" " (:street1 (:address vendor)) "\n"
|
||||
" " (:city (:address vendor)) ", " (:state (:address vendor)) " " (:zip (:address vendor))]]
|
||||
" " (:address/street1 (:vendor/address vendor)) "\n"
|
||||
" " (:address/city (:vendor/address vendor)) ", " (:address/state (:vendor/address vendor)) " " (:address/zip (:vendor/address vendor))]]
|
||||
[:cell {:align :right}
|
||||
"Paid to:\n"
|
||||
"Amount:\n"
|
||||
@@ -166,7 +169,7 @@
|
||||
[:cell {:colspan 5}
|
||||
[:paragraph check]
|
||||
[:paragraph vendor-name]
|
||||
[:paragraph (:name (:bank company))]
|
||||
[:paragraph (:name (:bank client))]
|
||||
[:paragraph paid-to]
|
||||
[:paragraph amount]
|
||||
[:paragraph date]]]
|
||||
@@ -180,9 +183,12 @@
|
||||
(loop [[check & checks] checks]
|
||||
(when check
|
||||
(s3/put-object :bucket-name (:data-bucket env)
|
||||
:key (:s3-key check)
|
||||
:key (:payment/s3-key check)
|
||||
:input-stream (-> check
|
||||
:pdf-data
|
||||
:payment/pdf-data
|
||||
(edn/read-string)
|
||||
|
||||
|
||||
make-check-pdf
|
||||
(io/make-input-stream {}))
|
||||
:metadata {:content-type "application/pdf"})
|
||||
@@ -203,94 +209,104 @@
|
||||
|
||||
|
||||
|
||||
(defmulti check-for-invoices (fn [invoices vendor-id vendors company bank-account type index invoice-amounts]
|
||||
(defmulti invoices->entities (fn [invoices vendor-id client bank-account type index invoice-amounts]
|
||||
type))
|
||||
(defn invoice-payments [invoices invoice-amounts]
|
||||
(->> (for [invoice invoices
|
||||
:let [invoice-amount (invoice-amounts (:db/id invoice))]]
|
||||
[{:invoice-payment/payment (-> invoice :invoice/vendor :db/id)
|
||||
:invoice-payment/amount invoice-amount
|
||||
:invoice-payment/invoice (:db/id invoice)}
|
||||
[:pay (:db/id invoice) invoice-amount]])
|
||||
(reduce into [])))
|
||||
|
||||
(defmethod check-for-invoices "check" [invoices vendor-id vendors company bank-account type index invoice-amounts]
|
||||
(defn base-payment [invoices vendor-id client bank-account type index invoice-amounts]
|
||||
{:db/id (str vendor-id)
|
||||
:payment/bank-account (:db/id bank-account)
|
||||
:payment/amount (reduce + 0 (map (comp invoice-amounts :db/id) invoices))
|
||||
:payment/vendor vendor-id
|
||||
:payment/client (:db/id client)
|
||||
:payment/date (c/to-date (time/now))
|
||||
: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))
|
||||
vendor (vendors vendor-id)
|
||||
|
||||
|
||||
memo (str "Invoice #'s: "
|
||||
(str/join ", "
|
||||
(map (fn [i]
|
||||
(str (:invoice/invoice-number i) "(" (invoice-amounts (:db/id i)) ")"))
|
||||
invoices)))]
|
||||
invoices)))
|
||||
payment (assoc (base-payment invoices vendor client bank-account type index invoice-amounts)
|
||||
:payment/s3-uuid uuid
|
||||
:payment/s3-key (str "checks/" uuid ".pdf")
|
||||
:payment/s3-url (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 {: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)}}}))]
|
||||
|
||||
{:payment/s3-uuid uuid
|
||||
:payment/s3-key (str "checks/" uuid ".pdf")
|
||||
:payment/s3-url (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/bank-account (:db/id bank-account)
|
||||
:payment/amount (reduce + 0 (map (comp invoice-amounts :db/id) invoices))
|
||||
:payment/memo memo
|
||||
:payment/vendor (:db/id vendor)
|
||||
:payment/client (:db/id company)
|
||||
:payment/date (time/now)
|
||||
#_#_:payment/pdf-data {: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))
|
||||
:company {:name (:name company)
|
||||
:address (:address company)
|
||||
:signature-file (:signature-file company)
|
||||
: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)}}}
|
||||
|
||||
:payment/invoices (map :db/id invoices)}))
|
||||
(-> []
|
||||
(conj payment)
|
||||
(conj [:inc (:db/id bank-account) :bank-account/check-number 1])
|
||||
(into (invoice-payments invoices invoice-amounts)))))
|
||||
|
||||
(defmethod check-for-invoices "debit" [invoices vendor-id vendors company bank-account type index invoice-amounts]
|
||||
(let [vendor (vendors vendor-id)]
|
||||
{:type "debit"
|
||||
:bank-account-id (:db/id bank-account)
|
||||
:amount (reduce + 0 (map (comp invoice-amounts :db/id) invoices))
|
||||
:status "cleared"
|
||||
:memo "Debit"
|
||||
:vendor-id (:db/id vendor)
|
||||
:client-id (:db/id company)
|
||||
:date (time/now)
|
||||
:invoices (map :db/id invoices)}))
|
||||
(defmethod invoices->entities :payment-type/debit [invoices vendor client bank-account type index invoice-amounts]
|
||||
(let [payment (assoc (base-payment invoices vendor client bank-account type index invoice-amounts)
|
||||
:payment/type :payment-type/debit
|
||||
:payment/memo "Debit"
|
||||
:payment/status :payment-status/cleared)]
|
||||
(-> []
|
||||
(conj payment)
|
||||
(into (invoice-payments invoices invoice-amounts)))))
|
||||
|
||||
(defmethod check-for-invoices "cash" [invoices vendor-id vendors company bank-account type index invoice-amounts]
|
||||
(let [vendor (vendors vendor-id)]
|
||||
{:type "cash"
|
||||
:bank-account-id (:db/id bank-account)
|
||||
:amount (reduce + 0 (map (comp invoice-amounts :db/id) invoices))
|
||||
:status "cleared"
|
||||
:memo "Cash"
|
||||
:vendor-id (:db/id vendor)
|
||||
:client-id (:db/id company)
|
||||
:date (time/now)
|
||||
:invoices (map :db/id invoices)}))
|
||||
(defmethod invoices->entities :payment-type/cash [invoices vendor client bank-account type index invoice-amounts]
|
||||
(let [payment (assoc (base-payment invoices vendor client bank-account type index invoice-amounts)
|
||||
:payment/type :payment-type/cash
|
||||
:payment/memo "Cash"
|
||||
:payment/status :payment-status/cleared)]
|
||||
(-> []
|
||||
(conj payment)
|
||||
(into (invoice-payments invoices invoice-amounts)))))
|
||||
|
||||
(defn print-checks [invoice-payments client-id bank-account-id type]
|
||||
|
||||
(let [client-id (Long/parseLong client-id)
|
||||
(let [type (keyword "payment-type" (name type))
|
||||
client-id (Long/parseLong client-id)
|
||||
bank-account-id (Long/parseLong bank-account-id)
|
||||
invoices (d-invoices/get-multi (map :invoice-id invoice-payments))
|
||||
client (d-clients/get-by-id client-id)
|
||||
vendors (by :db/id (d-vendors/get-graphql {}))
|
||||
|
||||
invoice-amounts (by (comp #(Long/parseLong %) :invoice-id) :amount invoice-payments)
|
||||
invoices-grouped-by-vendor (group-by (comp :db/id :invoice/vendor) invoices)
|
||||
|
||||
bank-account (d-bank-accounts/get-by-id bank-account-id)
|
||||
checks (-> (for [[[vendor-id invoices] index] (map vector invoices-grouped-by-vendor (range))]
|
||||
[invoices (check-for-invoices invoices vendor-id vendors client bank-account type index invoice-amounts)])
|
||||
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 [])
|
||||
doall)]
|
||||
|
||||
(clojure.pprint/pprint checks)
|
||||
@(d/transact (d/connect uri) (map second checks))
|
||||
(when (= type :payment-type/check)
|
||||
(make-pdfs (filter #(= :payment-type/check (:payment/type %)) checks)))
|
||||
@(d/transact (d/connect uri) checks)
|
||||
|
||||
|
||||
{:invoices [] #_(invoices/get-multi (map :id (mapcat first checks)))
|
||||
:pdf-url nil #_(if (= type "check")
|
||||
(merge-pdfs (map (comp :s3-key second) checks))
|
||||
nil)}))
|
||||
{:invoices []
|
||||
:pdf-url (if (= type :payment-type/check)
|
||||
(merge-pdfs (filter identity (map :payment/s3-key checks)))
|
||||
nil)}))
|
||||
|
||||
(defn get-payment-page [context args value]
|
||||
(let [args (assoc args :id (:id context))
|
||||
|
||||
@@ -155,8 +155,8 @@
|
||||
[:td (:name client)])
|
||||
[:td (:name vendor)]
|
||||
[:td (cond
|
||||
(= "cash" type) "Cash"
|
||||
(= "debit" type) "Debit"
|
||||
(= :cash type) "Cash"
|
||||
(= :debit type) "Debit"
|
||||
:else check-number)]
|
||||
[:td (date->str date) ]
|
||||
[:td (gstring/format "$%.2f" amount )]
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
(re-frame/reg-event-fx
|
||||
::print-checks
|
||||
(fn [{:keys [db]} [_ bank-account-id type]]
|
||||
(println type)
|
||||
(let [invoice-amounts (by :id :outstanding-balance (get-in db [::invoice-page :invoices]))]
|
||||
|
||||
{:db (-> db
|
||||
@@ -203,7 +204,13 @@
|
||||
:amount (invoice-amounts (:id x))})
|
||||
(get-in db [::advanced-print-checks :invoices]))
|
||||
bank-account-id
|
||||
(or type "check")
|
||||
(cond (= type :check)
|
||||
:check
|
||||
(= type :cash)
|
||||
:cash
|
||||
|
||||
:else
|
||||
:check)
|
||||
(:company db))
|
||||
|
||||
:on-success [::checks-created]}})))
|
||||
@@ -809,11 +816,11 @@
|
||||
[:div.dropdown-content
|
||||
(list
|
||||
(for [{:keys [id number name type]} (:bank-accounts current-company)]
|
||||
(if (= "cash" type)
|
||||
^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id "cash"])} "With cash"]
|
||||
(if (= :cash type)
|
||||
^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :cash])} "With cash"]
|
||||
(list
|
||||
^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id "check"])} "Print checks from " name]
|
||||
^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id "debit"])} "Debit from " name])))
|
||||
^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :check])} "Print checks from " name]
|
||||
^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :debit])} "Debit from " name])))
|
||||
^{:key "advanced-divider"} [:hr.dropdown-divider]
|
||||
|
||||
(when (= 1 (count checked))
|
||||
|
||||
Reference in New Issue
Block a user