From 4780f65ee712fa02a2540ff9fa12f867dd94ee55 Mon Sep 17 00:00:00 2001 From: BC Date: Thu, 14 Jun 2018 23:16:12 -0700 Subject: [PATCH] automated imports. --- deploy-staging.sh | 4 + src/clj/auto_ap/graphql/transactions.clj | 49 ++++++ src/clj/auto_ap/routes/events.clj | 35 ++++ .../auto_ap/views/pages/transactions.cljs | 158 ++++++++++++++++++ terraform/events.tf | 89 ++++++++++ 5 files changed, 335 insertions(+) create mode 100755 deploy-staging.sh create mode 100644 src/clj/auto_ap/graphql/transactions.clj create mode 100644 src/clj/auto_ap/routes/events.clj create mode 100644 src/cljs/auto_ap/views/pages/transactions.cljs create mode 100644 terraform/events.tf diff --git a/deploy-staging.sh b/deploy-staging.sh new file mode 100755 index 00000000..7112c5f4 --- /dev/null +++ b/deploy-staging.sh @@ -0,0 +1,4 @@ +#!/bin/sh +eval $(docker-machine env aws01) +docker-compose -f docker-compose.yml -f docker-compose.staging.yml -p staging up --build -d + diff --git a/src/clj/auto_ap/graphql/transactions.clj b/src/clj/auto_ap/graphql/transactions.clj new file mode 100644 index 00000000..3b9dbe96 --- /dev/null +++ b/src/clj/auto_ap/graphql/transactions.clj @@ -0,0 +1,49 @@ +(ns auto-ap.graphql.transactions + (:require [auto-ap.graphql.utils :refer [->graphql <-graphql]] + + [com.walmartlabs.lacinia :refer [execute]] + [com.walmartlabs.lacinia.executor :as executor] + [com.walmartlabs.lacinia.resolve :as resolve] + [auto-ap.db.transactions :as transactions] + [auto-ap.db.vendors :as vendors] + [auto-ap.db.checks :as checks] + [auto-ap.utils :refer [by]] + [auto-ap.db.companies :as companies] + [auto-ap.time :refer [parse normal-date]])) + +(defn get-vendor-for-transaction [context args value] + (->graphql + (if-let [vendor-cache (:vendor-cache context)] + (vendor-cache (:vendor_id value)) + (vendors/get-by-id (:vendor_id value))))) + +(defn get-check-for-transaction [context args value] + (->graphql + (checks/get-by-id (:check_id value)))) + +(defn get-company-for-transaction [context args value] + (->graphql + (if-let [company-cache (:company-cache context)] + (company-cache (:company_id value)) + (companies/get-by-id (:company_id value))))) + +(defn get-transaction-page [context args value] + (let [extra-context + (cond-> {} + (executor/selects-field? context :invoice/vendor) (assoc :vendor-cache (by :id (vendors/get-all))) + (executor/selects-field? context :invoice/company) (assoc :company-cache (by :id (companies/get-all)))) + + transactions (map + ->graphql + (transactions/get-graphql (<-graphql args))) + transactions-count (transactions/count-graphql (<-graphql args))] + (resolve/with-context + [{:transactions transactions + :total transactions-count + :count (count transactions) + :start (:start args 0) + :end (+ (:start args 0) (count transactions))}] extra-context))) + + + + diff --git a/src/clj/auto_ap/routes/events.clj b/src/clj/auto_ap/routes/events.clj new file mode 100644 index 00000000..64c7e2c1 --- /dev/null +++ b/src/clj/auto_ap/routes/events.clj @@ -0,0 +1,35 @@ +(ns auto-ap.routes.events + (:require + [auto-ap.db.reminders :as reminders] + [auto-ap.db.vendors :as vendors] + [auto-ap.routes.utils :refer [wrap-secure]] + [auto-ap.yodlee.import :as yodlee-import] + [config.core :refer [env]] + [clj-http.client :as http] + [clj-time.coerce :as c] + [clj-time.core :as time] + [clj-time.periodic :as p] + [clj-time.predicates :as pred] + [clojure.data.json :as json] + [compojure.core :refer [GET PUT POST context defroutes + wrap-routes]]) + (:import (org.joda.time DateTime))) + +(defroutes routes + (context "/events" [] + (POST "/yodlee-import" {:keys [query-params headers body] :as x} + (let [notification-type (get headers "x-amz-sns-message-type")] + (println "Received notification " notification-type) + (if (= "SubscriptionConfirmation" notification-type) + (do + (println "Responding to confirmation" ) + (let [json (json/read-str (slurp body))] + (println json) + (http/get (get json "SubscribeURL")))) + (do + (println "importing from yodlee") + (yodlee-import/do-import)))) + + {:status 200 + :body "{}" + :headers {"Content-Type" "application/edn"}}))) diff --git a/src/cljs/auto_ap/views/pages/transactions.cljs b/src/cljs/auto_ap/views/pages/transactions.cljs new file mode 100644 index 00000000..8b0398c7 --- /dev/null +++ b/src/cljs/auto_ap/views/pages/transactions.cljs @@ -0,0 +1,158 @@ +(ns auto-ap.views.pages.transactions + (:require [re-frame.core :as re-frame] + [auto-ap.entities.companies :as company] + [auto-ap.entities.vendors :as vendor] + [reagent.core :as reagent] + [goog.string :as gstring] + [auto-ap.views.components.sorter :refer [sorted-column]] + [auto-ap.views.components.paginator :refer [paginator]] + [auto-ap.events :as events] + [auto-ap.views.utils :refer [dispatch-event date->str ]] + [auto-ap.utils :refer [by]] + [auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table] + [auto-ap.subs :as subs])) + + +(re-frame/reg-sub + ::transaction-page + (fn [db] + (-> db ::transaction-page))) + +(re-frame/reg-sub + ::params + (fn [db] + (-> db (::params {})))) + +(re-frame/reg-event-fx + ::params-change + (fn [cofx [_ params]] + + {:db (-> (:db cofx) + (assoc-in [:status :loading] true) + (assoc-in [::params] params)) + :graphql {:token (-> cofx :db :user) + :query-obj {:venia/queries [[:transaction_page + (assoc params :company-id (:id @(re-frame/subscribe [::subs/company]))) + [[:transactions [:id + :amount + :date + :post_date + :status + :description_original + [:vendor [:name :id]] + [:check [:check_number :s3_url]] + [:company [:name :id]]]] + :total + :start + :end]]]} + :on-success [::received]}})) + +(re-frame/reg-event-db + ::received + (fn [db [_ data]] + (println data) + (-> db + (assoc ::transaction-page (first (:transaction-page data))) + (assoc-in [:status :loading] false)))) + +(re-frame/reg-event-fx + ::invalidated + (fn [cofx [_ params]] + {:dispatch [::params-change @(re-frame/subscribe [::params])]})) + +(defn transaction-table [{:keys [id transaction-page status on-params-change vendors params check-boxes checked on-check-changed expense-event]}] + (let [state (reagent/atom (or @params {})) + opc (fn [p] + (swap! state merge p) + (on-params-change p))] + (fn [{:keys [id transaction-page status on-params-change vendors checked]}] + (println @transaction-page) + (let [{:keys [sort-by asc]} @state + {:keys [transactions start end count total]} @transaction-page] + [:div + [paginator {:start start :end end :count count :total total + :on-change (fn [p ] + (on-params-change (swap! state merge p)))}] + "Showing " (inc start) "-" end "/" total + + [:table.table.is-fullwidth + [:thead + [:tr + [sorted-column {:on-sort opc + :style {:width "33%" :cursor "pointer"} + :sort-key "company" + :sort-by sort-by + :asc asc} + "Company"] + [sorted-column {:on-sort opc + :style {:width "33%" :cursor "pointer"} + :sort-key "vendor" + :sort-by sort-by + :asc asc} + "Vendor"] + [sorted-column {:on-sort opc + :style {:width "33%" :cursor "pointer"} + :sort-key "description-original" + :sort-by sort-by + :asc asc} + "Description"] + [sorted-column {:on-sort opc + :style {:width "8em" :cursor "pointer"} + :sort-key "date" + :sort-by sort-by + :asc asc} + "Date"] + [sorted-column {:on-sort opc + :style {:width "8em" :cursor "pointer"} + :sort-key "total" + :sort-by sort-by + :asc asc} + "Amount"] + + [sorted-column {:on-sort opc + :style {:width "8em" :cursor "pointer"} + :sort-key "status" + :sort-by sort-by + :asc asc} + "Status"] + + + [:th {:style {:width "10em"}} "" ]]] + [:tbody + (if (:loading @status) + [:tr + [:td {:col-span 5} + [:i.fa.fa-spin.fa-spinner]]] + (for [{:keys [company check status description-original date amount id vendor] :as i} (:transactions @transaction-page)] + ^{:key id} + [:tr {:class (:class i)} + + [:td (:name company)] + [:td (:name vendor)] + [:td description-original] + [:td (date->str date) ] + [:td (gstring/format "$%.2f" amount )] + [:td status] + + [:td + + (when check + [:a.tag {:href (:s3-url check) :target "_new"} [:i.fa.fa-money-check] [:span.icon [:i.fa.fa-money]] (str " " (:check-number check) " (" (gstring/format "$%.2f" amount ) ")")])] + ]))]]])))) + + +(def transactions-page + + (with-meta + (fn [] + (let [current-company @(re-frame/subscribe [::subs/company])] + [:div + [:h1.title "Transactions"] + [transaction-table {:id :transactions + :params (re-frame/subscribe [::params]) + :transaction-page (re-frame/subscribe [::transaction-page]) + :status (re-frame/subscribe [::subs/status]) + :on-params-change (fn [params] + (re-frame/dispatch [::params-change params]))}]])) + {:component-will-mount #(re-frame/dispatch-sync [::params-change {}]) })) + diff --git a/terraform/events.tf b/terraform/events.tf new file mode 100644 index 00000000..278b2e3a --- /dev/null +++ b/terraform/events.tf @@ -0,0 +1,89 @@ +resource "aws_sns_topic" "yodlee_topic" { + name = "events-yodlee-${var.stage}" + policy = <