Changes between Initial Version and Version 1 of BuyPackage


Ignore:
Timestamp:
03/03/26 09:35:01 (3 weeks ago)
Author:
202033
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • BuyPackage

    v1 v1  
     1= Купување пакет
     2
     3== Актери
     4 * Најавен корисник (клиент)
     5
     6== Чекор 1
     7Најавениот корисник ја отвора страницата за пакети, на пример:
     8 * страницата '''Book an Appointment''' (/book), каде се прикажува листа на пакети, или 
     9 * страницата '''My Packages''' (/my-packages).
     10
     11Системот му прикажува листа на достапни пакети со:
     12 * име на пакет,
     13 * максимален број користења (max_usage),
     14 * вкупна цена,
     15 * услугите што се вклучени во пакетот.
     16
     17Податоците за пакетите се вчитуваат со следниот SQL:
     18
     19{{{
     20SELECT
     21  p.package_id,
     22  p.name AS package_name,
     23  p.max_usage,
     24  CASE
     25    WHEN EXISTS (
     26      SELECT 1
     27      FROM information_schema.columns
     28      WHERE table_name = 'package'
     29        AND column_name = 'total_price'
     30    ) THEN p.total_price
     31    ELSE package_price.calc_total_price
     32  END::numeric AS total_price,
     33  s.service_id,
     34  s.name AS service_name,
     35  ps.discounted_price
     36FROM Package p
     37LEFT JOIN LATERAL (
     38  SELECT COALESCE(SUM(ps2.discounted_price), 0)::numeric AS calc_total_price
     39  FROM PackageService ps2
     40  WHERE ps2.package_id = p.package_id
     41) package_price ON true
     42LEFT JOIN PackageService ps
     43  ON ps.package_id = p.package_id
     44LEFT JOIN Service s
     45  ON s.service_id = ps.service_id
     46ORDER BY p.package_id, s.name;
     47}}}
     48
     49== Чекор 2
     50Корисникот избира конкретен пакет и кликнува на:
     51 * '''Buy only''' / '''Buy package''' – ако сака да го купи пакетот без веднаш да резервира термин, или
     52 * '''Buy & use now''' – ако сака да го купи пакетот и веднаш да го искористи при резервирање термин.
     53
     54Во двата случаи, системот треба да го купи пакетот за корисникот.
     55
     56== Чекор 3
     57Системот го проверува избраниот пакет и ја пресметува вкупната цена што треба да се плати.
     58
     59Се вчитува пакетот од базата според ''package_id'':
     60
     61{{{
     62SELECT
     63  p.package_id,
     64  p.name,
     65  p.max_usage,
     66  CASE
     67    WHEN EXISTS (
     68      SELECT 1
     69      FROM information_schema.columns
     70      WHERE table_name = 'package'
     71        AND column_name = 'total_price'
     72    ) THEN p.total_price
     73    ELSE package_price.calc_total_price
     74  END::numeric AS total_price
     75FROM package p
     76LEFT JOIN LATERAL (
     77  SELECT COALESCE(SUM(ps.discounted_price), 0)::numeric AS calc_total_price
     78  FROM packageservice ps
     79  WHERE ps.package_id = p.package_id
     80) package_price ON true
     81WHERE p.package_id = $1;
     82}}}
     83
     84Параметар:
     85 * $1 – ''package_id'' на избраниот пакет.
     86
     87Ако пакетот не постои, системот враќа грешка и купувањето се прекинува.
     88
     89== Чекор 4
     90Доколку пакетот е валиден, системот креира запис дека корисникот го купил пакетот, преку складираната функција '''sp_user_purchase_package''':
     91
     92{{{
     93SELECT sp_user_purchase_package($1::int, $2::int) AS purchase_id;
     94}}}
     95
     96Параметри:
     97 * $1 – ''user_id'' на најавениот корисник,
     98 * $2 – ''package_id'' на избраниот пакет.
     99
     100Функцијата ''sp_user_purchase_package'' вметнува ред во табелата ''UserPackagePurchase'' со:
     101 * ''user_id'' – корисникот кој купува пакет,
     102 * ''package_id'' – избраниот пакет,
     103 * ''total_uses'' – максимален број користења (''max_usage'' од ''Package''),
     104 * ''remaining_uses'' – почетно еднакво на ''total_uses'',
     105 * ''status'' – 'ACTIVE'.
     106
     107== Чекор 5
     108Потоа системот креира запис за плаќањето на овој пакет во табелата ''payment''. 
     109Ова плаќање е поврзано со купениот пакет (''package_purchase_id''), а не со конкретен термин (''appointment_id'' е NULL):
     110
     111{{{
     112INSERT INTO payment (amount, method, status, appointment_id, points_used, package_purchase_id)
     113VALUES ($1::numeric, $2::text, 'PENDING', NULL, 0, $3::int)
     114RETURNING payment_id;
     115}}}
     116
     117Параметри:
     118 * $1 – вкупната цена на пакетот (''total_price'' од Чекор 3),
     119 * $2 – метод на плаќање, на пример 'online' или 'CARD',
     120 * $3 – ''purchase_id'' добиен од ''sp_user_purchase_package''.
     121
     122Во овој тек:
     123 * ''appointment_id'' е NULL (се купува пакет, не термин),
     124 * ''points_used = 0'' – не се дозволува користење лојалти поени за купување пакет.
     125
     126Ограничувањата за ова плаќање се спроведуваат и преку trigger функцијата '''trg_payment_validate''', која осигурува дека:
     127 * има или ''appointment_id'' или ''package_purchase_id'',
     128 * за купување пакет (''appointment_id IS NULL'' и ''package_purchase_id IS NOT NULL'') сумата на плаќањето одговара на вкупната цена на пакетот,
     129 * не може да се користат лојалти поени (''points_used'' мора да биде 0).
     130
     131== Чекор 6
     132По успешно креирање на плаќањето, системот го означува плаќањето како платено и доделува лојалти поени на корисникот со повик на функцијата '''sp_mark_payment_paid''':
     133
     134{{{
     135SELECT sp_mark_payment_paid($1::int) AS points_used;
     136}}}
     137
     138Параметар:
     139 * $1 – ''payment_id'' на креираното плаќање.
     140
     141Во случај на купување пакет (т.е. кога плаќањето има ''package_purchase_id'' и ''appointment_id IS NULL''), функцијата:
     142
     143 * проверува дека не постои друго 'PAID' плаќање за истото ''package_purchase_id'',
     144 * ја ажурира табелата ''payment'':
     145   * ''status = 'PAID' '',
     146   * ''amount'' = вкупната цена на пакетот,
     147   * ''points_used = 0'',
     148 * се грижи да постои лојалти картичка за корисникот преку ''sp_ensure_loyalty_card'',
     149 * пресметува колку поени да се доделат (на пример 5% од вкупната цена на пакетот) и ги зголемува ''points'' во табелата ''loyaltycard''.
     150
     151Пример логика за доделување поени (во функцијата):
     152
     153 * ''v_points_earned := FLOOR(COALESCE(v_total_price, 0) * 0.05);''
     154 * ''UPDATE loyaltycard SET points = points + v_points_earned WHERE user_id = v_user_id;''
     155
     156== Чекор 7
     157По означувањето на плаќањето како платено, системот ги враќа деталите за купениот пакет за прикажување на корисникот:
     158
     159{{{
     160SELECT
     161  upp.purchase_id,
     162  upp.package_id,
     163  p.name AS package_name,
     164  upp.total_uses,
     165  upp.remaining_uses,
     166  upp.status,
     167  upp.purchased_at,
     168  upp.expires_at
     169FROM userpackagepurchase upp
     170JOIN package p
     171  ON p.package_id = upp.package_id
     172WHERE upp.purchase_id = $1
     173LIMIT 1;
     174}}}
     175
     176Параметар:
     177 * $1 – ''purchase_id'' на купениот пакет.
     178
     179Дополнително, се вчитува и моменталниот број лојалти поени:
     180
     181{{{
     182SELECT points
     183FROM loyaltycard
     184WHERE user_id = $1;
     185}}}
     186
     187== Резултат
     188 * Во табелата ''UserPackagePurchase'' постои нов запис за купениот пакет, со ''status = 'ACTIVE' '' и иницијално ''remaining_uses = total_uses''.
     189 * Во табелата ''payment'' постои запис за плаќањето на пакетот со ''status = 'PAID' '', правилен износ и ''points_used = 0''.
     190 * Во табелата ''loyaltycard'' се ажурира бројот на поени на корисникот (се доделуваат поени за купениот пакет).
     191 * Корисникот на екранот добива потврда дека пакетот е успешно купен и може:
     192   * да го види во '''My Packages''' со број на преостанати користења, или
     193   * во случај на опцијата '''Buy & use now''', веднаш да го искористи при создавање термин