/************************ * Point Of Sale * * Takes cash or credit. *************************/ /line_item parent_type = /datum var/name = "" var/price = 0 // Per unit var/units = 0 var/global/current_pos_id = 1 var/global/pos_sales = 0 var/const/RECEIPT_HEADER = {" "} var/const/POS_HEADER = {" "} #define POS_TAX_RATE 0.10 // 10% #define POS_SCREEN_LOGIN 0 #define POS_SCREEN_ORDER 1 #define POS_SCREEN_FINALIZE 2 #define POS_SCREEN_PRODUCTS 3 #define POS_SCREEN_IMPORT 4 #define POS_SCREEN_EXPORT 5 #define POS_SCREEN_SETTINGS 6 /obj/machinery/pos icon = 'icons/obj/machines/pos.dmi' icon_state = "pos" density = 0 name = "point of sale" desc = "Also known as a cash register, or, more commonly, \"robbery magnet\"." var/id = 0 var/sales = 0 var/department var/mob/logged_in var/datum/money_account/linked_account var/credits_held = 0 var/credits_needed = 0 var/list/products = list() // name = /line_item var/list/line_items = list() // # = /line_item var/screen=POS_SCREEN_LOGIN /obj/machinery/pos/New() ..() id = current_pos_id++ if(department) linked_account = department_accounts[department] else linked_account = station_account update_icon() /obj/machinery/pos/proc/AddToOrder(var/name, var/units) if(!(name in products)) return 0 var/line_item/LI = products[name] var/line_item/LIC = new LIC.name=LI.name LIC.price=LI.price LIC.units=units line_items.Add(LIC) /obj/machinery/pos/proc/RemoveFromOrder(var/order_id) line_items.Cut(order_id,order_id+1) /obj/machinery/pos/proc/NewOrder() line_items.Cut() /obj/machinery/pos/proc/PrintReceipt(var/order_id) var/receipt = {"[RECEIPT_HEADER]
POINT OF SALE #[id]
Paying to: [linked_account.owner_name]
Cashier: [logged_in]
"} receipt += areaMaster.name receipt += "
" receipt += {"
[worldtime2text()], [current_date_string]
"} var/subtotal=0 for(var/i=1;i<=line_items.len;i++) var/line_item/LI = line_items[i] var/linetotal=LI.units*LI.price receipt += "" subtotal += linetotal var/taxes = POS_TAX_RATE*subtotal receipt += {" "} receipt += {" "} receipt += "
Item Amount Unit Price Line Total
[LI.name][LI.units]$[num2septext(LI.price)]$[num2septext(linetotal)]
SUBTOTAL$[num2septext(subtotal)]
TAXES$[num2septext(taxes)]
TOTAL$[num2septext(taxes+subtotal)]
" var/obj/item/weapon/paper/P = new(loc) P.name="Receipt #[id]-[++sales]" P.info=receipt P = new(loc) P.name="Receipt #[id]-[sales] (Cashier Copy)" P.info=receipt /obj/machinery/pos/proc/LoginScreen() return "
Please swipe ID to log in.
" /obj/machinery/pos/proc/OrderScreen() var/receipt = {"
POS Info POINT OF SALE #[id]
Paying to: [linked_account.owner_name]
Cashier: [logged_in]
"} receipt += areaMaster.name receipt += "
" receipt += {"
Order Data
"} var/subtotal=0 if(line_items.len>0) for(var/i=1;i<=line_items.len;i++) var/line_item/LI = line_items[i] var/linetotal=LI.units*LI.price receipt += {""} subtotal += linetotal var/taxes = POS_TAX_RATE*subtotal var/presets = "(No presets available)" if(products.len>0) presets = {"" receipt += {" "} receipt += {" "} receipt += {"
Item Amount Unit Price Line Total ...
[LI.name] [LI.units] $[num2septext(LI.price)] $[num2septext(linetotal)] ×
[presets] units
SUBTOTAL$[num2septext(subtotal)]
TAXES$[num2septext(taxes)]
TOTAL$[num2septext(taxes+subtotal)]
"} return receipt /obj/machinery/pos/proc/ProductsScreen() var/dat={"
Product List
"} for(var/i in products) var/line_item/LI = products[i] dat += {""} dat += {"
Item Unit Price # Sold ...
[LI.name] $[num2septext(LI.price)] [LI.units] ×
New Product:

$

Import | Export
"} return dat /obj/machinery/pos/proc/ExportScreen() var/dat={"
Export Products as CSV OK
"} return dat /obj/machinery/pos/proc/ImportScreen() var/dat={"
Import Products as CSV

Data must be in the form of a CSV, with no headers or quotation marks.

First column must be product names, second must be prices as an unformatted number (####.##)

Deviations from this format will result in your import being rejected.

"} return dat /obj/machinery/pos/proc/FinalizeScreen() return "
Waiting for Credit
Cancel
" /obj/machinery/pos/proc/SettingsScreen() var/dat={"
Account Settings
Payable Account:
Locality Settings
Tax Rate: % (LOCKED)
"} return dat /obj/machinery/pos/update_icon() overlays = 0 if(stat & (NOPOWER|BROKEN)) return if(logged_in) overlays += "pos-working" else overlays += "pos-standby" /obj/machinery/pos/attack_robot(var/mob/user) if(isMoMMI(user)) return attack_hand(user) return ..() /obj/machinery/pos/attack_hand(var/mob/user) user.set_machine(src) var/logindata="" if(logged_in) logindata={"[logged_in.name]"} var/dat = POS_HEADER + {" "} switch(screen) if(POS_SCREEN_LOGIN) dat += LoginScreen() if(POS_SCREEN_ORDER) dat += OrderScreen() if(POS_SCREEN_FINALIZE) dat += FinalizeScreen() if(POS_SCREEN_PRODUCTS) dat += ProductsScreen() if(POS_SCREEN_EXPORT) dat += ExportScreen() if(POS_SCREEN_IMPORT) dat += ImportScreen() if(POS_SCREEN_SETTINGS) dat += SettingsScreen() dat += "" // END AUTOFIX user << browse(dat, "window=pos") onclose(user, "pos") return /obj/machinery/pos/proc/say(var/text) src.visible_message("\icon[src] [name] states, \"[text]\"") /obj/machinery/pos/Topic(var/href, var/list/href_list) if(..(href,href_list)) return if("logout" in href_list) if(alert(src, "You sure you want to log out?", "Confirm", "Yes", "No")!="Yes") return logged_in=null screen=POS_SCREEN_LOGIN update_icon() src.attack_hand(usr) return if(usr != logged_in) usr << "\red [logged_in.name] is already logged in. You cannot use this machine until they log out." return if("act" in href_list) switch(href_list["act"]) if("Reset") NewOrder() screen=POS_SCREEN_ORDER if("Finalize Sale") var/subtotal=0 if(line_items.len>0) for(var/i=1;i<=line_items.len;i++) var/line_item/LI = line_items[i] subtotal += LI.units*LI.price var/taxes = POS_TAX_RATE*subtotal credits_needed=taxes+subtotal say("Your total is $[num2septext(credits_needed)]. Please insert credit chips or swipe your ID.") screen=POS_SCREEN_FINALIZE if("Add Product") var/line_item/LI = new LI.name=sanitize(href_list["name"]) LI.price=text2num(href_list["price"]) products["[products.len+1]"]=LI if("Add to Order") AddToOrder(href_list["preset"],text2num(href_list["units"])) if("Add Products") for(var/list/line in text2list(href_list["csv"],"\n")) var/list/cells = text2list(line,",") if(cells.len<2) usr << "\red The CSV must have at least two columns: Product Name, followed by Price (as a number)." src.attack_hand(usr) return var/line_item/LI = new LI.name=sanitize(cells[1]) LI.price=text2num(cells[2]) products["[products.len+1]"]=LI if("Export Products") screen=POS_SCREEN_EXPORT if("Import Products") screen=POS_SCREEN_IMPORT if("Save Settings") var/datum/money_account/new_linked_account = get_money_account(text2num(href_list["payableto"]),z) if(!new_linked_account) usr << "\red Unable to link new account." else linked_account = new_linked_account screen=POS_SCREEN_SETTINGS else if("screen" in href_list) screen=text2num(href_list["screen"]) else if("rmproduct" in href_list) products.Remove(href_list["rmproduct"]) else if("removefromorder" in href_list) RemoveFromOrder(text2num(href_list["removefromorder"])) else if("setunits" in href_list) var/lid = text2num(href_list["setunits"]) var/newunits = input(usr,"Enter the units sold.") as num if(!newunits) return var/line_item/LI = line_items[lid] LI.units = newunits line_items[lid]=LI else if("setpname" in href_list) var/newtext = sanitize(input(usr,"Enter the product's name.")) if(!newtext) return var/pid = href_list["setpname"] var/line_item/LI = products[pid] LI.name = newtext products[pid]=LI else if("setprice" in href_list) var/newprice = input(usr,"Enter the product's price.") as num if(!newprice) return var/pid = href_list["setprice"] var/line_item/LI = products[pid] LI.price = newprice products[pid]=LI src.attack_hand(usr) /obj/machinery/pos/attackby(var/atom/movable/A, var/mob/user) ..() if(istype(A,/obj/item/weapon/card/id)) var/obj/item/weapon/card/id/I = A if(!logged_in) user.visible_message("\blue The machine beeps, and logs you in","You hear a beep.") logged_in = user screen=POS_SCREEN_ORDER update_icon() src.attack_hand(usr) else if(!linked_account) visible_message("\red The machine buzzes, and flashes \"NO LINKED ACCOUNT\" on the screen.","You hear a buzz.") flick(src,"pos-error") return if(screen!=POS_SCREEN_FINALIZE) visible_message("\blue The machine buzzes.","\red You hear a buzz.") flick(src,"pos-error") return var/datum/money_account/acct = get_card_account(I) if(!acct) visible_message("\red The machine buzzes, and flashes \"NO ACCOUNT\" on the screen.","You hear a buzz.") flick(src,"pos-error") return if(credits_needed > acct.money) visible_message("\red The machine buzzes, and flashes \"NOT ENOUGH FUNDS\" on the screen.","You hear a buzz.") flick(src,"pos-error") return visible_message("\blue The machine beeps, and begins printing a receipt","You hear a beep.") PrintReceipt() NewOrder() acct.charge(credits_needed,linked_account,"Purchase at POS #[id].") credits_needed=0 screen=POS_SCREEN_ORDER else if(istype(A,/obj/item/weapon/spacecash)) if(!linked_account) visible_message("\red The machine buzzes, and flashes \"NO LINKED ACCOUNT\" on the screen.","You hear a buzz.") flick(src,"pos-error") return if(!logged_in || screen!=POS_SCREEN_FINALIZE) visible_message("\blue The machine buzzes.","\red You hear a buzz.") flick(src,"pos-error") return var/obj/item/weapon/spacecash/C=A credits_held += C.worth*C.amount if(credits_held >= credits_needed) visible_message("\blue The machine beeps, and begins printing a receipt","You hear a beep and the sound of paper being shredded.") PrintReceipt() NewOrder() credits_held -= credits_needed credits_needed=0 screen=POS_SCREEN_ORDER if(credits_held) var/obj/item/weapon/storage/box/B = new(loc) dispense_cash(credits_held,B) B.name="change" B.desc="A box of change." credits_held=0