mirror of
https://codeberg.org/metamuffin/abrechenbarkeit.git
synced 2025-01-15 05:24:35 +00:00
add support for multible barcodes per product; products file needs to be migrated manually
This commit is contained in:
parent
a23cdf1ee4
commit
5be820b181
2 changed files with 160 additions and 22 deletions
|
@ -30,6 +30,7 @@ local matchers = {
|
||||||
barcode = "([%w_-]+)",
|
barcode = "([%w_-]+)",
|
||||||
barcode_opt = "([%w_-]*)",
|
barcode_opt = "([%w_-]*)",
|
||||||
name = "([%w_ -]+)",
|
name = "([%w_ -]+)",
|
||||||
|
name_opt = "([%w_ -]*)",
|
||||||
}
|
}
|
||||||
local matchers_global = (function()
|
local matchers_global = (function()
|
||||||
local s = {}
|
local s = {}
|
||||||
|
@ -142,6 +143,26 @@ local function format_amount(amount, tag, classes)
|
||||||
})
|
})
|
||||||
end
|
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 function get_user_theme(username)
|
||||||
local c = ""
|
local c = ""
|
||||||
if username == "_jeb" then
|
if username == "_jeb" then
|
||||||
|
@ -254,9 +275,9 @@ local function read_log()
|
||||||
if l == "" or l == nil then
|
if l == "" or l == nil then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
local time, user_src, user_dst, amount, pcode, pcount, comment = string.match(l,
|
local time, user_src, user_dst, amount, pname, pcount, comment = string.match(l,
|
||||||
format("^{time},{user},{user},{amount},{barcode_opt},{amount_opt},{comment_opt}$", matchers))
|
format("^{time},{user},{user},{amount},{name_opt},{amount_opt},{comment_opt}$", matchers))
|
||||||
return tonumber(time), user_src, user_dst, tonumber(amount), pcode, tonumber(pcount), comment
|
return tonumber(time), user_src, user_dst, tonumber(amount), pname, tonumber(pcount), comment
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -271,8 +292,24 @@ local function read_products()
|
||||||
if l == "" or l == nil then
|
if l == "" or l == nil then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
local barcode, price, user, name = string.match(l, format("^{barcode},{amount},{user_opt},{name}$", matchers))
|
local price, user, name = string.match(l, format("^{amount},{user_opt},{name}$", matchers))
|
||||||
return barcode, tonumber(price), user, name
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -336,10 +373,25 @@ 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 barcode_name = nil
|
||||||
|
|
||||||
if pcode ~= nil and pcode ~= "" then
|
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
|
local exists = false
|
||||||
for p_barcode, p_amount, p_user, p_name in read_products() do
|
for p_amount, p_user, p_name in read_products() do
|
||||||
if p_barcode == pcode then
|
if barcode_name == p_name then
|
||||||
pcount = (tonumber(data.pcount) or 1) * (data.negate_pcount ~= nil and -1 or 1)
|
pcount = (tonumber(data.pcount) or 1) * (data.negate_pcount ~= nil and -1 or 1)
|
||||||
amount = amount or pcount * p_amount
|
amount = amount or pcount * p_amount
|
||||||
user_src = user_src or p_user
|
user_src = user_src or p_user
|
||||||
|
@ -349,9 +401,11 @@ local function r_transaction_post()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not exists then
|
if not exists then
|
||||||
return error_box("{+error.unknown_product}")
|
return error_box("{+error.unknown_product}"..barcode_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- 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}")
|
||||||
|
@ -371,7 +425,7 @@ local function r_transaction_post()
|
||||||
end
|
end
|
||||||
local time = os.time()
|
local time = os.time()
|
||||||
log:write(string.format("%d,%s,%s,%d,%s,%s,%s\n",
|
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:flush()
|
||||||
log:close()
|
log:close()
|
||||||
return format([[
|
return format([[
|
||||||
|
@ -644,23 +698,41 @@ end
|
||||||
|
|
||||||
local function r_products_post()
|
local function r_products_post()
|
||||||
local data = form_data()
|
local data = form_data()
|
||||||
local barcode = data.barcode
|
local name = data.name
|
||||||
if barcode == nil or barcode:match("^[%w_-]*$") == nil then
|
if name == nil or name:match("^[%w_-]*$") == nil then
|
||||||
return error_box("{+error.invalid_barcode}")
|
return error_box("{+error.invalid_name}")
|
||||||
end
|
end
|
||||||
|
|
||||||
if data.delete then
|
if data.delete then
|
||||||
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
|
||||||
for a_barcode, price, user, name in read_products() do
|
for price, user, a_name in read_products() do
|
||||||
if barcode ~= a_barcode then
|
if name ~= a_name then
|
||||||
new_products:write(string.format("%s,%d,%s,%s\n", a_barcode, price, user, name))
|
new_products:write(string.format("%d,%s,%s\n", price, user, name))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
new_products:flush()
|
new_products:flush()
|
||||||
new_products:close()
|
new_products:close()
|
||||||
os.rename("products.new", "products")
|
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
|
else
|
||||||
local price = tonumber(data.price)
|
local price = tonumber(data.price)
|
||||||
local name = data.name
|
local name = data.name
|
||||||
|
@ -678,7 +750,7 @@ local function r_products_post()
|
||||||
if products == nil then
|
if products == nil then
|
||||||
return error_box("{+error.open_products}")
|
return error_box("{+error.open_products}")
|
||||||
end
|
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:flush()
|
||||||
products:close()
|
products:close()
|
||||||
end
|
end
|
||||||
|
@ -702,6 +774,23 @@ local function r_products()
|
||||||
<input type="number" name="price" id="price" />
|
<input type="number" name="price" id="price" />
|
||||||
<label for="user">{+field.user}: </label>
|
<label for="user">{+field.user}: </label>
|
||||||
<input type="text" name="user" id="user" />
|
<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>
|
<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" />
|
||||||
|
@ -709,8 +798,51 @@ local function r_products()
|
||||||
<form action="/?products" method="POST" class="box backgroundbox">
|
<form action="/?products" method="POST" class="box backgroundbox">
|
||||||
<h3>{+products.form.remove}</h3>
|
<h3>{+products.form.remove}</h3>
|
||||||
<input type="text" name="delete" value="1" hidden />
|
<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>
|
<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" />
|
<input type="submit" value="{+products.form.remove.submit}" class="amount-ntr button" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -720,26 +852,27 @@ local function r_products()
|
||||||
print(format([[<table class="productlist"><tr>
|
print(format([[<table class="productlist"><tr>
|
||||||
<th>{+field.name}</th>
|
<th>{+field.name}</th>
|
||||||
<th>{+field.price}</th>
|
<th>{+field.price}</th>
|
||||||
<th>{+field.barcode}</th>
|
|
||||||
<th>{+field.count}</th>
|
<th>{+field.count}</th>
|
||||||
<th>{+field.user}</th>
|
<th>{+field.user}</th>
|
||||||
|
<th>{+field.barcode}</th>
|
||||||
</tr>]]))
|
</tr>]]))
|
||||||
local pbals = product_balances()
|
local pbals = product_balances()
|
||||||
for barcode, price, user, name in read_products() do
|
for price, user, name in read_products() do
|
||||||
print(format([[<tr>
|
print(format([[<tr>
|
||||||
<td>{!name}</td>
|
<td>{!name}</td>
|
||||||
{price}
|
{price}
|
||||||
<td>{!barcode}</td>
|
|
||||||
<td>{!count}</td>
|
<td>{!count}</td>
|
||||||
<td>{!user}</td>
|
<td>{!user}</td>
|
||||||
|
<td>{barcodes}</td>
|
||||||
</tr>]], {
|
</tr>]], {
|
||||||
name = name,
|
name = name,
|
||||||
price = format_amount(-price, "td"),
|
price = format_amount(-price, "td"),
|
||||||
barcode = barcode,
|
|
||||||
count = tostring(pbals[barcode] or 0),
|
count = tostring(pbals[barcode] or 0),
|
||||||
user = user,
|
user = user,
|
||||||
|
barcodes = format_list(barcodes[name]) or "{+field.not_set}",
|
||||||
}))
|
}))
|
||||||
end
|
end
|
||||||
|
|
||||||
print("</table>")
|
print("</table>")
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,14 +16,17 @@ field.time=Time
|
||||||
field.upstream_price=Upstream Price
|
field.upstream_price=Upstream Price
|
||||||
field.user=User
|
field.user=User
|
||||||
field.username=Username
|
field.username=Username
|
||||||
|
field.not_set=Not Set
|
||||||
index.form.create_user.submit=Continue
|
index.form.create_user.submit=Continue
|
||||||
index.form.create_user=User Creation
|
index.form.create_user=User Creation
|
||||||
log.actions.revert=Revert
|
log.actions.revert=Revert
|
||||||
log.actions=Actions
|
log.actions=Actions
|
||||||
log=Log
|
log=Log
|
||||||
products.form.add=Add Product
|
products.form.add=Add Product
|
||||||
|
products.form.addbarcode=Add Barcode
|
||||||
products.form.add.submit=Add
|
products.form.add.submit=Add
|
||||||
products.form.remove=Remove Product
|
products.form.remove=Remove Product
|
||||||
|
products.form.removebarcode=Remove Barcode
|
||||||
products.form.remove.submit=Remove
|
products.form.remove.submit=Remove
|
||||||
products.form.title=Product List
|
products.form.title=Product List
|
||||||
products.title=Product List
|
products.title=Product List
|
||||||
|
@ -55,6 +58,7 @@ users=Users
|
||||||
user.special=This is a special user.
|
user.special=This is a special user.
|
||||||
users.filter=Filter
|
users.filter=Filter
|
||||||
error.unknown_product=Unknown product
|
error.unknown_product=Unknown product
|
||||||
|
error.unknown_barcode=Unknown barcode
|
||||||
error.invalid_amount=Amount invalid
|
error.invalid_amount=Amount invalid
|
||||||
error.invalid_comment=Comment invalid
|
error.invalid_comment=Comment invalid
|
||||||
error.invalid_user_src=Source user 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_price=Price invalid
|
||||||
error.invalid_name=Name invalid
|
error.invalid_name=Name invalid
|
||||||
error.open_products=Failed to open products file
|
error.open_products=Failed to open products file
|
||||||
|
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.
|
||||||
|
|
Loading…
Reference in a new issue