Skip to content

Instantly share code, notes, and snippets.

@diptigautam
Last active October 27, 2021 14:55
Show Gist options
  • Save diptigautam/32a45a2cc732e81447350cfc027ec1f2 to your computer and use it in GitHub Desktop.
Save diptigautam/32a45a2cc732e81447350cfc027ec1f2 to your computer and use it in GitHub Desktop.
Scheduling upgrade/downgrade of your subscription
(ns foo.service.scheduled-update
(:require [duct.logger :refer [log]]
[magnet.payments.core :as payment]
[foo.boundary.port.persistence :as persistence]
[foo.domain.upcoming-subscription :as dom-us]
[foo.service.schedule.upcoming-subscription :as scheduler-us]
[foo.util.thread-transactions :as tht]))
(defn schedule-update
[{:keys [p-adapter payment-adapter logger] :as config}
existing-subscription-id
{:keys [fixed-price-id excess-price-id] :as upcoming-subscription}
user-id]
(let [{:keys [org]} (persistence/get-org p-adapter logger {:operation :by-user :user-id user-id})
{:keys [subscription]} (persistence/get-subscription p-adapter logger existing-subscription-id)]
(-> [{:txn-fn (fn txn-1 [_]
(let [sub-to-update {:cancel_at_period_end true}
result (payment/update-subscription payment-adapter existing-subscription-id sub-to-update)]
(if-not (:success? result)
{:success? false
:reason :could-not-schedule-existing-subscription-cancellation
:error-details (:error-details result)}
result)))}
{:txn-fn (fn txn-2 [prv-result]
(let [org-id (:id org)
start-at (:current-period-end subscription)
upcoming-subscription (dom-us/subscription->upcoming-subscription upcoming-subscription user-id org-id start-at)
result (persistence/create-or-update-upcoming-subscription p-adapter logger upcoming-subscription)]
(if (:success? result)
(assoc prv-result :upcoming-subscription upcoming-subscription)
(assoc prv-result
:success? false
:reason :could-not-create-upcoming-subscription-record
:error-details (:error-details result)))))}
{:txn-fn (fn txn-3 [{:keys [upcoming-subscription]}]
(scheduler-us/schedule-jobs config [upcoming-subscription])
{:success? true})}]
(tht/thread-transactions {}))))
(ns foo.service.schedule.upcoming-subscription
(:require [duct.logger :refer [log]]
[integrant.core :as ig]
[java-time :as jt]
[java-time.temporal]
[foo.service.create-upcoming-stripe-subscription :as srv-us-stripe]
[foo.service.upcoming-subscription :as srv-us]
[twarc.core :refer [defjob delete-job]]))
(defjob create-subscription-job [scheduler {:keys [logger] :as config} upcoming-subscription]
(log logger :info :scheduled-create-upcoming-stripe-subscription-execute {})
(srv-us-stripe/main config upcoming-subscription))
(defn- schedule-job
[{:keys [scheduler logger] :as config} scheduler-config upcoming-subscription]
(let [time-zone (java.util.TimeZone/getTimeZone (:time-zone scheduler-config))]
(log logger :info :scheduled-create-upcoming-stripe-subscription-job-start scheduler-config)
(create-subscription-job scheduler
[config upcoming-subscription]
:trigger {:cron {:expression (:cron scheduler-config)
:misfire-handling :fire-and-process
:time-zone time-zone}}
:job {:identity (:identity scheduler-config)})))
(defn schedule-jobs [config upcoming-subscriptions]
(map
(fn [upcoming-subscription]
(let [start-at (jt/instant (:start-at upcoming-subscription))
zoned-date-time (.atZone start-at ZoneOffset/UTC)
year (.getYear zoned-date-time)
month (.getMonthValue zoned-date-time)
day-of-month (.getDayOfMonth zoned-date-time)
hour (.getHour zoned-date-time)
minute (.getMinute zoned-date-time)
cron-expression (format "0 %d %d %d %d ? %d" minute hour day-of-month month year)
job-identity (format "upcoming-subscription_%s" (:id upcoming-subscription))
scheduler-config {:cron cron-expression
:identity job-identity
:time-zone (:time-zone config)}]
(schedule-job config scheduler-config upcoming-subscription)))
upcoming-subscriptions))
(defmethod ig/init-key :foo.service.schedule/upcoming-subscription
[_ {:keys [logger] :as config}]
(let [{:keys [success? upcoming-subscriptions]} (srv-us/get-upcoming-subscriptions config)]
(if success?
(schedule-jobs config upcoming-subscriptions)
(log logger :error :upcoming-subscriptions-scheduling-failed {:reason :could-not-get-upcoming-subscriptions}))))
(ns foo.service.create-upcoming-stripe-subscription
(:require [magnet.payments.core :as payment]
[magnet.payments.stripe]
[foo.service.create-subscription :as srv-cs]
[foo.service.upcoming-subscription :as srv-us]
[foo.util.thread-transactions :as tht])
(:import [java.time ZoneOffset]))
(defn main
[{:keys [payment-adapter] :as config} {:keys [id] :as upcoming-subscription}]
(let [{:keys [upcoming-subscription] (srv-us/get-upcoming-subscription config id)}]
(-> [{:txn-fn (fn txn-2 [_]
(let [result (srv-us/delete-upcoming-subscription config id)]
(if (:success? result)
{:success? true}
{:success? false})))}
{:txn-fn (fn txn-3 [prv-result]
(let [{:keys [success? customer]} (payment/get-customer payment-adapter (:customer-id upcoming-subscription))]
(if success?
(assoc prv-result :payment-method-id (-> customer :invoice_settings :default_payment_method))
{:success? false})))}
{:txn-fn (fn txn-4 [{:keys [payment-method-id upcoming-subscription]}]
(let [subscription (-> upcoming-subscription
(assoc :payment-method-id payment-method-id)
(dissoc :user-id))
result (srv-cs/main config subscription)]
(if (:success? result)
result
{:success? false})))}]
(tht/thread-transactions {}))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment