diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index 5b76f1c..2207879 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -17,12 +17,12 @@ dependencies{ implementation(project(":core")) implementation(project(":documents")) implementation(project(":files")) - implementation(project(":items")) implementation(project(":legacy")) implementation(project(":markdown")) implementation(project(":messages")) implementation(project(":notes")) implementation(project(":project")) + implementation(project(":stock")) implementation(project(":tags")) implementation(project(":task")) implementation(project(":time")) @@ -50,12 +50,12 @@ tasks.jar { ":core:jar", ":documents:jar", ":files:jar", - ":items:jar", ":legacy:jar", ":markdown:jar", ":messages:jar", ":notes:jar", ":project:jar", + ":stock:jar", ":tags:jar", ":task:jar", ":time:jar", diff --git a/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java b/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java index a510189..cb25ec0 100644 --- a/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java +++ b/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java @@ -16,12 +16,12 @@ import de.srsoftware.umbrella.core.Util; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.documents.DocumentApi; import de.srsoftware.umbrella.files.FileModule; -import de.srsoftware.umbrella.items.ItemApi; import de.srsoftware.umbrella.legacy.*; import de.srsoftware.umbrella.markdown.MarkdownApi; import de.srsoftware.umbrella.message.MessageSystem; import de.srsoftware.umbrella.notes.NoteModule; import de.srsoftware.umbrella.project.ProjectModule; +import de.srsoftware.umbrella.stock.StockApi; import de.srsoftware.umbrella.tags.TagModule; import de.srsoftware.umbrella.task.TaskModule; import de.srsoftware.umbrella.time.TimeModule; @@ -71,7 +71,7 @@ public class Application { new CompanyLegacy(config).bindPath("/legacy/company").on(server); new ContactModule(config).bindPath("/api/contact").on(server); new DocumentApi(config).bindPath("/api/document").on(server); - new ItemApi(config).bindPath("/api/items").on(server); + new StockApi(config).bindPath("/api/stock").on(server); new UserLegacy(config).bindPath("/legacy/user").on(server); new NotesLegacy(config).bindPath("/legacy/notes").on(server); new MarkdownApi().bindPath("/api/markdown").on(server); diff --git a/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java b/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java index b70f76e..9422c17 100644 --- a/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java +++ b/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java @@ -38,7 +38,7 @@ public class CompanyModule extends BaseHandler implements CompanyService { var company = get(companyId); if (!membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); if (!documentService().list(companyId).isEmpty()) throw forbidden("There are documents owned by {0}",company.name()); - if (!itemService().list(companyId).isEmpty()) throw forbidden("There are items owned by {0}",company.name()); + if (!itemService().redefineMe(companyId).isEmpty()) throw forbidden("There are items owned by {0}",company.name()); if (!projectService().listCompanyProjects(companyId,true).isEmpty()) throw forbidden("There are projects owned by {0}",company.name()); return sendContent(ex, companyDb.drop(companyId)); } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/ModuleRegistry.java b/core/src/main/java/de/srsoftware/umbrella/core/ModuleRegistry.java index 6b8b614..594a7ae 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/ModuleRegistry.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/ModuleRegistry.java @@ -10,11 +10,11 @@ public class ModuleRegistry { private ContactService contactService; private DocumentService documentService; private FileService fileService; - private ItemService itemService; private MarkdownService markdownService; private NoteService noteService; private PostBox postBox; private ProjectService projectService; + private StockService stockService; private TagService tagService; private TaskService taskService; private TimeService timeService; @@ -33,7 +33,7 @@ public class ModuleRegistry { case ContactService cs: singleton.contactService = cs; break; case DocumentService ds: singleton.documentService = ds; break; case FileService fs: singleton.fileService = fs; break; - case ItemService is: singleton.itemService = is; break; + case StockService is: singleton.stockService = is; break; case MarkdownService ms: singleton.markdownService = ms; break; case NoteService ns: singleton.noteService = ns; break; case PostBox pb: singleton.postBox = pb; break; @@ -65,8 +65,8 @@ public class ModuleRegistry { return singleton.documentService; } - public static ItemService itemService(){ - return singleton.itemService; + public static StockService itemService(){ + return singleton.stockService; } public static FileService fileService(){ diff --git a/core/src/main/java/de/srsoftware/umbrella/core/api/ItemService.java b/core/src/main/java/de/srsoftware/umbrella/core/api/ItemService.java deleted file mode 100644 index ade844c..0000000 --- a/core/src/main/java/de/srsoftware/umbrella/core/api/ItemService.java +++ /dev/null @@ -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 list(long companyId) throws UmbrellaException; -} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/api/StockService.java b/core/src/main/java/de/srsoftware/umbrella/core/api/StockService.java new file mode 100644 index 0000000..061bf72 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/api/StockService.java @@ -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 redefineMe(long company_id); +} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Item.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Item.java index e2a91cd..1cdc3a1 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Item.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Item.java @@ -1,38 +1,12 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Constants.CODE; -import static de.srsoftware.umbrella.core.Util.mapMarkdown; - -import de.srsoftware.tools.Mappable; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Map; - -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 toMap() { - return Map.of( - ID,id, - COMPANY_ID,companyId, - CODE,code,NAME,name, - DESCRIPTION,mapMarkdown(description), - UNIT,unit, - UNIT_PRICE,unitPrice, - TAX,tax); - } +import java.util.Collection; + +public class Item { + private long id; + private String code; + private boolean physical; + private Location location; + private Collection properties; } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java new file mode 100644 index 0000000..5e21c10 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java @@ -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 +} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Property.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Property.java new file mode 100644 index 0000000..bede457 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Property.java @@ -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; +} diff --git a/frontend/src/routes/stock/ItemList.svelte b/frontend/src/routes/stock/ItemList.svelte index dbef8b9..0e1ab5d 100644 --- a/frontend/src/routes/stock/ItemList.svelte +++ b/frontend/src/routes/stock/ItemList.svelte @@ -3,10 +3,9 @@
  • - + + {t('add_object',{object:'item'})} +
  • Item 1
  • Item 2
  • diff --git a/frontend/src/routes/stock/Locations.svelte b/frontend/src/routes/stock/Locations.svelte index 457a3f4..a4d3ef1 100644 --- a/frontend/src/routes/stock/Locations.svelte +++ b/frontend/src/routes/stock/Locations.svelte @@ -1,8 +1,15 @@
      +
    • + + {t('add_object',{object:'location'})} + +
    • {#each Object.entries(locations) as [k,v]}
    • {k} diff --git a/items/src/main/java/de/srsoftware/umbrella/items/Constants.java b/items/src/main/java/de/srsoftware/umbrella/items/Constants.java deleted file mode 100644 index 899ab2a..0000000 --- a/items/src/main/java/de/srsoftware/umbrella/items/Constants.java +++ /dev/null @@ -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"; -} diff --git a/items/src/main/java/de/srsoftware/umbrella/items/ItemApi.java b/items/src/main/java/de/srsoftware/umbrella/items/ItemApi.java deleted file mode 100644 index db07ef5..0000000 --- a/items/src/main/java/de/srsoftware/umbrella/items/ItemApi.java +++ /dev/null @@ -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 = 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 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); - } -} \ No newline at end of file diff --git a/items/src/main/java/de/srsoftware/umbrella/items/ItemDb.java b/items/src/main/java/de/srsoftware/umbrella/items/ItemDb.java deleted file mode 100644 index 2f43c2f..0000000 --- a/items/src/main/java/de/srsoftware/umbrella/items/ItemDb.java +++ /dev/null @@ -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 list(long companyId) throws UmbrellaException; -} diff --git a/items/src/main/java/de/srsoftware/umbrella/items/SqliteDb.java b/items/src/main/java/de/srsoftware/umbrella/items/SqliteDb.java deleted file mode 100644 index 8de3705..0000000 --- a/items/src/main/java/de/srsoftware/umbrella/items/SqliteDb.java +++ /dev/null @@ -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 list(long companyId) throws UmbrellaException { - try { - var items = new HashSet(); - 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"); - } - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index d0f92b0..950a44a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,11 +8,11 @@ include("core") include("documents") include("files") include("legacy") -include("items") include("messages") include("markdown") include("notes") include("project") +include("stock") include("tags") include("task") include("time") diff --git a/items/build.gradle.kts b/stock/build.gradle.kts similarity index 60% rename from items/build.gradle.kts rename to stock/build.gradle.kts index 87abe3c..e6b6497 100644 --- a/items/build.gradle.kts +++ b/stock/build.gradle.kts @@ -1,4 +1,4 @@ -description = "Umbrella : Items" +description = "Umbrella : Stock" dependencies{ implementation(project(":core")) diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java b/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java new file mode 100644 index 0000000..92e9869 --- /dev/null +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java @@ -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"; +} diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java new file mode 100644 index 0000000..5d3bda6 --- /dev/null +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java @@ -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 listItems(long companyId) throws UmbrellaException { + return List.of(); + } + + @Override + public Collection listLocations(long companyId) { + return List.of(); + } + + +} diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockApi.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockApi.java new file mode 100644 index 0000000..853d6cd --- /dev/null +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockApi.java @@ -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 redefineMe(long company_id) { + return List.of(); + } +} \ No newline at end of file diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java new file mode 100644 index 0000000..9169d7d --- /dev/null +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java @@ -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 listItems(long companyId) throws UmbrellaException; + Collection listLocations(long companyId); +}