refactoring object model
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -89,6 +89,8 @@ public class ModuleRegistry {
|
|||||||
return singleton.projectService;
|
return singleton.projectService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static StockService stockService() { return singleton.stockService; }
|
||||||
|
|
||||||
public static TagService tagService(){
|
public static TagService tagService(){
|
||||||
return singleton.tagService;
|
return singleton.tagService;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
/* © SRSoftware 2025 */
|
|
||||||
package de.srsoftware.umbrella.core.api;
|
|
||||||
|
|
||||||
import de.srsoftware.tools.Mappable;
|
|
||||||
import de.srsoftware.umbrella.core.model.Location;
|
|
||||||
|
|
||||||
public interface LocationRef extends Mappable {
|
|
||||||
Location resolve(StockService stockService);
|
|
||||||
long id();
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,16 @@
|
|||||||
/* © SRSoftware 2025 */
|
/* © SRSoftware 2025 */
|
||||||
package de.srsoftware.umbrella.core.api;
|
package de.srsoftware.umbrella.core.api;
|
||||||
|
|
||||||
public interface Owner {
|
import static de.srsoftware.umbrella.core.Constants.*;
|
||||||
long signum();
|
|
||||||
|
import de.srsoftware.tools.Mappable;
|
||||||
|
|
||||||
|
public interface Owner extends Mappable {
|
||||||
|
public static final String SEPARATOR = ":";
|
||||||
|
default String dbCode(){
|
||||||
|
return type()+SEPARATOR+id();
|
||||||
|
}
|
||||||
|
long id();
|
||||||
|
String type();
|
||||||
|
public Owner resolve();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
/* © SRSoftware 2025 */
|
|
||||||
package de.srsoftware.umbrella.core.api;
|
|
||||||
|
|
||||||
import de.srsoftware.tools.Mappable;
|
|
||||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
|
||||||
|
|
||||||
public interface OwnerRef extends Mappable {
|
|
||||||
long id();
|
|
||||||
Owner resolve(ModuleRegistry registry);
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
package de.srsoftware.umbrella.core.api;
|
package de.srsoftware.umbrella.core.api;
|
||||||
|
|
||||||
|
|
||||||
|
import de.srsoftware.umbrella.core.model.DbLocation;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public interface StockService {
|
public interface StockService {
|
||||||
@@ -12,4 +13,6 @@ public interface StockService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Collection<Object> redefineMe(long company_id);
|
Collection<Object> redefineMe(long company_id);
|
||||||
|
|
||||||
|
DbLocation loadLocation(long locationId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import static de.srsoftware.umbrella.core.Constants.*;
|
|||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
|
|
||||||
import de.srsoftware.tools.Mappable;
|
import de.srsoftware.tools.Mappable;
|
||||||
|
import de.srsoftware.umbrella.core.api.Owner;
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -13,7 +14,7 @@ import java.util.*;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class Company implements Mappable {
|
public class Company implements Mappable, Owner {
|
||||||
private final long id;
|
private final long id;
|
||||||
private String name, address, court, taxId, phone, decimalSeparator, thousandsSeparator, customerNumberPrefix, currency, email, bankAccount;;
|
private String name, address, court, taxId, phone, decimalSeparator, thousandsSeparator, customerNumberPrefix, currency, email, bankAccount;;
|
||||||
private long lastCustomerNumber;
|
private long lastCustomerNumber;
|
||||||
@@ -80,7 +81,8 @@ public class Company implements Mappable {
|
|||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long id(){
|
@Override
|
||||||
|
public long id() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +164,11 @@ public class Company implements Mappable {
|
|||||||
return phone;
|
return phone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Owner resolve() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public String taxId() {
|
public String taxId() {
|
||||||
return taxId;
|
return taxId;
|
||||||
}
|
}
|
||||||
@@ -182,7 +189,6 @@ public class Company implements Mappable {
|
|||||||
memberMap.put(entry.getKey(),entry.getValue().toMap());
|
memberMap.put(entry.getKey(),entry.getValue().toMap());
|
||||||
}
|
}
|
||||||
return Map.ofEntries(
|
return Map.ofEntries(
|
||||||
entry(ID,id),
|
|
||||||
entry(NAME,name),
|
entry(NAME,name),
|
||||||
entry(ADDRESS,emptyIfNull(address)),
|
entry(ADDRESS,emptyIfNull(address)),
|
||||||
entry(FIELD_COURT,emptyIfNull(court)),
|
entry(FIELD_COURT,emptyIfNull(court)),
|
||||||
@@ -196,8 +202,14 @@ public class Company implements Mappable {
|
|||||||
entry(FIELD_CURRENCY,emptyIfNull(currency)),
|
entry(FIELD_CURRENCY,emptyIfNull(currency)),
|
||||||
entry(EMAIL,emptyIfNull(email)),
|
entry(EMAIL,emptyIfNull(email)),
|
||||||
entry(FIELD_BANK_ACCOUNT,emptyIfNull(bankAccount)),
|
entry(FIELD_BANK_ACCOUNT,emptyIfNull(bankAccount)),
|
||||||
entry(MEMBERS,memberMap)
|
entry(MEMBERS,memberMap),
|
||||||
);
|
entry(TYPE,type()),
|
||||||
|
entry(ID,id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return COMPANY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/* © SRSoftware 2025 */
|
||||||
|
package de.srsoftware.umbrella.core.model;
|
||||||
|
|
||||||
|
import static de.srsoftware.umbrella.core.Constants.*;
|
||||||
|
|
||||||
|
import de.srsoftware.umbrella.core.api.Owner;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DbLocation extends Location {
|
||||||
|
private Owner owner;
|
||||||
|
private Long parentLocationId;
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
private String relation; // when added to an item, this field describes the type of the relation
|
||||||
|
|
||||||
|
private DbLocation(long id, Owner owner, Long parentLocationId, String name, String description){
|
||||||
|
super(id);
|
||||||
|
this.owner = owner;
|
||||||
|
this.parentLocationId = parentLocationId;
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String description() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DbLocation of(ResultSet rs) throws SQLException {
|
||||||
|
|
||||||
|
return new DbLocation(rs.getLong(ID), OwnerRef.of(rs), rs.getLong(PARENT_LOCATION_ID), rs.getString(NAME),rs.getString(DESCRIPTION));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long parent(){
|
||||||
|
return parentLocationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DbLocation resolve() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> toMap() {
|
||||||
|
return Map.of(
|
||||||
|
OWNER,owner.toMap(),
|
||||||
|
ID,id(),
|
||||||
|
NAME,name,
|
||||||
|
DESCRIPTION,description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,7 @@ package de.srsoftware.umbrella.core.model;
|
|||||||
import static de.srsoftware.umbrella.core.Constants.*;
|
import static de.srsoftware.umbrella.core.Constants.*;
|
||||||
|
|
||||||
import de.srsoftware.tools.Mappable;
|
import de.srsoftware.tools.Mappable;
|
||||||
import de.srsoftware.umbrella.core.api.LocationRef;
|
import de.srsoftware.umbrella.core.api.Owner;
|
||||||
import de.srsoftware.umbrella.core.api.OwnerRef;
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -13,17 +12,17 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
public class Item implements Mappable {
|
public class Item implements Mappable {
|
||||||
private long id, number; // id is the database key, number the owner-relative id
|
private long id, number; // id is the database key, number the owner-relative id
|
||||||
private OwnerRef ownerRef;
|
private Owner owner;
|
||||||
private String code, name;
|
private String code, name;
|
||||||
private LocationRef locationRef;
|
private Location location;
|
||||||
private Collection<Property> properties;
|
private Collection<Property> properties;
|
||||||
private Set<String> dirtyFields = new HashSet<>();
|
private Set<String> dirtyFields = new HashSet<>();
|
||||||
|
|
||||||
private Item(long id, OwnerRef ownerRef, long number, LocationRef locationRef, String code, String name) {
|
private Item(long id, Owner owner, long number, Location location, String code, String name) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.ownerRef = ownerRef;
|
this.owner = owner;
|
||||||
this.number = number;
|
this.number = number;
|
||||||
this.locationRef = locationRef;
|
this.location = location;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.properties = new HashSet<>();
|
this.properties = new HashSet<>();
|
||||||
@@ -41,23 +40,26 @@ public class Item implements Mappable {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocationRef location(){
|
public Location location(){
|
||||||
return locationRef;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String name(){
|
public String name(){
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Item of(ResultSet rs, OwnerRef ownerRef, long number, LocationRef locationRef) throws SQLException {
|
public static Item of(ResultSet rs) throws SQLException {
|
||||||
var id = rs.getLong(ID);
|
var id = rs.getLong(ID);
|
||||||
var code = rs.getString(CODE);
|
var code = rs.getString(CODE);
|
||||||
var name = rs.getString(NAME);
|
var name = rs.getString(NAME);
|
||||||
return new Item(id, ownerRef, number, locationRef, code, name);
|
var owner = OwnerRef.of(rs);
|
||||||
|
var number = rs.getLong(NUMBER);
|
||||||
|
var location = Location.of(rs);
|
||||||
|
return new Item(id, owner, number, location, code, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OwnerRef ownerRef(){
|
public Owner owner(){
|
||||||
return ownerRef;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Property> properties() {
|
public Collection<Property> properties() {
|
||||||
@@ -67,9 +69,9 @@ public class Item implements Mappable {
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Object> toMap() {
|
public Map<String, Object> toMap() {
|
||||||
var map = new HashMap<String,Object>();
|
var map = new HashMap<String,Object>();
|
||||||
map.put(OWNER,ownerRef.toMap());
|
map.put(OWNER,owner.toMap());
|
||||||
map.put(ID,id);
|
map.put(ID,id);
|
||||||
map.put(LOCATION,locationRef.toMap());
|
map.put(LOCATION,location.toMap());
|
||||||
map.put(CODE,code);
|
map.put(CODE,code);
|
||||||
map.put(NAME,name);
|
map.put(NAME,name);
|
||||||
if (properties != null) map.put(PROPERTIES,properties.stream().map(Property::toMap).toList());
|
if (properties != null) map.put(PROPERTIES,properties.stream().map(Property::toMap).toList());
|
||||||
|
|||||||
@@ -1,72 +1,48 @@
|
|||||||
/* © SRSoftware 2025 */
|
/* © SRSoftware 2025 */
|
||||||
package de.srsoftware.umbrella.core.model;
|
package de.srsoftware.umbrella.core.model;
|
||||||
|
|
||||||
import static de.srsoftware.umbrella.core.Constants.*;
|
import static de.srsoftware.umbrella.core.Constants.ID;
|
||||||
|
import static de.srsoftware.umbrella.core.Constants.LOCATION_ID;
|
||||||
|
import static de.srsoftware.umbrella.core.ModuleRegistry.stockService;
|
||||||
|
import static java.text.MessageFormat.format;
|
||||||
|
|
||||||
import de.srsoftware.tools.Mappable;
|
import de.srsoftware.tools.Mappable;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class Location implements Mappable {
|
public class Location implements Mappable {
|
||||||
private long owner;
|
|
||||||
private boolean ownerIsCompany = false;
|
|
||||||
private long id;
|
|
||||||
private Long parentLocationId;
|
|
||||||
private String name;
|
|
||||||
private String description;
|
|
||||||
private String relation; // when added to an item, this field describes the type of the relation
|
|
||||||
|
|
||||||
private Location(long owner, boolean ownerIsCompany, long id, Long parentLocationId, String name, String description){
|
private final long id;
|
||||||
this.owner = owner;
|
|
||||||
this.ownerIsCompany = ownerIsCompany;
|
public Location(long id){
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.parentLocationId = parentLocationId;
|
|
||||||
this.name = name;
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final long id(){
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String description() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String name() {
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Location of(ResultSet rs) throws SQLException {
|
public static Location of(ResultSet rs) throws SQLException {
|
||||||
var owner = rs.getLong(OWNER);
|
return new Location(rs.getLong(LOCATION_ID));
|
||||||
var id = rs.getLong(ID);
|
|
||||||
var isCompany = owner < 0;
|
|
||||||
if (isCompany) owner = -owner;
|
|
||||||
return new Location(owner,isCompany,id, rs.getLong(PARENT_LOCATION_ID), rs.getString(NAME),rs.getString(DESCRIPTION));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Location of(long locationId) {
|
||||||
|
return new Location(locationId);
|
||||||
public long ownerCoded(){
|
|
||||||
return ownerIsCompany ? -owner : owner;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long parent(){
|
public DbLocation resolve(){
|
||||||
return parentLocationId;
|
return stockService().loadLocation(id());
|
||||||
|
}
|
||||||
|
|
||||||
|
public long id(){
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> toMap() {
|
public Map<String, Object> toMap() {
|
||||||
return Map.of(
|
return Map.of(ID,id);
|
||||||
ownerIsCompany ? COMPANY : USER,owner,
|
|
||||||
ID,id,
|
|
||||||
NAME,name,
|
|
||||||
DESCRIPTION,description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return name;
|
return format("Location({0})",id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/* © SRSoftware 2025 */
|
||||||
|
package de.srsoftware.umbrella.core.model;
|
||||||
|
|
||||||
|
import static de.srsoftware.umbrella.core.Constants.*;
|
||||||
|
import static de.srsoftware.umbrella.core.Constants.ID;
|
||||||
|
import static de.srsoftware.umbrella.core.ModuleRegistry.companyService;
|
||||||
|
import static de.srsoftware.umbrella.core.ModuleRegistry.userService;
|
||||||
|
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.unprocessable;
|
||||||
|
|
||||||
|
import de.srsoftware.umbrella.core.api.Owner;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class OwnerRef implements Owner {
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
private final long id;
|
||||||
|
|
||||||
|
public OwnerRef(String dbCode){
|
||||||
|
var parts = dbCode.split(":");
|
||||||
|
if (parts.length != 2) throw unprocessable("Encountered invalid dbCode: {0}",dbCode);
|
||||||
|
type = parts[0];
|
||||||
|
try {
|
||||||
|
id = Long.parseLong(parts[1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw unprocessable("Encountered invalid dbCode: {0}",dbCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public OwnerRef(String type, long id){
|
||||||
|
this.type = type;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Owner of(ResultSet rs) throws SQLException {
|
||||||
|
return new OwnerRef(rs.getString(OWNER));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String dbCode(){
|
||||||
|
return type+SEPARATOR+id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long id(){
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String type(){
|
||||||
|
// TODO: is this needed?
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the actual owner object
|
||||||
|
* @return the actual owner object
|
||||||
|
*/
|
||||||
|
public Owner resolve(){
|
||||||
|
return switch (type){
|
||||||
|
case COMPANY -> companyService().get(id());
|
||||||
|
case USER -> userService().loadUser(id());
|
||||||
|
case null, default -> throw unprocessable("Encountered invalid owner type: {0}",type);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> toMap() {
|
||||||
|
var map = new HashMap<String,Object>();
|
||||||
|
map.put(TYPE,type);
|
||||||
|
map.put(ID, id);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,12 +5,13 @@ package de.srsoftware.umbrella.core.model;
|
|||||||
import static de.srsoftware.umbrella.core.Constants.*;
|
import static de.srsoftware.umbrella.core.Constants.*;
|
||||||
|
|
||||||
import de.srsoftware.tools.Mappable;
|
import de.srsoftware.tools.Mappable;
|
||||||
|
import de.srsoftware.umbrella.core.api.Owner;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/* © SRSoftware 2025 */
|
/* © SRSoftware 2025 */
|
||||||
public class UmbrellaUser extends User implements Mappable {
|
public class UmbrellaUser extends User implements Mappable, Owner {
|
||||||
|
|
||||||
private final long id;
|
private final long id;
|
||||||
private final String theme;
|
private final String theme;
|
||||||
@@ -21,7 +22,6 @@ public class UmbrellaUser extends User implements Mappable {
|
|||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (!(o instanceof UmbrellaUser user)) return false;
|
if (!(o instanceof UmbrellaUser user)) return false;
|
||||||
@@ -40,6 +40,11 @@ public class UmbrellaUser extends User implements Mappable {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Owner resolve() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public String theme(){
|
public String theme(){
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
@@ -55,4 +60,9 @@ public class UmbrellaUser extends User implements Mappable {
|
|||||||
map.put(LANGUAGE,language());
|
map.put(LANGUAGE,language());
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return USER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import static de.srsoftware.tools.jdbc.Condition.isNull;
|
|||||||
import static de.srsoftware.tools.jdbc.Query.*;
|
import static de.srsoftware.tools.jdbc.Query.*;
|
||||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||||
import static de.srsoftware.umbrella.core.Constants.*;
|
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.core.exceptions.UmbrellaException.databaseException;
|
||||||
import static de.srsoftware.umbrella.stock.Constants.*;
|
import static de.srsoftware.umbrella.stock.Constants.*;
|
||||||
import static java.lang.System.Logger.Level.ERROR;
|
import static java.lang.System.Logger.Level.ERROR;
|
||||||
@@ -17,6 +15,7 @@ import static java.text.MessageFormat.format;
|
|||||||
|
|
||||||
import de.srsoftware.tools.Mappable;
|
import de.srsoftware.tools.Mappable;
|
||||||
import de.srsoftware.umbrella.core.BaseDb;
|
import de.srsoftware.umbrella.core.BaseDb;
|
||||||
|
import de.srsoftware.umbrella.core.model.Location;
|
||||||
import de.srsoftware.umbrella.core.model.*;
|
import de.srsoftware.umbrella.core.model.*;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
@@ -195,11 +194,11 @@ public class SqliteDb extends BaseDb implements StockDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Location> listChildLocations(long parentId) {
|
public Collection<DbLocation> listChildLocations(long parentId) {
|
||||||
try {
|
try {
|
||||||
var rs = select(ALL).from(TABLE_LOCATIONS).where(PARENT_LOCATION_ID,equal(parentId)).exec(db);
|
var rs = select(ALL).from(TABLE_LOCATIONS).where(PARENT_LOCATION_ID,equal(parentId)).exec(db);
|
||||||
var list = new ArrayList<Location>();
|
var list = new ArrayList<DbLocation>();
|
||||||
while (rs.next()) list.add(Location.of(rs));
|
while (rs.next()) list.add(DbLocation.of(rs));
|
||||||
rs.close();
|
rs.close();
|
||||||
return list;
|
return list;
|
||||||
} catch (SQLException e){
|
} catch (SQLException e){
|
||||||
@@ -208,11 +207,11 @@ public class SqliteDb extends BaseDb implements StockDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Location> listCompanyLocations(Company company) {
|
public Collection<DbLocation> listCompanyLocations(Company company) {
|
||||||
try {
|
try {
|
||||||
var rs = select(ALL).from(TABLE_LOCATIONS).where(OWNER,equal(-company.id())).where(PARENT_LOCATION_ID,isNull()).exec(db);
|
var rs = select(ALL).from(TABLE_LOCATIONS).where(OWNER,equal(-company.id())).where(PARENT_LOCATION_ID,isNull()).exec(db);
|
||||||
var list = new ArrayList<Location>();
|
var list = new ArrayList<DbLocation>();
|
||||||
while (rs.next()) list.add(Location.of(rs));
|
while (rs.next()) list.add(DbLocation.of(rs));
|
||||||
rs.close();
|
rs.close();
|
||||||
return list;
|
return list;
|
||||||
} catch (SQLException e){
|
} catch (SQLException e){
|
||||||
@@ -221,41 +220,32 @@ public class SqliteDb extends BaseDb implements StockDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Item> listItemsAt(long locationId) {
|
public Collection<Item> listItemsAt(Location location) {
|
||||||
try {
|
try {
|
||||||
var location = loadLocation(locationId);
|
var rs = select(ALL).from(TABLE_ITEMS).where(LOCATION_ID,equal(location.id())).exec(db);
|
||||||
var rs = select(ALL).from(TABLE_ITEMS).where(LOCATION_ID,equal(locationId)).exec(db);
|
|
||||||
var list = new ArrayList<Item>();
|
var list = new ArrayList<Item>();
|
||||||
var ownerMap = new HashMap<Long,Mappable>();
|
var ownerMap = new HashMap<Long,Mappable>();
|
||||||
while (rs.next()) {
|
while (rs.next()) list.add(Item.of(rs));
|
||||||
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();
|
rs.close();
|
||||||
|
|
||||||
for (var item : list){
|
for (var item : list){
|
||||||
var ownerId = item.ownerId();
|
var ownerId = item.owner();
|
||||||
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);
|
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));
|
while (rs.next()) item.properties().add(Property.of(rs));
|
||||||
rs.close();
|
rs.close();
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
} catch (SQLException e){
|
} catch (SQLException e){
|
||||||
throw databaseException("Failed to load items at {0}",locationId);
|
throw databaseException("Failed to load items at {0}",location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Item loadItem(Mappable owner, long itemId) {
|
public Item loadItem(long id) {
|
||||||
try {
|
try {
|
||||||
var rs = select(ALL).from(TABLE_ITEMS).where(OWNER,equal(Item.ownerId(owner))).where(ID,equal(itemId)).exec(db);
|
var rs = select(ALL).from(TABLE_ITEMS).where(ID,equal(id)).exec(db);
|
||||||
Item result = null;
|
Item result = null;
|
||||||
if (rs.next()) result = Item.of(rs,owner,null);
|
if (rs.next()) result = Item.of(rs);
|
||||||
rs.close();
|
rs.close();
|
||||||
if (result != null) return result;
|
if (result != null) return result;
|
||||||
} catch (SQLException ignored) {
|
} catch (SQLException ignored) {
|
||||||
@@ -263,11 +253,11 @@ public class SqliteDb extends BaseDb implements StockDb {
|
|||||||
throw databaseException("Failed to load item");
|
throw databaseException("Failed to load item");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Location loadLocation(long locationId) {
|
public DbLocation loadLocation(long locationId) {
|
||||||
try {
|
try {
|
||||||
var rs = select(ALL).from(TABLE_LOCATIONS).where(ID,equal(locationId)).exec(db);
|
var rs = select(ALL).from(TABLE_LOCATIONS).where(ID,equal(locationId)).exec(db);
|
||||||
Location loc = null;
|
DbLocation loc = null;
|
||||||
if (rs.next()) loc = Location.of(rs);
|
if (rs.next()) loc = DbLocation.of(rs);
|
||||||
rs.close();
|
rs.close();
|
||||||
if (loc != null) return loc;
|
if (loc != null) return loc;
|
||||||
throw databaseException("Failed to load location with id = {0}",locationId);
|
throw databaseException("Failed to load location with id = {0}",locationId);
|
||||||
@@ -290,11 +280,11 @@ public class SqliteDb extends BaseDb implements StockDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Location> listUserLocations(UmbrellaUser user) {
|
public Collection<DbLocation> listUserLocations(UmbrellaUser user) {
|
||||||
try {
|
try {
|
||||||
var rs = select(ALL).from(TABLE_LOCATIONS).where(OWNER,equal(user.id())).where(PARENT_LOCATION_ID,isNull()).exec(db);
|
var rs = select(ALL).from(TABLE_LOCATIONS).where(OWNER,equal(user.id())).where(PARENT_LOCATION_ID,isNull()).exec(db);
|
||||||
var list = new ArrayList<Location>();
|
var list = new ArrayList<DbLocation>();
|
||||||
while (rs.next()) list.add(Location.of(rs));
|
while (rs.next()) list.add(DbLocation.of(rs));
|
||||||
rs.close();
|
rs.close();
|
||||||
return list;
|
return list;
|
||||||
} catch (SQLException e){
|
} catch (SQLException e){
|
||||||
@@ -324,7 +314,7 @@ public class SqliteDb extends BaseDb implements StockDb {
|
|||||||
} else if (item.isDirty()) {
|
} else if (item.isDirty()) {
|
||||||
try {
|
try {
|
||||||
var location = item.location();
|
var location = item.location();
|
||||||
var query = update(TABLE_ITEMS).where(OWNER, equal(item.ownerId())).where(ID, equal(item.id()));
|
var query = update(TABLE_ITEMS).where(ID, equal(item.id()));
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
query.set(CODE,NAME);
|
query.set(CODE,NAME);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
/* © SRSoftware 2025 */
|
/* © SRSoftware 2025 */
|
||||||
package de.srsoftware.umbrella.stock;
|
package de.srsoftware.umbrella.stock;
|
||||||
|
|
||||||
import de.srsoftware.tools.Mappable;
|
import de.srsoftware.umbrella.core.model.Location;
|
||||||
import de.srsoftware.umbrella.core.model.*;
|
import de.srsoftware.umbrella.core.model.*;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public interface StockDb {
|
public interface StockDb {
|
||||||
Property addNewProperty(long ownerId, long itemId, String name, Object value, String unit);
|
Property addNewProperty(long ownerId, long itemId, String name, Object value, String unit);
|
||||||
Collection<Location> listChildLocations(long parentId);
|
Collection<DbLocation> listChildLocations(long parentId);
|
||||||
Collection<Location> listCompanyLocations(Company company);
|
Collection<DbLocation> listCompanyLocations(Company company);
|
||||||
Collection<Item> listItemsAt(long locationId);
|
Collection<Item> listItemsAt(Location location);
|
||||||
Collection<Property> listProperties();
|
Collection<Property> listProperties();
|
||||||
Collection<Location> listUserLocations(UmbrellaUser userId);
|
Collection<DbLocation> listUserLocations(UmbrellaUser userId);
|
||||||
Item loadItem(Mappable owner, long itemId);
|
Item loadItem(long id);
|
||||||
|
DbLocation loadLocation(long locationId);
|
||||||
Item save(Item item);
|
Item save(Item item);
|
||||||
Property setProperty(long ownerId, long itemId, long existingPropId, Object value);
|
Property setProperty(long ownerId, long itemId, long existingPropId, Object value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import de.srsoftware.tools.Path;
|
|||||||
import de.srsoftware.tools.SessionToken;
|
import de.srsoftware.tools.SessionToken;
|
||||||
import de.srsoftware.umbrella.core.BaseHandler;
|
import de.srsoftware.umbrella.core.BaseHandler;
|
||||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||||
|
import de.srsoftware.umbrella.core.model.Location;
|
||||||
import de.srsoftware.umbrella.core.api.StockService;
|
import de.srsoftware.umbrella.core.api.StockService;
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||||
import de.srsoftware.umbrella.core.model.*;
|
import de.srsoftware.umbrella.core.model.*;
|
||||||
@@ -49,7 +50,7 @@ public class StockModule extends BaseHandler implements StockService {
|
|||||||
case LOCATION -> {
|
case LOCATION -> {
|
||||||
try {
|
try {
|
||||||
var id = Long.parseLong(path.pop());
|
var id = Long.parseLong(path.pop());
|
||||||
yield getLocation(user.get(),id,ex);
|
yield getLocation(user.get(), Location.of(id),ex);
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
yield super.doGet(path,ex);
|
yield super.doGet(path,ex);
|
||||||
}
|
}
|
||||||
@@ -95,12 +96,12 @@ public class StockModule extends BaseHandler implements StockService {
|
|||||||
|
|
||||||
private boolean getChildLocations(UmbrellaUser user, long parentId, HttpExchange ex) throws IOException {
|
private boolean getChildLocations(UmbrellaUser user, long parentId, HttpExchange ex) throws IOException {
|
||||||
LOG.log(WARNING,"No security check implemented for {0}.getChildLocations(user, parentId, ex)!",getClass().getSimpleName()); // TODO check, that user is allowed to request that location
|
LOG.log(WARNING,"No security check implemented for {0}.getChildLocations(user, parentId, ex)!",getClass().getSimpleName()); // TODO check, that user is allowed to request that location
|
||||||
return sendContent(ex, stockDb.listChildLocations(parentId).stream().sorted(comparing(l -> l.name().toLowerCase())).map(Location::toMap));
|
return sendContent(ex, stockDb.listChildLocations(parentId).stream().sorted(comparing(l -> l.name().toLowerCase())).map(DbLocation::toMap));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean getLocation(UmbrellaUser user, long locationId, HttpExchange ex) throws IOException {
|
private boolean getLocation(UmbrellaUser user, Location location, HttpExchange ex) throws IOException {
|
||||||
return sendContent(ex, stockDb.listItemsAt(locationId).stream().map(Item::toMap).toList());
|
return sendContent(ex, stockDb.listItemsAt(location).stream().map(Item::toMap).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean getLocations(Path path, UmbrellaUser user, HttpExchange ex) throws IOException {
|
private boolean getLocations(Path path, UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||||
@@ -130,7 +131,7 @@ public class StockModule extends BaseHandler implements StockService {
|
|||||||
result.add(Map.of(
|
result.add(Map.of(
|
||||||
ID, user.id(),
|
ID, user.id(),
|
||||||
NAME,user.name(),
|
NAME,user.name(),
|
||||||
LOCATIONS,userLocations.stream().map(Location::toMap).toList()));
|
LOCATIONS,userLocations.stream().map(DbLocation::toMap).toList()));
|
||||||
|
|
||||||
var companies = companyService().listCompaniesOf(user);
|
var companies = companyService().listCompaniesOf(user);
|
||||||
companies.values().stream().sorted(comparing(a -> a.name().toLowerCase())).forEach(company -> {
|
companies.values().stream().sorted(comparing(a -> a.name().toLowerCase())).forEach(company -> {
|
||||||
@@ -138,37 +139,27 @@ public class StockModule extends BaseHandler implements StockService {
|
|||||||
result.add(Map.of(
|
result.add(Map.of(
|
||||||
ID, company.id(),
|
ID, company.id(),
|
||||||
NAME,company.name(),
|
NAME,company.name(),
|
||||||
LOCATIONS,locations.stream().sorted(comparing(a -> a.name().toLowerCase())).map(Location::toMap).toList()));
|
LOCATIONS,locations.stream().sorted(comparing(a -> a.name().toLowerCase())).map(DbLocation::toMap).toList()));
|
||||||
|
|
||||||
});
|
});
|
||||||
return sendContent(ex, result);
|
return sendContent(ex, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DbLocation loadLocation(long locationId) {
|
||||||
|
return stockDb.loadLocation(locationId);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean patchItem(UmbrellaUser user, HttpExchange ex) throws IOException {
|
private boolean patchItem(UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||||
var json = json(ex);
|
var json = json(ex);
|
||||||
if (!(json.get(ID) instanceof Number id)) throw missingFieldException(ID);
|
if (!(json.get(ID) instanceof Number id)) throw missingFieldException(ID);
|
||||||
if (!(json.get(OWNER) instanceof JSONObject ownerRef)) throw missingFieldException(OWNER);
|
|
||||||
json.remove(ID);
|
json.remove(ID);
|
||||||
json.remove(OWNER);
|
|
||||||
var owner = toOwner(ownerRef);
|
|
||||||
|
|
||||||
var item = stockDb.loadItem(owner,id.longValue());
|
var item = stockDb.loadItem(id.longValue());
|
||||||
item.patch(json);
|
item.patch(json);
|
||||||
return sendContent(ex,stockDb.save(item));
|
return sendContent(ex,stockDb.save(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
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 boolean postProperty(UmbrellaUser user, HttpExchange ex) throws IOException {
|
private boolean postProperty(UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||||
var json = json(ex);
|
var json = json(ex);
|
||||||
if (!(json.get(FIELD_ITEM) instanceof JSONObject itemData)) throw missingFieldException(FIELD_ITEM);
|
if (!(json.get(FIELD_ITEM) instanceof JSONObject itemData)) throw missingFieldException(FIELD_ITEM);
|
||||||
@@ -192,6 +183,18 @@ public class StockModule extends BaseHandler implements StockService {
|
|||||||
return sendContent(ex,property);
|
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) {
|
private long toOwnerId(JSONObject owner) {
|
||||||
var keys = owner.keySet();
|
var keys = owner.keySet();
|
||||||
if (keys.size() != 1) throw unprocessable("{0} expected to have only one child!",OWNER);
|
if (keys.size() != 1) throw unprocessable("{0} expected to have only one child!",OWNER);
|
||||||
|
|||||||
Reference in New Issue
Block a user