vendors.
This commit is contained in:
2
migrator/migrations/1522973754-DOWN-create-vendors.sql
Normal file
2
migrator/migrations/1522973754-DOWN-create-vendors.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- 1522973754 DOWN create-vendors
|
||||
drop table vendors;
|
||||
12
migrator/migrations/1522973754-UP-create-vendors.sql
Normal file
12
migrator/migrations/1522973754-UP-create-vendors.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- 1522973754 UP create-vendors
|
||||
|
||||
CREATE TABLE public.vendors (
|
||||
id serial PRIMARY KEY,
|
||||
name character varying(255),
|
||||
data text,
|
||||
email character varying(255),
|
||||
invoice_reminder_schedule character varying(255)
|
||||
);
|
||||
|
||||
|
||||
INSERT into vendors (name, data, email, invoice_reminder_schedule) values ('CINTAS', '{}', 'ses@brycecovertoperations.com', 'Weekly');
|
||||
22
src/clj/auto_ap/db/vendors.clj
Normal file
22
src/clj/auto_ap/db/vendors.clj
Normal file
@@ -0,0 +1,22 @@
|
||||
(ns auto-ap.db.vendors
|
||||
(:require [clojure.java.jdbc :as j]
|
||||
[auto-ap.db.utils :refer [clj->db db->clj get-conn]]
|
||||
[clojure.edn :as edn]))
|
||||
|
||||
(defn merge-data [{:keys [data] :as x}]
|
||||
(merge x (edn/read-string data)))
|
||||
|
||||
(defn parse [x]
|
||||
(-> x
|
||||
(db->clj)
|
||||
merge-data
|
||||
))
|
||||
|
||||
|
||||
(defn get-all []
|
||||
(->> (j/query (get-conn) "SELECT * FROM vendors")
|
||||
(map parse)))
|
||||
|
||||
(defn upsert [id data]
|
||||
(j/update! (get-conn) :vendors (clj->db data) ["id = ?" (Integer/parseInt id)] )
|
||||
(merge-data (db->clj (first (j/query (get-conn) ["SELECT * FROM vendors WHERE id = ?" (Integer/parseInt id)])))))
|
||||
@@ -24,6 +24,7 @@
|
||||
[buddy.auth.backends.token :refer [jws-backend]]
|
||||
[buddy.auth.middleware :refer [wrap-authorization wrap-authentication]]
|
||||
[auto-ap.db.companies :as companies]
|
||||
[auto-ap.db.vendors :as vendors]
|
||||
[amazonica.core :refer [defcredential]]
|
||||
[amazonica.aws.simpleemail :as ses]))
|
||||
(defn best-match [companies company-identifier]
|
||||
@@ -88,6 +89,11 @@
|
||||
{:status 200
|
||||
:body (pr-str (companies/get-all))
|
||||
:headers {"Content-Type" "application/edn"}})
|
||||
|
||||
(GET "/api/vendors" []
|
||||
{:status 200
|
||||
:body (pr-str (vendors/get-all))
|
||||
:headers {"Content-Type" "application/edn"}})
|
||||
|
||||
(GET "/api/invoices" []
|
||||
{:status 200
|
||||
@@ -105,7 +111,7 @@
|
||||
:headers {"Content-Type" "application/edn"}})
|
||||
|
||||
(POST "/api/reminders/send" {:keys [query-params]}
|
||||
(doseq [{:keys [name email invoice-reminder-schedule]} (companies/get-all)]
|
||||
(doseq [{:keys [name email invoice-reminder-schedule]} (vendors/get-all)]
|
||||
(when (= "Weekly" invoice-reminder-schedule)
|
||||
(println "Sending email to" email)
|
||||
(ses/send-email :destination {:to-addresses [email]}
|
||||
@@ -122,6 +128,11 @@
|
||||
:body (pr-str (companies/upsert id edn-params))
|
||||
:headers {"Content-Type" "application/edn"}})
|
||||
|
||||
(PUT "/api/vendors/:id" {:keys [edn-params] {:keys [id]} :route-params :as r}
|
||||
{:status 200
|
||||
:body (pr-str (vendors/upsert id edn-params))
|
||||
:headers {"Content-Type" "application/edn"}})
|
||||
|
||||
(POST "/api/invoices" {:keys [edn-params]}
|
||||
(invoices/insert-multi! (:rows edn-params))
|
||||
{:status 200
|
||||
|
||||
55
src/cljs/auto_ap/events/admin/vendors.cljs
Normal file
55
src/cljs/auto_ap/events/admin/vendors.cljs
Normal file
@@ -0,0 +1,55 @@
|
||||
(ns auto-ap.events.admin.vendors
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[auto-ap.db :as db]
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.effects :as effects]
|
||||
[bidi.bidi :as bidi]))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::edit
|
||||
(fn [db [_ vendor-id]]
|
||||
(assoc-in db [:admin-vendors :editing]
|
||||
(get (:vendors db) vendor-id))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::save
|
||||
(fn [{:keys [db]} _]
|
||||
(let [edited-vendor (get-in db [:admin-vendors :editing])]
|
||||
{:db (assoc-in db [:admin-vendors :editing :saving?] true)
|
||||
:http {:method :put
|
||||
:token (:user db)
|
||||
:body (pr-str (select-keys edited-vendor [:name :email :data :invoice-reminder-schedule]))
|
||||
:headers {"Content-Type" "application/edn"}
|
||||
:uri (str "/api/vendors/" (:id edited-vendor))
|
||||
:on-success [::save-complete]}})))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::save-complete
|
||||
(fn [db [_ vendor]]
|
||||
(-> db
|
||||
|
||||
(assoc-in [:admin-vendors :editing] nil)
|
||||
(assoc-in [:vendors (:id vendor)] vendor))))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::change
|
||||
(fn [db [_ path value]]
|
||||
(assoc-in db (concat [:admin-vendors :editing] path)
|
||||
value)))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [{:keys [db]} _]
|
||||
{:http {:method :get
|
||||
:token (:user db)
|
||||
:uri "/api/vendors"
|
||||
:on-success [::received-vendors]}}))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::received-vendors
|
||||
(fn [db [_ vendors]]
|
||||
|
||||
(assoc db :vendors (reduce (fn [vendors vendor]
|
||||
(assoc vendors (:id vendor) vendor))
|
||||
{}
|
||||
vendors))))
|
||||
@@ -4,7 +4,8 @@
|
||||
(def routes ["/" {"" :index
|
||||
"login/" :login
|
||||
"admin/" {"" :admin
|
||||
"companies" :admin-companies}
|
||||
"companies" :admin-companies
|
||||
"vendors" :admin-vendors}
|
||||
"invoices/" {"" :invoices
|
||||
"import" :import-invoices
|
||||
"unpaid" :unpaid-invoices
|
||||
|
||||
@@ -29,6 +29,16 @@
|
||||
(fn [db]
|
||||
(:admin-companies db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::vendors
|
||||
(fn [db]
|
||||
(vals (:vendors db))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::admin-vendors
|
||||
(fn [db]
|
||||
(:admin-vendors db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::user
|
||||
(fn [db]
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
:paid-invoices :left-panel
|
||||
:admin :admin-left-panel
|
||||
:admin-companies :admin-left-panel
|
||||
:admin-vendors :admin-left-panel
|
||||
:new-invoice :blank} page))
|
||||
|
||||
(defn login-dropdown []
|
||||
@@ -70,6 +71,12 @@
|
||||
[:i {:class "fa fa-star-o"}]]
|
||||
|
||||
[:span {:class "name"} "Companies"]]]
|
||||
[:li.menu-item
|
||||
[:a {:href (bidi/path-for routes/routes :admin-vendors) , :class (str "item" (active-when= ap :admin-vendors))}
|
||||
[:span {:class "icon"}
|
||||
[:i {:class "fa fa-star-o"}]]
|
||||
|
||||
[:span {:class "name"} "Vendors"]]]
|
||||
[:li.menu-item
|
||||
[:a {:href (bidi/path-for routes/routes :admin-users), :class (str "item" (active-when= ap :admin-users))}
|
||||
[:span {:class "icon"}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
[auto-ap.views.pages.index :refer [index-page]]
|
||||
[auto-ap.views.pages.admin :refer [admin-page]]
|
||||
[auto-ap.views.pages.admin.companies :refer [admin-companies-page]]
|
||||
[auto-ap.views.pages.admin.vendors :refer [admin-vendors-page]]
|
||||
[auto-ap.views.pages.unpaid-invoices :refer [unpaid-invoices-page]]
|
||||
[auto-ap.views.pages.new-invoice :refer [new-invoice-page]]
|
||||
[auto-ap.views.pages.import-invoices :refer [import-invoices-page]]
|
||||
@@ -34,12 +35,15 @@
|
||||
(defmethod active-page :admin-companies []
|
||||
[admin-companies-page])
|
||||
|
||||
(defmethod active-page :admin-vendors []
|
||||
[admin-vendors-page])
|
||||
|
||||
|
||||
(defmethod active-page :unpaid-invoices []
|
||||
[unpaid-invoices-page])
|
||||
|
||||
(defmethod active-page :paid-invoices []
|
||||
paid-invoices-page
|
||||
)
|
||||
paid-invoices-page)
|
||||
|
||||
(defmethod active-page :invoices []
|
||||
[(with-meta
|
||||
|
||||
102
src/cljs/auto_ap/views/pages/admin/vendors.cljs
Normal file
102
src/cljs/auto_ap/views/pages/admin/vendors.cljs
Normal file
@@ -0,0 +1,102 @@
|
||||
(ns auto-ap.views.pages.admin.vendors
|
||||
(:require-macros [cljs.core.async.macros :refer [go]])
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.events.admin.vendors :as events]
|
||||
[auto-ap.views.utils :refer [login-url dispatch-value-change]]
|
||||
[cljs.reader :as edn]
|
||||
[auto-ap.routes :as routes]
|
||||
[bidi.bidi :as bidi]))
|
||||
(defn vendors-table []
|
||||
(let [vendors (re-frame/subscribe [::subs/vendors])
|
||||
admin-vendors (re-frame/subscribe [::subs/admin-vendors])
|
||||
editing-vendor (:editing @admin-vendors)]
|
||||
(println @vendors)
|
||||
[:table {:class "table", :style {:width "100%"}}
|
||||
[:thead
|
||||
[:tr
|
||||
[:th "Name"]
|
||||
[:th "Email"]
|
||||
[:th "Invoice Reminders"]]]
|
||||
[:tbody (for [{:keys [id name email data invoice-reminder-schedule]} @vendors]
|
||||
^{:key (str name "-" id )}
|
||||
[:tr {:on-click (fn [] (re-frame/dispatch [::events/edit id]))
|
||||
:style {"cursor" "pointer"}}
|
||||
[:td name]
|
||||
[:td email]
|
||||
[:td invoice-reminder-schedule]])]]))
|
||||
|
||||
(defn admin-vendors-page []
|
||||
[(with-meta
|
||||
(fn []
|
||||
[:div {:class "inbox-messages"}
|
||||
[:div.hero
|
||||
[:div.hero-body
|
||||
[:div.container
|
||||
(let [vendors (re-frame/subscribe [::subs/vendors])
|
||||
admin-vendors (re-frame/subscribe [::subs/admin-vendors])
|
||||
editing-vendor (:editing @admin-vendors)]
|
||||
|
||||
[:div
|
||||
[:h1.title "Vendors"]
|
||||
[vendors-table]
|
||||
|
||||
|
||||
|
||||
(when editing-vendor
|
||||
[:div.modal.is-active
|
||||
[:div.modal-background {:on-click (fn [] (re-frame/dispatch [::events/edit nil]))}]
|
||||
|
||||
[:div.modal-card
|
||||
[:header.modal-card-head
|
||||
[:p.modal-card-title
|
||||
(str "Edit " (:name editing-vendor))]
|
||||
[:button.delete {:on-click (fn [] (re-frame/dispatch [::events/edit nil]))}]]
|
||||
[:section.modal-card-body
|
||||
[:div.field
|
||||
[:label.label "Name"]
|
||||
[:div.control
|
||||
[:input.input {:type "text" :value (:name editing-vendor)
|
||||
:on-change (dispatch-value-change [::events/change [:name]])}]]]
|
||||
|
||||
[:div.field
|
||||
[:label.label "Email"]
|
||||
[:div.control
|
||||
[:input.input {:type "email"
|
||||
:value (:email editing-vendor)
|
||||
:on-change (dispatch-value-change [::events/change [:email]])}]]]
|
||||
|
||||
[:div.field
|
||||
[:labal.label "Invoice Reminders"]
|
||||
[:div.control
|
||||
[:label.radio
|
||||
[:input {:type "radio"
|
||||
:name "schedule"
|
||||
:value "Weekly"
|
||||
:checked (if (= "Weekly" (:invoice-reminder-schedule editing-vendor))
|
||||
"checked"
|
||||
"")
|
||||
:on-change (dispatch-value-change [::events/change [:invoice-reminder-schedule]])}]
|
||||
" Send weekly"]]
|
||||
[:div.control
|
||||
[:label.radio
|
||||
[:input {:type "radio"
|
||||
:name "schedule"
|
||||
:value "Never"
|
||||
:checked (if (= "Never" (:invoice-reminder-schedule editing-vendor))
|
||||
"checked"
|
||||
"")
|
||||
:on-change (dispatch-value-change [::events/change [:invoice-reminder-schedule]])}]
|
||||
" Never"]]]
|
||||
|
||||
(when (:saving? editing-vendor) [:div.is-overlay {:style {"backgroundColor" "rgba(150,150,150, 0.5)"}}])]
|
||||
|
||||
[:footer.modal-card-foot
|
||||
[:a.button.is-primary {:on-click (fn [] (re-frame/dispatch [::events/save]))}
|
||||
[:span "Save"]
|
||||
(when (:saving? editing-vendor)
|
||||
[:span.icon
|
||||
[:i.fa.fa-spin.fa-spinner]])]]]])])]]]])
|
||||
{:component-did-mount (fn []
|
||||
(re-frame/dispatch [::events/mounted]))})])
|
||||
Reference in New Issue
Block a user