diff --git a/frontend/src/Components/LineEditor.svelte b/frontend/src/Components/LineEditor.svelte
index 8d91272..f44ca9e 100644
--- a/frontend/src/Components/LineEditor.svelte
+++ b/frontend/src/Components/LineEditor.svelte
@@ -21,8 +21,12 @@
async function applyEdit(){
let success = await onSet(editValue);
- if (success) value = editValue;
- editing=false;
+ if (success) {
+ value = editValue;
+ editing=false;
+ } else {
+ editValue = value;
+ }
}
function ignore(evt){
diff --git a/frontend/src/routes/stock/Index.svelte b/frontend/src/routes/stock/Index.svelte
index d5bcfab..6eb70ad 100644
--- a/frontend/src/routes/stock/Index.svelte
+++ b/frontend/src/routes/stock/Index.svelte
@@ -22,6 +22,32 @@
let properties = $state(null);
let top_level = $state(null);
+ async function deleteLocation(loc){
+ if (!confirm(t('confirm_delete',{element:loc.name}))) return;
+ const url = api(`stock/location/${loc.id}`);
+ const res = await fetch(url,{
+ credentials: 'include',
+ method: 'DELETE',
+ });
+ if (res.ok){
+ yikes();
+ for (var owner of top_level){
+ if (owner.locations && dropNestedLocation(owner.locations,loc)) break;
+ }
+ } else error(res);
+ }
+
+ function dropNestedLocation(locations,loc){
+ for (let [idx,entry] of locations.entries()){
+ if (entry.id == loc.id){
+ locations.splice(idx,1);
+ return true;
+ }
+ if (entry.locations && dropNestedLocation(entry.locations,loc)) return true;
+ }
+ return false;
+ }
+
async function move_dragged_to(new_loc){
const data = { item : draggedItem.id, target: new_loc.id };
const url = api('stock/move_item');
diff --git a/frontend/src/routes/stock/Locations.svelte b/frontend/src/routes/stock/Locations.svelte
index f19e009..8a32edf 100644
--- a/frontend/src/routes/stock/Locations.svelte
+++ b/frontend/src/routes/stock/Locations.svelte
@@ -39,6 +39,10 @@
return false;
}
+ function reset(){
+ new_location_name = '';
+ }
+
async function onSet(new_location_name){
const data = {
name: new_location_name,
@@ -54,6 +58,8 @@
yikes;
const saved = await res.json();
locations.push(saved);
+ show_location_form = false;
+ setTimeout(reset,500);
return true;
} else {
error(res);
@@ -86,18 +92,6 @@
-
\ No newline at end of file
+
diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java
index c340ed6..c904b84 100644
--- a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java
+++ b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java
@@ -14,6 +14,7 @@ import static java.lang.System.Logger.Level.ERROR;
import static java.lang.System.Logger.Level.WARNING;
import static java.text.MessageFormat.format;
+import de.srsoftware.tools.jdbc.Query;
import de.srsoftware.umbrella.core.BaseDb;
import de.srsoftware.umbrella.core.model.*;
import de.srsoftware.umbrella.core.model.Location;
@@ -56,6 +57,16 @@ public class SqliteDb extends BaseDb implements StockDb {
}
}
+ @Override
+ public Location delete(DbLocation location) {
+ try {
+ Query.delete().from(TABLE_LOCATIONS).where(ID,equal(location.id())).execute(db);
+ return location;
+ } catch (SQLException e){
+ throw databaseException("Failed to delete \"{0}\"",location.name());
+ }
+ }
+
/**
* id, owner, owner_id, code, name, location_id
* @throws SQLException
@@ -333,7 +344,7 @@ public class SqliteDb extends BaseDb implements StockDb {
rs.close();
if (prop == null) throw databaseException("Failed to add new property to item {0}",itemId);
if ("".equals(value)){
- delete().from(TABLE_ITEM_PROPERTIES).where(ITEM_ID,equal(itemId)).where(PROPERTY_ID,equal(existingPropId)).execute(db);
+ Query.delete().from(TABLE_ITEM_PROPERTIES).where(ITEM_ID,equal(itemId)).where(PROPERTY_ID,equal(existingPropId)).execute(db);
} else {
replaceInto(TABLE_ITEM_PROPERTIES,ITEM_ID,PROPERTY_ID,VALUE).values(itemId,existingPropId,value).execute(db);
}
diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java
index d93350d..80a954b 100644
--- a/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java
+++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java
@@ -7,6 +7,7 @@ import java.util.Collection;
public interface StockDb {
Property addNewProperty(long itemId, String name, Object value, String unit);
+ Location delete(DbLocation location);
Collection listChildLocations(long parentId);
Collection listCompanyLocations(Company company);
Collection- listItemsAt(Location location);
diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java
index 19a796c..a1205c8 100644
--- a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java
+++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java
@@ -44,7 +44,39 @@ public class StockModule extends BaseHandler implements StockService {
if (owner instanceof UmbrellaUser u && user.id() == u.id()) return true;
if (owner instanceof Company comp) return companyService().membership(comp.id(),user.id());
return false;
+ }
+
+ private boolean deleteLocation(UmbrellaUser user, Location locationRef, HttpExchange ex) throws IOException {
+ var location = locationRef.resolve();
+ var owner = location.owner().resolve();
+ if (!assigned(owner,user)) throw forbidden("You are not allowed to modify \"{0}\"",location);
+ if (!stockDb.listItemsAt(location).isEmpty()) throw forbidden("\"{0}\" cannot be deleted, as it contains items!",location);
+ if (!stockDb.listChildLocations(location.id()).isEmpty()) throw forbidden("\"{0}\" cannot be deleted, as it contains other locations!",location);
+ return sendContent(ex,stockDb.delete(location));
+ }
+ @Override
+ public boolean doDelete(Path path, HttpExchange ex) throws IOException {
+ addCors(ex);
+ try {
+ Optional token = SessionToken.from(ex).map(Token::of);
+ var user = userService().loadUser(token);
+ if (user.isEmpty()) return unauthorized(ex);
+ var head = path.pop();
+ return switch (head) {
+ case LOCATION -> {
+ try {
+ var location = Location.of(Long.parseLong(path.pop()));
+ yield deleteLocation(user.get(), location, ex);
+ } catch (NumberFormatException e){
+ yield super.doGet(path,ex);
+ }
+ }
+ case null, default -> super.doDelete(path,ex);
+ };
+ } catch (UmbrellaException e){
+ return send(ex,e);
+ }
}
@Override