# Բանկոմատ Վերջնաժամկետ՝ **01/12/2023 23:59** ## Ներածություն Պրոյեկտի շրջանակում ուզում ենք պատրաստել բանկոմատ։ Բանկոմատի հիմնական հնարավորությունները ընդգրկելու են՝ - Կոդերով թղթադրամներ - Հաղորդակցություն արտաքին բանկի հետ - (Ցանկուոյան դեպքում) Կոդավորված հաղորդակցություն բանկի հետ ## Բանկոմատի Ընդհանուր Աշխատանք Բանկոմատը անընդհատ աշխատում է այս սխեմայով՝ - Սպասում է քարտի համարի մութքի - Հարցնում է քարտի PIN կոդ 1. **WITHDRAW** ընտրելուց սպասարկում է գումարի ելքը 2. **DEPOSIT** ընտրելուց սպասարկում է գումարի մութքը 3. **CHECK BALANCE** ընտրելուց սպասարկում է քարտի բալանսի ստուգումը 4. **CHANGE PIN** ընտրելուց սպասարկում է PIN կոդի փոխումը Հրահանգների սպասարկամ մանրամասները հաջորթող մասերում են։ ### Բանկ Բանկի հետ կարելի է աշխատել [bank.py](https://gev.serveo.net/tent/project/bank.py)֊ի կողմից տրամադրած մեթոդների միջոցով։ Ցանկության դեպքում կարելի թեստավորման նպատակով որոշ փոփխություններ կատարել սեփական `bank.py`֊ին, բայց հարկավոր է հիշել, որ լուծումը ուղարկելուց փոփոխումներով `bank.py` չի ընդունվելու։ ### Քարտեր Քարտերը **string** են, որոնք ունեն "card0000" ֆորմատը, 0000֊ի տեղը քարտի համարը։ Քարտերը իրենց հետ կապված նաև ունեն 4֊նիշանոց PIN-կոդ որպես և դրամային բալանս։ PIN-կոդը որպես **string** և բալանսը որպես **int**։ Քարտերի օրինակները գտնվում են `bank.py`֊ի `db` բառարանում։ ### Թղթադրամներ Թղթադրամները ունեն կոդ, որը բաղկացաց է երկու տառից և չորս թվից։ Երկու տառը արտահայտում են թղթադրամի արժեքը `ha`, `er`, `hi`, `ta`, `qs` համապատասխանաբար `1000`, `2000`, `5000`, `10000`, `20000`։ Թղթադրամների կոդի օրինակ՝ `ha4851` համապատասխանում է կոդով `4851` հազար դրամանոցին։ ### Քարտի ստուգում Բանկոմատը տպում է "INSERT CARD: " և մութքից ստանում է քարտ։ Եթե քարտի տեղը մութքագրվել է "EXIT", ավարտում է աշխատանքը։ Հակառակ դեպքում ստուգում է քարտը `bank.card_exists(card)` մեթոդով։ Եթե քարտը գոյություն չունի կամ այլ մութքի տվյալների սխալներ կան, ապա տպում է "UNKNOWN CARD" և շարունակում իր աշխատանքը։ Ճիշտ քարտ ստանալուց հետո, հարցնում է PIN-կոդ։ PIN-կոդը կարելի է ստուգել `bank.valid_pin(card, otp, safe=True)` մեթոդով, որը ունի երկու ռեժիմ, անապահով և ապահով։ - Ապահով ռեժիմը կոդավորում է PIN-կոդը և ստանում է մեկ անգամվա օգտագործման կոդ (One-Time Password) կամ ուղակի otp (Կոդավորման Բաժին) - Անապահով ռեժիմը չի կոդավորում PIN-կոդը և ուղակի otp֊ի տեղը մի անգամից տալիս է PIN-կոդը, և `safe`֊ին տալիս է `False` արժեքը Եթե PIN-կոդը սխալ է, տպում է "WRONG PIN" և վերադառնում իր աշխատանքին։ Հակառակ դեպքում տպում է համարակալած մենյուն։ ``` 1 WITHDRAW 2 DEPOSIT 3 CHECK BALANCE 4 CHANGE PIN CHOICE: ``` 1-4 Մութքագրված թվիծ կախված սպասարկում է ընտրված օպեացիան։ Այլ արժեք ստանալու դեպքում, ուղակի նորից է հարցնում։ ---- ## 1 WITHDRAW Նախ տպելով ``` ONLY MULTIPLES OF 1000 ``` տեղեկացնում է, որ պատրաստ է տրամադրել միայն 1000֊ին բազմապատիկ արժեքներ։ Ապա տպում է "ENTER AMOUNT: " և ակնկալում է 1000֊ին բազմապատիկ թիվ։ ``` ENTER AMOUNT: 18000 ``` Եթե մութքագրված արժեքը սխալ ֆորմատ ունի, նորից է հարցնում։ Եթե մութքագրված արժեքը 1000֊ին բազմապատիկ չէ, տպում է ``` INVALID AMOUNT ``` Հետո, ստուգում է արդյոք քարտին այդքան գումար կա `bank.can_withdraw(card, otp, amount, safe=True)` մեթոդով։ Եթե ոչ տպում է ``` LACK OF FUNDS ``` Հետո, ստուգում է արդյոք իր ներսում եղած թղթադրամներով կարղ է ստանալ պահանջվող գումարը, եթե ոչ ապա տպում է ``` REQUESTED AMOUNT UNAVAILABLE ``` Վերջապես, `bank.withdraw(card, otp, amount, safe=True)` մեթոդով հաստատում է բալանսի մարումը բանկում, և տպում է ընտրված թղթադրամների կոդերը։ Օրինակ՝ ``` COLLECT YOUR CASH: ta0124 hi3123 er3214 ha4851 ``` Բանկոմատը պետք է փորձի տալ հնարավորինս մեծ թղթադրամներով։ **Բանկոմատը աշխատանքը սկսելուց չպետք է ունենա իր ներսում ոչ մի թղթադրամ**։ Ավտոմատ թեստերում ենթադրվելու է, որ բանկոմատը սկզբում դատարկ է։ Բանկոմատը ընտրում է թղթադրամներ կախված մութքագրման հերթականությանունից։ Այսինքն մութգարլեուց դրամարկղի նման թղթադրամները իրար վրա է հավաքում ըստ կատեգորիայի (Stack֊ի նման Last-In-First-Out)։ Հետևաբար, այն դեպքերում երբ, որ պետք է ընտրել օրինակ երկու հազար դրամից մեկը, կնտրվի ավելի ուշ մութքագրվածը ## 2 DEPOSIT Նախ տպելով ``` ONLY 1000, 2000, 5000, 10000, 20000 ``` տեղեկացնում է, որ պատրաստ է ընդունել միայն նշված թղթադրամները։ Ապա տպում է "ENTER BILLS: " և ակնկալում մի տողում գրված, բացատով առանձնացված թղթադրամների կոդեր։ Օրինակ՝ ``` ENTER BILLS: ta0124 hi3123 ``` Հետո, `bank.valid_bill(bill)` մեթոդի միջոցով ստուգում է թղթադրամի կոդի առկայությունը։ Եթե մութքագրած թղթադրամներից որևէ մեկը սխալ ֆորմատ ունի, կամ չի ճանաչվում բանկի կողմից ապա տպում է "INVALID BILLS: " և այդպիսի միայն թղթադրամների կոդերը բացատով առանձնացված։ Տպելուց հետո վերադառնում է իր աշխատանքին։ Օրինակ՝ ``` INVALID BILLS: hazar_dram ``` Եթե խնդիր չկա, իր հիշողության մեջ ավելացնում է այդ թղթադրամները, բանկում իրենց գումարով ավելացնում է balance֊ը `bank.deposit(card, otp, amount, safe=True)` մեթոդով և տպում է։ ``` SUCCESS. ENTERED AMOUNT XXXX AMD ``` Հակառակ դեպում եթե որևէ այլ խնդիր կա, ապա չի ընդունում թղթադրամները, բալանսը չի ավելացնում, և տպում է ``` DEPOSIT ERROR ``` Որից հետո վերադառնում իր աշխատանքին։ ## 3 CHECK BALANCE Օգտագործելով `bank.get_balance(card, otp, safe=True)` մեթոդը, տպում է քարտի բալանսը ``` BALANCE: XXXX AMD ``` ֆորմատով։ ## 4 CHANGE PIN Հարցնում է նոր PIN֊կոդ նախ "NEW PIN: " տպելով։ Եթե նոր PIN֊կոդը չի համապատասխանում PIN-կոդի 4 նշանոց ֆորմատին, ուղակի նորից է հարցնում։ Ճիշտ ֆորմատով PIN-կոդ ստանալուց հետո օգտագործելով `bank.change_pin(card, otp, new_pin, safe=True)` մեթոդը, փորձում է փոխել PIN֊ը։ Եթե հաջողվում է փոխել, ապա տպում է ``` PIN CHANGED ``` և վերադառնում իր աշխատանքին։ Իսկ եթե ոչ, ապա ոչ մի բան չի տպում, և ուղակի վերադառնում իր աշխատանքին։ ## Կոդավորում Ապահովության համար բանկոմատը չի պահում PIN֊կոդը, այլ պահում է hash(pin)֊ից ստացված հաշը։ Իսկ Բանկին այդ հաշը ուղարկելուց առաջ [1; 1000000] պատահական թիվ է ընտրում գումարում հաշին և նոր ուղարկում այդ արժեքը բանկին, որպես otp (One-Time Password)։ Բանկը և բանկոմատը նույն "CODETENT" Seed-ով են միացնում իրենց random օբյեկտները։ Ընդ, որում բանկոմատը ամեն հրահանգ կատարելուց որտեղ otp է օգտագործվում, պետք է սկզբնական հաշին նոր հաջորդական թիվ գումարի։ Բանկոմատը կարող է ասել բանկին, որպեսզի նա seed֊ով զրոյացնի իր random օբյեկտը։ Օգտվելով `bank.resync()` մեթոդից։ Այդպես կարելի անել բանկոմատի աշխատանքի ամենա սկզբում։ OTP Օրինակ: Ենթադրենք մենք նոր ենք միացրել բանկոմատը և մութգարվել է "4242" PIN-կոդը, մենք մի անգամից վերցնում ենք նրա հաշը, ենթադրենք -4067239946432026864։ Ապա կանչենք valid_pin մեթոդը, որի համար ``` otp = pin_hash + random.randint(1,1000000) ``` Քանի, որ random֊ը "CODETENT" Seed֊ով զրոյացվել էր, ապա կստանանք՝ ``` otp = -4067239946432026864 + 577862 = -4067239946431449002 ``` Հաջորդ otp արժեքը, օրինակ get_balance() կանչելու համար արդեն կլինի նույն ձև, բայց կստացվի ուրիշ արժեք ``` otp = -4067239946432026864 + 719988 = -4067239946431306876 ``` ## Գնահատում Ընդհանուր պրոյեկտի համար կարելի է հավաքել **100** միավոր։ Ընդ որում, ցանկության դեպքում կարելի է բաց թողել որոշ մասեր։ Ամեն մաս գնահատվելու է ըստ այս միավորների ցուցակի՝ (**25** միավոր): Բանկոմատի ընդհանուր ճիշտ աշխատանք։ (**25** միավոր): **WITHDRAW** (**20** միավոր): **DEPOSIT** (**10** միավոր): **CHECK BALANCE** (**10** միավոր): **CHANGE PIN** (**10** միավոր): Կոդավորված հաղորդակցություն բանկի հետ - Միավորներրը լինելու են ավտոմատ թեսթերից կախված, դրա համար **չի կարելի** տպել բնութագրված սահմաններից դուրս արժեքներ, ընդ որում, տերմինալը մաքրող նշաններ և կոդեր։ Ավտոմատ թեստերը լինելու են [tests.zip](https://gev.serveo.net/tent/project/tests.zip) թեստավորող ծրագրով։ Այն պատկանում է մի քանի պարզ թեսթեր, և վերջնական գնահատելուց ունենալու է հավելյալ թեստեր։ (Թեստավորող ծրագիրը ենթադրում է, որ բանկոմատը սկզբում դատարկ է)։