implemented stock display from location tree to property list
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -149,8 +149,6 @@ public class Constants {
|
||||
public static final String PROJECT = "project";
|
||||
public static final String PROJECT_ID = "project_id";
|
||||
public static final String PROPERTIES = "properties";
|
||||
|
||||
public static final String QUANTITY = "quantity";
|
||||
|
||||
public static final String RECEIVERS = "receivers";
|
||||
public static final String REDIRECT = "redirect";
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.core.model;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
|
||||
public class Item implements Mappable {
|
||||
private long id;
|
||||
private Mappable owner;
|
||||
@@ -27,6 +26,10 @@ public class Item implements Mappable {
|
||||
this.properties = new HashSet<>();
|
||||
}
|
||||
|
||||
public long id(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public static Item of(ResultSet rs, Mappable owner, Location location) throws SQLException {
|
||||
var id = rs.getLong(ID);
|
||||
var code = rs.getString(CODE);
|
||||
@@ -34,6 +37,14 @@ public class Item implements Mappable {
|
||||
return new Item(owner, id, location, code, name);
|
||||
}
|
||||
|
||||
public Mappable owner(){
|
||||
return owner;
|
||||
}
|
||||
|
||||
public Collection<Property> properties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
return Map.of(
|
||||
|
||||
@@ -1,18 +1,33 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.core.model;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
public class Property implements Mappable {
|
||||
long id;
|
||||
String name;
|
||||
Object value;
|
||||
String unit;
|
||||
String quantity;
|
||||
|
||||
public Property(long id, String name, Object value, String unit) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public static Property of(ResultSet rs) throws SQLException {
|
||||
var id = rs.getLong(ID);
|
||||
var name = rs.getString(NAME);
|
||||
var value = rs.getObject(VALUE);
|
||||
var unit = rs.getString(UNIT);
|
||||
return new Property(id, name, value, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
@@ -20,8 +35,7 @@ public class Property implements Mappable {
|
||||
ID, id,
|
||||
NAME, name,
|
||||
VALUE, value,
|
||||
UNIT, unit,
|
||||
QUANTITY, quantity
|
||||
UNIT, unit
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,19 @@
|
||||
import ItemProps from './ItemProps.svelte';
|
||||
|
||||
|
||||
let items = $derived.by(loadItems);
|
||||
let item = $state(null);
|
||||
let location = $state(null);
|
||||
let properties = $state(null);
|
||||
let top_level = $state(null);
|
||||
let selected = $state(null);
|
||||
let items = $derived(loadItems(selected));
|
||||
|
||||
async function loadItems(loc){
|
||||
if (!loc) return null;
|
||||
const url = api(`stock/items_at/${loc.id}`)
|
||||
async function loadItems(){
|
||||
if (!location) return null;
|
||||
const url = api(`stock/items_at/${location.id}`)
|
||||
const res = await fetch(url,{credentials:'include'});
|
||||
if (res.ok){
|
||||
yikes();
|
||||
return loc.name;
|
||||
return res.json();
|
||||
} else {
|
||||
error(res);
|
||||
return null;
|
||||
@@ -47,22 +49,23 @@
|
||||
{#each top_level as realm,idx}
|
||||
<h3>{realm.name}</h3>
|
||||
{#if realm.locations}
|
||||
<Locations locations={realm.locations} bind:selected />
|
||||
<Locations locations={realm.locations} bind:selected={location} />
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
</td>
|
||||
<td class="items">
|
||||
{#if selected}
|
||||
<h3>{selected.name}</h3>
|
||||
{#await items}
|
||||
<span>loading…</span>
|
||||
{:then data}
|
||||
{#if location}
|
||||
<h3>{location.name}</h3>
|
||||
{/if}
|
||||
{#if items}
|
||||
<pre>{JSON.stringify(items)}</pre>
|
||||
{/if}
|
||||
<ItemList />
|
||||
<ItemList items={data.sort((a,b) => a.code.localeCompare(b.code))} bind:selected={item} />
|
||||
{/await}
|
||||
</td>
|
||||
<td class="properties">
|
||||
<ItemProps />
|
||||
<ItemProps {item} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
<script>
|
||||
import { t } from '../../translations.svelte';
|
||||
|
||||
let { items, selected = $bindable(null) } = $props();
|
||||
</script>
|
||||
<ul>
|
||||
<li>
|
||||
<a>
|
||||
<span class="symbol"></span> {t('add_object',{object:'item'})}
|
||||
</a>
|
||||
</li>
|
||||
<li>Item 1</li>
|
||||
<li>Item 2</li>
|
||||
<li>Item 3</li>
|
||||
</ul>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t('id')}</th>
|
||||
<th>{t('code')}</th>
|
||||
<th>{t('name')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each items as item}
|
||||
<tr onclick={ev => selected = item}>
|
||||
<td>{item.id}</td>
|
||||
<td>{item.code}</td>
|
||||
<td>{item.name}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
<ul>
|
||||
<li>Prop 1</li>
|
||||
<li>Prop 2</li>
|
||||
<li>Prop 3</li>
|
||||
</ul>
|
||||
<script>
|
||||
let { item } = $props();
|
||||
</script>
|
||||
|
||||
{#if item}
|
||||
<h3>{item.name}</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
{#each item.properties as prop}
|
||||
<tr>
|
||||
<td>
|
||||
{prop.name}
|
||||
</td>
|
||||
<td>
|
||||
{prop.value}
|
||||
{prop.unit}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/if}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<ul>
|
||||
<li>
|
||||
<a>
|
||||
<span class="symbol"></span> {t('add_object',{object:'location'})}
|
||||
<span class="symbol"></span> {t('add_object',{object:t('location')})}
|
||||
</a>
|
||||
</li>
|
||||
{#each locations as location}
|
||||
|
||||
@@ -7,6 +7,8 @@ import static de.srsoftware.tools.jdbc.Condition.isNull;
|
||||
import static de.srsoftware.tools.jdbc.Query.*;
|
||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.ModuleRegistry.companyService;
|
||||
import static de.srsoftware.umbrella.core.ModuleRegistry.userService;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException;
|
||||
import static de.srsoftware.umbrella.stock.Constants.*;
|
||||
import static java.lang.System.Logger.Level.ERROR;
|
||||
@@ -15,12 +17,7 @@ import static java.text.MessageFormat.format;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import de.srsoftware.umbrella.core.BaseDb;
|
||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.Company;
|
||||
import de.srsoftware.umbrella.core.model.Item;
|
||||
import de.srsoftware.umbrella.core.model.Location;
|
||||
import de.srsoftware.umbrella.core.model.UmbrellaUser;
|
||||
import de.srsoftware.umbrella.core.model.*;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
@@ -53,23 +50,6 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
super(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int createTables() {
|
||||
int currentVersion = createSettingsTable();
|
||||
switch (currentVersion){
|
||||
case 0:
|
||||
createLocationsTable();
|
||||
createItemsTable();
|
||||
createPropertiesTable();
|
||||
createItemPropsTable();
|
||||
case 1:
|
||||
dropTokenTable();
|
||||
case 2:
|
||||
transformTables();
|
||||
}
|
||||
return setCurrentVersion(3);
|
||||
}
|
||||
|
||||
private void createIntermediateItemsTable() throws SQLException { // create intermediate table
|
||||
var sql = "CREATE TABLE IF NOT EXISTS items_temp ({0} LONG NOT NULL, {1} LONG NOT NULL, {2} VARCHAR(255), {3} VARCHAR(255) NOT NULL, {4} LONG NOT NULL, PRIMARY KEY({0}, {1}))";
|
||||
sql = format(sql, OWNER, ID, CODE, NAME, LOCATION_ID);
|
||||
@@ -128,6 +108,23 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int createTables() {
|
||||
int currentVersion = createSettingsTable();
|
||||
switch (currentVersion){
|
||||
case 0:
|
||||
createLocationsTable();
|
||||
createItemsTable();
|
||||
createPropertiesTable();
|
||||
createItemPropsTable();
|
||||
case 1:
|
||||
dropTokenTable();
|
||||
case 2:
|
||||
transformTables();
|
||||
}
|
||||
return setCurrentVersion(3);
|
||||
}
|
||||
|
||||
private void dropTokenTable() {
|
||||
try {
|
||||
db.prepareStatement("DROP TABLE IF EXISTS tokens").execute();
|
||||
@@ -136,48 +133,6 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Item> listItems(long companyId) throws UmbrellaException {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Item> listItemsAt(long locationId) {
|
||||
try {
|
||||
var rs = select(ALL).from(TABLE_ITEMS).where(LOCATION_ID,equal(locationId)).exec(db);
|
||||
var list = new ArrayList<Item>();
|
||||
|
||||
while (rs.next()) {
|
||||
var ownerId = rs.getLong(OWNER);
|
||||
Mappable owner = ownerId < 0 ? ModuleRegistry.companyService().get(-ownerId) : ModuleRegistry.userService().loadUser(ownerId);
|
||||
var location = loadLocation(rs.getLong(LOCATION_ID));
|
||||
list.add(Item.of(rs, owner, location));
|
||||
}
|
||||
rs.close();
|
||||
return list;
|
||||
} catch (SQLException e){
|
||||
throw databaseException("Failed to load items at {0}",locationId);
|
||||
}
|
||||
}
|
||||
|
||||
private Location loadLocation(long locationId) {
|
||||
try {
|
||||
var rs = select(ALL).from(TABLE_LOCATIONS).where(ID,equal(locationId)).exec(db);
|
||||
Location loc = null;
|
||||
if (rs.next()) loc = Location.of(rs);
|
||||
rs.close();
|
||||
if (loc != null) return loc;
|
||||
throw databaseException("Failed to load location with id = {0}",locationId);
|
||||
} catch (SQLException e){
|
||||
throw databaseException("Failed to load location with id = {0}",locationId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Location> listLocations(long companyId) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Location> listChildLocations(long parentId) {
|
||||
try {
|
||||
@@ -204,6 +159,51 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Item> listItemsAt(long locationId) {
|
||||
try {
|
||||
var location = loadLocation(locationId);
|
||||
var rs = select(ALL).from(TABLE_ITEMS).where(LOCATION_ID,equal(locationId)).exec(db);
|
||||
var list = new ArrayList<Item>();
|
||||
var ownerMap = new HashMap<Long,Mappable>();
|
||||
while (rs.next()) {
|
||||
var ownerId = rs.getLong(OWNER);
|
||||
var owner = ownerMap.get(ownerId);
|
||||
if (owner == null) {
|
||||
owner = ownerId < 0 ? companyService().get(-ownerId) : userService().loadUser(ownerId);
|
||||
ownerMap.put(ownerId,owner);
|
||||
}
|
||||
list.add(Item.of(rs, owner, location));
|
||||
}
|
||||
rs.close();
|
||||
|
||||
for (var item : list){
|
||||
var owner = item.owner();
|
||||
var ownerId = owner instanceof Company comp ? -comp.id() : (owner instanceof UmbrellaUser u ? u.id() : 0);
|
||||
if (ownerId == 0) throw databaseException("Encountered unknown item owner of type {0}",owner.getClass().getSimpleName());
|
||||
rs = select(ALL).from(TABLE_ITEM_PROPERTIES).leftJoin(PROPERTY_ID,TABLE_PROPERTIES,ID).where(OWNER,equal(ownerId)).where(ITEM_ID,equal(item.id())).exec(db);
|
||||
while (rs.next()) item.properties().add(Property.of(rs));
|
||||
rs.close();
|
||||
}
|
||||
return list;
|
||||
} catch (SQLException e){
|
||||
throw databaseException("Failed to load items at {0}",locationId);
|
||||
}
|
||||
}
|
||||
|
||||
private Location loadLocation(long locationId) {
|
||||
try {
|
||||
var rs = select(ALL).from(TABLE_LOCATIONS).where(ID,equal(locationId)).exec(db);
|
||||
Location loc = null;
|
||||
if (rs.next()) loc = Location.of(rs);
|
||||
rs.close();
|
||||
if (loc != null) return loc;
|
||||
throw databaseException("Failed to load location with id = {0}",locationId);
|
||||
} catch (SQLException e){
|
||||
throw databaseException("Failed to load location with id = {0}",locationId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Location> listUserLocations(UmbrellaUser user) {
|
||||
try {
|
||||
@@ -217,29 +217,6 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
}
|
||||
}
|
||||
|
||||
private void transformTables(){
|
||||
try {
|
||||
db.setAutoCommit(false);
|
||||
createIntermediateLocationTable();
|
||||
createIntermediateItemsTable();
|
||||
createIntermediatePropsTable();
|
||||
var oldLocationIdsToNew = transformLocations();
|
||||
transformItems(oldLocationIdsToNew);
|
||||
transformProperties();
|
||||
replaceLocationsTable();
|
||||
replaceItemsTable();
|
||||
replaceItemPropsTable();
|
||||
db.setAutoCommit(true);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
db.rollback();
|
||||
} catch (SQLException ignored) {
|
||||
}
|
||||
LOG.log(ERROR,"Failed to transform {0} table!",TABLE_LOCATIONS,e);
|
||||
throw databaseException("Failed to transform {0} table!",TABLE_LOCATIONS);
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceItemsTable() throws SQLException {
|
||||
db.prepareStatement(format("DROP TABLE {0}",TABLE_ITEMS)).execute();
|
||||
db.prepareStatement(format("ALTER TABLE {0} RENAME TO {1}","items_temp",TABLE_ITEMS)).execute();
|
||||
@@ -335,4 +312,27 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
rs.close();
|
||||
insert.execute(db).close();
|
||||
}
|
||||
|
||||
private void transformTables(){
|
||||
try {
|
||||
db.setAutoCommit(false);
|
||||
createIntermediateLocationTable();
|
||||
createIntermediateItemsTable();
|
||||
createIntermediatePropsTable();
|
||||
var oldLocationIdsToNew = transformLocations();
|
||||
transformItems(oldLocationIdsToNew);
|
||||
transformProperties();
|
||||
replaceLocationsTable();
|
||||
replaceItemsTable();
|
||||
replaceItemPropsTable();
|
||||
db.setAutoCommit(true);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
db.rollback();
|
||||
} catch (SQLException ignored) {
|
||||
}
|
||||
LOG.log(ERROR,"Failed to transform {0} table!",TABLE_LOCATIONS,e);
|
||||
throw databaseException("Failed to transform {0} table!",TABLE_LOCATIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.stock;
|
||||
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.Company;
|
||||
import de.srsoftware.umbrella.core.model.Item;
|
||||
import de.srsoftware.umbrella.core.model.Location;
|
||||
@@ -11,12 +10,6 @@ import java.util.Collection;
|
||||
public interface StockDb {
|
||||
Collection<Location> listChildLocations(long parentId);
|
||||
Collection<Location> listCompanyLocations(Company company);
|
||||
|
||||
Collection<Item> listItems(long companyId) throws UmbrellaException;
|
||||
|
||||
Collection<Item> listItemsAt(long locationId);
|
||||
|
||||
Collection<Location> listLocations(long companyId);
|
||||
|
||||
Collection<Item> listItemsAt(long locationId);
|
||||
Collection<Location> listUserLocations(UmbrellaUser userId);
|
||||
}
|
||||
|
||||
@@ -130,6 +130,7 @@
|
||||
"loading_object": "lade {object}…",
|
||||
"local_court": "Amtsgericht",
|
||||
"locality": "Ort",
|
||||
"location": "Ort",
|
||||
"login" : "Anmeldung",
|
||||
"login_services": "Login-Services",
|
||||
"logout": "Abmelden",
|
||||
|
||||
Reference in New Issue
Block a user