21 changed files with 209 additions and 189 deletions
@ -1,10 +0,0 @@ |
|||||||
/* © SRSoftware 2025 */ |
|
||||||
package de.srsoftware.umbrella.core.api; |
|
||||||
|
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; |
|
||||||
import de.srsoftware.umbrella.core.model.Item; |
|
||||||
import java.util.Collection; |
|
||||||
|
|
||||||
public interface ItemService { |
|
||||||
Collection<Item> list(long companyId) throws UmbrellaException; |
|
||||||
} |
|
||||||
@ -0,0 +1,15 @@ |
|||||||
|
/* © SRSoftware 2025 */ |
||||||
|
package de.srsoftware.umbrella.core.api; |
||||||
|
|
||||||
|
|
||||||
|
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. |
||||||
|
* @param company_id |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
Collection<Object> redefineMe(long company_id); |
||||||
|
} |
||||||
@ -1,38 +1,12 @@ |
|||||||
/* © SRSoftware 2025 */ |
/* © SRSoftware 2025 */ |
||||||
package de.srsoftware.umbrella.core.model; |
package de.srsoftware.umbrella.core.model; |
||||||
|
|
||||||
import static de.srsoftware.umbrella.core.Constants.*; |
import java.util.Collection; |
||||||
import static de.srsoftware.umbrella.core.Constants.CODE; |
|
||||||
import static de.srsoftware.umbrella.core.Util.mapMarkdown; |
public class Item { |
||||||
|
private long id; |
||||||
import de.srsoftware.tools.Mappable; |
private String code; |
||||||
import java.sql.ResultSet; |
private boolean physical; |
||||||
import java.sql.SQLException; |
private Location location; |
||||||
import java.util.Map; |
private Collection<Property> properties; |
||||||
|
|
||||||
public record Item(long id, long companyId, String code, String name, String description, String unit, long unitPrice, long tax) implements Mappable { |
|
||||||
public static Item of(ResultSet rs) throws SQLException { |
|
||||||
var id = rs.getLong(ID); |
|
||||||
var companyId = rs.getLong(COMPANY_ID); |
|
||||||
var code = rs.getString(CODE); |
|
||||||
var name = rs.getString(NAME); |
|
||||||
var desc = rs.getString(DESCRIPTION); |
|
||||||
var unit = rs.getString(UNIT); |
|
||||||
var unitPrice = rs.getLong(UNIT_PRICE); |
|
||||||
var tax = rs.getInt(TAX); |
|
||||||
|
|
||||||
return new Item(id,companyId,code,name,desc,unit,unitPrice,tax); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Map<String, Object> toMap() { |
|
||||||
return Map.of( |
|
||||||
ID,id, |
|
||||||
COMPANY_ID,companyId, |
|
||||||
CODE,code,NAME,name, |
|
||||||
DESCRIPTION,mapMarkdown(description), |
|
||||||
UNIT,unit, |
|
||||||
UNIT_PRICE,unitPrice, |
|
||||||
TAX,tax); |
|
||||||
} |
|
||||||
} |
} |
||||||
|
|||||||
@ -0,0 +1,10 @@ |
|||||||
|
/* © SRSoftware 2025 */ |
||||||
|
package de.srsoftware.umbrella.core.model; |
||||||
|
|
||||||
|
public class Location { |
||||||
|
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
|
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
/* © SRSoftware 2025 */ |
||||||
|
package de.srsoftware.umbrella.core.model; |
||||||
|
|
||||||
|
public class Property { |
||||||
|
long id; |
||||||
|
String name; |
||||||
|
Object value; |
||||||
|
String unit; |
||||||
|
String quantity; |
||||||
|
} |
||||||
@ -1,8 +0,0 @@ |
|||||||
/* © SRSoftware 2025 */ |
|
||||||
package de.srsoftware.umbrella.items; |
|
||||||
|
|
||||||
public class Constants { |
|
||||||
private Constants(){} |
|
||||||
public static final String CONFIG_DATABASE = "umbrella.modules.items.database"; |
|
||||||
public static final String TABLE_ITEMS = "items"; |
|
||||||
} |
|
||||||
@ -1,75 +0,0 @@ |
|||||||
/* © SRSoftware 2025 */ |
|
||||||
package de.srsoftware.umbrella.items; |
|
||||||
|
|
||||||
import static de.srsoftware.umbrella.core.ConnectionProvider.connect; |
|
||||||
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.Paths.LIST; |
|
||||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden; |
|
||||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; |
|
||||||
import static de.srsoftware.umbrella.items.Constants.CONFIG_DATABASE; |
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange; |
|
||||||
import de.srsoftware.configuration.Configuration; |
|
||||||
import de.srsoftware.tools.Path; |
|
||||||
import de.srsoftware.tools.SessionToken; |
|
||||||
import de.srsoftware.umbrella.core.BaseHandler; |
|
||||||
import de.srsoftware.umbrella.core.ModuleRegistry; |
|
||||||
import de.srsoftware.umbrella.core.api.ItemService; |
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; |
|
||||||
import de.srsoftware.umbrella.core.model.Item; |
|
||||||
import de.srsoftware.umbrella.core.model.Token; |
|
||||||
import de.srsoftware.umbrella.core.model.UmbrellaUser; |
|
||||||
import java.io.IOException; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Optional; |
|
||||||
|
|
||||||
public class ItemApi extends BaseHandler implements ItemService { |
|
||||||
|
|
||||||
private final ItemDb itemDb; |
|
||||||
|
|
||||||
public ItemApi(Configuration config) throws UmbrellaException { |
|
||||||
super(); |
|
||||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); |
|
||||||
itemDb = new SqliteDb(connect(dbFile)); |
|
||||||
ModuleRegistry.add(this); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean doPost(Path path, HttpExchange ex) throws IOException { |
|
||||||
addCors(ex); |
|
||||||
try { |
|
||||||
Optional<Token> 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 LIST -> listItems(ex,user.get()); |
|
||||||
default -> super.doGet(path,ex); |
|
||||||
}; |
|
||||||
} catch (UmbrellaException e){ |
|
||||||
return send(ex,e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Collection<Item> list(long companyId) throws UmbrellaException { |
|
||||||
return itemDb.list(companyId); |
|
||||||
} |
|
||||||
|
|
||||||
private boolean listItems(HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException { |
|
||||||
var json = json(ex); |
|
||||||
if (!(json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number cid)) throw missingFieldException(COMPANY_ID); |
|
||||||
var companyId = cid.longValue(); |
|
||||||
var company = companyService().get(companyId); |
|
||||||
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); |
|
||||||
var items = list(companyId) |
|
||||||
.stream() |
|
||||||
.map(Item::toMap) |
|
||||||
.map(HashMap::new) |
|
||||||
.peek(map -> map.put(FIELD_CURRENCY,company.currency())); |
|
||||||
return sendContent(ex,items); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,10 +0,0 @@ |
|||||||
/* © SRSoftware 2025 */ |
|
||||||
package de.srsoftware.umbrella.items; |
|
||||||
|
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; |
|
||||||
import de.srsoftware.umbrella.core.model.Item; |
|
||||||
import java.util.Collection; |
|
||||||
|
|
||||||
public interface ItemDb { |
|
||||||
Collection<Item> list(long companyId) throws UmbrellaException; |
|
||||||
} |
|
||||||
@ -1,37 +0,0 @@ |
|||||||
/* © SRSoftware 2025 */ |
|
||||||
package de.srsoftware.umbrella.items; |
|
||||||
|
|
||||||
import static de.srsoftware.tools.jdbc.Condition.equal; |
|
||||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; |
|
||||||
import static de.srsoftware.tools.jdbc.Query.select; |
|
||||||
import static de.srsoftware.umbrella.core.Constants.COMPANY_ID; |
|
||||||
import static de.srsoftware.umbrella.items.Constants.TABLE_ITEMS; |
|
||||||
|
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; |
|
||||||
import de.srsoftware.umbrella.core.model.Item; |
|
||||||
import java.sql.Connection; |
|
||||||
import java.sql.SQLException; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.HashSet; |
|
||||||
|
|
||||||
public class SqliteDb implements ItemDb{ |
|
||||||
|
|
||||||
private final Connection db; |
|
||||||
|
|
||||||
public SqliteDb(Connection connection) { |
|
||||||
db = connection; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Collection<Item> list(long companyId) throws UmbrellaException { |
|
||||||
try { |
|
||||||
var items = new HashSet<Item>(); |
|
||||||
var rs = select(ALL).from(TABLE_ITEMS).where(COMPANY_ID, equal(companyId)).exec(db); |
|
||||||
while (rs.next()) items.add(Item.of(rs)); |
|
||||||
rs.close(); |
|
||||||
return items; |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new UmbrellaException("Failed to load items from database"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,4 +1,4 @@ |
|||||||
description = "Umbrella : Items" |
description = "Umbrella : Stock" |
||||||
|
|
||||||
dependencies{ |
dependencies{ |
||||||
implementation(project(":core")) |
implementation(project(":core")) |
||||||
@ -0,0 +1,15 @@ |
|||||||
|
/* © SRSoftware 2025 */ |
||||||
|
package de.srsoftware.umbrella.stock; |
||||||
|
|
||||||
|
public class Constants { |
||||||
|
private Constants(){} |
||||||
|
|
||||||
|
|
||||||
|
public static final String CONFIG_DATABASE = "umbrella.modules.stock.database"; |
||||||
|
public static final String ITEM_ID = "item_id"; public static final String LOCATION_ID = "location_id"; |
||||||
|
public static final String PROPERTY_ID = "prop_id"; |
||||||
|
public static final String TABLE_ITEMS = "items"; |
||||||
|
public static final String TABLE_ITEM_PROPERTIES = "item_props"; |
||||||
|
public static final String TABLE_LOCATIONS = "locations"; |
||||||
|
public static final String TABLE_PROPERTIES = "properties"; |
||||||
|
} |
||||||
@ -0,0 +1,87 @@ |
|||||||
|
/* © SRSoftware 2025 */ |
||||||
|
package de.srsoftware.umbrella.stock; |
||||||
|
|
||||||
|
import static de.srsoftware.umbrella.core.Constants.*; |
||||||
|
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; |
||||||
|
import static de.srsoftware.umbrella.stock.Constants.*; |
||||||
|
import static java.text.MessageFormat.format; |
||||||
|
|
||||||
|
import de.srsoftware.umbrella.core.BaseDb; |
||||||
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; |
||||||
|
import de.srsoftware.umbrella.core.model.Item; |
||||||
|
import de.srsoftware.umbrella.core.model.Location; |
||||||
|
import java.sql.Connection; |
||||||
|
import java.sql.SQLException; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
public class SqliteDb extends BaseDb implements StockDb { |
||||||
|
public SqliteDb(Connection connection) { |
||||||
|
super(connection); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected int createTables() { |
||||||
|
int currentVersion = createSettingsTable(); |
||||||
|
switch (currentVersion){ |
||||||
|
case 0: |
||||||
|
createLocationsTable(); |
||||||
|
createItemsTable(); |
||||||
|
createPropertiesTable(); |
||||||
|
createItemPropsTable(); |
||||||
|
} |
||||||
|
return setCurrentVersion(1); |
||||||
|
} |
||||||
|
|
||||||
|
private void createItemsTable() { |
||||||
|
try { |
||||||
|
var sql = "CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) NOT NULL, {3} TEXT, {4} VARCHAR(255))"; |
||||||
|
sql = format(sql, TABLE_ITEMS, ID, CODE, NAME, LOCATION_ID); |
||||||
|
db.prepareStatement(sql).execute(); |
||||||
|
} catch (SQLException e) { |
||||||
|
throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_ITEMS); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void createItemPropsTable() { |
||||||
|
try { |
||||||
|
var sql = "CREATE TABLE IF NOT EXISTS {0} ( {1} INT NOT NULL, {2} INT NOT NULL, {3} VARCHAR(255) NOT NULL, PRIMARY KEY({1}, {2}))"; |
||||||
|
sql = format(sql, TABLE_ITEM_PROPERTIES, ITEM_ID, PROPERTY_ID,VALUE); |
||||||
|
db.prepareStatement(sql).execute(); |
||||||
|
} catch (SQLException e) { |
||||||
|
throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_ITEM_PROPERTIES); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void createLocationsTable() { |
||||||
|
try { |
||||||
|
var sql = "CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) DEFAULT NULL, {3} VARCHAR(255) NOT NULL, {4} TEXT)"; |
||||||
|
sql = format(sql, TABLE_LOCATIONS, ID, LOCATION_ID, NAME, DESCRIPTION); |
||||||
|
db.prepareStatement(sql).execute(); |
||||||
|
} catch (SQLException e) { |
||||||
|
throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_LOCATIONS); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void createPropertiesTable() { |
||||||
|
try { |
||||||
|
var sql = "CREATE TABLE IF NOT EXISTS {0} ( {1} LONG PRIMARY KEY, {2} VARCHAR(255) NOT NULL, {3} INT NOT NULL, {4} VARCHAR(255))"; |
||||||
|
sql = format(sql, TABLE_PROPERTIES, ID, NAME, TYPE, UNIT); |
||||||
|
db.prepareStatement(sql).execute(); |
||||||
|
} catch (SQLException e) { |
||||||
|
throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_PROPERTIES); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<Item> listItems(long companyId) throws UmbrellaException { |
||||||
|
return List.of(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<Location> listLocations(long companyId) { |
||||||
|
return List.of(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,31 @@ |
|||||||
|
/* © SRSoftware 2025 */ |
||||||
|
package de.srsoftware.umbrella.stock; |
||||||
|
|
||||||
|
import static de.srsoftware.umbrella.core.ConnectionProvider.connect; |
||||||
|
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; |
||||||
|
import static de.srsoftware.umbrella.stock.Constants.CONFIG_DATABASE; |
||||||
|
|
||||||
|
import de.srsoftware.configuration.Configuration; |
||||||
|
import de.srsoftware.umbrella.core.BaseHandler; |
||||||
|
import de.srsoftware.umbrella.core.ModuleRegistry; |
||||||
|
import de.srsoftware.umbrella.core.api.StockService; |
||||||
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
public class StockApi extends BaseHandler implements StockService { |
||||||
|
|
||||||
|
private final StockDb stockDb; |
||||||
|
|
||||||
|
public StockApi(Configuration config) throws UmbrellaException { |
||||||
|
super(); |
||||||
|
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); |
||||||
|
stockDb = new SqliteDb(connect(dbFile)); |
||||||
|
ModuleRegistry.add(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<Object> redefineMe(long company_id) { |
||||||
|
return List.of(); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
/* © SRSoftware 2025 */ |
||||||
|
package de.srsoftware.umbrella.stock; |
||||||
|
|
||||||
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; |
||||||
|
import de.srsoftware.umbrella.core.model.Item; |
||||||
|
import de.srsoftware.umbrella.core.model.Location; |
||||||
|
import java.util.Collection; |
||||||
|
|
||||||
|
public interface StockDb { |
||||||
|
Collection<Item> listItems(long companyId) throws UmbrellaException; |
||||||
|
Collection<Location> listLocations(long companyId); |
||||||
|
} |
||||||
Loading…
Reference in new issue