added reminder scheduling and sending.
This commit is contained in:
@@ -3,6 +3,6 @@ CREATE TABLE reminders
|
|||||||
(
|
(
|
||||||
id serial primary key,
|
id serial primary key,
|
||||||
vendor_id integer,
|
vendor_id integer,
|
||||||
scheduled date,
|
scheduled timestamp with time zone,
|
||||||
sent date
|
sent timestamp with time zone
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,44 @@
|
|||||||
(ns auto-ap.db.reminders
|
(ns auto-ap.db.reminders
|
||||||
(:require [clojure.java.jdbc :as j]
|
(:require [clojure.java.jdbc :as j]
|
||||||
[auto-ap.parse :as parse]
|
[auto-ap.parse :as parse]
|
||||||
[auto-ap.db.utils :refer [clj->db db->clj get-conn]]))
|
[auto-ap.db.utils :refer [clj->db db->clj get-conn]]
|
||||||
|
[clj-time.jdbc]
|
||||||
|
[clj-time.core :as time]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
(defn insert [row]
|
||||||
|
(db->clj (first (j/insert! (get-conn)
|
||||||
|
:reminders
|
||||||
|
(clj->db row)))))
|
||||||
|
|
||||||
(defn get-all []
|
(defn get-all []
|
||||||
(doto (map db->clj (j/query (get-conn) "SELECT reminders.*, vendors.name as vendor_name FROM reminders INNER join vendors on reminders.vendor_id = vendors.id"))
|
(map db->clj (j/query (get-conn)
|
||||||
println))
|
(str
|
||||||
|
" SELECT reminders.*, vendors.name as vendor_name "
|
||||||
|
" FROM reminders INNER join vendors on reminders.vendor_id = vendors.id "
|
||||||
|
" ORDER BY sent DESC, scheduled DESC"))))
|
||||||
|
|
||||||
|
(defn delete-all []
|
||||||
|
(j/delete! (get-conn) :reminders []))
|
||||||
|
|
||||||
|
(defn find-future [vendors]
|
||||||
|
(map db->clj (j/query (get-conn) (into [(str "SELECT * FROM reminders "
|
||||||
|
"WHERE vendor_id in ("
|
||||||
|
(str/join "," (take (count vendors) (repeat "?")))
|
||||||
|
") "
|
||||||
|
"AND "
|
||||||
|
"scheduled > NOW()"
|
||||||
|
) ]
|
||||||
|
vendors))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn get-ready []
|
||||||
|
(map db->clj (j/query (get-conn)
|
||||||
|
(str
|
||||||
|
" SELECT reminders.*, vendors.name as vendor_name, vendors.email "
|
||||||
|
" FROM reminders INNER join vendors on reminders.vendor_id = vendors.id "
|
||||||
|
" WHERE reminders.sent IS NULL AND reminders.scheduled < NOW()"))))
|
||||||
|
|
||||||
|
(defn finish [id]
|
||||||
|
(j/update! (get-conn) :reminders {:sent (time/now)} ["id = ?" id] ))
|
||||||
|
|
||||||
|
|||||||
@@ -24,3 +24,6 @@
|
|||||||
(parse (first (j/insert! (get-conn)
|
(parse (first (j/insert! (get-conn)
|
||||||
:vendors
|
:vendors
|
||||||
(clj->db data)))))
|
(clj->db data)))))
|
||||||
|
|
||||||
|
(defn find-with-reminders []
|
||||||
|
(map parse (j/query (get-conn) ["SELECT * FROM vendors WHERE invoice_reminder_schedule = ?" "Weekly"])))
|
||||||
|
|||||||
@@ -4,26 +4,74 @@
|
|||||||
[auto-ap.db.reminders :as reminders]
|
[auto-ap.db.reminders :as reminders]
|
||||||
[auto-ap.routes.utils :refer [wrap-secure]]
|
[auto-ap.routes.utils :refer [wrap-secure]]
|
||||||
[amazonica.aws.simpleemail :as ses]
|
[amazonica.aws.simpleemail :as ses]
|
||||||
))
|
[clj-time.core :as time]
|
||||||
|
[clj-time.coerce :as c]
|
||||||
|
[clj-time.predicates :as pred]
|
||||||
|
[clj-time.periodic :as p]
|
||||||
|
[clj-time.local :as l]
|
||||||
|
[clj-time.jdbc]
|
||||||
|
)
|
||||||
|
(:import [org.joda.time DateTime]))
|
||||||
|
|
||||||
|
(defn next-sunday []
|
||||||
|
(let [sunday (->> (p/periodic-seq (time/today) (time/days 1))
|
||||||
|
(filter pred/sunday?)
|
||||||
|
first)
|
||||||
|
]
|
||||||
|
|
||||||
|
(.toDateTime (time/local-date-time (time/year sunday) (time/month sunday) (time/day sunday)))))
|
||||||
|
|
||||||
|
(defn schedule-reminders []
|
||||||
|
(let [vendors (vendors/find-with-reminders)
|
||||||
|
future-reminders (reminders/find-future (map :id vendors))
|
||||||
|
has-reminder-scheduled? (set (map :vendor-id future-reminders))
|
||||||
|
vendors-without-scheduled (filter #(not (has-reminder-scheduled? (:id %))) vendors)]
|
||||||
|
(println "Reminders already scheduled:" future-reminders)
|
||||||
|
(println "Reminders will happen at" (next-sunday))
|
||||||
|
(println "Reminders to schedule" vendors-without-scheduled)
|
||||||
|
|
||||||
|
(doseq [{:keys [id invoice-reminder-schedule]} vendors-without-scheduled]
|
||||||
|
(reminders/insert {:vendor-id id
|
||||||
|
:scheduled (next-sunday)}))))
|
||||||
|
|
||||||
|
(defn find-ready-reminders []
|
||||||
|
(let [vendors (vendors/get-all)
|
||||||
|
ready-reminders (reminders/get-ready)]
|
||||||
|
ready-reminders
|
||||||
|
))
|
||||||
|
|
||||||
|
(defn send-emails [reminders]
|
||||||
|
(doseq [{:keys [name email id]} reminders]
|
||||||
|
(println "Sending email to" email)
|
||||||
|
(ses/send-email :destination {:to-addresses [email]}
|
||||||
|
:source "invoices@mail.integreat.aws.brycecovertoperations.com"
|
||||||
|
:message {:subject "Reminder to send invoices"
|
||||||
|
:body {:html (str "<h1>Hello " name ",</h1><p>This is a reminder to send this week's invoices to us. You can just reply to this email.</p> <p> - Integreat. </p>")
|
||||||
|
:text (str "Hello " name ",\r\nThis is a reminder to send this week's invoices to us. You can just reply to this email.\r\n - Integreat.")}})
|
||||||
|
(reminders/finish id)))
|
||||||
|
|
||||||
|
(defn replace-joda [x]
|
||||||
|
(into {} (map (fn [[k v]]
|
||||||
|
[k (if (instance? DateTime v)
|
||||||
|
(c/to-string v)
|
||||||
|
v)])
|
||||||
|
x))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
(defroutes routes
|
(defroutes routes
|
||||||
(context "/reminders" []
|
(context "/reminders" []
|
||||||
(POST "/send" {:keys [query-params]}
|
(POST "/send" {:keys [query-params]}
|
||||||
(doseq [{:keys [name email invoice-reminder-schedule]} (vendors/get-all)]
|
(schedule-reminders)
|
||||||
(when (= "Weekly" invoice-reminder-schedule)
|
(-> (reminders/get-ready)
|
||||||
(println "Sending email to" email)
|
(send-emails))
|
||||||
(ses/send-email :destination {:to-addresses [email]}
|
|
||||||
:source "invoices@mail.integreat.aws.brycecovertoperations.com"
|
|
||||||
:message {:subject "Reminder to send invoices"
|
|
||||||
:body {:html (str "<h1>Hello " name ",</h1><p>This is a reminder to send this week's invoices to us. You can just reply to this email.</p> <p> - Integreat. </p>")
|
|
||||||
:text (str "Hello " name ",\r\nThis is a reminder to send this week's invoices to us. You can just reply to this email.\r\n - Integreat.")}})))
|
|
||||||
{:status 200
|
{:status 200
|
||||||
:body "{}"
|
:body "{}"
|
||||||
:headers {"Content-Type" "application/edn"}})
|
:headers {"Content-Type" "application/edn"}})
|
||||||
|
|
||||||
(wrap-routes (GET "/" {:keys [query-params]}
|
(wrap-routes (GET "/" {:keys [query-params]}
|
||||||
{:status 200
|
{:status 200
|
||||||
:body (pr-str (reminders/get-all))
|
:body (pr-str (map replace-joda (reminders/get-all)))
|
||||||
:headers {"Content-Type" "application/edn"}})
|
:headers {"Content-Type" "application/edn"}})
|
||||||
wrap-secure)))
|
wrap-secure)))
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
^{:key id}
|
^{:key id}
|
||||||
[:tr
|
[:tr
|
||||||
[:td vendor-name]
|
[:td vendor-name]
|
||||||
[:td (.toString scheduled)]
|
[:td (str scheduled)]
|
||||||
[:td (when sent
|
[:td (when sent
|
||||||
[:span [:span.icon [:i.fa.fa-check]] "Sent " (.toString sent)]) ]])]]))
|
[:span [:span.icon [:i.fa.fa-check]] "Sent " (str sent)]) ]])]]))
|
||||||
|
|
||||||
|
|
||||||
(defn admin-reminders-page []
|
(defn admin-reminders-page []
|
||||||
|
|||||||
Reference in New Issue
Block a user