Done Category, Product Catalogue, Customer, Vendor, Purchase Invoice Module
This commit is contained in:
17
kifi-api/TestJwt.java
Normal file
17
kifi-api/TestJwt.java
Normal file
@@ -0,0 +1,17 @@
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import java.util.HashMap;
|
||||
public class TestJwt {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
byte[] key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".getBytes();
|
||||
HashMap<String, Object> claims = new HashMap<>();
|
||||
claims.put("userId", 1L);
|
||||
String token = Jwts.builder().claims(claims).signWith(Keys.hmacShaKeyFor(key)).compact();
|
||||
Long parsed = Jwts.parser().verifyWith(Keys.hmacShaKeyFor(key)).build().parseSignedClaims(token).getPayload().get("userId", Long.class);
|
||||
System.out.println("Parsed: " + parsed);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,9 @@ USERNAME="technobee_admin"
|
||||
PASSWORD='M@tr!x#149@dm!N'
|
||||
IMAGE_NAME="kifi-api"
|
||||
TAG="latest"
|
||||
TAG_ONE="kifi-v2"
|
||||
FULL_IMAGE_NAME="$REGISTRY/$IMAGE_NAME:$TAG"
|
||||
FULL_IMAGE_NAME_ONE="$REGISTRY/$IMAGE_NAME:$TAG_ONE"
|
||||
|
||||
# Stop on any error
|
||||
set -e
|
||||
@@ -14,7 +16,7 @@ set -e
|
||||
echo "Logging into Docker registry: $REGISTRY..."
|
||||
echo "$PASSWORD" | docker login "$REGISTRY" -u "$USERNAME" --password-stdin
|
||||
|
||||
echo "Building and pushing Docker image for linux/amd64: $FULL_IMAGE_NAME..."
|
||||
docker buildx build --platform linux/amd64 -t "$FULL_IMAGE_NAME" --push .
|
||||
echo "Building and pushing Docker image for linux/amd64: $FULL_IMAGE_NAME and $FULL_IMAGE_NAME_ONE..."
|
||||
docker buildx build --no-cache --platform linux/amd64 -t "$FULL_IMAGE_NAME" -t "$FULL_IMAGE_NAME_ONE" --push .
|
||||
|
||||
echo "Done! Image built and pushed successfully."
|
||||
|
||||
@@ -45,10 +45,11 @@ public class SecurityConfig {
|
||||
.securityContextRepository(securityContextRepository)
|
||||
.authorizeExchange(exchange -> exchange
|
||||
.pathMatchers(HttpMethod.OPTIONS).permitAll()
|
||||
.pathMatchers("/api/kifi-v2/auth/**").permitAll()
|
||||
.pathMatchers("/api/kifi-v2/health/**").permitAll()
|
||||
.pathMatchers("/api/kifi-v2/auth/**", "/api/kifi-v2/categories/**", "/api/kifi-v2/purchase-orders/test/**").permitAll()
|
||||
.pathMatchers("/api/kifi-v2/health/**", "/api/kifi-v2/upload/view**").permitAll()
|
||||
.pathMatchers("/api/kifi-v2/wallets/test/**").permitAll()
|
||||
.pathMatchers("/public/legal/**").permitAll()
|
||||
.pathMatchers("/test/**").permitAll()
|
||||
.anyExchange().authenticated()
|
||||
)
|
||||
.build();
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.kifi.api.controller;
|
||||
|
||||
import com.kifi.api.service.MinioServiceClient;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.codec.multipart.FilePart;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/kifi-v2/upload")
|
||||
@RequiredArgsConstructor
|
||||
public class UploadController {
|
||||
|
||||
private final MinioServiceClient minioServiceClient;
|
||||
|
||||
@PostMapping
|
||||
public Mono<Map<String, String>> upload(@RequestPart("file") Mono<FilePart> filePartMono) {
|
||||
return filePartMono.flatMap(filePart ->
|
||||
DataBufferUtils.join(filePart.content())
|
||||
.flatMap(dataBuffer -> {
|
||||
byte[] bytes = new byte[dataBuffer.readableByteCount()];
|
||||
dataBuffer.read(bytes);
|
||||
DataBufferUtils.release(dataBuffer);
|
||||
|
||||
String base64 = Base64.getEncoder().encodeToString(bytes);
|
||||
String fileName = UUID.randomUUID().toString() + "-" + filePart.filename();
|
||||
|
||||
return minioServiceClient.uploadFile(
|
||||
"general",
|
||||
filePart.headers().getContentType() != null ? filePart.headers().getContentType().toString() : "application/octet-stream",
|
||||
fileName,
|
||||
base64
|
||||
).map(response -> Map.of("url", response.getFilePath()));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/view")
|
||||
public Mono<ResponseEntity<byte[]>> viewFile(@RequestParam("path") String path) {
|
||||
String contentType = "image/jpeg";
|
||||
if (path.endsWith(".png")) contentType = "image/png";
|
||||
else if (path.endsWith(".pdf")) contentType = "application/pdf";
|
||||
else if (path.endsWith(".webp")) contentType = "image/webp";
|
||||
|
||||
final String finalContentType = contentType;
|
||||
return minioServiceClient.downloadFile(contentType, path)
|
||||
.map(response -> {
|
||||
byte[] decodedBytes = Base64.getDecoder().decode(response.getBase64Content());
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_TYPE, finalContentType)
|
||||
.header(HttpHeaders.CACHE_CONTROL, "max-age=86400")
|
||||
.body(decodedBytes);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,12 @@ public class InventoryItemController {
|
||||
return inventoryItemService.getItemsByUserId(userId);
|
||||
}
|
||||
|
||||
@GetMapping("/product/{productId}")
|
||||
public Flux<InventoryItem> getItemsByProductId(@PathVariable Long productId, Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return inventoryItemService.getItemsByProductId(userId, productId);
|
||||
}
|
||||
|
||||
@GetMapping("/total-value")
|
||||
public Mono<ResponseEntity<BigDecimal>> getTotalInventoryValue(Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
|
||||
@@ -46,12 +46,12 @@ public class ProductCategoryController {
|
||||
existing.setName(category.getName());
|
||||
existing.setParentCategoryId(category.getParentCategoryId());
|
||||
existing.setHasChild(category.getHasChild());
|
||||
existing.setCommodityCode(category.getCommodityCode());
|
||||
existing.setDefaultHsn(category.getDefaultHsn());
|
||||
existing.setDefaultGst(category.getDefaultGst());
|
||||
existing.setHuidRequired(category.getHuidRequired());
|
||||
existing.setDefaultMakingCharge(category.getDefaultMakingCharge());
|
||||
existing.setMakingChargeType(category.getMakingChargeType());
|
||||
existing.setCalculationMethod(category.getCalculationMethod());
|
||||
existing.setBaseUnit(category.getBaseUnit());
|
||||
existing.setIsActive(category.getIsActive());
|
||||
existing.setSortOrder(category.getSortOrder());
|
||||
|
||||
@@ -24,6 +24,17 @@ public class PurchaseOrderController {
|
||||
return Mono.just(ResponseEntity.ok(purchaseOrderService.getPurchaseOrders(userId)));
|
||||
}
|
||||
|
||||
@GetMapping("/test/{id}")
|
||||
public Mono<ResponseEntity<PurchaseOrder>> testGet(@PathVariable Long id) {
|
||||
return purchaseOrderService.getPurchaseOrder(1L, id)
|
||||
.flatMap(po -> purchaseOrderService.getPurchaseOrderItems(id)
|
||||
.collectList()
|
||||
.map(items -> {
|
||||
po.setItems(items);
|
||||
return ResponseEntity.ok(po);
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public Mono<ResponseEntity<PurchaseOrder>> getPurchaseOrder(@PathVariable Long id, Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
@@ -31,6 +42,7 @@ public class PurchaseOrderController {
|
||||
.flatMap(po -> purchaseOrderService.getPurchaseOrderItems(id)
|
||||
.collectList()
|
||||
.map(items -> {
|
||||
System.out.println("Fetched PO ID " + id + ", Items count: " + items.size());
|
||||
po.setItems(items);
|
||||
return ResponseEntity.ok(po);
|
||||
}))
|
||||
@@ -40,6 +52,8 @@ public class PurchaseOrderController {
|
||||
@PostMapping
|
||||
public Mono<ResponseEntity<PurchaseOrder>> createPurchaseOrder(Authentication authentication, @RequestBody PurchaseOrder po) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
System.out.println("---- CREATE PO RECEIVED ITEMS ----");
|
||||
System.out.println(po.getItems());
|
||||
return purchaseOrderService.createPurchaseOrder(userId, po, po.getItems())
|
||||
.map(ResponseEntity::ok);
|
||||
}
|
||||
|
||||
@@ -23,4 +23,8 @@ public class InventoryMovementItem {
|
||||
private BigDecimal quantity;
|
||||
private BigDecimal unitPrice;
|
||||
private LocalDateTime createdAt;
|
||||
private String huid;
|
||||
private BigDecimal weight;
|
||||
private String photoUrl;
|
||||
private BigDecimal purchaseAmount;
|
||||
}
|
||||
|
||||
@@ -28,11 +28,9 @@ public class Product {
|
||||
private String barcode;
|
||||
private String hsnCode;
|
||||
private String description;
|
||||
private BigDecimal purchasePrice;
|
||||
private BigDecimal sellingPrice;
|
||||
private BigDecimal gstRate;
|
||||
private String dimensions;
|
||||
private BigDecimal weight;
|
||||
private String color;
|
||||
private String size;
|
||||
private String priceCalcRule;
|
||||
@@ -40,9 +38,6 @@ public class Product {
|
||||
private Double makingCharges;
|
||||
private String makingChargesType;
|
||||
private Double wastagePercentage;
|
||||
private BigDecimal minStock;
|
||||
private BigDecimal reorderLevel;
|
||||
private Boolean trackInventory;
|
||||
private Boolean isActive;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@@ -5,6 +5,7 @@ import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@@ -22,6 +23,7 @@ public class ProductCategory {
|
||||
private Long parentCategoryId;
|
||||
@Builder.Default
|
||||
private Boolean hasChild = false;
|
||||
private String commodityCode;
|
||||
private String defaultHsn;
|
||||
private java.math.BigDecimal defaultGst;
|
||||
@Builder.Default
|
||||
@@ -29,7 +31,6 @@ public class ProductCategory {
|
||||
private Double defaultMakingCharge;
|
||||
private String makingChargeType;
|
||||
|
||||
private String calculationMethod;
|
||||
private String baseUnit;
|
||||
|
||||
@Builder.Default
|
||||
|
||||
@@ -29,6 +29,9 @@ public class PurchaseOrder {
|
||||
private LocalDate dueDate;
|
||||
private BigDecimal subtotal;
|
||||
private BigDecimal taxTotal;
|
||||
private BigDecimal cgstTotal;
|
||||
private BigDecimal sgstTotal;
|
||||
private BigDecimal igstTotal;
|
||||
private BigDecimal discountTotal;
|
||||
private BigDecimal totalAmount;
|
||||
private String status; // DRAFT, RECEIVED, CANCELLED
|
||||
@@ -41,5 +44,16 @@ public class PurchaseOrder {
|
||||
private String vendorInvoiceUrl;
|
||||
|
||||
@Transient
|
||||
@com.fasterxml.jackson.annotation.JsonProperty(value = "items", access = com.fasterxml.jackson.annotation.JsonProperty.Access.READ_WRITE)
|
||||
private List<PurchaseOrderItem> items;
|
||||
|
||||
@com.fasterxml.jackson.annotation.JsonProperty("items")
|
||||
public List<PurchaseOrderItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@com.fasterxml.jackson.annotation.JsonProperty("items")
|
||||
public void setItems(List<PurchaseOrderItem> items) {
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,16 @@ public class PurchaseOrderItem {
|
||||
private BigDecimal quantity;
|
||||
private BigDecimal unitPrice;
|
||||
private BigDecimal taxRate;
|
||||
private BigDecimal cgstRate;
|
||||
private BigDecimal sgstRate;
|
||||
private BigDecimal igstRate;
|
||||
private BigDecimal discount;
|
||||
private BigDecimal total;
|
||||
private String description;
|
||||
private BigDecimal makingCharge;
|
||||
private BigDecimal otherCharges;
|
||||
private String sku;
|
||||
private String huid;
|
||||
private BigDecimal weight;
|
||||
private String photoUrl;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
public interface InventoryItemRepository extends ReactiveCrudRepository<InventoryItem, Long> {
|
||||
Flux<InventoryItem> findByUserId(Long userId);
|
||||
Flux<InventoryItem> findByUserIdAndProductId(Long userId, Long productId);
|
||||
Flux<InventoryItem> findByProductId(Long productId);
|
||||
Mono<InventoryItem> findByTagNumber(String tagNumber);
|
||||
Mono<InventoryItem> findByHuid(String huid);
|
||||
|
||||
@@ -25,7 +25,8 @@ public class AuthenticationManager implements ReactiveAuthenticationManager {
|
||||
if (jwtUtil.validateToken(authToken)) {
|
||||
Claims claims = jwtUtil.getAllClaimsFromToken(authToken);
|
||||
String email = claims.getSubject();
|
||||
Long userId = claims.get("userId", Long.class);
|
||||
Number userIdNumber = claims.get("userId", Number.class);
|
||||
Long userId = userIdNumber != null ? userIdNumber.longValue() : null;
|
||||
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
|
||||
email,
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.kifi.api.entity.business.BusinessProfile;
|
||||
import com.kifi.api.entity.business.BusinessFeature;
|
||||
import com.kifi.api.repository.business.BusinessProfileRepository;
|
||||
import com.kifi.api.repository.business.BusinessFeatureRepository;
|
||||
import com.kifi.api.util.CryptoUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -15,9 +16,15 @@ import java.time.LocalDateTime;
|
||||
public class BusinessService {
|
||||
private final BusinessProfileRepository businessProfileRepository;
|
||||
private final BusinessFeatureRepository businessFeatureRepository;
|
||||
private final CryptoUtils cryptoUtils;
|
||||
|
||||
public Mono<BusinessProfile> getProfileByUserId(Long userId) {
|
||||
return businessProfileRepository.findByUserId(userId);
|
||||
return businessProfileRepository.findByUserId(userId)
|
||||
.map(profile -> {
|
||||
profile.setPanNumber(cryptoUtils.decrypt(profile.getPanNumber()));
|
||||
profile.setGstin(cryptoUtils.decrypt(profile.getGstin()));
|
||||
return profile;
|
||||
});
|
||||
}
|
||||
|
||||
public Mono<BusinessFeature> getFeaturesByUserId(Long userId) {
|
||||
@@ -76,6 +83,8 @@ public class BusinessService {
|
||||
profile.setUserId(userId);
|
||||
profile.setCreatedAt(LocalDateTime.now());
|
||||
profile.setUpdatedAt(LocalDateTime.now());
|
||||
profile.setPanNumber(profile.getPanNumber());
|
||||
profile.setGstin(profile.getGstin());
|
||||
return businessProfileRepository.save(profile);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ public class InventoryItemService {
|
||||
return inventoryItemRepository.findByUserId(userId);
|
||||
}
|
||||
|
||||
public Flux<InventoryItem> getItemsByProductId(Long userId, Long productId) {
|
||||
return inventoryItemRepository.findByUserIdAndProductId(userId, productId);
|
||||
}
|
||||
|
||||
public Mono<InventoryItem> createItem(Long userId, InventoryItem item) {
|
||||
item.setUserId(userId);
|
||||
item.setCreatedAt(LocalDateTime.now());
|
||||
|
||||
@@ -67,7 +67,6 @@ public class ProductService {
|
||||
product.setCreatedAt(LocalDateTime.now());
|
||||
product.setUpdatedAt(LocalDateTime.now());
|
||||
if (product.getIsActive() == null) product.setIsActive(true);
|
||||
if (product.getTrackInventory() == null) product.setTrackInventory(true);
|
||||
if (product.getPriceCalcRule() == null) product.setPriceCalcRule("MANUAL");
|
||||
if (product.getPurityFactor() == null) product.setPurityFactor(1.0);
|
||||
return productRepository.save(product);
|
||||
@@ -81,10 +80,9 @@ public class ProductService {
|
||||
existingProduct.setSku(updatedProduct.getSku());
|
||||
existingProduct.setCategoryId(updatedProduct.getCategoryId());
|
||||
existingProduct.setUomId(updatedProduct.getUomId());
|
||||
existingProduct.setPurchasePrice(updatedProduct.getPurchasePrice());
|
||||
existingProduct.setSellingPrice(updatedProduct.getSellingPrice());
|
||||
existingProduct.setGstRate(updatedProduct.getGstRate());
|
||||
existingProduct.setWeight(updatedProduct.getWeight());
|
||||
existingProduct.setHsnCode(updatedProduct.getHsnCode());
|
||||
existingProduct.setColor(updatedProduct.getColor());
|
||||
existingProduct.setSize(updatedProduct.getSize());
|
||||
existingProduct.setDimensions(updatedProduct.getDimensions());
|
||||
@@ -93,9 +91,6 @@ public class ProductService {
|
||||
existingProduct.setMakingCharges(updatedProduct.getMakingCharges());
|
||||
existingProduct.setMakingChargesType(updatedProduct.getMakingChargesType());
|
||||
existingProduct.setWastagePercentage(updatedProduct.getWastagePercentage());
|
||||
existingProduct.setMinStock(updatedProduct.getMinStock());
|
||||
existingProduct.setReorderLevel(updatedProduct.getReorderLevel());
|
||||
existingProduct.setTrackInventory(updatedProduct.getTrackInventory());
|
||||
existingProduct.setIsActive(updatedProduct.getIsActive());
|
||||
existingProduct.setUpdatedAt(LocalDateTime.now());
|
||||
return productRepository.save(existingProduct);
|
||||
|
||||
@@ -35,14 +35,27 @@ public class PurchaseOrderService {
|
||||
private final LedgerService ledgerService;
|
||||
private final TransactionService transactionService;
|
||||
private final VendorRepository vendorRepository;
|
||||
private final com.kifi.api.repository.inventory.InventoryBalanceRepository inventoryBalanceRepository;
|
||||
|
||||
public Flux<PurchaseOrder> getPurchaseOrders(Long userId) {
|
||||
return purchaseOrderRepository.findByUserId(userId)
|
||||
.flatMap(po -> purchaseOrderItemRepository.findByPoId(po.getId())
|
||||
.collectList()
|
||||
.map(items -> {
|
||||
po.setItems(items);
|
||||
return po;
|
||||
}))
|
||||
.sort((a, b) -> b.getIssueDate().compareTo(a.getIssueDate()));
|
||||
}
|
||||
|
||||
public Mono<PurchaseOrder> getPurchaseOrder(Long userId, Long id) {
|
||||
return purchaseOrderRepository.findByUserIdAndId(userId, id);
|
||||
return purchaseOrderRepository.findByUserIdAndId(userId, id)
|
||||
.flatMap(po -> purchaseOrderItemRepository.findByPoId(po.getId())
|
||||
.collectList()
|
||||
.map(items -> {
|
||||
po.setItems(items);
|
||||
return po;
|
||||
}));
|
||||
}
|
||||
|
||||
public Flux<PurchaseOrderItem> getPurchaseOrderItems(Long poId) {
|
||||
@@ -64,13 +77,21 @@ public class PurchaseOrderService {
|
||||
|
||||
return purchaseOrderRepository.save(po)
|
||||
.flatMap(savedPo -> {
|
||||
if (items == null || items.isEmpty()) {
|
||||
savedPo.setItems(List.of());
|
||||
return Mono.just(savedPo);
|
||||
}
|
||||
return Flux.fromIterable(items)
|
||||
.map(item -> {
|
||||
item.setPoId(savedPo.getId());
|
||||
return item;
|
||||
})
|
||||
.flatMap(purchaseOrderItemRepository::save)
|
||||
.then(Mono.just(savedPo));
|
||||
.collectList()
|
||||
.map(savedItems -> {
|
||||
savedPo.setItems(savedItems);
|
||||
return savedPo;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -78,6 +99,9 @@ public class PurchaseOrderService {
|
||||
public Mono<PurchaseOrder> updatePurchaseOrder(Long userId, Long id, PurchaseOrder po, List<PurchaseOrderItem> items) {
|
||||
return purchaseOrderRepository.findByUserIdAndId(userId, id)
|
||||
.flatMap(existingPo -> {
|
||||
if (items == null) {
|
||||
return Mono.error(new IllegalArgumentException("Items cannot be null"));
|
||||
}
|
||||
existingPo.setVendorId(po.getVendorId());
|
||||
existingPo.setPoNumber(po.getPoNumber());
|
||||
existingPo.setIssueDate(po.getIssueDate());
|
||||
@@ -94,11 +118,16 @@ public class PurchaseOrderService {
|
||||
.flatMap(savedPo -> purchaseOrderItemRepository.deleteByPoId(id)
|
||||
.thenMany(Flux.fromIterable(items)
|
||||
.map(item -> {
|
||||
item.setId(null);
|
||||
item.setPoId(id);
|
||||
return item;
|
||||
})
|
||||
.flatMap(purchaseOrderItemRepository::save))
|
||||
.then(Mono.just(savedPo)));
|
||||
.collectList()
|
||||
.map(savedItems -> {
|
||||
savedPo.setItems(savedItems);
|
||||
return savedPo;
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -117,6 +146,7 @@ public class PurchaseOrderService {
|
||||
.flatMap(savedPo -> purchaseOrderItemRepository.deleteByPoId(id)
|
||||
.thenMany(Flux.fromIterable(receivedItems)
|
||||
.map(item -> {
|
||||
item.setId(null);
|
||||
item.setPoId(id);
|
||||
return item;
|
||||
})
|
||||
@@ -126,21 +156,34 @@ public class PurchaseOrderService {
|
||||
// Update inventory for received items
|
||||
return Flux.fromIterable(savedItems)
|
||||
.flatMap(item -> {
|
||||
if (item.getProductId() != null && item.getQuantity() != null && item.getQuantity().compareTo(BigDecimal.ZERO) > 0) {
|
||||
int quantity = item.getQuantity().intValue();
|
||||
return Flux.range(0, quantity)
|
||||
.flatMap(i -> {
|
||||
InventoryItem invItem = InventoryItem.builder()
|
||||
.userId(userId)
|
||||
.productId(item.getProductId())
|
||||
.vendorId(savedPo.getVendorId())
|
||||
.purchaseRef(savedPo.getPoNumber())
|
||||
.purchaseCost(item.getUnitPrice())
|
||||
.makingCharges(item.getMakingCharge())
|
||||
.sku(item.getSku() != null ? item.getSku() + "-" + (i + 1) : null)
|
||||
.build();
|
||||
return inventoryItemService.createItem(userId, invItem);
|
||||
})
|
||||
if (item.getProductId() != null) {
|
||||
InventoryItem invItem = InventoryItem.builder()
|
||||
.userId(userId)
|
||||
.productId(item.getProductId())
|
||||
.vendorId(savedPo.getVendorId())
|
||||
.purchaseRef(savedPo.getPoNumber())
|
||||
.purchaseCost(item.getUnitPrice())
|
||||
.makingCharges(item.getMakingCharge())
|
||||
.sku(item.getSku())
|
||||
.huid(item.getHuid())
|
||||
.grossWeight(item.getWeight())
|
||||
.netWeight(item.getWeight())
|
||||
.build();
|
||||
return inventoryItemService.createItem(userId, invItem)
|
||||
.then(inventoryBalanceRepository.findByProductIdAndLocationId(item.getProductId(), 2L) // Default location 2L
|
||||
.flatMap(balance -> {
|
||||
balance.setQuantity(balance.getQuantity().add(item.getWeight() != null ? item.getWeight() : BigDecimal.ONE));
|
||||
balance.setLastUpdated(LocalDateTime.now());
|
||||
return inventoryBalanceRepository.save(balance);
|
||||
})
|
||||
.switchIfEmpty(Mono.defer(() -> {
|
||||
com.kifi.api.entity.inventory.InventoryBalance newBalance = new com.kifi.api.entity.inventory.InventoryBalance();
|
||||
newBalance.setProductId(item.getProductId());
|
||||
newBalance.setLocationId(2L);
|
||||
newBalance.setQuantity(item.getWeight() != null ? item.getWeight() : BigDecimal.ONE);
|
||||
newBalance.setLastUpdated(LocalDateTime.now());
|
||||
return inventoryBalanceRepository.save(newBalance);
|
||||
})))
|
||||
.then(Mono.just(item));
|
||||
}
|
||||
return Mono.just(item);
|
||||
@@ -162,7 +205,11 @@ public class PurchaseOrderService {
|
||||
.build();
|
||||
return transactionService.addTransaction(userId, tx);
|
||||
})
|
||||
.thenReturn(savedPo);
|
||||
.thenReturn(savedPo)
|
||||
.map(poResult -> {
|
||||
poResult.setItems(savedItems);
|
||||
return poResult;
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -202,8 +202,7 @@ CREATE TABLE IF NOT EXISTS product_categories (
|
||||
huid_required BOOLEAN DEFAULT FALSE,
|
||||
default_making_charge DECIMAL(15, 2),
|
||||
making_charge_type VARCHAR(50),
|
||||
calculation_method VARCHAR(50) DEFAULT 'UNIT',
|
||||
base_unit VARCHAR(50) DEFAULT 'pcs',
|
||||
base_unit VARCHAR(20) DEFAULT 'pcs',
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
|
||||
26
kifi-api/src/test/java/RunSchema.java
Normal file
26
kifi-api/src/test/java/RunSchema.java
Normal file
@@ -0,0 +1,26 @@
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.Statement;
|
||||
|
||||
public class RunSchema {
|
||||
public static void main(String[] args) {
|
||||
String url = "jdbc:postgresql://localhost:5432/kifi_db";
|
||||
String user = "postgres";
|
||||
String password = "postgres";
|
||||
|
||||
try (Connection conn = DriverManager.getConnection(url, user, password);
|
||||
Statement stmt = conn.createStatement()) {
|
||||
|
||||
stmt.execute("ALTER TABLE purchase_orders ADD COLUMN IF NOT EXISTS cgst_total NUMERIC(10,2)");
|
||||
stmt.execute("ALTER TABLE purchase_orders ADD COLUMN IF NOT EXISTS sgst_total NUMERIC(10,2)");
|
||||
stmt.execute("ALTER TABLE purchase_orders ADD COLUMN IF NOT EXISTS igst_total NUMERIC(10,2)");
|
||||
stmt.execute("ALTER TABLE purchase_order_items ADD COLUMN IF NOT EXISTS cgst_rate NUMERIC(10,2)");
|
||||
stmt.execute("ALTER TABLE purchase_order_items ADD COLUMN IF NOT EXISTS sgst_rate NUMERIC(10,2)");
|
||||
stmt.execute("ALTER TABLE purchase_order_items ADD COLUMN IF NOT EXISTS igst_rate NUMERIC(10,2)");
|
||||
|
||||
System.out.println("Schema updated successfully!");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.kifi.api;
|
||||
import com.kifi.api.entity.vendor.PurchaseOrder;
|
||||
import com.kifi.api.entity.vendor.PurchaseOrderItem;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
public class PurchaseOrderJacksonTest {
|
||||
@Test
|
||||
public void testJackson() throws Exception {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String json = "{\"poNumber\": \"TEST-123\", \"items\": [{\"productId\": 1}]}";
|
||||
PurchaseOrder po = mapper.readValue(json, PurchaseOrder.class);
|
||||
System.out.println("Parsed items: " + po.getItems());
|
||||
if (po.getItems() == null || po.getItems().isEmpty()) {
|
||||
throw new RuntimeException("ITEMS NOT PARSED");
|
||||
}
|
||||
}
|
||||
}
|
||||
18
kifi-api/src/test/java/com/kifi/api/TestJackson.java
Normal file
18
kifi-api/src/test/java/com/kifi/api/TestJackson.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.kifi.api;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.kifi.api.entity.vendor.PurchaseOrder;
|
||||
import com.kifi.api.entity.vendor.PurchaseOrderItem;
|
||||
import java.util.List;
|
||||
|
||||
public class TestJackson {
|
||||
public static void main(String[] args) throws Exception {
|
||||
PurchaseOrder po = new PurchaseOrder();
|
||||
po.setId(5L);
|
||||
PurchaseOrderItem item = new PurchaseOrderItem();
|
||||
item.setId(6L);
|
||||
po.setItems(List.of(item));
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
System.out.println(mapper.writeValueAsString(po));
|
||||
}
|
||||
}
|
||||
19
kifi-api/src/test/java/com/kifi/api/TestService.java
Normal file
19
kifi-api/src/test/java/com/kifi/api/TestService.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.kifi.api;
|
||||
|
||||
import com.kifi.api.entity.vendor.PurchaseOrder;
|
||||
import com.kifi.api.service.vendor.PurchaseOrderService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
public class TestService {
|
||||
@Autowired
|
||||
private PurchaseOrderService service;
|
||||
|
||||
@Test
|
||||
public void testGetPO() {
|
||||
PurchaseOrder po = service.getPurchaseOrder(6L, 5L).block();
|
||||
System.out.println("ITEMS COUNT: " + po.getItems().size());
|
||||
}
|
||||
}
|
||||
15
kifi-api/src/test/java/com/kifi/api/TestUserMapping.java
Normal file
15
kifi-api/src/test/java/com/kifi/api/TestUserMapping.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package com.kifi.api;
|
||||
import com.kifi.api.repository.UserRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@SpringBootTest
|
||||
public class TestUserMapping {
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
@Test
|
||||
public void test() {
|
||||
var user = userRepository.findById(6L).block();
|
||||
System.out.println("STATUS_IS: " + user.getSetupStatus());
|
||||
}
|
||||
}
|
||||
11
kifi-api/test_flux.java
Normal file
11
kifi-api/test_flux.java
Normal file
@@ -0,0 +1,11 @@
|
||||
import reactor.core.publisher.Flux;
|
||||
public class test_flux {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
Flux.fromIterable(null).subscribe();
|
||||
System.out.println("Did not throw");
|
||||
} catch(Exception e) {
|
||||
System.out.println("Threw: " + e.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
kifi-api/test_flux2.class
Normal file
BIN
kifi-api/test_flux2.class
Normal file
Binary file not shown.
10
kifi-api/test_flux2.java
Normal file
10
kifi-api/test_flux2.java
Normal file
@@ -0,0 +1,10 @@
|
||||
public class test_flux2 {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
reactor.core.publisher.Flux.fromIterable(null).subscribe();
|
||||
System.out.println("Did not throw");
|
||||
} catch(Exception e) {
|
||||
System.out.println("Threw: " + e.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user