mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 19:00:23 +01:00
feat(inventory): Bestandsposition anlegen (#4)
Stock-Aggregate mit MinimumLevel, MinimumShelfLife und StockDraft. Quantity/UnitOfMeasure nach shared.common verschoben für BC-übergreifende Nutzung. REST-Endpoint POST /api/inventory/stocks mit Duplikat-Prüfung, Validierung und Liquibase-Migration.
This commit is contained in:
parent
7079f12475
commit
5219c93dd1
43 changed files with 1340 additions and 18 deletions
|
|
@ -0,0 +1,262 @@
|
|||
package de.effigenix.domain.inventory;
|
||||
|
||||
import de.effigenix.domain.masterdata.ArticleId;
|
||||
import de.effigenix.shared.common.Quantity;
|
||||
import de.effigenix.shared.common.UnitOfMeasure;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class StockTest {
|
||||
|
||||
// ==================== Create ====================
|
||||
|
||||
@Nested
|
||||
@DisplayName("create()")
|
||||
class Create {
|
||||
|
||||
@Test
|
||||
@DisplayName("should create Stock with all fields")
|
||||
void shouldCreateWithAllFields() {
|
||||
var draft = new StockDraft(
|
||||
"article-1", "location-1", "10.5", "KILOGRAM", 30);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
var stock = result.unsafeGetValue();
|
||||
assertThat(stock.id()).isNotNull();
|
||||
assertThat(stock.articleId().value()).isEqualTo("article-1");
|
||||
assertThat(stock.storageLocationId().value()).isEqualTo("location-1");
|
||||
assertThat(stock.minimumLevel()).isNotNull();
|
||||
assertThat(stock.minimumLevel().quantity().amount()).isEqualByComparingTo(new BigDecimal("10.5"));
|
||||
assertThat(stock.minimumLevel().quantity().uom()).isEqualTo(UnitOfMeasure.KILOGRAM);
|
||||
assertThat(stock.minimumShelfLife()).isNotNull();
|
||||
assertThat(stock.minimumShelfLife().days()).isEqualTo(30);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should create Stock with only required fields")
|
||||
void shouldCreateWithOnlyRequiredFields() {
|
||||
var draft = new StockDraft("article-1", "location-1", null, null, null);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
var stock = result.unsafeGetValue();
|
||||
assertThat(stock.articleId().value()).isEqualTo("article-1");
|
||||
assertThat(stock.storageLocationId().value()).isEqualTo("location-1");
|
||||
assertThat(stock.minimumLevel()).isNull();
|
||||
assertThat(stock.minimumShelfLife()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when articleId is null")
|
||||
void shouldFailWhenArticleIdNull() {
|
||||
var draft = new StockDraft(null, "location-1", null, null, null);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isFailure()).isTrue();
|
||||
assertThat(result.unsafeGetError()).isInstanceOf(StockError.InvalidArticleId.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when articleId is blank")
|
||||
void shouldFailWhenArticleIdBlank() {
|
||||
var draft = new StockDraft("", "location-1", null, null, null);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isFailure()).isTrue();
|
||||
assertThat(result.unsafeGetError()).isInstanceOf(StockError.InvalidArticleId.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when storageLocationId is null")
|
||||
void shouldFailWhenStorageLocationIdNull() {
|
||||
var draft = new StockDraft("article-1", null, null, null, null);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isFailure()).isTrue();
|
||||
assertThat(result.unsafeGetError()).isInstanceOf(StockError.InvalidStorageLocationId.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when storageLocationId is blank")
|
||||
void shouldFailWhenStorageLocationIdBlank() {
|
||||
var draft = new StockDraft("article-1", "", null, null, null);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isFailure()).isTrue();
|
||||
assertThat(result.unsafeGetError()).isInstanceOf(StockError.InvalidStorageLocationId.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when minimumLevel amount is negative")
|
||||
void shouldFailWhenMinimumLevelNegative() {
|
||||
var draft = new StockDraft("article-1", "location-1", "-1", "KILOGRAM", null);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isFailure()).isTrue();
|
||||
assertThat(result.unsafeGetError()).isInstanceOf(StockError.InvalidMinimumLevel.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when minimumLevel amount is not a number")
|
||||
void shouldFailWhenMinimumLevelNotNumber() {
|
||||
var draft = new StockDraft("article-1", "location-1", "abc", "KILOGRAM", null);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isFailure()).isTrue();
|
||||
assertThat(result.unsafeGetError()).isInstanceOf(StockError.InvalidMinimumLevel.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when minimumLevel unit is invalid")
|
||||
void shouldFailWhenMinimumLevelUnitInvalid() {
|
||||
var draft = new StockDraft("article-1", "location-1", "10", "INVALID_UNIT", null);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isFailure()).isTrue();
|
||||
assertThat(result.unsafeGetError()).isInstanceOf(StockError.InvalidMinimumLevel.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should accept minimumLevel amount of zero")
|
||||
void shouldAcceptMinimumLevelZero() {
|
||||
var draft = new StockDraft("article-1", "location-1", "0", "KILOGRAM", null);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.unsafeGetValue().minimumLevel().quantity().amount())
|
||||
.isEqualByComparingTo(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when minimumShelfLife is zero")
|
||||
void shouldFailWhenMinimumShelfLifeZero() {
|
||||
var draft = new StockDraft("article-1", "location-1", null, null, 0);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isFailure()).isTrue();
|
||||
assertThat(result.unsafeGetError()).isInstanceOf(StockError.InvalidMinimumShelfLife.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when minimumShelfLife is negative")
|
||||
void shouldFailWhenMinimumShelfLifeNegative() {
|
||||
var draft = new StockDraft("article-1", "location-1", null, null, -5);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isFailure()).isTrue();
|
||||
assertThat(result.unsafeGetError()).isInstanceOf(StockError.InvalidMinimumShelfLife.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should accept minimumShelfLife of 1")
|
||||
void shouldAcceptMinimumShelfLifeOne() {
|
||||
var draft = new StockDraft("article-1", "location-1", null, null, 1);
|
||||
|
||||
var result = Stock.create(draft);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.unsafeGetValue().minimumShelfLife().days()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should create with all UnitOfMeasure values")
|
||||
void shouldCreateWithAllUnits() {
|
||||
for (UnitOfMeasure unit : UnitOfMeasure.values()) {
|
||||
var draft = new StockDraft("article-1", "location-1", "5", unit.name(), null);
|
||||
var result = Stock.create(draft);
|
||||
assertThat(result.isSuccess()).as("UnitOfMeasure %s should be valid", unit).isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Reconstitute ====================
|
||||
|
||||
@Nested
|
||||
@DisplayName("reconstitute()")
|
||||
class Reconstitute {
|
||||
|
||||
@Test
|
||||
@DisplayName("should reconstitute Stock from persistence")
|
||||
void shouldReconstitute() {
|
||||
var id = StockId.generate();
|
||||
var articleId = ArticleId.of("article-1");
|
||||
var locationId = StorageLocationId.of("location-1");
|
||||
var quantity = Quantity.reconstitute(new BigDecimal("10"), UnitOfMeasure.KILOGRAM, null, null);
|
||||
var minimumLevel = new MinimumLevel(quantity);
|
||||
var minimumShelfLife = new MinimumShelfLife(30);
|
||||
|
||||
var stock = Stock.reconstitute(id, articleId, locationId, minimumLevel, minimumShelfLife);
|
||||
|
||||
assertThat(stock.id()).isEqualTo(id);
|
||||
assertThat(stock.articleId()).isEqualTo(articleId);
|
||||
assertThat(stock.storageLocationId()).isEqualTo(locationId);
|
||||
assertThat(stock.minimumLevel()).isEqualTo(minimumLevel);
|
||||
assertThat(stock.minimumShelfLife()).isEqualTo(minimumShelfLife);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should reconstitute Stock without optional fields")
|
||||
void shouldReconstituteWithoutOptionals() {
|
||||
var id = StockId.generate();
|
||||
var articleId = ArticleId.of("article-1");
|
||||
var locationId = StorageLocationId.of("location-1");
|
||||
|
||||
var stock = Stock.reconstitute(id, articleId, locationId, null, null);
|
||||
|
||||
assertThat(stock.minimumLevel()).isNull();
|
||||
assertThat(stock.minimumShelfLife()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Equality ====================
|
||||
|
||||
@Nested
|
||||
@DisplayName("equals / hashCode")
|
||||
class Equality {
|
||||
|
||||
@Test
|
||||
@DisplayName("should be equal if same ID")
|
||||
void shouldBeEqualBySameId() {
|
||||
var id = StockId.generate();
|
||||
var stock1 = Stock.reconstitute(id, ArticleId.of("a1"), StorageLocationId.of("l1"), null, null);
|
||||
var stock2 = Stock.reconstitute(id, ArticleId.of("a2"), StorageLocationId.of("l2"), null, null);
|
||||
|
||||
assertThat(stock1).isEqualTo(stock2);
|
||||
assertThat(stock1.hashCode()).isEqualTo(stock2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should not be equal if different ID")
|
||||
void shouldNotBeEqualByDifferentId() {
|
||||
var stock1 = createValidStock();
|
||||
var stock2 = createValidStock();
|
||||
|
||||
assertThat(stock1).isNotEqualTo(stock2);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Helpers ====================
|
||||
|
||||
private Stock createValidStock() {
|
||||
var draft = new StockDraft("article-1", "location-1", "10", "KILOGRAM", 30);
|
||||
return Stock.create(draft).unsafeGetValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package de.effigenix.domain.production;
|
||||
|
||||
import de.effigenix.shared.common.QuantityError;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package de.effigenix.domain.production;
|
||||
|
||||
import de.effigenix.shared.common.UnitOfMeasure;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package de.effigenix.domain.production;
|
||||
|
||||
import de.effigenix.shared.common.Quantity;
|
||||
import de.effigenix.shared.common.UnitOfMeasure;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package de.effigenix.domain.production;
|
||||
|
||||
import de.effigenix.shared.common.UnitOfMeasure;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ import org.junit.jupiter.params.provider.ValueSource;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static de.effigenix.domain.production.UnitOfMeasure.*;
|
||||
import de.effigenix.shared.common.Quantity;
|
||||
import de.effigenix.shared.common.QuantityError;
|
||||
|
||||
import static de.effigenix.shared.common.UnitOfMeasure.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,220 @@
|
|||
package de.effigenix.infrastructure.inventory.web;
|
||||
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.infrastructure.AbstractIntegrationTest;
|
||||
import de.effigenix.infrastructure.inventory.web.dto.CreateStockRequest;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
/**
|
||||
* Integrationstests für StockController.
|
||||
*
|
||||
* Abgedeckte Testfälle:
|
||||
* - Story 2.1 – Bestandsposition anlegen
|
||||
*/
|
||||
@DisplayName("Stock Controller Integration Tests")
|
||||
class StockControllerIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
private String adminToken;
|
||||
private String viewerToken;
|
||||
|
||||
private String storageLocationId;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
RoleEntity adminRole = createRole(RoleName.ADMIN, "Admin");
|
||||
RoleEntity viewerRole = createRole(RoleName.PRODUCTION_WORKER, "Viewer");
|
||||
|
||||
UserEntity admin = createUser("stock.admin", "stock.admin@test.com", Set.of(adminRole), "BRANCH-01");
|
||||
UserEntity viewer = createUser("stock.viewer", "stock.viewer@test.com", Set.of(viewerRole), "BRANCH-01");
|
||||
|
||||
adminToken = generateToken(admin.getId(), "stock.admin", "STOCK_WRITE,STOCK_READ");
|
||||
viewerToken = generateToken(viewer.getId(), "stock.viewer", "USER_READ");
|
||||
|
||||
storageLocationId = createStorageLocation();
|
||||
}
|
||||
|
||||
// ==================== Bestandsposition anlegen – Pflichtfelder ====================
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition mit Pflichtfeldern erstellen → 201")
|
||||
void createStock_withRequiredFields_returns201() throws Exception {
|
||||
var request = new CreateStockRequest(
|
||||
UUID.randomUUID().toString(), storageLocationId, null, null, null);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.id").isNotEmpty())
|
||||
.andExpect(jsonPath("$.articleId").value(request.articleId()))
|
||||
.andExpect(jsonPath("$.storageLocationId").value(storageLocationId))
|
||||
.andExpect(jsonPath("$.minimumLevel").isEmpty())
|
||||
.andExpect(jsonPath("$.minimumShelfLifeDays").isEmpty());
|
||||
}
|
||||
|
||||
// ==================== Bestandsposition mit allen Feldern ====================
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition mit allen Feldern erstellen → 201")
|
||||
void createStock_withAllFields_returns201() throws Exception {
|
||||
var request = new CreateStockRequest(
|
||||
UUID.randomUUID().toString(), storageLocationId, "10.5", "KILOGRAM", 30);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.articleId").value(request.articleId()))
|
||||
.andExpect(jsonPath("$.storageLocationId").value(storageLocationId))
|
||||
.andExpect(jsonPath("$.minimumLevel.amount").value(10.5))
|
||||
.andExpect(jsonPath("$.minimumLevel.unit").value("KILOGRAM"))
|
||||
.andExpect(jsonPath("$.minimumShelfLifeDays").value(30));
|
||||
}
|
||||
|
||||
// ==================== Duplikat ====================
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition Duplikat (gleiche articleId+storageLocationId) → 409")
|
||||
void createStock_duplicate_returns409() throws Exception {
|
||||
String articleId = UUID.randomUUID().toString();
|
||||
var request = new CreateStockRequest(articleId, storageLocationId, null, null, null);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isConflict())
|
||||
.andExpect(jsonPath("$.code").value("DUPLICATE_STOCK"));
|
||||
}
|
||||
|
||||
// ==================== Validierungsfehler ====================
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition ohne articleId → 400")
|
||||
void createStock_withBlankArticleId_returns400() throws Exception {
|
||||
var request = new CreateStockRequest("", storageLocationId, null, null, null);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition ohne storageLocationId → 400")
|
||||
void createStock_withBlankStorageLocationId_returns400() throws Exception {
|
||||
var request = new CreateStockRequest(UUID.randomUUID().toString(), "", null, null, null);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition mit ungültigem MinimumLevel → 400")
|
||||
void createStock_withInvalidMinimumLevel_returns400() throws Exception {
|
||||
var request = new CreateStockRequest(
|
||||
UUID.randomUUID().toString(), storageLocationId, "-1", "KILOGRAM", null);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.code").value("INVALID_MINIMUM_LEVEL"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition mit ungültiger Unit → 400")
|
||||
void createStock_withInvalidUnit_returns400() throws Exception {
|
||||
var request = new CreateStockRequest(
|
||||
UUID.randomUUID().toString(), storageLocationId, "10", "INVALID_UNIT", null);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.code").value("INVALID_MINIMUM_LEVEL"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition mit ungültigem MinimumShelfLife → 400")
|
||||
void createStock_withInvalidMinimumShelfLife_returns400() throws Exception {
|
||||
var request = new CreateStockRequest(
|
||||
UUID.randomUUID().toString(), storageLocationId, null, null, 0);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.code").value("INVALID_MINIMUM_SHELF_LIFE"));
|
||||
}
|
||||
|
||||
// ==================== Autorisierung ====================
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition erstellen ohne STOCK_WRITE → 403")
|
||||
void createStock_withViewerToken_returns403() throws Exception {
|
||||
var request = new CreateStockRequest(
|
||||
UUID.randomUUID().toString(), storageLocationId, null, null, null);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.header("Authorization", "Bearer " + viewerToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Bestandsposition erstellen ohne Token → 401")
|
||||
void createStock_withoutToken_returns401() throws Exception {
|
||||
var request = new CreateStockRequest(
|
||||
UUID.randomUUID().toString(), storageLocationId, null, null, null);
|
||||
|
||||
mockMvc.perform(post("/api/inventory/stocks")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
// ==================== Hilfsmethoden ====================
|
||||
|
||||
private String createStorageLocation() throws Exception {
|
||||
String json = """
|
||||
{"name": "Testlager-%s", "storageType": "DRY_STORAGE"}
|
||||
""".formatted(UUID.randomUUID().toString().substring(0, 8));
|
||||
|
||||
var result = mockMvc.perform(post("/api/inventory/storage-locations")
|
||||
.header("Authorization", "Bearer " + adminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(json))
|
||||
.andExpect(status().isCreated())
|
||||
.andReturn();
|
||||
|
||||
return objectMapper.readTree(result.getResponse().getContentAsString()).get("id").asText();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
package de.effigenix.domain.production;
|
||||
package de.effigenix.shared.common;
|
||||
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static de.effigenix.domain.production.UnitOfMeasure.*;
|
||||
import static de.effigenix.shared.common.UnitOfMeasure.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DisplayName("Quantity Value Object")
|
||||
Loading…
Add table
Add a link
Reference in a new issue