Compare commits

...

2 Commits

Author SHA1 Message Date
Stephan Richter 6bb03f4e04 implemented adding stock items to documents 4 hours ago
Stephan Richter 438d8d4aad preparing to make items available as document positions 8 hours ago
  1. 21
      frontend/src/Components/Item.svelte
  2. 14
      frontend/src/routes/document/ItemList.svelte
  3. 18
      frontend/src/routes/document/PositionSelector.svelte
  4. 16
      stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java
  5. 1
      stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java
  6. 17
      stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java

21
frontend/src/Components/Item.svelte

@ -1,9 +1,26 @@
<script> <script>
import { t } from '../translations.svelte';
let { item, onclick } = $props(); let { item, onclick } = $props();
</script> </script>
<fieldset {onclick}> <fieldset {onclick}>
<legend>{item.code} | {item.name}</legend> <legend>{item.code} | {item.name}</legend>
<div>{@html item.description.rendered}</div> {#if item.properties}
<span>{item.unit_price/100} {item.currency} / {item.unit}</span> <table>
<tbody>
{#if item.location.name}
<tr>
<th>{t('location')}</th>
<td>{item.location.name}</td>
</tr>
{/if}
{#each Object.entries(item.properties) as [idx,prop]}
<tr>
<th>{prop.name}</th>
<td>{prop.value} {prop.unit}</td>
</tr>
{/each}
</tbody>
</table>
{/if}
</fieldset> </fieldset>

14
frontend/src/routes/document/ItemList.svelte

@ -1,7 +1,7 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { api } from '../../urls.svelte.js'; import { api, post } from '../../urls.svelte.js';
import { error, yikes } from '../../warn.svelte'; import { error, yikes } from '../../warn.svelte';
import { t } from '../../translations.svelte.js'; import { t } from '../../translations.svelte.js';
@ -15,13 +15,9 @@
let items = $state(null); let items = $state(null);
async function loadItems(){ async function loadItems(){
const url = api('items/list'); const url = api('stock/list');
let data = { company_id: company_id }; let data = { company_id };
const resp = await fetch(url,{ const resp = await post(url,data);
credentials: 'include',
method : 'POST',
body : JSON.stringify(data)
});
if (resp.ok){ if (resp.ok){
items = await resp.json(); items = await resp.json();
yikes(); yikes();
@ -37,7 +33,7 @@
<div> <div>
<h1>{t('items')}</h1> <h1>{t('items')}</h1>
{#if items} {#if items}
{#each items as item,id} {#each items as item,idx}
<Item item={item} onclick={() => onSelect(item)} /> <Item item={item} onclick={() => onSelect(item)} />
{/each} {/each}
{/if} {/if}

18
frontend/src/routes/document/PositionSelector.svelte

@ -29,14 +29,24 @@
} }
function itemSelected(item){ function itemSelected(item){
let unit_price = null;
let description = '';
for (let prop of item.properties) {
if (prop.name.toLowerCase().indexOf(t('price').toLowerCase())>-1){
unit_price = 100*prop.value.replace(',','.');
} else {
description += `* ${prop.name}: ${prop.value}\n`;
}
}
select({ select({
item_code : item.code, item_code : item.code,
title : item.name, title : item.name,
description : item.description.source, description : description,
amount : 1, amount : 1,
unit : item.unit, unit : t('pieces'),
unit_price : item.unit_price, unit_price : unit_price,
tax : item.tax tax : 0
}); });
} }

16
stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java

@ -218,6 +218,22 @@ public class SqliteDb extends BaseDb implements StockDb {
} }
} }
@Override
public Collection<Item> listItemsOf(Company company) {
try {
var owner = company.dbCode();
var rs = select(ALL).from(TABLE_ITEMS).where(OWNER,equal(owner)).exec(db);
var list = new ArrayList<Item>();
while (rs.next()) list.add(Item.of(rs));
rs.close();
for (var item : list) loadProperties(item);
return list;
} catch (SQLException e){
throw databaseException("Failed to load items of {0}",company);
}
}
@Override @Override
public Item loadProperties(Item item){ public Item loadProperties(Item item){
try { try {

1
stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java

@ -13,6 +13,7 @@ public interface StockDb {
Collection<DbLocation> listChildLocations(long parentId); Collection<DbLocation> listChildLocations(long parentId);
Collection<DbLocation> listCompanyLocations(Company company); Collection<DbLocation> listCompanyLocations(Company company);
Collection<Item> listItemsAt(Location location); Collection<Item> listItemsAt(Location location);
Collection<Item> listItemsOf(Company company);
Collection<Property> listProperties(); Collection<Property> listProperties();
Collection<DbLocation> listUserLocations(UmbrellaUser userId); Collection<DbLocation> listUserLocations(UmbrellaUser userId);
Item loadItem(long id); Item loadItem(long id);

17
stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java

@ -8,6 +8,8 @@ import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Field.ITEM; import static de.srsoftware.umbrella.core.Field.ITEM;
import static de.srsoftware.umbrella.core.ModuleRegistry.companyService; import static de.srsoftware.umbrella.core.ModuleRegistry.companyService;
import static de.srsoftware.umbrella.core.ModuleRegistry.userService; import static de.srsoftware.umbrella.core.ModuleRegistry.userService;
import static de.srsoftware.umbrella.core.Paths.LIST;
import static de.srsoftware.umbrella.core.Util.mapValues;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static de.srsoftware.umbrella.stock.Constants.*; import static de.srsoftware.umbrella.stock.Constants.*;
import static java.lang.System.Logger.Level.WARNING; import static java.lang.System.Logger.Level.WARNING;
@ -33,6 +35,7 @@ import org.json.JSONObject;
public class StockModule extends BaseHandler implements StockService { public class StockModule extends BaseHandler implements StockService {
private final StockDb stockDb; private final StockDb stockDb;
private Comparator<Item> byName = (a,b) -> a.name().compareToIgnoreCase(b.name());
public StockModule(Configuration config) throws UmbrellaException { public StockModule(Configuration config) throws UmbrellaException {
super(); super();
@ -160,6 +163,7 @@ public class StockModule extends BaseHandler implements StockService {
var head = path.pop(); var head = path.pop();
return switch (head) { return switch (head) {
case ITEM -> postItem(user.get(), ex); case ITEM -> postItem(user.get(), ex);
case LIST -> postItemList(user.get(), path, ex);
case LOCATION -> postLocation(user.get(),ex); case LOCATION -> postLocation(user.get(),ex);
case PROPERTY -> postProperty(user.get(),ex); case PROPERTY -> postProperty(user.get(),ex);
case null, default -> super.doPost(path,ex); case null, default -> super.doPost(path,ex);
@ -316,6 +320,19 @@ public class StockModule extends BaseHandler implements StockService {
return sendContent(ex,stockDb.save(newItem)); return sendContent(ex,stockDb.save(newItem));
} }
private boolean postItemList(UmbrellaUser user, Path path, HttpExchange ex) throws IOException {
var json = json(ex);
if (!json.has(COMPANY_ID) || !(json.get(COMPANY_ID) instanceof Number company_id)) throw missingFieldException(COMPANY_ID);
var company = companyService().get(company_id.longValue());
if (!companyService().membership(company_id.longValue(),user.id())) throw forbidden("You are not a member of {0}!", company.name());
var map = new HashMap<Long,Location>();
var items = stockDb.listItemsOf(company)
.stream()
.peek(item -> item.location(map.computeIfAbsent(item.location().id(), k -> item.location().resolve()))).sorted(byName)
.map(Item::toMap);
return sendContent(ex,items);
}
private boolean postLocation(UmbrellaUser user, HttpExchange ex) throws IOException { private boolean postLocation(UmbrellaUser user, HttpExchange ex) throws IOException {
var json = json(ex); var json = json(ex);
if (!(json.get(NAME) instanceof String name)) throw missingFieldException(NAME); if (!(json.get(NAME) instanceof String name)) throw missingFieldException(NAME);

Loading…
Cancel
Save