working on migration of items to stock db
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -41,7 +41,7 @@ subprojects {
|
||||
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
implementation("de.srsoftware:configuration.api:1.0.2")
|
||||
implementation("de.srsoftware:tools.jdbc:2.0.3")
|
||||
implementation("de.srsoftware:tools.jdbc:2.0.4")
|
||||
implementation("de.srsoftware:tools.http:6.0.5")
|
||||
implementation("de.srsoftware:tools.mime:1.1.3")
|
||||
implementation("de.srsoftware:tools.logging:1.3.2")
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Collection;
|
||||
public interface StockService {
|
||||
/**
|
||||
* Das war mal die methode um zu checken, ob einer Firma noch Items zugewiesen sind.
|
||||
* Diese Methode muss neu definiert werden, sobald der Stock-Service neu implementiert ist.
|
||||
* TODO: Diese Methode muss neu definiert werden, sobald der Stock-Service neu implementiert ist.
|
||||
* @param company_id
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -13,18 +13,19 @@ import org.json.JSONObject;
|
||||
public class Item implements Mappable {
|
||||
private long id, ownerNumber; // id is the database key, number the owner-relative id
|
||||
private Owner owner;
|
||||
private String code, name;
|
||||
private String code, description, name;
|
||||
private Location location;
|
||||
private Collection<Property> properties;
|
||||
private Set<String> dirtyFields = new HashSet<>();
|
||||
|
||||
public Item(long id, Owner owner, long ownerNumber, Location location, String code, String name) {
|
||||
public Item(long id, Owner owner, long ownerNumber, Location location, String code, String name, String description) {
|
||||
this.id = id;
|
||||
this.owner = owner;
|
||||
this.ownerNumber = ownerNumber;
|
||||
this.location = location;
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.properties = new HashSet<>();
|
||||
}
|
||||
|
||||
@@ -37,6 +38,10 @@ public class Item implements Mappable {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String description(){
|
||||
return description;
|
||||
}
|
||||
|
||||
public boolean isDirty(){
|
||||
return !dirtyFields.isEmpty();
|
||||
}
|
||||
@@ -71,7 +76,8 @@ public class Item implements Mappable {
|
||||
var location = Location.of(rs);
|
||||
var code = rs.getString(CODE);
|
||||
var name = rs.getString(NAME);
|
||||
return new Item(id, owner, ownerNumber, location, code, name);
|
||||
var description = rs.getString(DESCRIPTION);
|
||||
return new Item(id, owner, ownerNumber, location, code, name, description);
|
||||
}
|
||||
|
||||
public Owner owner(){
|
||||
@@ -92,6 +98,9 @@ public class Item implements Mappable {
|
||||
case NAME:
|
||||
name = json.getString(field);
|
||||
break;
|
||||
case DESCRIPTION:
|
||||
description = json.getString(field);
|
||||
break;
|
||||
default:
|
||||
known = false;
|
||||
}
|
||||
@@ -112,6 +121,7 @@ public class Item implements Mappable {
|
||||
map.put(LOCATION,location.toMap());
|
||||
map.put(CODE,code);
|
||||
map.put(NAME,name);
|
||||
map.put(DESCRIPTION,description);
|
||||
map.put(OWNER_NUMBER,ownerNumber);
|
||||
if (properties != null) map.put(PROPERTIES,properties.stream().map(Property::toMap).toList());
|
||||
return map;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package de.srsoftware.umbrella.core.model;
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static java.text.MessageFormat.format;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import java.sql.ResultSet;
|
||||
@@ -22,6 +23,14 @@ public class Property implements Mappable {
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public long id(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public String name(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public static Property of(ResultSet rs) throws SQLException {
|
||||
var id = rs.getLong(ID);
|
||||
var name = rs.getString(NAME);
|
||||
@@ -45,6 +54,19 @@ public class Property implements Mappable {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return format("{0} ({1} = {2}{3})",getClass().getSimpleName(),name,value,unit==null?"":" "+unit);
|
||||
}
|
||||
|
||||
public String unit(){
|
||||
return unit;
|
||||
}
|
||||
|
||||
public Object value(){
|
||||
return value;
|
||||
}
|
||||
|
||||
public Property value(Object newVal){
|
||||
value = newVal;
|
||||
return this;
|
||||
|
||||
63
stock/src/main/java/de/srsoftware/umbrella/stock/ItemDb.java
Normal file
63
stock/src/main/java/de/srsoftware/umbrella/stock/ItemDb.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.stock;
|
||||
|
||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||
import static de.srsoftware.tools.jdbc.Query.select;
|
||||
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.Field.COMPANY_ID;
|
||||
import static de.srsoftware.umbrella.core.Field.UNIT_PRICE;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException;
|
||||
import static de.srsoftware.umbrella.stock.Constants.TABLE_ITEMS;
|
||||
|
||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||
import de.srsoftware.umbrella.core.model.DbLocation;
|
||||
import de.srsoftware.umbrella.core.model.Item;
|
||||
import de.srsoftware.umbrella.core.model.Location;
|
||||
import de.srsoftware.umbrella.core.model.Property;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ItemDb {
|
||||
private final System.Logger LOG = System.getLogger(getClass().getSimpleName());
|
||||
private final Connection db;
|
||||
|
||||
public ItemDb(String dbFilePath){
|
||||
db = connect(dbFilePath);
|
||||
}
|
||||
|
||||
public void migrateTo(StockDb stockDb) {
|
||||
try {
|
||||
var companyLocations = new HashMap<Long,Location>();
|
||||
var rs = select(ALL).from(TABLE_ITEMS).exec(db);
|
||||
while (rs.next()){
|
||||
var id = rs.getLong(ID);
|
||||
var companyId = rs.getLong(COMPANY_ID);
|
||||
var code = rs.getString(CODE);
|
||||
var name = rs.getString(NAME);
|
||||
var description = rs.getString(DESCRIPTION);
|
||||
var unit = rs.getString(UNIT);
|
||||
var unitPrice = rs.getLong(UNIT_PRICE);
|
||||
var tax = rs.getLong(TAX);
|
||||
var company = ModuleRegistry.companyService().get(companyId);
|
||||
var location = companyLocations.get(companyId);
|
||||
if (location == null) { // TODO: ids currently do not get assigned
|
||||
location = stockDb.save(new DbLocation(0,company,null,"virtual items",null));
|
||||
companyLocations.put(companyId,location);
|
||||
}
|
||||
var stockItem = new Item(0,company,0,location,code,name,description);
|
||||
var props = stockItem.properties(); // TODO: saving props currently does not work
|
||||
props.add(new Property(0,UNIT_PRICE,unitPrice/100d,company.currency()));
|
||||
props.add(new Property(0,UNIT,unit,null));
|
||||
props.add(new Property(0,TAX,tax,"%"));
|
||||
props.add(new Property(0,"legacy_id",id,null));
|
||||
stockDb.save(stockItem);
|
||||
}
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
throw databaseException("Failed to migrate items from itemDB to stockDB!");
|
||||
}
|
||||
LOG.log(System.Logger.Level.WARNING,"migrateTo({0}) not implemented", stockDb);
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,7 @@ import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.ModuleRegistry.noteService;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException;
|
||||
import static de.srsoftware.umbrella.stock.Constants.*;
|
||||
import static java.lang.System.Logger.Level.ERROR;
|
||||
import static java.lang.System.Logger.Level.WARNING;
|
||||
import static java.lang.System.Logger.Level.*;
|
||||
import static java.text.MessageFormat.format;
|
||||
|
||||
import de.srsoftware.tools.jdbc.Query;
|
||||
@@ -51,21 +50,21 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
Long propertyId = null;
|
||||
if (rs.next()) propertyId = rs.getLong(1);
|
||||
rs.close();
|
||||
if (propertyId == null || propertyId == 0) throw databaseException("Failed to create new property {0} to DB",name);
|
||||
if (propertyId == null || propertyId == 0) throw databaseException("Failed to create new property {0} in DB",name);
|
||||
insertInto(TABLE_ITEM_PROPERTIES,ITEM_ID,PROPERTY_ID,VALUE).values(itemId,propertyId,value).execute(db);
|
||||
return new Property(propertyId,name,value,unit);
|
||||
} catch (SQLException e) {
|
||||
throw databaseException("Failed to create new property {0} to DB",name);
|
||||
throw databaseException("Failed to create new property {0} in DB",name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location delete(DbLocation location) {
|
||||
private void createDescriptionColumn(){
|
||||
try {
|
||||
Query.delete().from(TABLE_LOCATIONS).where(ID,equal(location.id())).execute(db);
|
||||
return location;
|
||||
var sql = "ALTER TABLE {0} ADD COLUMN {1} TEXT";
|
||||
sql = format(sql,TABLE_ITEMS,DESCRIPTION);
|
||||
db.prepareStatement(sql).execute();
|
||||
} catch (SQLException e) {
|
||||
throw databaseException("Failed to delete \"{0}\"",location.name());
|
||||
throw databaseException("failed to create {0} column in {1} table!",DESCRIPTION,TABLE_ITEMS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,8 +164,20 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
dropTokenTable();
|
||||
case 2:
|
||||
transformTables();
|
||||
case 3:
|
||||
createDescriptionColumn();
|
||||
}
|
||||
return setCurrentVersion(4);
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
return setCurrentVersion(3);
|
||||
}
|
||||
|
||||
private void dropTokenTable() {
|
||||
@@ -400,7 +411,6 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
.execute(db).getGeneratedKeys();
|
||||
if (rs.next()) item.id(rs.getLong(1));
|
||||
rs.close();
|
||||
return item;
|
||||
} catch (SQLException e) {
|
||||
throw databaseException("Failed to save new item to database!");
|
||||
}
|
||||
@@ -419,15 +429,43 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
} else {
|
||||
pq.apply(item.code(),item.name(),item.location().id());
|
||||
}
|
||||
return item.clear();
|
||||
item.clear();
|
||||
} catch (SQLException e){
|
||||
throw databaseException("Failed to update item {0}",item.name());
|
||||
}
|
||||
}
|
||||
saveProperties(item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void saveProperties(Item item){
|
||||
var saved = new ArrayList<Property>();
|
||||
for (var property : item.properties()) {
|
||||
saved.add(saveProperty(item, property));
|
||||
}
|
||||
item.properties().clear();
|
||||
item.properties().addAll(saved);
|
||||
}
|
||||
|
||||
private Property saveProperty(Item item, Property property) {
|
||||
Long propId = property.id();
|
||||
if (is0(propId)) {
|
||||
LOG.log(DEBUG,"Saving new property {0}",property);
|
||||
try {
|
||||
var rs = select(ID).from(TABLE_PROPERTIES).where(NAME,equal(property.name())).where(UNIT,equal(property.unit())).exec(db);
|
||||
if (rs.next()) {
|
||||
propId = rs.getLong(1);
|
||||
}
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
throw databaseException("Failed to load property \"{}\"!",property.name());
|
||||
}
|
||||
}
|
||||
if (is0(propId)) return addNewProperty(item.id(), property.name(), property.value(), property.unit());
|
||||
return setProperty(item.id(),propId,property.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property setProperty(long itemId, long existingPropId, Object value) {
|
||||
try {
|
||||
@@ -435,7 +473,7 @@ public class SqliteDb extends BaseDb implements StockDb {
|
||||
var rs = select(ALL).from(TABLE_PROPERTIES).where(ID,equal(existingPropId)).exec(db);
|
||||
if (rs.next()) prop = Property.of(rs);
|
||||
rs.close();
|
||||
if (prop == null) throw databaseException("Failed to add new property to item {0}",itemId);
|
||||
if (prop == null) throw databaseException("Failed to load property {0} for item {1}",existingPropId,itemId);
|
||||
if ("".equals(value)){
|
||||
Query.delete().from(TABLE_ITEM_PROPERTIES).where(ITEM_ID,equal(itemId)).where(PROPERTY_ID,equal(existingPropId)).execute(db);
|
||||
} else {
|
||||
|
||||
@@ -12,12 +12,10 @@ import static de.srsoftware.umbrella.core.Paths.LIST;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
|
||||
import static de.srsoftware.umbrella.stock.Constants.*;
|
||||
import static java.lang.System.Logger.Level.WARNING;
|
||||
import static java.text.MessageFormat.format;
|
||||
import static java.util.Comparator.comparing;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.configuration.Configuration;
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import de.srsoftware.tools.Path;
|
||||
import de.srsoftware.tools.SessionToken;
|
||||
import de.srsoftware.umbrella.core.BaseHandler;
|
||||
@@ -40,6 +38,8 @@ public class StockModule extends BaseHandler implements StockService {
|
||||
super();
|
||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||
stockDb = new SqliteDb(connect(dbFile));
|
||||
Optional<String> itemDbConfig = config.get("umbrella.modules.items.database");
|
||||
itemDbConfig.map(ItemDb::new).ifPresent(itemDb -> itemDb.migrateTo(stockDb));
|
||||
ModuleRegistry.add(this);
|
||||
}
|
||||
|
||||
@@ -309,13 +309,14 @@ public class StockModule extends BaseHandler implements StockService {
|
||||
private boolean postItem(UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||
var json = json(ex);
|
||||
if (!json.has(NAME) || !(json.get(NAME) instanceof String name)) throw missingFieldException(NAME);
|
||||
var description = json.has(DESCRIPTION) && json.get(DESCRIPTION) instanceof String d ? d : null;
|
||||
if (!json.has(CODE) || !(json.get(CODE) instanceof String code)) throw missingFieldException(CODE);
|
||||
if (!json.has(LOCATION) || !(json.get(LOCATION) instanceof JSONObject locationData)) throw missingFieldException(LOCATION);
|
||||
var location = stockDb.loadLocation(locationData.getLong(ID));
|
||||
var owner = location.owner().resolve();
|
||||
if (!assigned(owner,user)) throw forbidden("You are not allowed to add items to {0}!",location);
|
||||
var number = stockDb.nextItemNumberFor(owner);
|
||||
var newItem = new Item(0,owner,number,location,code,name);
|
||||
var newItem = new Item(0,owner,number,location,code,name,description);
|
||||
return sendContent(ex,stockDb.save(newItem));
|
||||
}
|
||||
|
||||
@@ -380,32 +381,9 @@ public class StockModule extends BaseHandler implements StockService {
|
||||
return sendContent(ex,property);
|
||||
}
|
||||
|
||||
private Mappable toOwner(JSONObject owner) {
|
||||
var keys = owner.keySet();
|
||||
if (keys.size() != 1) throw unprocessable("{0} expected to have only one child!",OWNER);
|
||||
String key = new ArrayList<>(keys).getFirst();
|
||||
return switch (key) {
|
||||
case COMPANY -> companyService().get(owner.getLong(key));
|
||||
case USER -> userService().loadUser(owner.getLong(key));
|
||||
default -> throw invalidFieldException(format("Single child of {0}", OWNER), format("either {0} or {1}", COMPANY, USER));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private long toOwnerId(JSONObject owner) {
|
||||
var keys = owner.keySet();
|
||||
if (keys.size() != 1) throw unprocessable("{0} expected to have only one child!",OWNER);
|
||||
String key = new ArrayList<>(keys).getFirst();
|
||||
return switch (key) {
|
||||
case COMPANY -> -owner.getLong(key);
|
||||
case USER -> owner.getLong(key);
|
||||
default -> throw invalidFieldException(format("Single child of {0}", OWNER), format("either {0} or {1}", COMPANY, USER));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> redefineMe(long company_id) {
|
||||
// TODO
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user