mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-27 14:07:51 +01:00
Merge pull request #14799 from variableundefined/tgui-atm
[TGUI] Convert ATM to TGUI
This commit is contained in:
+153
-143
@@ -7,11 +7,12 @@ log transactions
|
||||
|
||||
*/
|
||||
|
||||
#define NO_SCREEN 0
|
||||
#define DEFAULT_SCREEN 0
|
||||
#define CHANGE_SECURITY_LEVEL 1
|
||||
#define TRANSFER_FUNDS 2
|
||||
#define VIEW_TRANSACTION_LOGS 3
|
||||
#define PRINT_DELAY 100
|
||||
#define LOCKOUT_TIME 120
|
||||
|
||||
/obj/machinery/atm
|
||||
name = "Nanotrasen automatic teller machine"
|
||||
@@ -31,7 +32,7 @@ log transactions
|
||||
var/machine_id = ""
|
||||
var/obj/item/card/held_card
|
||||
var/editing_security_level = 0
|
||||
var/view_screen = NO_SCREEN
|
||||
var/view_screen = DEFAULT_SCREEN
|
||||
var/lastprint = 0 // Printer needs time to cooldown
|
||||
|
||||
/obj/machinery/atm/New()
|
||||
@@ -97,7 +98,7 @@ log transactions
|
||||
if(!powered())
|
||||
return
|
||||
var/obj/item/stack/spacecash/C = I
|
||||
playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 50, 1)
|
||||
playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 50, TRUE)
|
||||
|
||||
authenticated_account.credit(C.amount, "Credit deposit", machine_id, authenticated_account.owner_name)
|
||||
|
||||
@@ -115,21 +116,19 @@ log transactions
|
||||
return
|
||||
if(!linked_db)
|
||||
reconnect_database()
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atm/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
user.set_machine(src)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/atm/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "atm.tmpl", name, 550, 650)
|
||||
ui = new(user, src, ui_key, "ATM", name, 550, 650)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atm/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
data["src"] = UID()
|
||||
/obj/machinery/atm/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["view_screen"] = view_screen
|
||||
data["machine_id"] = machine_id
|
||||
data["held_card_name"] = held_card ? held_card.name : "------"
|
||||
@@ -155,139 +154,150 @@ log transactions
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/atm/Topic(href, list/href_list)
|
||||
if(href_list["choice"])
|
||||
switch(href_list["choice"])
|
||||
if("transfer")
|
||||
if(authenticated_account && linked_db)
|
||||
var/transfer_amount = text2num(href_list["funds_amount"])
|
||||
if(transfer_amount <= 0)
|
||||
alert("That is not a valid amount.")
|
||||
else if(transfer_amount <= authenticated_account.money)
|
||||
var/target_account_number = text2num(href_list["target_acc_number"])
|
||||
var/transfer_purpose = href_list["purpose"]
|
||||
if(linked_db.charge_to_account(target_account_number, authenticated_account, transfer_purpose, machine_id, transfer_amount))
|
||||
to_chat(usr, "[bicon(src)]<span class='info'>Funds transfer successful.</span>")
|
||||
else
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>Funds transfer failed.</span>")
|
||||
|
||||
else
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
if("view_screen")
|
||||
view_screen = text2num(href_list["view_screen"])
|
||||
if("change_security_level")
|
||||
if(authenticated_account)
|
||||
var/new_sec_level = max( min(text2num(href_list["new_security_level"]), 2), 0)
|
||||
authenticated_account.security_level = new_sec_level
|
||||
if("attempt_auth")
|
||||
if(linked_db)
|
||||
if(!ticks_left_locked_down)
|
||||
var/tried_account_num = text2num(href_list["account_num"])
|
||||
if(!tried_account_num && held_card)
|
||||
tried_account_num = held_card.associated_account_number
|
||||
var/tried_pin = text2num(href_list["account_pin"])
|
||||
|
||||
authenticated_account = attempt_account_access(tried_account_num, tried_pin, held_card && held_card.associated_account_number == tried_account_num ? 2 : 1)
|
||||
if(!authenticated_account)
|
||||
number_incorrect_tries++
|
||||
if(previous_account_number == tried_account_num)
|
||||
if(number_incorrect_tries > max_pin_attempts)
|
||||
//lock down the atm
|
||||
ticks_left_locked_down = 30
|
||||
playsound(src, 'sound/machines/buzz-two.ogg', 50, 1)
|
||||
|
||||
//create an entry in the account transaction log
|
||||
var/datum/money_account/failed_account = linked_db.get_account(tried_account_num)
|
||||
if(failed_account)
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = failed_account.owner_name
|
||||
T.purpose = "Unauthorised login attempt"
|
||||
T.source_terminal = machine_id
|
||||
T.date = GLOB.current_date_string
|
||||
T.time = station_time_timestamp()
|
||||
failed_account.transaction_log.Add(T)
|
||||
else
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining.</span>")
|
||||
previous_account_number = tried_account_num
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 1)
|
||||
else
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>Incorrect pin/account combination entered.</span>")
|
||||
number_incorrect_tries = 0
|
||||
else
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
ticks_left_timeout = 120
|
||||
view_screen = NO_SCREEN
|
||||
|
||||
//create a transaction log entry
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = authenticated_account.owner_name
|
||||
T.purpose = "Remote terminal access"
|
||||
T.source_terminal = machine_id
|
||||
T.date = GLOB.current_date_string
|
||||
T.time = station_time_timestamp()
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
to_chat(usr, "[bicon(src)]<span class='notice'>Access granted. Welcome user '[authenticated_account.owner_name].'</span>")
|
||||
previous_account_number = tried_account_num
|
||||
if("withdrawal")
|
||||
var/amount = max(text2num(href_list["funds_amount"]),0)
|
||||
if(amount <= 0)
|
||||
alert("That is not a valid amount.")
|
||||
else if(authenticated_account && amount > 0)
|
||||
if(amount <= authenticated_account.money)
|
||||
playsound(src, 'sound/machines/chime.ogg', 50, 1)
|
||||
|
||||
//remove the money
|
||||
if(amount > 100000) // prevent crashes
|
||||
to_chat(usr, "<span class='notice'>The ATM's screen flashes, 'Maximum single withdrawl limit reached, defaulting to 100,000.'</span>")
|
||||
amount = 100000
|
||||
withdraw_arbitrary_sum(amount)
|
||||
authenticated_account.charge(amount, null, "Credit withdrawal", machine_id, authenticated_account.owner_name)
|
||||
else
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
if("balance_statement")
|
||||
if(authenticated_account)
|
||||
if(world.timeofday < lastprint + PRINT_DELAY)
|
||||
to_chat(usr, "<span class='notice'>The [name] flashes an error on its display.</span>")
|
||||
return
|
||||
lastprint = world.timeofday
|
||||
playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, 1)
|
||||
var/obj/item/paper/R = new(loc)
|
||||
R.name = "Account balance: [authenticated_account.owner_name]"
|
||||
R.info = {"<b>NT Automated Teller Account Statement</b><br><br>
|
||||
<i>Account holder:</i> [authenticated_account.owner_name]<br>
|
||||
<i>Account number:</i> [authenticated_account.account_number]<br>
|
||||
<i>Balance:</i> $[authenticated_account.money]<br>
|
||||
<i>Date and time:</i> [station_time_timestamp()], [GLOB.current_date_string]<br><br>
|
||||
<i>Service terminal ID:</i> [machine_id]<br>"}
|
||||
|
||||
//stamp the paper
|
||||
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi')
|
||||
stampoverlay.icon_state = "paper_stamp-cent"
|
||||
if(!R.stamped)
|
||||
R.stamped = new()
|
||||
R.stamped += /obj/item/stamp
|
||||
R.overlays += stampoverlay
|
||||
R.stamps += "<HR><i>This paper has been stamped by the Automatic Teller Machine.</i>"
|
||||
|
||||
playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 50, 1)
|
||||
if("insert_card")
|
||||
if(held_card)
|
||||
held_card.forceMove(loc)
|
||||
authenticated_account = null
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(held_card)
|
||||
held_card = null
|
||||
/obj/machinery/atm/tgui_act(action, params)
|
||||
switch(action)
|
||||
if("transfer")
|
||||
if(!authenticated_account || !linked_db)
|
||||
return
|
||||
var/transfer_amount = text2num(params["funds_amount"])
|
||||
if(transfer_amount <= 0)
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>That is not a valid amount.</span>")
|
||||
else if(transfer_amount <= authenticated_account.money)
|
||||
var/target_account_number = text2num(params["target_acc_number"])
|
||||
var/transfer_purpose = params["purpose"]
|
||||
if(linked_db.charge_to_account(target_account_number, authenticated_account, transfer_purpose, machine_id, transfer_amount))
|
||||
to_chat(usr, "[bicon(src)]<span class='info'>Funds transfer successful.</span>")
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/card/id))
|
||||
usr.drop_item()
|
||||
I.forceMove(src)
|
||||
held_card = I
|
||||
if("logout")
|
||||
authenticated_account = null
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>Funds transfer failed.</span>")
|
||||
else
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
|
||||
SSnanoui.update_uis(src)
|
||||
return 1
|
||||
if("view_screen")
|
||||
var/list/valid_screen = list(DEFAULT_SCREEN, CHANGE_SECURITY_LEVEL, TRANSFER_FUNDS, VIEW_TRANSACTION_LOGS)
|
||||
var/screen_proper = text2num(params["view_screen"])
|
||||
if(screen_proper in valid_screen)
|
||||
view_screen = screen_proper
|
||||
else
|
||||
message_admins("Warning: possible href exploit by [key_name(usr)] - Invalid screen number passed into an ATM")
|
||||
log_debug("Warning: possible href exploit by [key_name(usr)] - Invalid screen number passed into an ATM")
|
||||
|
||||
if("change_security_level")
|
||||
if(authenticated_account)
|
||||
var/new_sec_level = max(min(text2num(params["new_security_level"]), 2), 0)
|
||||
authenticated_account.security_level = new_sec_level
|
||||
|
||||
if("attempt_auth")
|
||||
if(linked_db)
|
||||
if(!ticks_left_locked_down)
|
||||
var/tried_account_num = text2num(params["account_num"])
|
||||
if(!tried_account_num && held_card)
|
||||
tried_account_num = held_card.associated_account_number
|
||||
var/tried_pin = text2num(params["account_pin"])
|
||||
|
||||
authenticated_account = attempt_account_access(tried_account_num, tried_pin, held_card && held_card.associated_account_number == tried_account_num ? 2 : 1)
|
||||
if(!authenticated_account)
|
||||
number_incorrect_tries++
|
||||
if(previous_account_number == tried_account_num)
|
||||
if(number_incorrect_tries > max_pin_attempts)
|
||||
//lock down the atm
|
||||
ticks_left_locked_down = 30
|
||||
playsound(src, 'sound/machines/buzz-two.ogg', 50, TRUE)
|
||||
|
||||
//create an entry in the account transaction log
|
||||
var/datum/money_account/failed_account = linked_db.get_account(tried_account_num)
|
||||
if(failed_account)
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = failed_account.owner_name
|
||||
T.purpose = "Unauthorised login attempt"
|
||||
T.source_terminal = machine_id
|
||||
T.date = GLOB.current_date_string
|
||||
T.time = station_time_timestamp()
|
||||
failed_account.transaction_log.Add(T)
|
||||
else
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempt\s remaining.</span>")
|
||||
previous_account_number = tried_account_num
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
|
||||
else
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>Incorrect pin/account combination entered.</span>")
|
||||
number_incorrect_tries = 0
|
||||
else
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 50, TRUE)
|
||||
ticks_left_timeout = LOCKOUT_TIME
|
||||
view_screen = DEFAULT_SCREEN
|
||||
|
||||
//create a transaction log entry
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = authenticated_account.owner_name
|
||||
T.purpose = "Remote terminal access"
|
||||
T.source_terminal = machine_id
|
||||
T.date = GLOB.current_date_string
|
||||
T.time = station_time_timestamp()
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
to_chat(usr, "[bicon(src)]<span class='notice'>Access granted. Welcome user '[authenticated_account.owner_name].'</span>")
|
||||
previous_account_number = tried_account_num
|
||||
|
||||
if("withdrawal")
|
||||
var/amount = max(text2num(params["funds_amount"]),0)
|
||||
if(amount <= 0)
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>That is not a valid amount.</span>")
|
||||
else if(authenticated_account && amount > 0)
|
||||
if(amount <= authenticated_account.money)
|
||||
playsound(src, 'sound/machines/chime.ogg', 50, TRUE)
|
||||
|
||||
//remove the money
|
||||
if(amount > 100000) // prevent crashes
|
||||
to_chat(usr, "<span class='notice'>The ATM's screen flashes, 'Maximum single withdrawl limit reached, defaulting to 100,000.'</span>")
|
||||
amount = 100000
|
||||
withdraw_arbitrary_sum(amount)
|
||||
authenticated_account.charge(amount, null, "Credit withdrawal", machine_id, authenticated_account.owner_name)
|
||||
else
|
||||
to_chat(usr, "[bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
|
||||
if("balance_statement")
|
||||
if(authenticated_account)
|
||||
if(world.timeofday < lastprint + PRINT_DELAY)
|
||||
to_chat(usr, "<span class='notice'>The [name] flashes an error on its display.</span>")
|
||||
return
|
||||
lastprint = world.timeofday
|
||||
playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, TRUE)
|
||||
var/obj/item/paper/R = new(loc)
|
||||
R.name = "Account balance: [authenticated_account.owner_name]"
|
||||
R.info = {"<b>NT Automated Teller Account Statement</b><br><br>
|
||||
<i>Account holder:</i> [authenticated_account.owner_name]<br>
|
||||
<i>Account number:</i> [authenticated_account.account_number]<br>
|
||||
<i>Balance:</i> $[authenticated_account.money]<br>
|
||||
<i>Date and time:</i> [station_time_timestamp()], [GLOB.current_date_string]<br><br>
|
||||
<i>Service terminal ID:</i> [machine_id]<br>"}
|
||||
|
||||
//stamp the paper
|
||||
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi')
|
||||
stampoverlay.icon_state = "paper_stamp-cent"
|
||||
if(!R.stamped)
|
||||
R.stamped = new()
|
||||
R.stamped += /obj/item/stamp
|
||||
R.overlays += stampoverlay
|
||||
R.stamps += "<HR><i>This paper has been stamped by the Automatic Teller Machine.</i>"
|
||||
|
||||
playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 50, TRUE)
|
||||
|
||||
if("insert_card")
|
||||
if(held_card)
|
||||
held_card.forceMove(loc)
|
||||
authenticated_account = null
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(held_card)
|
||||
held_card = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/card/id))
|
||||
usr.drop_item()
|
||||
I.forceMove(src)
|
||||
held_card = I
|
||||
|
||||
if("logout")
|
||||
authenticated_account = null
|
||||
|
||||
. = TRUE
|
||||
|
||||
//create the most effective combination of notes to make up the requested amount
|
||||
/obj/machinery/atm/proc/withdraw_arbitrary_sum(arbitrary_sum)
|
||||
|
||||
@@ -19,7 +19,7 @@ GLOBAL_LIST_EMPTY(all_money_accounts)
|
||||
GLOB.station_account = new()
|
||||
GLOB.station_account.owner_name = "[station_name()] Station Account"
|
||||
GLOB.station_account.account_number = rand(111111, 999999)
|
||||
GLOB.station_account.remote_access_pin = rand(1111, 111111)
|
||||
GLOB.station_account.remote_access_pin = rand(111111, 999999)
|
||||
GLOB.station_account.money = STATION_START_CASH
|
||||
|
||||
//create an entry in the account transaction log for when it was created
|
||||
@@ -35,7 +35,7 @@ GLOBAL_LIST_EMPTY(all_money_accounts)
|
||||
var/datum/money_account/department_account = new()
|
||||
department_account.owner_name = "[department] Account"
|
||||
department_account.account_number = rand(111111, 999999)
|
||||
department_account.remote_access_pin = rand(1111, 111111)
|
||||
department_account.remote_access_pin = rand(111111, 999999)
|
||||
department_account.money = DEPARTMENT_START_CASH
|
||||
|
||||
//create an entry in the account transaction log for when it was created
|
||||
@@ -55,7 +55,7 @@ GLOBAL_LIST_EMPTY(all_money_accounts)
|
||||
//create a new account
|
||||
var/datum/money_account/M = new()
|
||||
M.owner_name = new_owner_name
|
||||
M.remote_access_pin = rand(1111, 111111)
|
||||
M.remote_access_pin = rand(111111, 999999)
|
||||
M.money = starting_funds
|
||||
|
||||
//create an entry in the account transaction log for when it was created
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
<!--
|
||||
Title: ATM
|
||||
Used In File(s): /code/modules/economy/ATM.dm
|
||||
-->
|
||||
|
||||
<!--
|
||||
#define NO_SCREEN 0
|
||||
#define CHANGE_SECURITY_LEVEL 1
|
||||
#define TRANSFER_FUNDS 2
|
||||
#define VIEW_TRANSACTION_LOGS 3
|
||||
-->
|
||||
|
||||
<style type="text/css">
|
||||
input[type=text], input[type=submit] {
|
||||
border: 1px solid #161616;
|
||||
background-color: #40628a;
|
||||
color: #FFFFFF;
|
||||
padding: 4px;
|
||||
}
|
||||
input[type=submit]:hover {
|
||||
background-color: #507aac;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Nanotrasen Automatic Teller Machine</h1>
|
||||
For all your monetary needs!
|
||||
<br>
|
||||
<i>This terminal is</i> {{:data.machine_id}}. <i>Report this code when contacting Nanotrasen IT Support</i>
|
||||
<br>
|
||||
|
||||
<div class="item">
|
||||
<div class='itemLabel'>Card:</div>
|
||||
<div class='itemContent'>{{:helper.link(data.held_card_name, 'eject', {'choice' : 'insert_card'})}}</div>
|
||||
</div>
|
||||
<hr>
|
||||
{{if data.ticks_left_locked_down > 0}}
|
||||
<span class='exclamation-triangle'>Maximum number of pin attempts exceeded! Access to this ATM has been temporarily disabled.</span>
|
||||
{{else data.authenticated_account}}
|
||||
{{if data.view_screen == 1}} <!-- CHANGE_SECURITY_LEVEL -->
|
||||
<h4>Select a new security level for this account:</h4>
|
||||
<div class="item">
|
||||
<div class='itemLabel'>Level:</div>
|
||||
<div class='itemContent'>{{:helper.link('Zero', 'unlock', {'choice' : 'change_security_level', 'new_security_level' : 0}, data.security_level == 0 ? 'selected' : null)}}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class='itemLabel'>Description:</div>
|
||||
<div class='itemContent'>Either the account number or card is required to access this account. EFTPOS transactions will require a card and ask for a pin, but not verify the pin is correct.</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="item">
|
||||
<div class='itemLabel'>Level:</div>
|
||||
<div class='itemContent'>{{:helper.link('One', 'unlock-alt', {'choice' : 'change_security_level', 'new_security_level' : 1}, data.security_level == 1 ? 'selected' : null)}}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class='itemLabel'>Description:</div>
|
||||
<div class='itemContent'>An account number and pin must be manually entered to access this account and process transactions.</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="item">
|
||||
<div class='itemLabel'>Level:</div>
|
||||
<div class='itemContent'>{{:helper.link('Two', 'lock', {'choice' : 'change_security_level', 'new_security_level' : 2}, data.security_level == 2 ? 'selected' : null)}}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class='itemLabel'>Description:</div>
|
||||
<div class='itemContent'>In addition to account number and pin, a card is required to access this account and process transactions.</div>
|
||||
</div>
|
||||
<hr>
|
||||
{{:helper.link('Back', 'arrow-left', {'choice' : 'view_screen', 'view_screen' : 0})}}
|
||||
{{else data.view_screen == 2}} <!-- TRANSFER_FUNDS -->
|
||||
<div class='line'><b>Account balance:</b> ${{:helper.smoothRound(data.money)}}</div>
|
||||
<form name='transfer' id='transfer' action='?src={{:data.src}}' method='get'>
|
||||
<input type='hidden' name='src' value='{{:data.src}}'>
|
||||
<input type='hidden' name='choice' value='transfer'>
|
||||
<div class='itemLabel'>Target account number:</div>
|
||||
<div class='itemContent'><input type='text' name='target_acc_number' value='' style='width:200px;'></div>
|
||||
|
||||
<div class='itemLabel'>Funds to transfer:</div>
|
||||
<div class='itemContent'><input type='text' name='funds_amount' value='' style='width:200px;'></div>
|
||||
|
||||
<div class='itemLabel'>Transaction purpose:</div>
|
||||
<div class='itemContent'><input type='text' name='purpose' value='Funds transfer' style='width:200px;'></div>
|
||||
<input type='submit' value='Transfer funds'>
|
||||
</form>
|
||||
<hr>
|
||||
{{:helper.link('Back', 'arrow-left', {'choice' : 'view_screen', 'view_screen' : 0})}}
|
||||
{{else data.view_screen == 3}} <!-- VIEW_TRANSACTION_LOGS -->
|
||||
<h4>Transaction logs</h4>
|
||||
<div class='item'>{{:helper.link('Back', 'arrow-left', {'choice' : 'view_screen', 'view_screen' : 0})}}</div>
|
||||
|
||||
<div class="statusDisplay" style="overflow: auto;">
|
||||
{{if data.transaction_log}}
|
||||
<table style='width: 100%'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><b>Timestamp</b></th>
|
||||
<th><b>Target</b></th>
|
||||
<th><b>Reason</b></th>
|
||||
<th><b>Value</b></th>
|
||||
<th><b>Terminal</b></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{for data.transaction_log}}
|
||||
<tr>
|
||||
<td>{{:value.date}} {{:value.time}}</td>
|
||||
<td>{{:value.target_name}}</td>
|
||||
<td>{{:value.purpose}}</td>
|
||||
<td>${{:value.amount}}</td>
|
||||
<td>{{:value.source_terminal}}</td>
|
||||
</tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<span class='exclamation-triangle'>Your account has no financial transactions on record for today.</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}} <!-- NO_SCREEN -->
|
||||
Welcome, <b>{{:data.owner_name}}</b>.<br>
|
||||
<b>Account balance:</b> ${{:helper.smoothRound(data.money)}}
|
||||
<form name='withdrawal' action='?src={{:data.src}}' method='get'>
|
||||
<input type='hidden' name='src' value='{{:data.src}}'>
|
||||
<input type='hidden' name='choice' value='withdrawal'>
|
||||
<input type='text' name='funds_amount' value=''> <input type='submit' value='Withdraw funds'><br>
|
||||
</form>
|
||||
<hr>
|
||||
|
||||
<h3>Menu</h3>
|
||||
<div class="line">{{:helper.link('Change account security level', 'lock', {'choice' : 'view_screen', 'view_screen' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Make transfer', 'exchange', {'choice' : 'view_screen', 'view_screen' : 2})}}</div>
|
||||
<div class="line">{{:helper.link('View transaction log', 'list', {'choice' : 'view_screen', 'view_screen' : 3})}}</div>
|
||||
<div class="line">{{:helper.link('Print balance statement', 'print', {'choice' : 'balance_statement'})}}</div>
|
||||
<div class="line">{{:helper.link('Logout', 'sign-out', {'choice' : 'logout'})}}</div>
|
||||
{{/if}}
|
||||
{{else data.linked_db}}
|
||||
<form name='atm_auth' action='?src={{:data.src}}' method='get'>
|
||||
<input type='hidden' name='src' value='{{:data.src}}'>
|
||||
<input type='hidden' name='choice' value='attempt_auth'>
|
||||
<div class='itemLabel'>Account:</div>
|
||||
<div class='itemContent'><input type='text' id='account_num' name='account_num' style='width:250px;'></div>
|
||||
|
||||
<div class='itemLabel'>PIN:</div>
|
||||
<div class='itemContent'><input type='text' id='account_pin' name='account_pin' style='width:250px;'></div>
|
||||
<br>
|
||||
<input type='submit' value='Submit'>
|
||||
</form>
|
||||
{{else}}
|
||||
<span class='exclamation-triangle'>Unable to connect to accounts database, please retry and if the issue persists contact Nanotrasen IT support.</span>
|
||||
{{/if}}
|
||||
@@ -0,0 +1,380 @@
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Button, Table, Icon, Input, Divider, Box, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
/*
|
||||
#define NO_SCREEN 0
|
||||
#define CHANGE_SECURITY_LEVEL 1
|
||||
#define TRANSFER_FUNDS 2
|
||||
#define VIEW_TRANSACTION_LOGS 3
|
||||
*/
|
||||
|
||||
export const ATM = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
view_screen,
|
||||
authenticated_account,
|
||||
ticks_left_locked_down,
|
||||
linked_db,
|
||||
} = data;
|
||||
let body;
|
||||
if (ticks_left_locked_down > 0) {
|
||||
body = (
|
||||
<Box bold color="bad">
|
||||
<Icon name="exclamation-triangle" />
|
||||
Maximum number of pin attempts exceeded! Access to this ATM has been temporarily disabled.
|
||||
</Box>
|
||||
);
|
||||
} else if (!linked_db) {
|
||||
body = (
|
||||
<Box bold color="bad">
|
||||
<Icon name="exclamation-triangle" />
|
||||
Unable to connect to accounts database, please retry and if the issue persists contact Nanotrasen IT support.
|
||||
</Box>
|
||||
);
|
||||
} else if (authenticated_account) {
|
||||
switch (view_screen) {
|
||||
case 1: // CHANGE_SECURITY_LEVEL
|
||||
body = <ChangeSecurityLevel />;
|
||||
break;
|
||||
case 2: // TRANSFER_FUNDS
|
||||
body = <TransferFunds />;
|
||||
break;
|
||||
case 3: // VIEW_TRANSACTION_LOGS
|
||||
body = <ViewTransactionLogs />;
|
||||
break;
|
||||
default:
|
||||
body = <DefaultScreen />;
|
||||
}
|
||||
}
|
||||
else {
|
||||
body = <LoginScreen />;
|
||||
}
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content scrollable>
|
||||
<IntroductionAndCard />
|
||||
<Section>
|
||||
{body}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const IntroductionAndCard = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
machine_id,
|
||||
held_card_name,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Nanotrasen Automatic Teller Machine" >
|
||||
<Box>
|
||||
For all your monetary need!
|
||||
</Box>
|
||||
<Divider />
|
||||
<Box>
|
||||
<Icon name="info-circle" /> This terminal is <i>{machine_id}</i>, report this code when contacting Nanotrasen IT Support.
|
||||
</Box>
|
||||
<Divider />
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Card">
|
||||
<Button
|
||||
content={held_card_name}
|
||||
icon="eject"
|
||||
onClick={
|
||||
() => act('insert_card')
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const ChangeSecurityLevel = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
security_level,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Select a new security level for this account" >
|
||||
<LabeledList>
|
||||
<Divider />
|
||||
<LabeledList.Item label="Level">
|
||||
<Button
|
||||
content="Zero"
|
||||
icon="unlock"
|
||||
selected={security_level === 0}
|
||||
onClick={
|
||||
() => act('change_security_level', { new_security_level: 0 })
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Description">
|
||||
Either the account number or card is required to access this account.
|
||||
EFTPOS transactions will require a card and ask for a pin, but not verify the pin is correct.
|
||||
</LabeledList.Item>
|
||||
<Divider />
|
||||
<LabeledList.Item label="Level">
|
||||
<Button
|
||||
content="One"
|
||||
icon="unlock"
|
||||
selected={security_level === 1}
|
||||
onClick={
|
||||
() => act('change_security_level', { new_security_level: 1 })
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Description">
|
||||
An account number and pin must be manually entered to access this account and process transactions.
|
||||
</LabeledList.Item>
|
||||
<Divider />
|
||||
<LabeledList.Item label="Level">
|
||||
<Button
|
||||
content="Two"
|
||||
selected={security_level === 2}
|
||||
icon="unlock"
|
||||
onClick={
|
||||
() => act('change_security_level', { new_security_level: 2 })
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Description">
|
||||
In addition to account number and pin, a card is required to access this account and process transactions.
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Divider />
|
||||
<BackButton />
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const TransferFunds = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const [targetAccNumber, setTargetAccNumber] = useLocalState(context, "targetAccNumber", 0);
|
||||
const [fundsAmount, setFundsAmount] = useLocalState(context, "fundsAmount", 0);
|
||||
const [purpose, setPurpose] = useLocalState(context, "purpose", 0);
|
||||
const {
|
||||
money,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Transfer Fund" >
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Account Balance">
|
||||
${money}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Target account number">
|
||||
<Input
|
||||
placeholder="6 Digit Number"
|
||||
onInput={(e, value) => setTargetAccNumber(value)}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Funds to transfer">
|
||||
<Input
|
||||
onInput={(e, value) => setFundsAmount(value)}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Transaction Purpose">
|
||||
<Input
|
||||
fluid
|
||||
onInput={(e, value) => setPurpose(value)}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Divider />
|
||||
<Button
|
||||
content="Transfer"
|
||||
icon="sign-out-alt"
|
||||
onClick={
|
||||
() => act('transfer', { target_acc_number: targetAccNumber, funds_amount: fundsAmount, purpose: purpose })
|
||||
} />
|
||||
<Divider />
|
||||
<BackButton />
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const DefaultScreen = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const [fundsAmount, setFundsAmount] = useLocalState(context, "fundsAmount", 0);
|
||||
const {
|
||||
owner_name,
|
||||
money,
|
||||
} = data;
|
||||
return (
|
||||
<Fragment>
|
||||
<Section
|
||||
title={"Welcome, " + owner_name}
|
||||
buttons={
|
||||
<Button
|
||||
content="Logout"
|
||||
icon="sign-out-alt"
|
||||
onClick={
|
||||
() => act('logout')
|
||||
} />
|
||||
}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item
|
||||
label="Account Balance">
|
||||
${money}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item
|
||||
label="Withdrawal Amount">
|
||||
<Input
|
||||
onInput={(e, value) => setFundsAmount(value)} />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item>
|
||||
<Button
|
||||
content="Withdraw Fund"
|
||||
icon="sign-out-alt"
|
||||
onClick={
|
||||
() => act('withdrawal', { funds_amount: fundsAmount })
|
||||
} />
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
<Section title="Menu">
|
||||
<Box>
|
||||
<Button
|
||||
content="Change account security level"
|
||||
icon="lock"
|
||||
onClick={
|
||||
() => act('view_screen', { view_screen: 1 })
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Button
|
||||
content="Make transfer"
|
||||
icon="exchange-alt"
|
||||
onClick={
|
||||
() => act('view_screen', { view_screen: 2 })
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Button
|
||||
content="View transaction log"
|
||||
icon="list"
|
||||
onClick={
|
||||
() => act('view_screen', { view_screen: 3 })
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Button
|
||||
content="Print balance statement"
|
||||
icon="print"
|
||||
onClick={
|
||||
() => act('balance_statement')
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const LoginScreen = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const [accountID, setAccountID] = useLocalState(context, "accountID", null);
|
||||
const [accountPin, setAccountPin] = useLocalState(context, "accountPin", null);
|
||||
const {
|
||||
machine_id,
|
||||
held_card_name,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Insert card or enter ID and pin to login">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Account ID">
|
||||
<Input
|
||||
placeholder="6 Digit Number"
|
||||
onInput={(e, value) => setAccountID(value)}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Pin">
|
||||
<Input
|
||||
placeholder="6 Digit Number"
|
||||
onInput={(e, value) => setAccountPin(value)}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item>
|
||||
<Button
|
||||
content="Login"
|
||||
icon="sign-in-alt"
|
||||
onClick={
|
||||
() => act('attempt_auth', { account_num: accountID, account_pin: accountPin })
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const ViewTransactionLogs = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
transaction_log,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Transactions">
|
||||
<Table>
|
||||
<Table.Row header>
|
||||
<Table.Cell>
|
||||
Timestamp
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
Target
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
Reason
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
Value
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
Terminal
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{transaction_log.map(t => (
|
||||
<Table.Row key={t}>
|
||||
<Table.Cell p="1rem">
|
||||
{t.date} {t.time}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{t.target_name}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{t.purpose}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
${t.amount}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{t.source_terminal}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
<Divider />
|
||||
<BackButton />
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BackButton = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
return (
|
||||
<Button
|
||||
content="Back"
|
||||
icon="sign-out-alt"
|
||||
onClick={
|
||||
() => act('view_screen', { view_screen: 0 })
|
||||
} />
|
||||
);
|
||||
};
|
||||
@@ -1,13 +1,11 @@
|
||||
import { createSearch, decodeHtmlEntities } from 'common/string';
|
||||
import { createSearch } from 'common/string';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend, useLocalState } from "../backend";
|
||||
import { Box, Button, Flex, Icon, Input, LabeledList, NumberInput, Section, Table, Tabs } from '../components';
|
||||
import { Button, Flex, Icon, Input, LabeledList, Section, Table } from '../components';
|
||||
import { FlexItem } from '../components/Flex';
|
||||
import { Window } from "../layouts";
|
||||
import { ComplexModal, modalOpen } from './common/ComplexModal';
|
||||
import { LoginInfo } from './common/LoginInfo';
|
||||
import { LoginScreen } from './common/LoginScreen';
|
||||
import { TemporaryNotice } from './common/TemporaryNotice';
|
||||
|
||||
export const AccountsUplinkTerminal = (properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
@@ -193,7 +191,7 @@ const DetailedAccountInfo = (properties, context) => {
|
||||
<LabeledList.Item label="Account Holder">
|
||||
{owner_name}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Account Balnce">
|
||||
<LabeledList.Item label="Account Balance">
|
||||
{money}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Account Status" color={suspended ? "red" : "green"}>
|
||||
@@ -240,7 +238,7 @@ const DetailedAccountInfo = (properties, context) => {
|
||||
{t.purpose}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{t.amount}
|
||||
${t.amount}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{t.source_terminal}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user