Implement the SKUs and the Inventory Movement Manager, to apply variability and functions for sales, restock co.
This commit is contained in:
0
apps/workspace-api/Doc.txt
Normal file
0
apps/workspace-api/Doc.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
package com.voyage.workspace.inventory;
|
||||
|
||||
import com.voyage.workspace.products.SkuRepository;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/inventory")
|
||||
public class InventoryController {
|
||||
|
||||
private final InventoryMovementRepository movementRepo;
|
||||
private final SkuRepository skuRepo;
|
||||
|
||||
public InventoryController(InventoryMovementRepository movementRepo, SkuRepository skuRepo) {
|
||||
this.movementRepo = movementRepo;
|
||||
this.skuRepo = skuRepo;
|
||||
}
|
||||
|
||||
@PostMapping("/movements")
|
||||
public ResponseEntity<?> createMovement(@RequestBody InventoryMovementCreateRequest req) {
|
||||
var skuOpt = skuRepo.findById(req.skuId());
|
||||
if (skuOpt.isEmpty()) return ResponseEntity.badRequest().body("Unknown skuId: " + req.skuId());
|
||||
|
||||
InventoryMovement m = new InventoryMovement();
|
||||
m.setSku(skuOpt.get());
|
||||
m.setDelta(req.delta());
|
||||
m.setReason(req.reason());
|
||||
m.setReference(req.reference());
|
||||
|
||||
return ResponseEntity.ok(movementRepo.save(m));
|
||||
}
|
||||
|
||||
@GetMapping("/stock/{skuId}")
|
||||
public int getCurrentStock(@PathVariable Long skuId) {
|
||||
return movementRepo.currentStock(skuId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.voyage.workspace.inventory;
|
||||
|
||||
import com.voyage.workspace.products.Sku;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
@Table(name = "inventory_movements")
|
||||
public class InventoryMovement {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "sku_id", nullable = false)
|
||||
private Sku sku;
|
||||
|
||||
@Column(nullable = false)
|
||||
private int delta;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String reason; // PRODUCTION, SALE, RETURN, ADJUSTMENT
|
||||
|
||||
private String reference;
|
||||
|
||||
@Column(nullable=false, updatable=false)
|
||||
private Instant createdAt = Instant.now();
|
||||
|
||||
public InventoryMovement() {}
|
||||
|
||||
public Long getId() { return id; }
|
||||
public Sku getSku() { return sku; }
|
||||
public int getDelta() { return delta; }
|
||||
public String getReason() { return reason; }
|
||||
public String getReference() { return reference; }
|
||||
public Instant getCreatedAt() { return createdAt; }
|
||||
|
||||
public void setSku(Sku sku) { this.sku = sku; }
|
||||
public void setDelta(int delta) { this.delta = delta; }
|
||||
public void setReason(String reason) { this.reason = reason; }
|
||||
public void setReference(String reference) { this.reference = reference; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.voyage.workspace.inventory;
|
||||
|
||||
public record InventoryMovementCreateRequest(
|
||||
Long skuId,
|
||||
int delta,
|
||||
String reason,
|
||||
String reference
|
||||
) {}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.voyage.workspace.inventory;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface InventoryMovementRepository extends JpaRepository<InventoryMovement, Long> {
|
||||
|
||||
@Query("select coalesce(sum(m.delta), 0) from InventoryMovement m where m.sku.id = :skuId")
|
||||
int currentStock(@Param("skuId") Long skuId);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.voyage.workspace.products;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Table(name = "skus")
|
||||
public class Sku {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "product_id", nullable = false)
|
||||
private Product product;
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
private String skuCode;
|
||||
|
||||
private String size;
|
||||
private String color;
|
||||
|
||||
@Column(nullable = false)
|
||||
private BigDecimal price;
|
||||
|
||||
@Column(nullable = false)
|
||||
private boolean active = true;
|
||||
|
||||
public Sku() {}
|
||||
|
||||
public Long getId() { return id; }
|
||||
public Product getProduct() { return product; }
|
||||
public String getSkuCode() { return skuCode; }
|
||||
public String getSize() { return size; }
|
||||
public String getColor() { return color; }
|
||||
public BigDecimal getPrice() { return price; }
|
||||
public boolean isActive() { return active; }
|
||||
|
||||
public void setProduct(Product product) { this.product = product; }
|
||||
public void setSkuCode(String skuCode) { this.skuCode = skuCode; }
|
||||
public void setSize(String size) { this.size = size; }
|
||||
public void setColor(String color) { this.color = color; }
|
||||
public void setPrice(BigDecimal price) { this.price = price; }
|
||||
public void setActive(boolean active) { this.active = active; }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.voyage.workspace.products;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/skus")
|
||||
public class SkuController {
|
||||
|
||||
private final SkuRepository skuRepo;
|
||||
private final ProductRepository productRepo;
|
||||
|
||||
public SkuController(SkuRepository skuRepo, ProductRepository productRepo) {
|
||||
this.skuRepo = skuRepo;
|
||||
this.productRepo = productRepo;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<Sku> list(@RequestParam(required = false) Long productId) {
|
||||
if (productId != null) return skuRepo.findByProductId(productId);
|
||||
return skuRepo.findAll();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> create(@RequestBody SkuCreateRequest req) {
|
||||
var productOpt = productRepo.findById(req.productId());
|
||||
if (productOpt.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body("Unknown productId: " + req.productId());
|
||||
}
|
||||
|
||||
Sku sku = new Sku();
|
||||
sku.setProduct(productOpt.get());
|
||||
sku.setSkuCode(req.skuCode());
|
||||
sku.setSize(req.size());
|
||||
sku.setColor(req.color());
|
||||
sku.setPrice(req.price());
|
||||
|
||||
return ResponseEntity.ok(skuRepo.save(sku));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.voyage.workspace.products;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public record SkuCreateRequest(
|
||||
Long productId,
|
||||
String skuCode,
|
||||
String size,
|
||||
String color,
|
||||
BigDecimal price
|
||||
) {}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.voyage.workspace.products;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface SkuRepository extends JpaRepository<Sku, Long> {
|
||||
List<Sku> findByProductId(Long productId);
|
||||
Optional<Sku> findBySkuCode(String skuCode);
|
||||
}
|
||||
Reference in New Issue
Block a user