Files
integreat/src/clj/auto_ap/graphql.clj
2019-05-12 20:31:28 -07:00

852 lines
35 KiB
Clojure

(ns auto-ap.graphql
(:require
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
[com.walmartlabs.lacinia.schema :as schema]
[com.walmartlabs.lacinia :refer [execute]]
[com.walmartlabs.lacinia.executor :as executor]
[com.walmartlabs.lacinia.resolve :as resolve]
[buddy.auth :refer [throw-unauthorized]]
[auto-ap.utils :refer [by]]
[auto-ap.graphql.utils :refer [assert-admin can-see-client? assert-can-see-client]]
[auto-ap.datomic :refer [uri merge-query]]
[datomic.api :as d]
[clj-time.coerce :as coerce]
[auto-ap.datomic.clients :as d-clients]
[auto-ap.datomic.checks :as d-checks]
[auto-ap.datomic.users :as d-users]
[auto-ap.datomic.invoices :as d-invoices]
[auto-ap.datomic.vendors :as d-vendors]
[auto-ap.graphql.users :as gq-users]
[auto-ap.graphql.ledger :as gq-ledger]
[auto-ap.graphql.accounts :as gq-accounts]
[auto-ap.graphql.clients :as gq-clients]
[auto-ap.graphql.vendors :as gq-vendors]
[auto-ap.graphql.checks :as gq-checks]
[auto-ap.graphql.invoices :as gq-invoices]
[auto-ap.graphql.transactions :as gq-transactions]
[auto-ap.graphql.transaction-rules :as gq-transaction-rules]
[auto-ap.time :as time]
[clojure.walk :as walk]
[clojure.string :as str])
(:import
(clojure.lang IPersistentMap)))
(def integreat-schema
{
:scalars {:id {:parse (schema/as-conformer #(when % (Long/parseLong %)))
:serialize (schema/as-conformer #(.toString %))}
:ident {:parse (schema/as-conformer (fn [x] {:db/ident x}))
:serialize (schema/as-conformer #(or (:ident %) (:db/ident %) %))}
:iso_date {:parse (schema/as-conformer #(time/parse % time/iso-date))
:serialize (schema/as-conformer #(time/unparse % time/iso-date))}
:money {:parse (schema/as-conformer #(if (and (string? %)
(not (str/blank? %)))
(Double/parseDouble %)
%))
:serialize (schema/as-conformer #(if (double? %)
(str %)
%))
}
:percentage {:parse (schema/as-conformer #(if (and (string? %)
(not (str/blank? %)))
(Double/parseDouble %)
%))
:serialize (schema/as-conformer #(if (double? %)
(str %)
%))}}
:objects
{
:client
{:fields {:id {:type :id}
:name {:type 'String}
:code {:type 'String}
:email {:type 'String}
:address {:type :address}
:locations {:type '(list String)}
:bank_accounts {:type '(list :bank_account)}}}
:contact
{:fields {:id {:type :id}
:name {:type 'String}
:email {:type 'String}
:phone {:type 'String}}}
:bank_account
{:fields {:id {:type :id }
:type {:type :ident}
:number {:type 'String}
:sort_order {:type 'Int}
:visible {:type 'Boolean}
:routing {:type 'String}
:code {:type 'String}
:check_number {:type 'Int}
:name {:type 'String}
:bank_code {:type 'String}
:bank_name {:type 'String}
:yodlee_account_id {:type 'Int}}}
:balance_sheet_account
{:fields {:id {:type 'String}
:amount {:type 'String}
:location {:type 'String}
:numeric_code {:type 'Int}
:account_type {:type :account_type}
:name {:type 'String}}}
:balance_sheet
{:fields {:balance_sheet_accounts {:type '(list :balance_sheet_account)}
:comparable_balance_sheet_accounts {:type '(list :balance_sheet_account)}}}
:address
{:fields {:street1 {:type 'String}
:street2 {:type 'String}
:city {:type 'String}
:state {:type 'String}
:zip {:type 'String}}}
:vendor
{:fields {:id {:type :id}
:name {:type 'String}
:code {:type 'String}
:hidden {:type 'Boolean}
:print_as {:type 'String}
:primary_contact {:type :contact}
:secondary_contact {:type :contact}
:address {:type :address}
:default_account {:type :account}
:invoice_reminder_schedule {:type 'String}}}
:reminder
{:fields {:id {:type 'Int}
:email {:type 'String}
:subject {:type 'String}
:body {:type 'String}
:scheduled {:type 'String}
:sent {:type 'String}
:vendor {:type :vendor}
}}
:journal_entry_line
{:fields {:id {:type :id}
:account {:type :account}
:location {:type 'String}
:debit {:type 'String}
:credit {:type 'String}}}
:journal_entry
{:fields {:id {:type :id}
:source {:type 'String}
:amount {:type 'String}
:client {:type :client}
:vendor {:type :vendor}
:date {:type 'String}
:line_items {:type '(list :journal_entry_line)}}}
: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}
:name {:type 'String}}}
:transaction {:fields {:id {:type :id}
:amount {:type 'String}
:description_original {:type 'String}
:description_simple {:type 'String}
:location {:type 'String}
:exclude_from_ledger {:type 'Boolean}
:status {:type 'String}
:yodlee_merchant {:type :yodlee_merchant}
:client {:type :client}
:accounts {:type '(list :invoices_expense_accounts)}
:payment {:type :payment}
:vendor {:type :vendor}
:bank_account {:type :bank_account}
:date {:type 'String}
:post_date {:type 'String}}}
:transaction_rule {:fields {:id {:type :id}
:note {:type 'String}
:client {:type :client}
:bank_account {:type :bank_account}
:yodlee_merchant {:type :yodlee_merchant}
:description {:type 'String}
:amount_lte {:type 'String}
:amount_gte {:type 'String}
:dom_lte {:type 'Int}
:dom_gte {:type 'Int}
:vendor {:type :vendor}
: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}
:name {:type 'String}
:role {:type 'String}
:clients {:type '(list :client)}}}
:account {:fields {:id {:type :id}
:numeric_code {:type 'Int}
:type {:type :ident}
:account_set {:type 'String}
:location {:type 'String}
:name {:type 'String}}}
:invoices_expense_accounts
{:fields {:id {:type :id}
:invoice_id {:type 'String}
:account {:type :account}
:location {:type 'String}
:amount {:type 'String}}}
:percentage_account
{:fields {:id {:type :id}
:account {:type :account}
:location {:type 'String}
:percentage {:type :percentage}}}
:invoice
{:fields {:id {:type :id}
:original_id {:type 'Int}
:total {:type 'String}
:outstanding_balance {:type 'String}
:invoice_number {:type 'String}
:status {:type 'String}
:expense_accounts {:type '(list :invoices_expense_accounts)}
:date {:type 'String}
:client_id {:type 'Int}
:payments {:type '(list :invoice_payment)}
:vendor {:type :vendor}
:client {:type :client}}}
:invoice_page {:fields {:invoices {:type '(list :invoice)}
:count {:type 'Int}
:total {:type 'Int}
: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_page {:fields {:transactions {:type '(list :transaction)}
: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}
:total {:type 'Int}
:start {:type 'Int}
:end {:type 'Int}}}
:ledger_page {:fields {:journal_entries {:type '(list :journal_entry)}
:count {:type 'Int}
:total {:type 'Int}
:start {:type 'Int}
:end {:type 'Int}}}
:reminder_page {:fields {:reminders {:type '(list :reminder)}
:count {:type 'Int}
:total {:type 'Int}
:start {:type 'Int}
:end {:type 'Int}}}
:check_result {:fields {:invoices {:type '(list :invoice)}
:pdf_url {:type 'String}}}
:expense_account_stat {:fields {:account {:type :account}
:total {:type 'String}}}
:invoice_stat {:fields {:name {:type 'String}
:paid {:type 'String}
:unpaid {:type 'String}}}
:import_ledger_entry_result {:fields {:external_id {:type 'String}
:error {:type 'String}
:status {:type 'String}}}
:import_ledger_result {:fields {:successful {:type '(list :import_ledger_entry_result)}
:existing {:type '(list :import_ledger_entry_result)}
:errors {:type '(list :import_ledger_entry_result)}
}}
}
:queries
{:expense_account_stats {:type '(list :expense_account_stat)
:args {:client_id {:type :id}}
:resolve :get-expense-account-stats}
:test_transaction_rule {:type '(list :transaction)
:args {:transaction_rule {:type :edit_transaction_rule}}
:resolve :test-transaction-rule}
:invoice_stats {:type '(list :invoice_stat)
:args {:client_id {:type :id}}
:resolve :get-invoice-stats}
:potential_payment_matches {:type '(list :payment)
:args {:transaction_id {:type :id}}
:resolve :get-potential-payments}
:balance_sheet {:type :balance_sheet
:args {:client_id {:type :id}
:date {:type :iso_date}}
:resolve :get-balance-sheet}
:profit_and_loss {:type :balance_sheet
:args {:client_id {:type :id}
:from_date {:type :iso_date}
:to_date {:type :iso_date}}
:resolve :get-profit-and-loss}
:invoice_page {:type '(list :invoice_page)
:args {:import_status {:type 'String}
:date_range {:type :date_range}
:status {:type 'String}
:client_id {:type :id}
:vendor_id {:type :id}
:invoice_number_like {:type 'String}
:start {:type 'Int}
:sort_by {:type 'String}
:asc {:type 'Boolean}}
:resolve :get-invoice-page}
:all_invoices {:type '(list :invoice)
:args {:client_id {:type :id}
:client_code {:type 'String}
:original_id {:type 'Int}
:statuses {:type '(list String)}}
:resolve :get-all-invoices}
:accounts {:type '(list :account)
: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}
:transaction_page {:type '(list :transaction_page)
:args {:client_id {:type :id}
:bank_account_id {:type :id}
:date_range {:type :date_range}
:start {:type 'Int}
:sort_by {:type 'String}
:asc {:type 'Boolean}}
:resolve :get-transaction-page}
:transaction_rule_page {:type :transaction_rule_page
:args {:client_id {:type :id}
:start {:type 'Int}
:sort_by {:type 'String}
:asc {:type 'Boolean}}
:resolve :get-transaction-rule-page}
:ledger_page {:type :ledger_page
:args {:client_id {:type :id}
:bank_account_id {:type :id}
:from_date {:type :iso_date}
:to_date {:type :iso_date}
:location {:type 'String}
:from_numeric_code {:type 'Int}
:to_numeric_code {:type 'Int}
:start {:type 'Int}
:sort_by {:type 'String}
:asc {:type 'Boolean}}
:resolve :get-ledger-page}
:payment_page {:type '(list :payment_page)
:args {:client_id {:type :id}
:vendor_id {:type :id}
:date_range {:type :date_range}
:check_number_like {:type 'String}
:start {:type 'Int}
:sort_by {:type 'String}
:asc {:type 'Boolean}}
:resolve :get-payment-page}
:client {:type '(list :client)
:resolve :get-client}
:vendor {:type '(list :vendor)
:resolve :get-vendor}
:user {:type '(list :user)
:resolve :get-user}
}
:input-objects
{
:invoice_payment_amount {:fields {:invoice_id {:type :id}
:amount {:type 'Float}}}
:date_range {:fields {:start {:type :iso_date}
:end {:type :iso_date}}}
:import_ledger_line_item {:fields {:account_identifier {:type 'String}
:location {:type 'String}
:debit {:type 'String}
:credit {:type 'String}}}
:import_ledger_entry {:fields {:source {:type 'String}
:external_id {:type 'String}
:client_code {:type 'String}
:date {:type 'String}
:vendor_name {:type 'String}
:amount {:type 'String}
:line_items {:type '(list :import_ledger_line_item)}}}
:edit_client {:fields {:id {:type :id}
:name {:type 'String}
:code {:type 'String}
:email {:type 'String}
:address {:type :add_address}
:locations {:type '(list String)}
:bank_accounts {:type '(list :edit_bank_account)}}}
:edit_bank_account
{:fields {:id {:type :id }
:code {:type 'String}
:type {:type :bank_account_type}
:number {:type 'String}
:check_number {:type 'Int}
:visible {:type 'Boolean}
:sort_order {:type 'Int}
:name {:type 'String}
:bank_code {:type 'String}
:routing {:type 'String}
:bank_name {:type 'String}
:yodlee_account_id {:type 'Int}}}
:edit_user
{:fields {:id {:type :id}
:name {:type 'String}
:role {:type 'String}
:clients {:type '(list String)}}}
:add_contact
{:fields {:id {:type :id}
:name {:type 'String}
:email {:type 'String}
:phone {:type 'String}}}
:add_address
{:fields {:street1 {:type 'String}
:street2 {:type 'String}
:city {:type 'String}
:state {:type 'String}
:zip {:type 'String}}}
:add_vendor
{:fields {:id {:type :id}
:name {:type 'String}
:code {:type 'String}
:hidden {:type 'Boolean}
:print_as {:type 'String}
:primary_contact {:type :add_contact}
:secondary_contact {:type :add_contact}
:address {:type :add_address}
:default_account_id {:type :id}
:invoice_reminder_schedule {:type 'String}}}
:edit_expense_account
{:fields {:id {:type :id}
:account_id {:type :id}
:location {:type 'String}
:amount {:type 'String}}}
:add_invoice
{:fields {:id {:type :id}
:invoice_number {:type 'String}
:expense_accounts {:type '(list :edit_expense_account)}
:location {:type 'String}
:date {:type 'String}
:client_id {:type :id}
:vendor_id {:type :id}
:vendor_name {:type 'String}
:total {:type 'Float}}}
:edit_invoice
{:fields {:id {:type :id}
:invoice_number {:type 'String}
:expense_accounts {:type '(list :edit_expense_account)}
:date {:type 'String}
:total {:type 'Float}}}
:edit_transaction
{:fields {:id {:type :id}
:exclude_from_ledger {:type 'Boolean}
:vendor_id {:type :id}
:accounts {:type '(list :edit_expense_account)}}}
:edit_percentage_account
{:fields {:id {:type :id}
:account_id {:type :id}
:location {:type 'String}
:percentage {:type :percentage}}}
:edit_transaction_rule
{:fields {:id {:type :id}
:description {:type 'String}
:note {:type 'String}
:bank_account_id {:type :id}
:client_id {:type :id}
:amount_lte {:type :money}
:amount_gte {:type :money}
:dom_lte {:type 'Int}
:dom_gte {:type 'Int}
:vendor_id {:type :id}
:accounts {:type '(list :edit_percentage_account)}
:transaction_approval_status {:type :transaction_approval_status}}}
:edit_account
{:fields {:id {:type :id}
:type {:type :account_type}
:numeric_code {:type 'Int}
:location {:type 'String}
:account_set {:type 'String}
:name {:type 'String}}}}
:enums {:payment_type {:values [{:enum-value :check}
{:enum-value :cash}
{:enum-value :debit}]}
:bank_account_type {:values [{:enum-value :check}
{:enum-value :credit}
{:enum-value :cash}]}
:account_type {:values [{:enum-value :dividend}
{:enum-value :expense}
{:enum-value :asset}
{:enum-value :liability}
{:enum-value :equities}
{:enum-value :revenue}]}
:transaction_approval_status {:values [{:enum-value :approved}
{:enum-value :unapproved}
{:enum-value :requires_feedback}]}}
:mutations
{:reject_invoices {:type '(list :id)
:args {:invoices {:type '(list :id)}}
:resolve :mutation/reject-invoices}
:approve_invoices {:type '(list :id)
:args {:invoices {:type '(list :id)}}
:resolve :mutation/approve-invoices}
:add_and_print_invoice {:type :check_result
:args {:invoice {:type :add_invoice}
:bank_account_id {:type :id}
:type {:type :payment_type}}
:resolve :mutation/add-and-print-invoice}
: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}
:edit_client {:type :client
:args {:edit_client {:type :edit_client}}
:resolve :mutation/edit-client}
:upsert_vendor {:type :vendor
:args {:vendor {:type :add_vendor}}
:resolve :mutation/upsert-vendor}
:upsert_transaction_rule {:type :transaction_rule
:args {:transaction_rule {:type :edit_transaction_rule}}
:resolve :mutation/upsert-transaction-rule}
:add_invoice {:type :invoice
:args {:invoice {:type :add_invoice}}
:resolve :mutation/add-invoice}
:import_ledger {:type :import_ledger_result
:args {:entries {:type '(list :import_ledger_entry)}}
:resolve :mutation/import-ledger}
:edit_invoice {:type :invoice
:args {:invoice {:type :edit_invoice}}
:resolve :mutation/edit-invoice}
:upsert_account {:type :account
:args {:account {:type :edit_account}}
:resolve :mutation/upsert-account}
:edit_transaction {:type :transaction
:args {:transaction {:type :edit_transaction}}
:resolve :mutation/edit-transaction}
:match_transaction {:type :transaction
:args {:transaction_id {:type :id}
:payment_id {:type :id}}
:resolve :mutation/match-transaction}
:void_invoice {:type :invoice
:args {:invoice_id {:type :id}}
:resolve :mutation/void-invoice}
:unvoid_invoice {:type :invoice
:args {:invoice_id {:type :id}}
:resolve :mutation/unvoid-invoice}
:void_payment {:type :payment
:args {:payment_id {:type :id}}
:resolve :mutation/void-payment}
:edit_expense_accounts {:type :invoice
:args {:invoice_id {:type :id}
:expense_accounts {:type '(list :edit_expense_account)}}
:resolve :mutation/edit-expense-accounts}}})
(defn snake->kebab [s]
(str/replace s #"_" "-"))
(defn kebab [x]
(keyword (snake->kebab (name x))))
(defn kebab->snake [s]
(str/replace s #"-" "_"))
(defn snake [x]
(keyword (kebab->snake (name x))))
(defn ->graphql [m]
(walk/postwalk
(fn [node]
(cond
(keyword? node)
(snake node)
:else
node))
m))
(defn <-graphql [m]
(walk/postwalk
(fn [node]
(cond
(keyword? node)
(kebab node)
:else
node))
m))
(defn get-all-payments [context args value]
(assert-admin (:id context))
(map
->graphql
(d-checks/get-graphql (assoc (<-graphql args) :count Integer/MAX_VALUE))))
(defn get-user [context args value]
(assert-admin (:id context))
(doto (let [users (d-users/get-graphql args)]
(->graphql users))
println))
(defn get-vendor [context args value]
(->graphql
(d-vendors/get-graphql args)))
(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))))
(defn get-expense-account-stats [context {:keys [client_id] } value]
(let [result (cond-> {:query {:find ['?account '?account-name '(sum ?amount)]
:in ['$]
:where []}
:args [(d/db (d/connect uri)) client_id]}
client_id (merge-query {:query {:in ['?c]}
:args [client_id]})
(not client_id) (merge-query {:query {:where ['[?c :client/name]]}})
true (merge-query {:query {:where ['[?i :invoice/client ?c]
'[?i :invoice/expense-accounts ?expense-account]
'[?expense-account :invoice-expense-account/account ?account]
'[?account :account/name ?account-name]
'[?expense-account :invoice-expense-account/amount ?amount]]}})
true (d/query ))]
(for [[account-id account-name total] result]
{:account {:id account-id :name account-name} :total total })))
(defn categorize [x]
(cond (<= x 0) :due
(<= x 30 ) :due-30
(<= x 60 ) :due-60
:else :due-later))
(defn get-invoice-stats [context {:keys [client_id] } value]
(let [result (cond-> {:query {:find ['?name '(sum ?outstanding-balance) '(sum ?total)]
:in ['$]
:where []}
:args [(d/db (d/connect uri)) client_id]}
client_id (merge-query {:query {:in ['?c]}
:args [client_id]})
(not client_id) (merge-query {:query {:where ['[?c :client/name]]}})
true (merge-query {:query {:where ['[?i :invoice/client ?c]
'[?i :invoice/outstanding-balance ?outstanding-balance]
'[?i :invoice/total ?total]
'[?i :invoice/date ?date]
'[(.toInstant ^java.util.Date ?date) ?d2]
'[(.between java.time.temporal.ChronoUnit/DAYS (java.time.Instant/now) ?d2 ) ?d3]
'[(+ 30 ?d3) ?d4]
'[(auto-ap.graphql/categorize ?d4) ?name]]}})
true (d/query ))
result (group-by first result)]
(for [[id name] [[:due "Due"] [:due-30 "0-30 days"] [:due-60 "31-60 days"] [:due-later ">60 days"] ]
:let [[[_ outstanding-balance total] ] (id result nil)
outstanding-balance (or outstanding-balance 0)
total (or total 0)]]
{:name name :unpaid outstanding-balance :paid (if (= :due id)
0
(- total outstanding-balance))})))
(def schema
(-> integreat-schema
(attach-resolvers {:get-invoice-page gq-invoices/get-invoice-page
:get-all-invoices gq-invoices/get-all-invoices
:get-all-payments get-all-payments
:get-payment-page gq-checks/get-payment-page
:get-potential-payments gq-checks/get-potential-payments
:get-accounts gq-accounts/get-accounts
:get-transaction-page gq-transactions/get-transaction-page
:get-ledger-page gq-ledger/get-ledger-page
:get-balance-sheet gq-ledger/get-balance-sheet
:get-profit-and-loss gq-ledger/get-profit-and-loss
:get-transaction-rule-page gq-transaction-rules/get-transaction-rule-page
:get-expense-account-stats get-expense-account-stats
:get-invoice-stats get-invoice-stats
:get-client gq-clients/get-client
:get-user get-user
:mutation/add-handwritten-check gq-checks/add-handwritten-check
:mutation/print-checks print-checks
:mutation/reject-invoices gq-invoices/reject-invoices
:mutation/approve-invoices gq-invoices/approve-invoices
:mutation/edit-user gq-users/edit-user
:mutation/add-invoice gq-invoices/add-invoice
:mutation/add-and-print-invoice gq-invoices/add-and-print-invoice
:mutation/edit-invoice gq-invoices/edit-invoice
:mutation/edit-transaction gq-transactions/edit-transaction
:mutation/upsert-transaction-rule gq-transaction-rules/upsert-transaction-rule
:test-transaction-rule gq-transaction-rules/test-transaction-rule
:mutation/match-transaction gq-transactions/match-transaction
:mutation/edit-client gq-clients/edit-client
:mutation/upsert-vendor gq-vendors/upsert-vendor
:mutation/upsert-account gq-accounts/upsert-account
:mutation/void-invoice gq-invoices/void-invoice
:mutation/unvoid-invoice gq-invoices/unvoid-invoice
:mutation/void-payment gq-checks/void-check
:mutation/edit-expense-accounts gq-invoices/edit-expense-accounts
:mutation/import-ledger gq-ledger/import-ledger
:get-vendor get-vendor})
schema/compile))
(defn simplify
"Converts all ordered maps nested within the map into standard hash maps, and
sequences into vectors, which makes for easier constants in the tests, and eliminates ordering problems."
[m]
(walk/postwalk
(fn [node]
(cond
(instance? IPersistentMap node)
(into {} node)
(seq? node)
(vec node)
(keyword? node)
(kebab node)
:else
node))
m))
(defn query
([id q]
(query id q nil ))
([id q v]
(println "executing graphql query" id q v)
(try
(let [result (time (simplify (execute schema q v {:id id})))]
(when (seq (:errors result))
(throw (ex-info "GraphQL error" {:result result})))
result)
(catch Exception e
(if-let [v (:validation-error (ex-data e))]
(println "validation error" v)
(println e))
(throw e)))))
#_(query nil "{ ledger_page { count }}" nil)