| Version 1 (modified by , 3 weeks ago) ( diff ) |
|---|
Купување пакет
Актери
- Најавен корисник (клиент)
Чекор 1
Најавениот корисник ја отвора страницата за пакети, на пример:
- страницата Book an Appointment (/book), каде се прикажува листа на пакети, или
- страницата My Packages (/my-packages).
Системот му прикажува листа на достапни пакети со:
- име на пакет,
- максимален број користења (max_usage),
- вкупна цена,
- услугите што се вклучени во пакетот.
Податоците за пакетите се вчитуваат со следниот SQL:
SELECT
p.package_id,
p.name AS package_name,
p.max_usage,
CASE
WHEN EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'package'
AND column_name = 'total_price'
) THEN p.total_price
ELSE package_price.calc_total_price
END::numeric AS total_price,
s.service_id,
s.name AS service_name,
ps.discounted_price
FROM Package p
LEFT JOIN LATERAL (
SELECT COALESCE(SUM(ps2.discounted_price), 0)::numeric AS calc_total_price
FROM PackageService ps2
WHERE ps2.package_id = p.package_id
) package_price ON true
LEFT JOIN PackageService ps
ON ps.package_id = p.package_id
LEFT JOIN Service s
ON s.service_id = ps.service_id
ORDER BY p.package_id, s.name;
Чекор 2
Корисникот избира конкретен пакет и кликнува на:
- Buy only / Buy package – ако сака да го купи пакетот без веднаш да резервира термин, или
- Buy & use now – ако сака да го купи пакетот и веднаш да го искористи при резервирање термин.
Во двата случаи, системот треба да го купи пакетот за корисникот.
Чекор 3
Системот го проверува избраниот пакет и ја пресметува вкупната цена што треба да се плати.
Се вчитува пакетот од базата според package_id:
SELECT
p.package_id,
p.name,
p.max_usage,
CASE
WHEN EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'package'
AND column_name = 'total_price'
) THEN p.total_price
ELSE package_price.calc_total_price
END::numeric AS total_price
FROM package p
LEFT JOIN LATERAL (
SELECT COALESCE(SUM(ps.discounted_price), 0)::numeric AS calc_total_price
FROM packageservice ps
WHERE ps.package_id = p.package_id
) package_price ON true
WHERE p.package_id = $1;
Параметар:
- $1 – package_id на избраниот пакет.
Ако пакетот не постои, системот враќа грешка и купувањето се прекинува.
Чекор 4
Доколку пакетот е валиден, системот креира запис дека корисникот го купил пакетот, преку складираната функција sp_user_purchase_package:
SELECT sp_user_purchase_package($1::int, $2::int) AS purchase_id;
Параметри:
- $1 – user_id на најавениот корисник,
- $2 – package_id на избраниот пакет.
Функцијата sp_user_purchase_package вметнува ред во табелата UserPackagePurchase со:
- user_id – корисникот кој купува пакет,
- package_id – избраниот пакет,
- total_uses – максимален број користења (max_usage од Package),
- remaining_uses – почетно еднакво на total_uses,
- status – 'ACTIVE'.
Чекор 5
Потоа системот креира запис за плаќањето на овој пакет во табелата payment. Ова плаќање е поврзано со купениот пакет (package_purchase_id), а не со конкретен термин (appointment_id е NULL):
INSERT INTO payment (amount, method, status, appointment_id, points_used, package_purchase_id) VALUES ($1::numeric, $2::text, 'PENDING', NULL, 0, $3::int) RETURNING payment_id;
Параметри:
- $1 – вкупната цена на пакетот (total_price од Чекор 3),
- $2 – метод на плаќање, на пример 'online' или 'CARD',
- $3 – purchase_id добиен од sp_user_purchase_package.
Во овој тек:
- appointment_id е NULL (се купува пакет, не термин),
- points_used = 0 – не се дозволува користење лојалти поени за купување пакет.
Ограничувањата за ова плаќање се спроведуваат и преку trigger функцијата trg_payment_validate, која осигурува дека:
- има или appointment_id или package_purchase_id,
- за купување пакет (appointment_id IS NULL и package_purchase_id IS NOT NULL) сумата на плаќањето одговара на вкупната цена на пакетот,
- не може да се користат лојалти поени (points_used мора да биде 0).
Чекор 6
По успешно креирање на плаќањето, системот го означува плаќањето како платено и доделува лојалти поени на корисникот со повик на функцијата sp_mark_payment_paid:
SELECT sp_mark_payment_paid($1::int) AS points_used;
Параметар:
- $1 – payment_id на креираното плаќање.
Во случај на купување пакет (т.е. кога плаќањето има package_purchase_id и appointment_id IS NULL), функцијата:
- проверува дека не постои друго 'PAID' плаќање за истото package_purchase_id,
- ја ажурира табелата payment:
- status = 'PAID' ,
- amount = вкупната цена на пакетот,
- points_used = 0,
- се грижи да постои лојалти картичка за корисникот преку sp_ensure_loyalty_card,
- пресметува колку поени да се доделат (на пример 5% од вкупната цена на пакетот) и ги зголемува points во табелата loyaltycard.
Пример логика за доделување поени (во функцијата):
- v_points_earned := FLOOR(COALESCE(v_total_price, 0) * 0.05);
- UPDATE loyaltycard SET points = points + v_points_earned WHERE user_id = v_user_id;
Чекор 7
По означувањето на плаќањето како платено, системот ги враќа деталите за купениот пакет за прикажување на корисникот:
SELECT upp.purchase_id, upp.package_id, p.name AS package_name, upp.total_uses, upp.remaining_uses, upp.status, upp.purchased_at, upp.expires_at FROM userpackagepurchase upp JOIN package p ON p.package_id = upp.package_id WHERE upp.purchase_id = $1 LIMIT 1;
Параметар:
- $1 – purchase_id на купениот пакет.
Дополнително, се вчитува и моменталниот број лојалти поени:
SELECT points FROM loyaltycard WHERE user_id = $1;
Резултат
- Во табелата UserPackagePurchase постои нов запис за купениот пакет, со status = 'ACTIVE' и иницијално remaining_uses = total_uses.
- Во табелата payment постои запис за плаќањето на пакетот со status = 'PAID' , правилен износ и points_used = 0.
- Во табелата loyaltycard се ажурира бројот на поени на корисникот (се доделуваат поени за купениот пакет).
- Корисникот на екранот добива потврда дека пакетот е успешно купен и може:
- да го види во My Packages со број на преостанати користења, или
- во случај на опцијата Buy & use now, веднаш да го искористи при создавање термин
