Add print button

This commit is contained in:
metamuffin 2025-05-13 19:29:56 +02:00
parent ee7987599e
commit 3b5948682a
No known key found for this signature in database
GPG key ID: 718F9749DCDBD654
2 changed files with 154 additions and 146 deletions

View file

@ -114,6 +114,8 @@ local translations = load_translations({ "en", config.language })
local stylesheet = io.open("style.css"):read("a") local stylesheet = io.open("style.css"):read("a")
local script = io.open("script.js"):read("a") local script = io.open("script.js"):read("a")
local can_print = false
local function format(template, params) local function format(template, params)
params = params or {} params = params or {}
if template == nil then return "NIL TEMPLATE" end if template == nil then return "NIL TEMPLATE" end
@ -144,23 +146,23 @@ local function format_amount(amount, tag, classes)
end end
local function format_list(list) local function format_list(list)
if list == nil then if list == nil then
return nil return nil
end end
local not_first = false local not_first = false
local out = "" local out = ""
for _, barcode in pairs(list) do for _, barcode in pairs(list) do
if not_first then if not_first then
out = out .. ", " .. barcode out = out .. ", " .. barcode
else else
out = barcode out = barcode
end end
not_first = true not_first = true
end end
return out return out
end end
local function get_user_theme(username) local function get_user_theme(username)
@ -225,6 +227,7 @@ local function respond(status, title, body)
<a href="/?spus">{+spus}</a> <a href="/?spus">{+spus}</a>
<a href="/?products">{+products}</a> <a href="/?products">{+products}</a>
<a href="/?log">{+log}</a> <a href="/?log">{+log}</a>
{print_button}
<a href="/?about">{+about}</a> <a href="/?about">{+about}</a>
</nav> </nav>
]], { ]], {
@ -232,7 +235,9 @@ local function respond(status, title, body)
style = stylesheet, style = stylesheet,
user_style = get_user_theme(path and path:sub(2)), user_style = get_user_theme(path and path:sub(2)),
script = script, script = script,
head_extra = config.head_extra or "" head_extra = config.head_extra or "",
print_button = can_print and
[[<script>document.write('<a href="javascript:print()" style="float:right;">{+print}</a>')</script>]] or ""
})) }))
if config.header ~= nil then if config.header ~= nil then
print(config.header) print(config.header)
@ -373,24 +378,24 @@ local function r_transaction_post()
local pcode = data.pcode local pcode = data.pcode
local pcount = tonumber(data.pcount) local pcount = tonumber(data.pcount)
local comment = data.comment local comment = data.comment
local pname = data.pname local pname = data.pname
if pname ~= nil or (pcode ~= nil and pcode ~= "") then if pname ~= nil or (pcode ~= nil and pcode ~= "") then
-- check if barcode exists -- check if barcode exists
if pname == nil then if pname == nil then
local exists = false local exists = false
for p_name, p_barcode in read_barcodes() do for p_name, p_barcode in read_barcodes() do
if p_barcode == pcode then if p_barcode == pcode then
exists = true exists = true
pname = p_name pname = p_name
end end
end end
if not exists then if not exists then
return error_box("{+error.unknown_barcode}") return error_box("{+error.unknown_barcode}")
end end
end end
-- check if product exists -- check if product exists
local exists = false local exists = false
for p_amount, p_user, p_name in read_products() do for p_amount, p_user, p_name in read_products() do
if pname == p_name then if pname == p_name then
@ -403,11 +408,11 @@ local function r_transaction_post()
end end
end end
if not exists then if not exists then
return error_box("{+error.unknown_product}: "..pname) return error_box("{+error.unknown_product}: " .. pname)
end end
end end
-- for outside money -- for outside money
user_src = user_src or "@Potential" user_src = user_src or "@Potential"
if amount == nil then if amount == nil then
return error_box("{+error.invalid_amount}") return error_box("{+error.invalid_amount}")
@ -469,8 +474,8 @@ local function r_user(username)
{ time = format_duration(os.time() - last_txn), username = urlencode(username) })) { time = format_duration(os.time() - last_txn), username = urlencode(username) }))
print([[</div>]]) print([[</div>]])
end end
print([[<ul class="userforms"><li> print([[<ul class="userforms"><li>
<div class="amount-presets backgroundbox">]]) <div class="amount-presets backgroundbox">]])
for _, type in ipairs({ 1, -1 }) do for _, type in ipairs({ 1, -1 }) do
for _, amount in ipairs({ 50, 100, 150, 200, 500, 1000 }) do for _, amount in ipairs({ 50, 100, 150, 200, 500, 1000 }) do
@ -490,45 +495,45 @@ local function r_user(username)
end end
end end
print("</div></li>") print("</div></li>")
print(format([[<li><div class="backgroundbox shortcuts"> print(format([[<li><div class="backgroundbox shortcuts">
<h3>{+user.shortcuts}</h3>]])) <h3>{+user.shortcuts}</h3>]]))
local lastcategory = nil local lastcategory = nil
-- user is category; @ is removed for ZSKs -- user is category; @ is removed for ZSKs
for price, category, name in read_products() do for price, category, name in read_products() do
if lastcategory ~= category then if lastcategory ~= category then
if lastcategory ~= nil then if lastcategory ~= nil then
print("</ul></div></label>") print("</ul></div></label>")
end end
print(format([[<label> print(format([[<label>
<input type="checkbox" hidden /> <input type="checkbox" hidden />
<div> <div>
<span class="button amount-ntr">{c}</span> <span class="button amount-ntr">{c}</span>
<ul>]], { <ul>]], {
c = category:gsub("@", ""), c = category:gsub("@", ""),
})) }))
lastcategory = category lastcategory = category
end end
print(format([[<li><form method="POST"> print(format([[<li><form method="POST">
<input type="text" name="user_dst" value="{!username}" hidden /> <input type="text" name="user_dst" value="{!username}" hidden />
<input type="number" name="pcount" value="-1" hidden /> <input type="number" name="pcount" value="-1" hidden />
<input type="text" name="pname" value="{name}" hidden /> <input type="text" name="pname" value="{name}" hidden />
<input class="button amount-ntr" value="{name} <input class="button amount-ntr" value="{name}
{+price.amount}" type="submit" /> {+price.amount}" type="submit" />
</form></li>]], { </form></li>]], {
name = name, name = name,
username = username, username = username,
sign = price >= 0 and "-" or "+", sign = price >= 0 and "-" or "+",
amount = string.format("%.2f", math.abs(price / 100)), amount = string.format("%.2f", math.abs(price / 100)),
unit = config.unit or "", unit = config.unit or "",
})) }))
end end
print("</ul></div></label>") print("</ul></div></label>")
print("</div></li>") print("</div></li>")
print(format([[ print(format([[
<li><form class="transaction box backgroundbox {disable_class}" action="" method="POST"> <li><form class="transaction box backgroundbox {disable_class}" action="" method="POST">
<h3>{+user.form.transaction}</h3> <h3>{+user.form.transaction}</h3>
<input type="text" name="user_dst" value="{!username}" hidden /> <input type="text" name="user_dst" value="{!username}" hidden />
@ -552,13 +557,13 @@ local function r_user(username)
<h3>{+user.form.transfer}</h3> <h3>{+user.form.transfer}</h3>
<label for="user_dst">{+field.destination}: </label> <label for="user_dst">{+field.destination}: </label>
<select name="user_dst">]], <select name="user_dst">]],
{ username = username, disable_class = is_special and "disabled" or "" })) { username = username, disable_class = is_special and "disabled" or "" }))
local users = get_active_users(); local users = get_active_users();
for _, u in ipairs(users) do for _, u in ipairs(users) do
if u.name ~= username then if u.name ~= username then
print(format([[<option value="{!name}">{name}</option>]], { name = u.name })) print(format([[<option value="{!name}">{name}</option>]], { name = u.name }))
end end
end end
print(format([[</select> print(format([[</select>
<input type="text" name="user_src" value="{!username}" hidden /> <input type="text" name="user_src" value="{!username}" hidden />
<label for="amount">{+field.amount}: </label> <label for="amount">{+field.amount}: </label>
@ -579,8 +584,8 @@ local function r_user(username)
<input type="submit" value="{+user.form.restock.submit}" class="button amount-pos" /> <input type="submit" value="{+user.form.restock.submit}" class="button amount-pos" />
</form></li>]], </form></li>]],
{ {
username = username, username = username,
disable_class = is_special and "disabled" or "", disable_class = is_special and "disabled" or "",
})) }))
print("</ul>") print("</ul>")
end) end)
@ -591,6 +596,7 @@ local function r_log(filter)
if method == "POST" then if method == "POST" then
notif = r_transaction_post() notif = r_transaction_post()
end end
can_print = true
return respond(200, "Abrechnungen", function() return respond(200, "Abrechnungen", function()
if notif then print(notif) end if notif then print(notif) end
print([[<table class="log"]]) print([[<table class="log"]])
@ -648,9 +654,9 @@ local function r_log(filter)
end end
local function r_users(show_special, filter_negative) local function r_users(show_special, filter_negative)
if filter_negative ~= nil then if filter_negative ~= nil then
filter_negative = tonumber(filter_negative) or 0 filter_negative = tonumber(filter_negative) or 0
end end
return respond(200, "Abrechenbarkeit", function() return respond(200, "Abrechenbarkeit", function()
local users = get_active_users() local users = get_active_users()
@ -701,8 +707,8 @@ local function r_users(show_special, filter_negative)
local is_spu = user.name:sub(1, 1) == "@" local is_spu = user.name:sub(1, 1) == "@"
local filter_out = query.prefix ~= nil and user.name:sub(1, 1):lower() ~= query.prefix local filter_out = query.prefix ~= nil and user.name:sub(1, 1):lower() ~= query.prefix
if is_spu == show_special and if is_spu == show_special and
((filter_negative ~= nil and user.balance < filter_negative) ((filter_negative ~= nil and user.balance < filter_negative)
or (filter_negative == nil and (not filter_out))) then or (filter_negative == nil and (not filter_out))) then
print(format([[<li> print(format([[<li>
<a href="/{username_url}"> <a href="/{username_url}">
<span class="name">{!username}</span> <span class="name">{!username}</span>
@ -715,31 +721,31 @@ local function r_users(show_special, filter_negative)
})) }))
end end
end end
if filter_negative ~= nil then if filter_negative ~= nil then
table.sort(users, function(a, b) table.sort(users, function(a, b)
return a.balance < b.balance return a.balance < b.balance
end) end)
end end
local inactive_cutoff = os.time() - (tonumber(config.inactive_cutoff) or (30 * 24 * 60 * 60)) local inactive_cutoff = os.time() - (tonumber(config.inactive_cutoff) or (30 * 24 * 60 * 60))
local embezzlement = 0 local embezzlement = 0
for _, user in ipairs(users) do for _, user in ipairs(users) do
if filter_negative or user.time > inactive_cutoff then if filter_negative or user.time > inactive_cutoff then
show_user(user) show_user(user)
if user.name:sub(1,1) ~= "@" then if user.name:sub(1, 1) ~= "@" then
if user.balance < 0 then embezzlement = embezzlement - user.balance end if user.balance < 0 then embezzlement = embezzlement - user.balance end
end end
end end
end end
print("</ul>") print("</ul>")
if filter_negative ~= nil then if filter_negative ~= nil then
print(format([[<section class="section" style="margin-top: 0">{+users.embezzlement}</section>]], { print(format([[<section class="section" style="margin-top: 0">{+users.embezzlement}</section>]], {
amount = format_amount(embezzlement) amount = format_amount(embezzlement)
})) }))
return return
end end
print(format([[ print(format([[
<details {oclass}><summary>{+users.inactive_list}</summary><ul class="userlist"> <details {oclass}><summary>{+users.inactive_list}</summary><ul class="userlist">
@ -763,7 +769,7 @@ local function r_products_post()
local data = form_data() local data = form_data()
if data.deletebarcode then if data.deletebarcode then
local barcode = data.barcode local barcode = data.barcode
-- remove barcode -- remove barcode
local new_barcodes = io.open("barcodes.new", "w+") local new_barcodes = io.open("barcodes.new", "w+")
@ -778,9 +784,9 @@ local function r_products_post()
new_barcodes:flush() new_barcodes:flush()
new_barcodes:close() new_barcodes:close()
os.rename("barcodes.new", "barcodes") os.rename("barcodes.new", "barcodes")
return return
end end
local name = data.name local name = data.name
if name == nil or name:match("^" .. matchers.name .. "$") == nil then if name == nil or name:match("^" .. matchers.name .. "$") == nil then
return error_box("{+error.invalid_name}") return error_box("{+error.invalid_name}")
@ -801,31 +807,31 @@ local function r_products_post()
new_products:close() new_products:close()
os.rename("products.new", "products") os.rename("products.new", "products")
elseif data.addbarcode then elseif data.addbarcode then
-- add barcode -- add barcode
local name = data.name local name = data.name
local barcode = data.barcode local barcode = data.barcode
if name == nil or name:match(matchers_global.name) == nil then if name == nil or name:match(matchers_global.name) == nil then
return error_box("{+error.invalid_name}") return error_box("{+error.invalid_name}")
end end
if barcode == nil or barcode:match(matchers_global.barcode) == nil then if barcode == nil or barcode:match(matchers_global.barcode) == nil then
return error_box("{+error.invalid_barcode}") return error_box("{+error.invalid_barcode}")
end end
local exists = false local exists = false
for _, a_barcode in read_barcodes() do for _, a_barcode in read_barcodes() do
if a_barcode == barcode then if a_barcode == barcode then
exists = true exists = true
end end
end end
if exists then if exists then
return error_box("{+error.invalid_barcode}") return error_box("{+error.invalid_barcode}")
end end
local barcodes = io.open("barcodes", "a+") local barcodes = io.open("barcodes", "a+")
if barcodes == nil then if barcodes == nil then
return error_box("{+error.open_barcodes}") return error_box("{+error.open_barcodes}")
end end
barcodes:write(string.format("%s,%s\n", name, barcode)) barcodes:write(string.format("%s,%s\n", name, barcode))
barcodes:flush() barcodes:flush()
barcodes:close() barcodes:close()
else else
@ -841,26 +847,26 @@ local function r_products_post()
if user == nil or user:match(matchers_global.user) == nil then if user == nil or user:match(matchers_global.user) == nil then
return error_box("{+error.invalid_user}") return error_box("{+error.invalid_user}")
end end
-- add product -- add product
local new_products = io.open("products.new", "w+") local new_products = io.open("products.new", "w+")
if new_products == nil then if new_products == nil then
return error_box("{+error.open_new_products}") return error_box("{+error.open_new_products}")
end end
local wrote = nil local wrote = nil
-- prepend to any block in the file containing products of the same user -- prepend to any block in the file containing products of the same user
-- the shortcuts feature expects this! -- the shortcuts feature expects this!
for a_price, a_user, a_name in read_products() do for a_price, a_user, a_name in read_products() do
if user == a_user and not wrote then if user == a_user and not wrote then
wrote = true wrote = true
products:write(string.format("%d,%s,%s\n", price, user, name)) products:write(string.format("%d,%s,%s\n", price, user, name))
end end
new_products:write(string.format("%d,%s,%s\n", a_price, a_user, a_name)) new_products:write(string.format("%d,%s,%s\n", a_price, a_user, a_name))
end end
-- append if not wrote already -- append if not wrote already
if not wrote then if not wrote then
products:write(string.format("%d,%s,%s\n", price, user, name)) products:write(string.format("%d,%s,%s\n", price, user, name))
end end
new_products:flush() new_products:flush()
@ -874,6 +880,7 @@ local function r_products()
if method == "POST" then if method == "POST" then
notif = r_products_post() notif = r_products_post()
end end
can_print = true
respond(200, "Abrechenbare Product List", function() respond(200, "Abrechenbare Product List", function()
print(format("<h1>{+products.title}</h1>")) print(format("<h1>{+products.title}</h1>"))
if notif then print(notif) end if notif then print(notif) end
@ -895,15 +902,15 @@ local function r_products()
<label for="name">{+field.name}: </label> <label for="name">{+field.name}: </label>
<select type="text" name="name" id="name"> <select type="text" name="name" id="name">
]], { ]], {
currency = config.unit or "", currency = config.unit or "",
})) }))
for _, _, name in read_products() do for _, _, name in read_products() do
print(format([[<option value="{name}">{name}</option>]], { print(format([[<option value="{name}">{name}</option>]], {
name = name, name = name,
})) }))
end end
print(format([[</select> print(format([[</select>
<label for="barcode">{+field.barcode}: </label> <label for="barcode">{+field.barcode}: </label>
<input type="text" name="barcode" id="barcode" /> <input type="text" name="barcode" id="barcode" />
<input type="submit" value="{+products.form.add.submit}" class="amount-ntr button" /> <input type="submit" value="{+products.form.add.submit}" class="amount-ntr button" />
@ -914,14 +921,14 @@ local function r_products()
<label for="name">{+field.name}: </label> <label for="name">{+field.name}: </label>
<select type="text" name="name" id="name"> <select type="text" name="name" id="name">
]], { ]], {
currency = config.unit or "", currency = config.unit or "",
})) }))
for _, _, name in read_products() do for _, _, name in read_products() do
print(format([[<option value="{name}">{!name}</option>]], { print(format([[<option value="{name}">{!name}</option>]], {
name = name, name = name,
})) }))
end end
print(format([[</select> print(format([[</select>
<input type="submit" value="{+products.form.remove.submit}" class="amount-ntr button" /> <input type="submit" value="{+products.form.remove.submit}" class="amount-ntr button" />
</form> </form>
<!-- remove barcode --> <!-- remove barcode -->
@ -931,24 +938,24 @@ local function r_products()
<label for="barcode">{+field.barcode}: </label> <label for="barcode">{+field.barcode}: </label>
<select type="text" name="barcode" id="barcode"> <select type="text" name="barcode" id="barcode">
]], { ]], {
currency = config.unit or "", currency = config.unit or "",
})) }))
local barcodes = {} local barcodes = {}
for name, barcode in read_barcodes() do for name, barcode in read_barcodes() do
print(format([[<option value="{barcode}">{!barcode} ({!name})</option>]], { print(format([[<option value="{barcode}">{!barcode} ({!name})</option>]], {
name = name, name = name,
barcode = barcode, barcode = barcode,
})) }))
if barcodes[name] ~= nil then if barcodes[name] ~= nil then
table.insert(barcodes[name], barcode) table.insert(barcodes[name], barcode)
else else
barcodes[name] = {} barcodes[name] = {}
table.insert(barcodes[name], barcode) table.insert(barcodes[name], barcode)
end end
end end
print(format([[</select> print(format([[</select>
<input type="submit" value="{+products.form.remove.submit}" class="amount-ntr button" /> <input type="submit" value="{+products.form.remove.submit}" class="amount-ntr button" />
</form> </form>
</div> </div>
@ -977,8 +984,8 @@ local function r_products()
user = user, user = user,
barcodes = format_list(barcodes[name]) or "{+field.not_set}", barcodes = format_list(barcodes[name]) or "{+field.not_set}",
})) }))
end end
print("</table>") print("</table>")
end) end)
end end
@ -1063,7 +1070,7 @@ if path == "/" then
elseif query.spus then elseif query.spus then
return r_users(true, nil) return r_users(true, nil)
elseif query.users and query.export then elseif query.users and query.export then
return r_export_balances() return r_export_balances()
else else
return r_users(false, query.negative and (query.maximum or 0)) return r_users(false, query.negative and (query.maximum or 0))
end end

View file

@ -79,3 +79,4 @@ error.open_barcodes=Failed to open barcodes file
error.no_path=No path error.no_path=No path
users.inactive_list=Inactive Users users.inactive_list=Inactive Users
users.embezzlement=A total of {amount} are currently under embezzlement. users.embezzlement=A total of {amount} are currently under embezzlement.
print=Print