Skip to content

Commit

Permalink
OK-748 invalidate payments on demand
Browse files Browse the repository at this point in the history
  • Loading branch information
vaeinoe committed Dec 9, 2024
1 parent c0f7813 commit 320963a
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
ALTER TABLE invoices ADD COLUMN invalidated_at TIMESTAMP;

CREATE OR REPLACE VIEW all_invoices
AS
SELECT
i.id,
i.order_id,
i.first_name,
i.last_name,
i.email,
i.amount,
i.origin,
i.reference,
i.due_date,
i.created_at,
s.secret,
CASE
WHEN p.paid_at IS NOT NULL THEN 'paid'
WHEN i.invalidated_at IS NOT NULL THEN 'invalidated'
WHEN i.due_date < CURRENT_DATE THEN 'overdue'
ELSE 'active'
END AS status,
p.paid_at,
i.metadata,
i.vat,
i.invalidated_at
FROM invoices i
LEFT OUTER JOIN latest_secrets s on (i.id = s.id)
LEFT OUTER JOIN latest_payments p on (i.id = p.id);
11 changes: 8 additions & 3 deletions src/clj/maksut/maksut/db/maksut_queries.clj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
(declare select-payment)
(declare insert-payment!)
(declare insert-secret-for-invoice!)
(declare invalidate-laskut-by-reference!)

(defn invalidate-laskut-by-reference [db refs]
(invalidate-laskut-by-reference! db {:refs refs}))

(defn- insert-new-secret [db invoice-id order-id]
;prefix secrets with order-id to force them unique even if random would generate two identical
Expand Down Expand Up @@ -50,9 +54,10 @@
(let [status (:status old-ai)
same-origin (= (:origin old-ai) (:origin new))]
(cond
(= status "overdue") (maksut-error :invoice-invalidstate-overdue (str "Ei voi muuttaa, eräpäivä mennyt: " new))
(= status "paid") (maksut-error :invoice-invalidstate-paid (str "Ei voi muuttaa, lasku on jo maksettu: " new))
(not same-origin) (maksut-error :invoice-createerror-originclash (str "Sama lasku eri lähteestä on jo olemassa: " new)))
(= status "overdue") (maksut-error :invoice-invalidstate-overdue (str "Ei voi muuttaa, eräpäivä mennyt: " new))
(= status "paid") (maksut-error :invoice-invalidstate-paid (str "Ei voi muuttaa, lasku on jo maksettu: " new))
(= status "invalidated") (maksut-error :invoice-invalidstate-invalidated (str "Ei voi muuttaa, mitätöity: " new))
(not same-origin) (maksut-error :invoice-createerror-originclash (str "Sama lasku eri lähteestä on jo olemassa: " new)))
true))

(defn get-lasku [db order-id]
Expand Down
5 changes: 5 additions & 0 deletions src/clj/maksut/maksut/db/maksut_queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ SET
--~ (when (some? (:metadata params)) ", metadata = :metadata")
WHERE order_id = :order-id AND CURRENT_DATE <= due_date;

-- :name invalidate-laskut-by-reference! :! :n
UPDATE invoices
SET invalidated_at = now()
WHERE reference IN (:v*:refs) AND CURRENT_DATE <= due_date;

-- :name get-lasku-locked :? :1
SELECT *
FROM invoices
Expand Down
11 changes: 10 additions & 1 deletion src/clj/maksut/maksut/maksut_service.clj
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,13 @@
(get-lasku-contact [_ _ secret]
(if-let [laskut (seq (maksut-queries/get-laskut-by-secret db secret))]
{:contact (contact-email (first laskut))}
(maksut-error :invoice-notfound-secret (str "Linkki on väärä tai vanhentunut: " secret) {:status-code 404}))))
(maksut-error :invoice-notfound-secret (str "Linkki on väärä tai vanhentunut: " secret) {:status-code 404})))

; NB: only marks the payments invalid on our side so that it can't be accidentally paid anymore.
; The actual Paytrail payment is still open and updated internally.
(invalidate-laskut [_ _ input]
(log/info (str "Invalidating invoices with references:" keys))
(let [{:keys [keys]} input
_ (maksut-queries/invalidate-laskut-by-reference db keys)
statuses (maksut-queries/check-laskut-statuses-by-reference db keys)]
(map LaskuStatus->json statuses))))
3 changes: 2 additions & 1 deletion src/clj/maksut/maksut/maksut_service_protocol.clj
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
(check-status [this session input])
(get-lasku [this session order-id])
(get-lasku-contact [this session secret])
(get-laskut-by-secret [this session secret]))
(get-laskut-by-secret [this session secret])
(invalidate-laskut [this session input]))
3 changes: 2 additions & 1 deletion src/clj/maksut/payment/payment_service.clj
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"items" [{"description" (case origin
"tutu" (create-description language-code order-number)
"astu" (str (get-translation (keyword language-code) :astukuitti/oph) " " form-name)
"kkhakemusmaksu" (create-kk-payment-description language-code form-name))
"kkhakemusmaksu" (create-kk-payment-description language-code haku-name))
"units" 1
"unitPrice" amount-in-euro-cents
"vatPercentage" (or vat vat-zero)
Expand Down Expand Up @@ -158,6 +158,7 @@
(cond
(not (some? lasku)) (maksut-error :invoice-notfound (str "Laskua ei löydy: " secret))
(= (:status lasku) "overdue") (maksut-error :invoice-invalidstate-overdue (str "Lasku on erääntynyt: " secret))
(= (:status lasku) "invalidated") (maksut-error :invoice-invalidstate-invalidated (str "Lasku on mitätöity: " secret))
(= (:status lasku) "paid") (maksut-error :invoice-invalidstate-paid (str "Lasku on jo maksettu: " secret)))

(when (not= (:status lasku) "active")
Expand Down
12 changes: 12 additions & 0 deletions src/clj/maksut/routes.clj
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,18 @@
(let [x (maksut-protocol/check-status maksut-service session input)]
(response/ok x)))}}]]

["/lasku-invalidate"
[""
{:post {:middleware auth
:tags ["Lasku"]
:summary "Mitätöi yhden tai useamman laskun viitenumeron perusteella"
:responses {200 {:body schema/LaskuStatusList}}
:parameters {:body schema/LaskuRefList}
:handler (fn [{session :session {input :body} :parameters}]
(log/info "Invalidate invoices for" (count input) "keys")
(let [resp (maksut-protocol/invalidate-laskut maksut-service session input)]
(response/ok resp)))}}]]

["/lasku/:application-key"
[""
{:get {:middleware auth
Expand Down
3 changes: 2 additions & 1 deletion src/cljc/maksut/api_schemas.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@
(s/enum
:active
:paid
:overdue))
:overdue
:invalidated))

(s/defschema LaskuRefList
{:keys [s/Str]})
Expand Down
6 changes: 6 additions & 0 deletions src/cljc/maksut/translations.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
:KkHakemusmaksuPanel.eraantynyt {:fi "Hakemusmaksun määräaika on erääntynyt, etkä voi enää maksaa hakemusmaksua. Hakemustasi ei käsitellä, etkä voi tulla valituksi koulutukseen. Mikäli hakuaikaa on vielä jäljellä, voit täyttää uuden hakemuksen."
:en "The due date for your application fee payment has expired. You can no longer pay the application fee. Your application will not be reviewed, and you cannot be offered admission. If the application period is still ongoing, you can fill in and send a new application."
:sv "Tidsfristen för ansökningsavgiften har gått ut och du kan inte längre betala avgiften. Din ansökan behandlas inte och du kan inte bli antagen till utbildningen. Om ansökningstiden ännu pågår kan du fylla i en ny ansökan."}
:KkHakemusmaksuPanel.mitatoity {:fi "Olet jo maksanut hakemusmaksun tälle aloituskaudelle."
:en "EN Olet jo maksanut hakemusmaksun tälle aloituskaudelle."
:sv "SV Olet jo maksanut hakemusmaksun tälle aloituskaudelle."}
:KkHakemusmaksuPanel.aloituskausi {:fi "Alkamiskausi"
:en "Start term"
:sv "Starttermin"}
Expand Down Expand Up @@ -118,6 +121,9 @@
:Maksu.overdue {:fi "Erääntynyt"
:en "Expired"
:sv "Förfallen"}
:Maksu.invalidated {:fi "Mitätöity"
:en "EN: mitätöity"
:sv "SV: mitätöity"}
:Maksu.summa {:fi "Määrä"
:en "Amount"
:sv "Summa"}
Expand Down
6 changes: 6 additions & 0 deletions src/maksut-ui/app/components/KkHakemusmaksuPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ const KkHakemusmaksuPanel = ({ lasku }: { lasku: Lasku }) => {
<span>{t('eraantynyt')}</span>
</>
);
} else if (lasku.status === 'invalidated') {
return (
<>
<span>{t('mitatoity')}</span>
</>
);
} else {
return (
<>
Expand Down
5 changes: 5 additions & 0 deletions src/maksut-ui/app/components/Maksu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ const StatusRow = ({ status }: { status: PaymentStatus }) => {
dot: '#61a33b',
text: '#237a00',
},
invalidated: {
backgroundColor: '#e2fae4',
dot: '#61a33b',
text: '#237a00',
},
};

return (
Expand Down
2 changes: 1 addition & 1 deletion src/maksut-ui/app/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type PaymentStatus = 'active' | 'paid' | 'overdue';
export type PaymentStatus = 'active' | 'paid' | 'overdue' | 'invalidated';

export type PaymentState =
| 'kasittelymaksamatta'
Expand Down
39 changes: 39 additions & 0 deletions test/clj/maksut/payment/payment_service_spec.clj
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,45 @@
(is (= (:code data) :invoice-invalidstate-overdue)))))
))

(deftest pay-invalidated-invoice
(let [service (:payment-service @test-system)
maksut-service (:maksut-service @test-system)
db (:db @test-system)

due-date (time/from-now (time/days +7))
db-data (db-invoice-hakemusmaksu due-date)
secret "foobar"
invoice-insert (test-fixtures/add-invoice! db
(merge db-data {:invalidated_at (to-sql-date "2024-12-09 10:23:54")}))
invoice-id (-> invoice-insert first :id)]

(jdbc/insert! db :secrets {:fk_invoice invoice-id
:secret secret})

(testing "Try to pay invoice that has been invalidated"
(let [exc (catch-thrown-info (payment-protocol/payment service maksut-test-fixtures/fake-session
{:order-id (:order_id db-data)
:locale "fi"
:secret secret}))
data (:data exc)]
(is (= (:type data) :maksut.error))
(is (= (:code data) :invoice-invalidstate-invalidated))
))

(testing "Try to edit invalidated invoice"
(let [lasku {:reference (:reference db-data)
:first-name (:first_name db-data)
:last-name (:last_name db-data)
:email (:email db-data)
:amount "222.00"
:due-days 7
:origin (:origin db-data)}]
(let [exc (catch-thrown-info (maksut-protocol/create maksut-service maksut-test-fixtures/fake-session lasku))
data (:data exc)]
(is (= (:type data) :maksut.error))
(is (= (:code data) :invoice-invalidstate-invalidated)))))
))

(deftest pay-at-due-date
(let [service (:payment-service @test-system)
db (:db @test-system)
Expand Down

0 comments on commit 320963a

Please sign in to comment.