diff --git a/src/clj/auto_ap/datomic/invoices.clj b/src/clj/auto_ap/datomic/invoices.clj index b0cdd7f5..44b5a013 100644 --- a/src/clj/auto_ap/datomic/invoices.clj +++ b/src/clj/auto_ap/datomic/invoices.clj @@ -11,18 +11,26 @@ (update-in [:query :where] conj where))] (reduce #(update-in %1 [:query :where] conj %2) query rest))) +(def default-read '(pull ?e [* + {:invoice/client [:client/name :db/id]} + {:invoice/vendor [:vendor/name :db/id]} + {:invoice/status [:db/ident]} + {:invoice-payment/_invoice [* {:invoice-payment/payment [*]}]}])) + +(defn <-datomic [x] + (->> x + (map first) + + (map #(update % :invoice/date c/from-date)) + (map #(update % :invoice/status :db/ident)) + (map #(rename-keys % {:invoice-payment/_invoice :invoice/payments})))) + (defn raw-graphql [args] (->> (d/query - (cond-> (doto {:query {:find ['(pull ?e [* - {:invoice/client [:client/name :db/id]} - {:invoice/vendor [:vendor/name :db/id]} - {:invoice/status [:db/ident]} - {:invoice-payment/_invoice [* {:invoice-payment/payment [*]}]}])] - :in ['$] - :where ['[?e :invoice/original-id] - ]} - :args [(d/db (d/connect uri))]} - println) + (cond-> {:query {:find [default-read] + :in ['$] + :where ['[?e :invoice/invoice-number]]} + :args [(d/db (d/connect uri))]} (:client-id args) (add-arg '?client-id (cond-> (:client-id args) (string? (:client-id args)) @@ -34,13 +42,7 @@ '[?c :client/original-id ?original-id]) (:status args) (add-arg '?status (keyword "invoice-status" (:status args)) '[?e :invoice/status ?status]))) - (map first) - - (map #(update % :invoice/date c/from-date)) - (map #(update % :invoice/status :db/ident)) - (map #(rename-keys % {:invoice-payment/_invoice :invoice/payments})) - - #_(map #(update % :transaction/post-date c/from-date)))) + (<-datomic))) (defn sort-fn [args] (cond @@ -65,3 +67,23 @@ (->> (raw-graphql args) (count))) + +(defn get-by-id [id] + (->> + (d/query (-> {:query {:find [default-read] + :in ['$] + :where []} + :args [(d/db (d/connect uri))]} + (add-arg '?e (cond-> id (string? id) Long/parseLong) ['?e]))) + (<-datomic) + (first))) + +(defn find-conflicting [{:keys [:invoice/invoice-number :invoice/vendor :invoice/client]}] + (->> (d/query + (cond-> {:query {:find [default-read] + :in ['$ '?invoice-number '?vendor '?client] + :where ['[?e :invoice/invoice-number ?invoice-number] + '[?e :invoice/vendor ?vendor] + '[?e :invoice/client ?client]]} + :args [(d/db (d/connect uri)) invoice-number (Long/parseLong vendor) (Long/parseLong client)]})) + (<-datomic))) diff --git a/src/clj/auto_ap/datomic/vendors.clj b/src/clj/auto_ap/datomic/vendors.clj index 4b391dff..df17baba 100644 --- a/src/clj/auto_ap/datomic/vendors.clj +++ b/src/clj/auto_ap/datomic/vendors.clj @@ -14,3 +14,19 @@ (map (fn [ba] (update ba :bank-account/type :db/ident )) bas))))))) + +(defn get-by-id [id] + + (->> (d/q '[:find (pull ?e [*]) + :in $ ?e + :where [?e]] + (d/db (d/connect uri)) + (Long/parseLong id)) + (map first) + (first) + #_(map (fn [c] + (update c :client/bank-accounts + (fn [bas] + (map (fn [ba] + (update ba :bank-account/type :db/ident )) + bas))))))) diff --git a/src/clj/auto_ap/graphql.clj b/src/clj/auto_ap/graphql.clj index 2d4aa089..9500e66d 100644 --- a/src/clj/auto_ap/graphql.clj +++ b/src/clj/auto_ap/graphql.clj @@ -273,12 +273,12 @@ :amount {:type 'String}}} :add_invoice - {:fields {:id {:type 'Int} + {:fields {:id {:type 'String} :invoice_number {:type 'String} :location {:type 'String} :date {:type 'String} - :company_id {:type 'Int} - :vendor_id {:type 'Int} + :client_id {:type 'String} + :vendor_id {:type 'String} :vendor_name {:type 'String} :total {:type 'Float}}} @@ -316,9 +316,9 @@ :void_invoice {:type :invoice :args {:invoice_id {:type 'Int}} :resolve :mutation/void-invoice} - :void_check {:type :payment + :void_payment {:type :payment :args {:payment_id {:type 'String}} - :resolve :mutation/void-check} + :resolve :mutation/void-payment} :edit_expense_accounts {:type :invoice :args {:invoice_id {:type 'Int} :expense_accounts {:type '(list :edit_expense_account)}} @@ -483,7 +483,7 @@ :mutation/add-invoice gq-invoices/add-invoice :mutation/edit-invoice gq-invoices/edit-invoice :mutation/void-invoice gq-invoices/void-invoice - :mutation/void-check gq-checks/void-check + :mutation/void-payment gq-checks/void-check :mutation/edit-expense-accounts gq-invoices/edit-expense-accounts :get-vendor get-vendor :get-expense-account expense-accounts/get-expense-account diff --git a/src/clj/auto_ap/graphql/invoices.clj b/src/clj/auto_ap/graphql/invoices.clj index 34d4e827..560ca98f 100644 --- a/src/clj/auto_ap/graphql/invoices.clj +++ b/src/clj/auto_ap/graphql/invoices.clj @@ -2,40 +2,48 @@ (:require [auto-ap.graphql.utils :refer [->graphql assert-can-see-company]] [auto-ap.db.invoices :as invoices] [auto-ap.db.vendors :as vendors] + [auto-ap.datomic.vendors :as d-vendors] + [auto-ap.datomic.invoices :as d-invoices] [auto-ap.db.companies :as companies] [auto-ap.db.invoices-expense-accounts :as invoices-expense-accounts] [auto-ap.expense-accounts :as expense-accounts] - [auto-ap.time :refer [parse iso-date]])) + [auto-ap.time :refer [parse iso-date]] + [datomic.api :as d] + [auto-ap.datomic :refer [uri]] + [clj-time.coerce :as coerce])) (defn -create-or-get-vendor [vendor-id vendor-name] (if vendor-id (vendors/get-by-id vendor-id) (vendors/insert {:name vendor-name :default-expense-account 0}))) -(defn add-invoice [context {{:keys [total invoice_number location company_id vendor_id vendor_name date] :as in} :invoice} value] - (when (seq (invoices/find-conflicting {:invoice-number invoice_number - :vendor-id vendor_id - :company-id company_id})) +(defn add-invoice [context {{:keys [total invoice_number location client_id vendor_id vendor_name date] :as in} :invoice} value] + (when (seq (d-invoices/find-conflicting {:invoice/invoice-number invoice_number + :invoice/vendor vendor_id + :invoice/client client_id})) (throw (ex-info (str "Invoice '" invoice_number "' already exists.") {:invoice-number invoice_number}))) - (let [vendor (-create-or-get-vendor vendor_id vendor_name) - _ (assert-can-see-company (:id context) company_id) - _ (when-not (:default-expense-account vendor) - (throw (ex-info (str "Vendor '" (:name vendor) "' does not have a default expense acount.") {:vendor-id vendor_id} ))) - company (companies/get-by-id company_id) - - [invoice] (invoices/insert-multi! [{:invoice-number invoice_number - :company-id company_id - :vendor-id (:id vendor) - :total total - :outstanding-balance total - :status "unpaid" - :imported true - :date (parse date iso-date)}])] - (invoices-expense-accounts/replace-for-invoice - (:id invoice) [{:expense-account-id (:default-expense-account vendor) - :location (get-in expense-accounts/expense-accounts [(:default-expense-account vendor) :location] location) - :amount total}] ) - (-> invoice + (let [_ (assert-can-see-company (:id context) client_id) + vendor (d-vendors/get-by-id vendor_id) + + expense-account-id (:vendor/default-expense-account vendor) + _ (when-not expense-account-id + (throw (ex-info (str "Vendor '" (:vendor/name vendor) "' does not have a default expense acount.") {:vendor-id vendor_id} ))) + transaction [{:db/id "invoice" + :invoice/invoice-number invoice_number + :invoice/client (Long/parseLong client_id) + :invoice/vendor (Long/parseLong vendor_id) + :invoice/total total + :invoice/outstanding-balance total + :invoice/status :invoice-status/unpaid + :invoice/date (coerce/to-date date) + :invoice/expense-accounts [{:invoice-expense-account/expense-account-id expense-account-id + :invoice-expense-account/location (get-in expense-accounts/expense-accounts [expense-account-id :location] location) + :invoice-expense-account/amount total}]}] + transaction-result @(d/transact (d/connect uri) transaction) + ] + + + (-> (d-invoices/get-by-id (get-in transaction-result [:tempids "invoice"])) (->graphql)))) @@ -66,9 +74,7 @@ (->graphql)))) -(defn get-invoices-expense-accounts [context args value] - (->graphql - (invoices-expense-accounts/get-for-invoice (:id value)))) + (defn edit-expense-accounts [context args value] (assert-can-see-company (:id context) (:company-id (invoices/get-by-id (:invoice_id args)))) diff --git a/src/cljc/auto_ap/entities/invoice.cljc b/src/cljc/auto_ap/entities/invoice.cljc index 4cd5d85b..11a04bca 100644 --- a/src/cljc/auto_ap/entities/invoice.cljc +++ b/src/cljc/auto_ap/entities/invoice.cljc @@ -2,14 +2,14 @@ (:require [clojure.spec.alpha :as s] [auto-ap.entities.shared :as shared])) -(s/def ::vendor-id int?) +(s/def ::vendor-id string?) (s/def ::vendor-name string?) -(s/def ::company-id int?) +(s/def ::client-id string?) (s/def ::invoice-number ::shared/required-identifier) (s/def ::date ::shared/date) (s/def ::total ::shared/money) -(s/def ::invoice (s/keys :req-un [::company-id +(s/def ::invoice (s/keys :req-un [::client-id ::invoice-number ::date ::vendor-id diff --git a/src/cljs/auto_ap/views/pages/checks.cljs b/src/cljs/auto_ap/views/pages/checks.cljs index 0c61d7ff..432b2b19 100644 --- a/src/cljs/auto_ap/views/pages/checks.cljs +++ b/src/cljs/auto_ap/views/pages/checks.cljs @@ -17,9 +17,9 @@ (re-frame/reg-sub - ::check-page + ::payment-page (fn [db] - (-> db ::check-page))) + (-> db ::payment-page))) (re-frame/reg-sub ::params @@ -44,33 +44,33 @@ (re-frame/reg-event-fx ::void-check - (fn [{:keys [db]} [_ check]] + (fn [{:keys [db]} [_ payment]] {:graphql {:token (-> db :user) :query-obj {:venia/operation {:operation/type :mutation - :operation/name "VoidCheck"} + :operation/name "VoidPayment"} - :venia/queries [{:query/data [:void-check - {:payment-id (:id check)} + :venia/queries [{:query/data [:void-payment + {:payment-id (:id payment)} [:id :status :amount :check_number :s3_url :date [:vendor [:name :id]] [:client [:name :id]]]]}]} - :on-success [::check-voided]}})) + :on-success [::payment-voided]}})) (re-frame/reg-event-db - ::check-voided - (fn [db [_ {:keys [void-check]}]] + ::payment-voided + (fn [db [_ {:keys [void-payment]}]] (-> db - (update-in [::check-page :payments] (fn [checks] + (update-in [::payment-page :payments] (fn [payments] (mapv (fn [c] - (if (= (:id c) (:id void-check)) - (assoc void-check :class "live-removed") + (if (= (:id c) (:id void-payment)) + (assoc void-payment :class "live-removed") c)) - checks)))))) + payments)))))) (re-frame/reg-event-db ::received (fn [db [_ data]] (-> db - (assoc ::check-page (first (:payment-page data))) + (assoc ::payment-page (first (:payment-page data))) (assoc-in [:status :loading] false)))) (re-frame/reg-event-fx @@ -78,15 +78,15 @@ (fn [cofx [_ params]] {:dispatch [::params-change @(re-frame/subscribe [::params])]})) -(defn check-table [{:keys [id check-page status on-params-change vendors params check-boxes checked on-check-changed expense-event]}] +(defn check-table [{:keys [id payment-page status on-params-change vendors params check-boxes checked on-check-changed expense-event]}] (let [state (reagent/atom (or @params {})) selected-company @(re-frame/subscribe [::subs/company]) opc (fn [p] (swap! state merge p) (on-params-change p))] - (fn [{:keys [id check-page status on-params-change vendors checked]}] + (fn [{:keys [id payment-page status on-params-change vendors checked]}] (let [{:keys [sort-by asc]} @state - {:keys [payments start end count total]} @check-page + {:keys [payments start end count total]} @payment-page selected-company @(re-frame/subscribe [::subs/company]) percentage-size (if selected-company "50%" "33%")] [:div @@ -147,7 +147,7 @@ [:tr [:td {:col-span 5} [:i.fa.fa-spin.fa-spinner]]] - (for [{:keys [client s3-url payments type check-number date amount id vendor status] :as i} (:payments @check-page)] + (for [{:keys [client s3-url payments type check-number date amount id vendor status] :as i} (:payments @payment-page)] ^{:key id} [:tr {:class (:class i)} @@ -179,9 +179,9 @@ (let [current-company @(re-frame/subscribe [::subs/company])] [:div [:h1.title "Checks"] - [check-table {:id :checks + [check-table {:id :payments :params (re-frame/subscribe [::params]) - :check-page (re-frame/subscribe [::check-page]) + :payment-page (re-frame/subscribe [::payment-page]) :status (re-frame/subscribe [::subs/status]) :on-params-change (fn [params] (re-frame/dispatch [::params-change params]))}]])) diff --git a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs index a9d1abcc..811a9cff 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -237,7 +237,7 @@ ::new-invoice (fn [{:keys [db]} _] {:dispatch [::events/modal-status ::new-invoice {:visible? true}] - :db (assoc-in db [::new-invoice] {:company-id (:id @(re-frame/subscribe [::subs/company])) + :db (assoc-in db [::new-invoice] {:client-id (:id @(re-frame/subscribe [::subs/company])) :date (date->str (c/now) standard) :location (first (:locations @(re-frame/subscribe [::subs/company])))})})) @@ -261,7 +261,7 @@ :venia/queries [{:query/data [:add-invoice {:invoice new-invoice} [:id :total :outstanding-balance :date :invoice-number - [:company [:id :name :locations]] + [:client [:id :name :locations]] [:vendor [:id :name]] [:expense_accounts [:amount :id :expense_account_id :location @@ -645,7 +645,7 @@ (defn new-invoice-modal [] (let [data @(re-frame/subscribe [::new-invoice]) change-event [::events/change-form [::new-invoice]] - locations (get-in @(re-frame/subscribe [::subs/companies-by-id]) [(:company-id data) :locations]) + locations (get-in @(re-frame/subscribe [::subs/companies-by-id]) [(:client-id data) :locations]) should-select-location? (and locations (> (count locations) 1))] [action-modal {:id ::new-invoice @@ -656,13 +656,13 @@ (when-not @(re-frame/subscribe [::subs/company]) [horizontal-field - [:label.label "Company"] + [:label.label "Client"] [bind-field [typeahead {:matches (map (fn [x] [(:id x) (:name x)]) @(re-frame/subscribe [::subs/companies])) :type "typeahead" - :field [:company-id] + :field [:client-id] :event [::change-new-invoice-company [::new-invoice]] - :spec ::invoice/company-id + :spec ::invoice/client-id :subscription data}]]]) (when should-select-location? [horizontal-field