add support for multible barcodes per product; products file needs to be migrated manually

This commit is contained in:
Riley L. 2025-01-02 00:03:45 +01:00
parent a23cdf1ee4
commit 5be820b181
2 changed files with 160 additions and 22 deletions

View file

@ -30,6 +30,7 @@ local matchers = {
barcode = "([%w_-]+)",
barcode_opt = "([%w_-]*)",
name = "([%w_ -]+)",
name_opt = "([%w_ -]*)",
}
local matchers_global = (function()
local s = {}
@ -142,6 +143,26 @@ local function format_amount(amount, tag, classes)
})
end
local function format_list(list)
if list == nil then
return nil
end
local not_first = false
local out = ""
for _, barcode in pairs(list) do
if not_first then
out = out .. ", " .. barcode
else
out = barcode
end
not_first = true
end
return out
end
local function get_user_theme(username)
local c = ""
if username == "_jeb" then
@ -254,9 +275,9 @@ local function read_log()
if l == "" or l == nil then
return nil
end
local time, user_src, user_dst, amount, pcode, pcount, comment = string.match(l,
format("^{time},{user},{user},{amount},{barcode_opt},{amount_opt},{comment_opt}$", matchers))
return tonumber(time), user_src, user_dst, tonumber(amount), pcode, tonumber(pcount), comment
local time, user_src, user_dst, amount, pname, pcount, comment = string.match(l,
format("^{time},{user},{user},{amount},{name_opt},{amount_opt},{comment_opt}$", matchers))
return tonumber(time), user_src, user_dst, tonumber(amount), pname, tonumber(pcount), comment
end
end
@ -271,8 +292,24 @@ local function read_products()
if l == "" or l == nil then
return nil
end
local barcode, price, user, name = string.match(l, format("^{barcode},{amount},{user_opt},{name}$", matchers))
return barcode, tonumber(price), user, name
local price, user, name = string.match(l, format("^{amount},{user_opt},{name}$", matchers))
return tonumber(price), user, name
end
end
local function read_barcodes()
local log = io.open("barcodes", "r")
if log == nil then
return function() return nil end
end
local lines = log:lines("l")
return function()
local l = lines()
if l == "" or l == nil then
return nil
end
local name, barcode = string.match(l, format("^{name},{barcode}$", matchers))
return name, barcode
end
end
@ -336,10 +373,25 @@ local function r_transaction_post()
local pcode = data.pcode
local pcount = tonumber(data.pcount)
local comment = data.comment
local barcode_name = nil
if pcode ~= nil and pcode ~= "" then
-- check if barcode exists
local exists = false
for p_name, p_barcode in read_barcodes() do
if p_barcode == pcode then
exists = true
barcode_name = p_name
end
end
if not exists then
return error_box("{+error.unknown_barcode}")
end
-- check if product exists
local exists = false
for p_barcode, p_amount, p_user, p_name in read_products() do
if p_barcode == pcode then
for p_amount, p_user, p_name in read_products() do
if barcode_name == p_name then
pcount = (tonumber(data.pcount) or 1) * (data.negate_pcount ~= nil and -1 or 1)
amount = amount or pcount * p_amount
user_src = user_src or p_user
@ -349,9 +401,11 @@ local function r_transaction_post()
end
end
if not exists then
return error_box("{+error.unknown_product}")
return error_box("{+error.unknown_product}"..barcode_name)
end
end
-- for outside money
user_src = user_src or "@Potential"
if amount == nil then
return error_box("{+error.invalid_amount}")
@ -371,7 +425,7 @@ local function r_transaction_post()
end
local time = os.time()
log:write(string.format("%d,%s,%s,%d,%s,%s,%s\n",
time, user_src, user_dst, amount, pcode or "", pcount or "", comment))
time, user_src, user_dst, amount, barcode_name or "", pcount or "", comment))
log:flush()
log:close()
return format([[
@ -644,23 +698,41 @@ end
local function r_products_post()
local data = form_data()
local barcode = data.barcode
if barcode == nil or barcode:match("^[%w_-]*$") == nil then
return error_box("{+error.invalid_barcode}")
local name = data.name
if name == nil or name:match("^[%w_-]*$") == nil then
return error_box("{+error.invalid_name}")
end
if data.delete then
local new_products = io.open("products.new", "w+")
if new_products == nil then
return error_box("{+error.open_new_products}")
end
for a_barcode, price, user, name in read_products() do
if barcode ~= a_barcode then
new_products:write(string.format("%s,%d,%s,%s\n", a_barcode, price, user, name))
for price, user, a_name in read_products() do
if name ~= a_name then
new_products:write(string.format("%d,%s,%s\n", price, user, name))
end
end
new_products:flush()
new_products:close()
os.rename("products.new", "products")
elseif data.addbarcode then
-- add barcode
local name = data.name
local barcode = data.barcode
if name == nil or name:match(matchers_global.name) == nil then
return error_box("{+error.invalid_name}")
end
if barcode == nil or barcode:match(matchers_global.barcode) == nil then
return error_box("{+error.invalid_barcode}")
end
local barcodes = io.open("barcodes", "a+")
if barcodes == nil then
return error_box("{+error.open_barcodes}")
end
barcodes:write(string.format("%s,%s\n", name, barcode))
barcodes:flush()
barcodes:close()
else
local price = tonumber(data.price)
local name = data.name
@ -678,7 +750,7 @@ local function r_products_post()
if products == nil then
return error_box("{+error.open_products}")
end
products:write(string.format("%s,%d,%s,%s\n", barcode, price, user, name))
products:write(string.format("%d,%s,%s\n", price, user, name))
products:flush()
products:close()
end
@ -702,6 +774,23 @@ local function r_products()
<input type="number" name="price" id="price" />
<label for="user">{+field.user}: </label>
<input type="text" name="user" id="user" />
<input type="submit" value="{+products.form.add.submit}" class="amount-ntr button" />
</form>
<form action="/?products" method="POST" class="box backgroundbox">
<h3>{+products.form.addbarcode}</h3>
<input type="text" name="addbarcode" value="1" hidden />
<label for="name">{+field.name}: </label>
<select type="text" name="name" id="name">
]], {
currency = config.unit or "",
}))
for _, _, name in read_products() do
print(format([[<option name="{name}">{name}</option>]], {
name = name,
}))
end
print(format([[</select>
<label for="barcode">{+field.barcode}: </label>
<input type="text" name="barcode" id="barcode" />
<input type="submit" value="{+products.form.add.submit}" class="amount-ntr button" />
@ -709,8 +798,51 @@ local function r_products()
<form action="/?products" method="POST" class="box backgroundbox">
<h3>{+products.form.remove}</h3>
<input type="text" name="delete" value="1" hidden />
<label for="name">{+field.name}: </label>
<select type="text" name="name" id="name">
]], {
currency = config.unit or "",
}))
for _, _, name in read_products() do
print(format([[<option name="{name}">{!name}</option>]], {
name = name,
}))
end
print(format([[</select>
<input type="submit" value="{+products.form.remove.submit}" class="amount-ntr button" />
</form>
<!-- remove barcode -->
<form action="/?products" method="POST" class="box backgroundbox">
<h3>{+products.form.removebarcode}</h3>
<input type="text" name="delete" value="1" hidden />
<label for="barcode">{+field.barcode}: </label>
<input type="text" name="barcode" id="barcode" />
<select type="text" name="barcode" id="barcode">
]], {
currency = config.unit or "",
}))
local barcodes = {}
for name, barcode in read_barcodes() do
print(format([[<option name="{barcode}">{!barcode} ({!name})</option>]], {
name = name,
barcode = barcode,
}))
if barcodes[name] ~= nil then
table.insert(barcodes[name], barcode)
else
barcodes[name] = {}
table.insert(barcodes[name], barcode)
end
end
for a, b in pairs(barcodes) do
print("name: " .. a)
for _, c in pairs(b) do
print("\t"..c)
end
end
print(format([[</select>
<input type="submit" value="{+products.form.remove.submit}" class="amount-ntr button" />
</form>
</div>
@ -720,26 +852,27 @@ local function r_products()
print(format([[<table class="productlist"><tr>
<th>{+field.name}</th>
<th>{+field.price}</th>
<th>{+field.barcode}</th>
<th>{+field.count}</th>
<th>{+field.user}</th>
<th>{+field.barcode}</th>
</tr>]]))
local pbals = product_balances()
for barcode, price, user, name in read_products() do
for price, user, name in read_products() do
print(format([[<tr>
<td>{!name}</td>
{price}
<td>{!barcode}</td>
<td>{!count}</td>
<td>{!user}</td>
<td>{barcodes}</td>
</tr>]], {
name = name,
price = format_amount(-price, "td"),
barcode = barcode,
count = tostring(pbals[barcode] or 0),
user = user,
barcodes = format_list(barcodes[name]) or "{+field.not_set}",
}))
end
end
print("</table>")
end)
end

View file

@ -16,14 +16,17 @@ field.time=Time
field.upstream_price=Upstream Price
field.user=User
field.username=Username
field.not_set=Not Set
index.form.create_user.submit=Continue
index.form.create_user=User Creation
log.actions.revert=Revert
log.actions=Actions
log=Log
products.form.add=Add Product
products.form.addbarcode=Add Barcode
products.form.add.submit=Add
products.form.remove=Remove Product
products.form.removebarcode=Remove Barcode
products.form.remove.submit=Remove
products.form.title=Product List
products.title=Product List
@ -55,6 +58,7 @@ users=Users
user.special=This is a special user.
users.filter=Filter
error.unknown_product=Unknown product
error.unknown_barcode=Unknown barcode
error.invalid_amount=Amount invalid
error.invalid_comment=Comment invalid
error.invalid_user_src=Source user invalid
@ -66,6 +70,7 @@ error.open_new_products=Failed to open new products file
error.invalid_price=Price invalid
error.invalid_name=Name invalid
error.open_products=Failed to open products file
error.open_barcodes=Failed to open barcodes file
error.no_path=No path
users.inactive_list=Inactive Users
users.embezzlement=A total of {amount} are currently under embezzlement.