Fixed upto purchases and rate sync process
This commit is contained in:
@@ -9,20 +9,27 @@ import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/kifi-v2/inventory/commodity-rates")
|
||||
@RequiredArgsConstructor
|
||||
public class CommodityRateController {
|
||||
private final CommodityRateService rateService;
|
||||
|
||||
@GetMapping("/{commodityName}")
|
||||
public Flux<CommodityRateHistory> getRateHistory(@PathVariable String commodityName) {
|
||||
return rateService.getRateHistory(commodityName);
|
||||
@GetMapping("/latest")
|
||||
public Flux<CommodityRateHistory> getAllLatestRates() {
|
||||
return rateService.getAllLatestRates();
|
||||
}
|
||||
|
||||
@GetMapping("/{commodityName}/latest")
|
||||
public Mono<ResponseEntity<CommodityRateHistory>> getLatestRate(@PathVariable String commodityName) {
|
||||
return rateService.getLatestRate(commodityName)
|
||||
@GetMapping("/{commodityCode}")
|
||||
public Flux<CommodityRateHistory> getRateHistory(@PathVariable String commodityCode) {
|
||||
return rateService.getRateHistory(commodityCode);
|
||||
}
|
||||
|
||||
@GetMapping("/{commodityCode}/latest")
|
||||
public Mono<ResponseEntity<CommodityRateHistory>> getLatestRate(@PathVariable String commodityCode) {
|
||||
return rateService.getLatestRate(commodityCode)
|
||||
.map(ResponseEntity::ok)
|
||||
.defaultIfEmpty(ResponseEntity.notFound().build());
|
||||
}
|
||||
@@ -32,12 +39,28 @@ public class CommodityRateController {
|
||||
Authentication authentication,
|
||||
@RequestBody CommodityRateHistory rateHistory) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
String code = rateHistory.getCommodityCode() != null ? rateHistory.getCommodityCode() : rateHistory.getCommodityName();
|
||||
String name = rateHistory.getCommodityName() != null ? rateHistory.getCommodityName() : code;
|
||||
return rateService.addRate(
|
||||
rateHistory.getCommodityName(),
|
||||
code,
|
||||
name,
|
||||
rateHistory.getPurity(),
|
||||
rateHistory.getRate(),
|
||||
rateHistory.getSource() != null ? rateHistory.getSource() : "MANUAL",
|
||||
userId
|
||||
).map(ResponseEntity::ok);
|
||||
}
|
||||
|
||||
@PostMapping("/{commodityCode}/sync")
|
||||
public Mono<ResponseEntity<Map<String, Object>>> syncRatesToProducts(
|
||||
Authentication authentication,
|
||||
@PathVariable String commodityCode) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return rateService.syncRatesToProducts(commodityCode, userId)
|
||||
.map(count -> ResponseEntity.ok(Map.<String, Object>of(
|
||||
"commodityCode", commodityCode,
|
||||
"updatedCount", count,
|
||||
"message", "Successfully synced rates for " + count + " products"
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ public class ProductCategoryController {
|
||||
existing.setParentCategoryId(category.getParentCategoryId());
|
||||
existing.setHasChild(category.getHasChild());
|
||||
existing.setCommodityCode(category.getCommodityCode());
|
||||
existing.setPurityFactor(category.getPurityFactor() != null ? category.getPurityFactor() : 1.0);
|
||||
existing.setDefaultHsn(category.getDefaultHsn());
|
||||
existing.setDefaultGst(category.getDefaultGst());
|
||||
existing.setHuidRequired(category.getHuidRequired());
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.time.LocalDateTime;
|
||||
public class CommodityRateHistory {
|
||||
@Id
|
||||
private Long id;
|
||||
private String commodityCode;
|
||||
private String commodityName;
|
||||
private String purity;
|
||||
private BigDecimal rate;
|
||||
|
||||
@@ -24,6 +24,8 @@ public class ProductCategory {
|
||||
@Builder.Default
|
||||
private Boolean hasChild = false;
|
||||
private String commodityCode;
|
||||
@Builder.Default
|
||||
private Double purityFactor = 1.0;
|
||||
private String defaultHsn;
|
||||
private java.math.BigDecimal defaultGst;
|
||||
@Builder.Default
|
||||
|
||||
@@ -4,8 +4,10 @@ import com.kifi.api.entity.TransactionItem;
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Repository
|
||||
public interface TransactionItemRepository extends ReactiveCrudRepository<TransactionItem, Long> {
|
||||
Flux<TransactionItem> findByTransactionId(Long transactionId);
|
||||
Mono<Void> deleteByTransactionId(Long transactionId);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
package com.kifi.api.repository.inventory;
|
||||
|
||||
import com.kifi.api.entity.inventory.CommodityRateHistory;
|
||||
import org.springframework.data.r2dbc.repository.Query;
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface CommodityRateHistoryRepository extends ReactiveCrudRepository<CommodityRateHistory, Long> {
|
||||
Flux<CommodityRateHistory> findByCommodityCodeOrderByEffectiveAtDesc(String commodityCode);
|
||||
Flux<CommodityRateHistory> findByCommodityNameOrderByEffectiveAtDesc(String commodityName);
|
||||
|
||||
@Query("SELECT DISTINCT ON (commodity_code) * FROM commodity_rate_history WHERE commodity_code IS NOT NULL ORDER BY commodity_code, effective_at DESC")
|
||||
Flux<CommodityRateHistory> findLatestRatesForAllCommodities();
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ import reactor.core.publisher.Flux;
|
||||
|
||||
public interface ProductCategoryRepository extends ReactiveCrudRepository<ProductCategory, Long> {
|
||||
Flux<ProductCategory> findByUserId(Long userId);
|
||||
Flux<ProductCategory> findByUserIdAndCommodityCode(Long userId, String commodityCode);
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ public class TransactionService {
|
||||
public Mono<Transaction> updateTransaction(Long id, Long userId, Transaction updatedTransaction) {
|
||||
return transactionRepository.findById(id)
|
||||
.filter(t -> t.getUserId().equals(userId))
|
||||
.switchIfEmpty(Mono.error(new org.springframework.web.server.ResponseStatusException(org.springframework.http.HttpStatus.NOT_FOUND, "Transaction not found")))
|
||||
.flatMap(t -> {
|
||||
// Revert old balances
|
||||
Mono<Void> revertBalances = updateWalletBalances(t.getToWalletId(), t.getFromWalletId(), t.getAmount());
|
||||
@@ -152,9 +153,26 @@ public class TransactionService {
|
||||
t.setAmount(updatedTransaction.getAmount());
|
||||
t.setDate(updatedTransaction.getDate());
|
||||
t.setDescription(updatedTransaction.getDescription());
|
||||
t.setDueDate(updatedTransaction.getDueDate());
|
||||
t.setAlertSchedule(updatedTransaction.getAlertSchedule());
|
||||
t.setAlertTime(updatedTransaction.getAlertTime());
|
||||
|
||||
return revertBalances.then(applyNewBalances).then(transactionRepository.save(t));
|
||||
}).flatMap(this::populateItemsAndAttachments);
|
||||
})
|
||||
.flatMap(savedTx -> {
|
||||
Mono<Void> deleteOldItems = transactionItemRepository.deleteByTransactionId(savedTx.getId());
|
||||
Mono<Void> saveNewItems = Mono.empty();
|
||||
if (updatedTransaction.getItems() != null && !updatedTransaction.getItems().isEmpty()) {
|
||||
for (TransactionItem item : updatedTransaction.getItems()) {
|
||||
item.setId(null);
|
||||
item.setTransactionId(savedTx.getId());
|
||||
item.setCreatedAt(LocalDateTime.now());
|
||||
}
|
||||
saveNewItems = transactionItemRepository.saveAll(updatedTransaction.getItems()).then();
|
||||
}
|
||||
return deleteOldItems.then(saveNewItems).thenReturn(savedTx);
|
||||
})
|
||||
.flatMap(this::populateItemsAndAttachments);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
||||
@@ -1,38 +1,82 @@
|
||||
package com.kifi.api.service.inventory;
|
||||
|
||||
import com.kifi.api.entity.inventory.CommodityRateHistory;
|
||||
import com.kifi.api.entity.inventory.Product;
|
||||
import com.kifi.api.entity.inventory.ProductCategory;
|
||||
import com.kifi.api.repository.inventory.CommodityRateHistoryRepository;
|
||||
import com.kifi.api.repository.inventory.ProductCategoryRepository;
|
||||
import com.kifi.api.repository.inventory.ProductRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CommodityRateService {
|
||||
private final CommodityRateHistoryRepository rateHistoryRepository;
|
||||
private final ProductCategoryRepository productCategoryRepository;
|
||||
private final ProductRepository productRepository;
|
||||
|
||||
public Mono<CommodityRateHistory> addRate(String commodityName, String purity, BigDecimal rate, String source, Long userId) {
|
||||
public Mono<CommodityRateHistory> addRate(String commodityCode, String commodityName, String purity, BigDecimal rate, String source, Long userId) {
|
||||
CommodityRateHistory history = CommodityRateHistory.builder()
|
||||
.commodityName(commodityName)
|
||||
.commodityCode(commodityCode)
|
||||
.commodityName(commodityName != null && !commodityName.isEmpty() ? commodityName : commodityCode)
|
||||
.purity(purity)
|
||||
.rate(rate)
|
||||
.effectiveAt(LocalDateTime.now())
|
||||
.source(source)
|
||||
.source(source != null ? source : "MANUAL")
|
||||
.createdBy(userId)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.build();
|
||||
return rateHistoryRepository.save(history);
|
||||
}
|
||||
|
||||
public Flux<CommodityRateHistory> getRateHistory(String commodityName) {
|
||||
return rateHistoryRepository.findByCommodityNameOrderByEffectiveAtDesc(commodityName);
|
||||
public Flux<CommodityRateHistory> getRateHistory(String commodityCode) {
|
||||
return rateHistoryRepository.findByCommodityCodeOrderByEffectiveAtDesc(commodityCode)
|
||||
.switchIfEmpty(rateHistoryRepository.findByCommodityNameOrderByEffectiveAtDesc(commodityCode));
|
||||
}
|
||||
|
||||
public Mono<CommodityRateHistory> getLatestRate(String commodityName) {
|
||||
return getRateHistory(commodityName).next();
|
||||
public Mono<CommodityRateHistory> getLatestRate(String commodityCode) {
|
||||
return getRateHistory(commodityCode).next();
|
||||
}
|
||||
|
||||
public Flux<CommodityRateHistory> getAllLatestRates() {
|
||||
return rateHistoryRepository.findLatestRatesForAllCommodities();
|
||||
}
|
||||
|
||||
public Mono<Integer> syncRatesToProducts(String commodityCode, Long userId) {
|
||||
return getLatestRate(commodityCode)
|
||||
.flatMap(latestRate ->
|
||||
productCategoryRepository.findByUserIdAndCommodityCode(userId, commodityCode)
|
||||
.flatMap(category -> {
|
||||
double categoryPurity = category.getPurityFactor() != null ? category.getPurityFactor() : 1.0;
|
||||
return productRepository.findByCategoryId(category.getId())
|
||||
.flatMap(product -> {
|
||||
double productPurity = product.getPurityFactor() != null ? product.getPurityFactor() : categoryPurity;
|
||||
BigDecimal baseRate = latestRate.getRate().multiply(BigDecimal.valueOf(productPurity));
|
||||
|
||||
if ("WEIGHT_BASED".equalsIgnoreCase(product.getPriceCalcRule())) {
|
||||
BigDecimal making = product.getMakingCharges() != null ? BigDecimal.valueOf(product.getMakingCharges()) : BigDecimal.ZERO;
|
||||
BigDecimal newPrice = baseRate;
|
||||
if ("PERCENTAGE".equalsIgnoreCase(product.getMakingChargesType())) {
|
||||
newPrice = baseRate.add(baseRate.multiply(making).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
|
||||
} else {
|
||||
newPrice = baseRate.add(making);
|
||||
}
|
||||
product.setSellingPrice(newPrice.setScale(2, RoundingMode.HALF_UP));
|
||||
}
|
||||
product.setUpdatedAt(LocalDateTime.now());
|
||||
return productRepository.save(product);
|
||||
});
|
||||
})
|
||||
.collectList()
|
||||
.map(list -> list.size())
|
||||
)
|
||||
.defaultIfEmpty(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +201,8 @@ CREATE TABLE IF NOT EXISTS product_categories (
|
||||
default_gst DECIMAL(5, 2),
|
||||
huid_required BOOLEAN DEFAULT FALSE,
|
||||
default_making_charge DECIMAL(15, 2),
|
||||
making_charge_type VARCHAR(50),
|
||||
commodity_code VARCHAR(10),
|
||||
purity_factor DECIMAL(5, 4) DEFAULT 1.0,
|
||||
base_unit VARCHAR(20) DEFAULT 'pcs',
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
@@ -210,7 +211,8 @@ CREATE TABLE IF NOT EXISTS product_categories (
|
||||
|
||||
CREATE TABLE IF NOT EXISTS commodity_rate_history (
|
||||
id SERIAL PRIMARY KEY,
|
||||
commodity_name VARCHAR(100) NOT NULL,
|
||||
commodity_code VARCHAR(100) NOT NULL,
|
||||
commodity_name VARCHAR(100),
|
||||
purity VARCHAR(50),
|
||||
rate DECIMAL(15, 2) NOT NULL,
|
||||
effective_at TIMESTAMP NOT NULL,
|
||||
|
||||
Reference in New Issue
Block a user