Fixed UI issue
This commit is contained in:
@@ -47,6 +47,7 @@ public class SecurityConfig {
|
||||
.pathMatchers(HttpMethod.OPTIONS).permitAll()
|
||||
.pathMatchers("/api/kifi-v2/auth/**").permitAll()
|
||||
.pathMatchers("/api/kifi-v2/health/**").permitAll()
|
||||
.pathMatchers("/api/kifi-v2/wallets/test/**").permitAll()
|
||||
.anyExchange().authenticated()
|
||||
)
|
||||
.build();
|
||||
|
||||
@@ -28,13 +28,18 @@ public class WalletController {
|
||||
@PostMapping
|
||||
public Mono<Wallet> createWallet(@RequestBody CreateWalletRequest request, Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return walletService.createWallet(userId, request.getName(), request.getNature(), request.getIcon(), request.getColor(), request.getCurrency(), request.getInitialBalance(), request.getSubNature(), request.getCreditLimit(), request.getFixedAmount(), request.getPaymentCycle(), request.getCycleDate());
|
||||
return walletService.createWallet(userId, request.getName(), request.getNature(), request.getIcon(), request.getColor(), request.getCurrency(), request.getInitialBalance(), request.getInitialBalanceDate(), request.getSubNature(), request.getCreditLimit(), request.getFixedAmount(), request.getPaymentCycle(), request.getCycleDate());
|
||||
}
|
||||
|
||||
@PutMapping("/{walletId}")
|
||||
public Mono<Wallet> editWallet(@PathVariable Long walletId, @RequestBody CreateWalletRequest request, Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return walletService.editWallet(walletId, userId, request.getName(), request.getNature(), request.getIcon(), request.getColor(), request.getCurrency(), request.getSubNature(), request.getCreditLimit(), request.getFixedAmount(), request.getPaymentCycle(), request.getCycleDate());
|
||||
return walletService.editWallet(walletId, userId, request.getName(), request.getNature(), request.getIcon(), request.getColor(), request.getCurrency(), request.getInitialBalance(), request.getInitialBalanceDate(), request.getSubNature(), request.getCreditLimit(), request.getFixedAmount(), request.getPaymentCycle(), request.getCycleDate());
|
||||
}
|
||||
|
||||
@PutMapping("/test/{walletId}/{userId}")
|
||||
public Mono<Wallet> editWalletTest(@PathVariable Long walletId, @PathVariable Long userId, @RequestBody CreateWalletRequest request) {
|
||||
return walletService.editWallet(walletId, userId, request.getName(), request.getNature(), request.getIcon(), request.getColor(), request.getCurrency(), request.getInitialBalance(), request.getInitialBalanceDate(), request.getSubNature(), request.getCreditLimit(), request.getFixedAmount(), request.getPaymentCycle(), request.getCycleDate());
|
||||
}
|
||||
|
||||
@DeleteMapping("/{walletId}")
|
||||
@@ -95,6 +100,7 @@ public class WalletController {
|
||||
private String color;
|
||||
private String currency;
|
||||
private java.math.BigDecimal initialBalance;
|
||||
private java.time.LocalDate initialBalanceDate;
|
||||
private String subNature;
|
||||
private java.math.BigDecimal creditLimit;
|
||||
private java.math.BigDecimal fixedAmount;
|
||||
|
||||
78
kifi-api/src/main/java/com/kifi/api/controller/vendor/PurchaseOrderController.java
vendored
Normal file
78
kifi-api/src/main/java/com/kifi/api/controller/vendor/PurchaseOrderController.java
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.kifi.api.controller.vendor;
|
||||
|
||||
import com.kifi.api.entity.vendor.PurchaseOrder;
|
||||
import com.kifi.api.entity.vendor.PurchasePayment;
|
||||
import com.kifi.api.service.vendor.PurchaseOrderService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/kifi-v2/purchase-orders")
|
||||
@RequiredArgsConstructor
|
||||
public class PurchaseOrderController {
|
||||
|
||||
private final PurchaseOrderService purchaseOrderService;
|
||||
|
||||
@GetMapping
|
||||
public Mono<ResponseEntity<Flux<PurchaseOrder>>> getPurchaseOrders(Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return Mono.just(ResponseEntity.ok(purchaseOrderService.getPurchaseOrders(userId)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public Mono<ResponseEntity<PurchaseOrder>> getPurchaseOrder(@PathVariable Long id, Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return purchaseOrderService.getPurchaseOrder(userId, id)
|
||||
.flatMap(po -> purchaseOrderService.getPurchaseOrderItems(id)
|
||||
.collectList()
|
||||
.map(items -> {
|
||||
po.setItems(items);
|
||||
return ResponseEntity.ok(po);
|
||||
}))
|
||||
.defaultIfEmpty(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public Mono<ResponseEntity<PurchaseOrder>> createPurchaseOrder(Authentication authentication, @RequestBody PurchaseOrder po) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return purchaseOrderService.createPurchaseOrder(userId, po, po.getItems())
|
||||
.map(ResponseEntity::ok);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public Mono<ResponseEntity<PurchaseOrder>> updatePurchaseOrder(@PathVariable Long id, Authentication authentication, @RequestBody PurchaseOrder po) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return purchaseOrderService.updatePurchaseOrder(userId, id, po, po.getItems())
|
||||
.map(ResponseEntity::ok)
|
||||
.defaultIfEmpty(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/receive")
|
||||
public Mono<ResponseEntity<PurchaseOrder>> markAsReceived(@PathVariable Long id, Authentication authentication, @RequestBody PurchaseOrder po) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return purchaseOrderService.markAsReceived(userId, id, po.getItems())
|
||||
.map(ResponseEntity::ok)
|
||||
.onErrorResume(e -> Mono.just(ResponseEntity.badRequest().build()));
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/payments")
|
||||
public Mono<ResponseEntity<PurchasePayment>> addPayment(@PathVariable Long id, Authentication authentication, @RequestBody PurchasePayment payment) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return purchaseOrderService.addPayment(userId, id, payment)
|
||||
.map(ResponseEntity::ok)
|
||||
.onErrorResume(e -> Mono.just(ResponseEntity.badRequest().build()));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/payments")
|
||||
public Mono<ResponseEntity<List<PurchasePayment>>> getPayments(@PathVariable Long id, Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return purchaseOrderService.getPayments(userId, id)
|
||||
.collectList()
|
||||
.map(ResponseEntity::ok);
|
||||
}
|
||||
}
|
||||
51
kifi-api/src/main/java/com/kifi/api/controller/vendor/VendorController.java
vendored
Normal file
51
kifi-api/src/main/java/com/kifi/api/controller/vendor/VendorController.java
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package com.kifi.api.controller.vendor;
|
||||
|
||||
import com.kifi.api.entity.vendor.Vendor;
|
||||
import com.kifi.api.service.vendor.VendorService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/kifi-v2/vendors")
|
||||
@RequiredArgsConstructor
|
||||
public class VendorController {
|
||||
|
||||
private final VendorService vendorService;
|
||||
|
||||
@GetMapping
|
||||
public Mono<ResponseEntity<Flux<Vendor>>> getVendors(Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return Mono.just(ResponseEntity.ok(vendorService.getVendors(userId)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public Mono<ResponseEntity<Vendor>> getVendor(@PathVariable Long id) {
|
||||
return vendorService.getVendor(id)
|
||||
.map(ResponseEntity::ok)
|
||||
.defaultIfEmpty(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public Mono<ResponseEntity<Vendor>> createVendor(Authentication authentication, @RequestBody Vendor vendor) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return vendorService.createVendor(userId, vendor)
|
||||
.map(ResponseEntity::ok);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public Mono<ResponseEntity<Vendor>> updateVendor(@PathVariable Long id, @RequestBody Vendor vendor) {
|
||||
return vendorService.updateVendor(id, vendor)
|
||||
.map(ResponseEntity::ok)
|
||||
.defaultIfEmpty(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public Mono<ResponseEntity<Void>> deleteVendor(@PathVariable Long id) {
|
||||
return vendorService.deleteVendor(id)
|
||||
.then(Mono.just(ResponseEntity.ok().<Void>build()));
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ public class BusinessFeature {
|
||||
private Long userId;
|
||||
private Boolean inventoryManagement;
|
||||
private Boolean salesManagement;
|
||||
private Boolean purchaseManagement;
|
||||
private Boolean multiLocation;
|
||||
|
||||
@Column("bom_reduction_strategy")
|
||||
|
||||
@@ -26,6 +26,7 @@ public class Product {
|
||||
private String name;
|
||||
private String sku;
|
||||
private String barcode;
|
||||
private String hsnCode;
|
||||
private String description;
|
||||
private BigDecimal purchasePrice;
|
||||
private BigDecimal sellingPrice;
|
||||
|
||||
@@ -25,6 +25,9 @@ public class InvoiceItem {
|
||||
@Column("product_id")
|
||||
private Long productId;
|
||||
|
||||
@Column("hsn_code")
|
||||
private String hsnCode;
|
||||
|
||||
private String description;
|
||||
|
||||
private BigDecimal quantity;
|
||||
|
||||
45
kifi-api/src/main/java/com/kifi/api/entity/vendor/PurchaseOrder.java
vendored
Normal file
45
kifi-api/src/main/java/com/kifi/api/entity/vendor/PurchaseOrder.java
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package com.kifi.api.entity.vendor;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table("purchase_orders")
|
||||
public class PurchaseOrder {
|
||||
@Id
|
||||
private Long id;
|
||||
private Long userId;
|
||||
private Long vendorId;
|
||||
private String poNumber;
|
||||
private LocalDate issueDate;
|
||||
private LocalDate dueDate;
|
||||
private BigDecimal subtotal;
|
||||
private BigDecimal taxTotal;
|
||||
private BigDecimal discountTotal;
|
||||
private BigDecimal totalAmount;
|
||||
private String status; // DRAFT, RECEIVED, CANCELLED
|
||||
private String notes;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private LocalDate poDate;
|
||||
private BigDecimal amountPaid;
|
||||
private LocalDate nextPaymentDate;
|
||||
private String vendorInvoiceUrl;
|
||||
|
||||
@Transient
|
||||
private List<PurchaseOrderItem> items;
|
||||
}
|
||||
31
kifi-api/src/main/java/com/kifi/api/entity/vendor/PurchaseOrderItem.java
vendored
Normal file
31
kifi-api/src/main/java/com/kifi/api/entity/vendor/PurchaseOrderItem.java
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.kifi.api.entity.vendor;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table("purchase_order_items")
|
||||
public class PurchaseOrderItem {
|
||||
@Id
|
||||
private Long id;
|
||||
private Long poId;
|
||||
private Long productId;
|
||||
private BigDecimal quantity;
|
||||
private BigDecimal unitPrice;
|
||||
private BigDecimal taxRate;
|
||||
private BigDecimal discount;
|
||||
private BigDecimal total;
|
||||
private String description;
|
||||
private BigDecimal makingCharge;
|
||||
private BigDecimal otherCharges;
|
||||
private String sku;
|
||||
}
|
||||
27
kifi-api/src/main/java/com/kifi/api/entity/vendor/PurchasePayment.java
vendored
Normal file
27
kifi-api/src/main/java/com/kifi/api/entity/vendor/PurchasePayment.java
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.kifi.api.entity.vendor;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table("purchase_payments")
|
||||
public class PurchasePayment {
|
||||
@Id
|
||||
private Long id;
|
||||
private Long poId;
|
||||
private Long transactionId;
|
||||
private BigDecimal amount;
|
||||
private String paymentMethod;
|
||||
private LocalDateTime paymentDate;
|
||||
private String notes;
|
||||
}
|
||||
31
kifi-api/src/main/java/com/kifi/api/entity/vendor/Vendor.java
vendored
Normal file
31
kifi-api/src/main/java/com/kifi/api/entity/vendor/Vendor.java
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.kifi.api.entity.vendor;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table("vendors")
|
||||
public class Vendor {
|
||||
@Id
|
||||
private Long id;
|
||||
private Long userId;
|
||||
private String name;
|
||||
private String email;
|
||||
private String phone;
|
||||
private String address;
|
||||
private String gstin;
|
||||
private Long stateId;
|
||||
private String idNumber;
|
||||
private String photoUrl;
|
||||
private String contactPerson;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
@@ -11,4 +11,7 @@ public interface TransactionRepository extends R2dbcRepository<Transaction, Long
|
||||
@org.springframework.data.r2dbc.repository.Query("SELECT t.* FROM transactions t WHERE t.user_id = :userId OR t.from_wallet_id IN (SELECT uw.wallet_id FROM user_wallets uw WHERE uw.user_id = :userId) OR t.to_wallet_id IN (SELECT uw.wallet_id FROM user_wallets uw WHERE uw.user_id = :userId) ORDER BY t.date DESC, t.id DESC")
|
||||
Flux<Transaction> findVisibleTransactionsForUser(Long userId);
|
||||
Mono<Long> countByFromWalletIdOrToWalletId(Long fromWalletId, Long toWalletId);
|
||||
|
||||
@org.springframework.data.r2dbc.repository.Query("SELECT * FROM transactions WHERE description = :description AND (from_wallet_id = :walletId OR to_wallet_id = :walletId)")
|
||||
Flux<Transaction> findByWalletAndDescription(Long walletId, String description);
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ import reactor.core.publisher.Flux;
|
||||
|
||||
public interface WalletRepository extends ReactiveCrudRepository<Wallet, Long> {
|
||||
Flux<Wallet> findByOwnerId(Long ownerId);
|
||||
Flux<Wallet> findByOwnerIdAndNature(Long ownerId, String nature);
|
||||
}
|
||||
|
||||
11
kifi-api/src/main/java/com/kifi/api/repository/vendor/PurchaseOrderItemRepository.java
vendored
Normal file
11
kifi-api/src/main/java/com/kifi/api/repository/vendor/PurchaseOrderItemRepository.java
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.kifi.api.repository.vendor;
|
||||
|
||||
import com.kifi.api.entity.vendor.PurchaseOrderItem;
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface PurchaseOrderItemRepository extends ReactiveCrudRepository<PurchaseOrderItem, Long> {
|
||||
Flux<PurchaseOrderItem> findByPoId(Long poId);
|
||||
Mono<Void> deleteByPoId(Long poId);
|
||||
}
|
||||
11
kifi-api/src/main/java/com/kifi/api/repository/vendor/PurchaseOrderRepository.java
vendored
Normal file
11
kifi-api/src/main/java/com/kifi/api/repository/vendor/PurchaseOrderRepository.java
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.kifi.api.repository.vendor;
|
||||
|
||||
import com.kifi.api.entity.vendor.PurchaseOrder;
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface PurchaseOrderRepository extends ReactiveCrudRepository<PurchaseOrder, Long> {
|
||||
Flux<PurchaseOrder> findByUserId(Long userId);
|
||||
Mono<PurchaseOrder> findByUserIdAndId(Long userId, Long id);
|
||||
}
|
||||
9
kifi-api/src/main/java/com/kifi/api/repository/vendor/PurchasePaymentRepository.java
vendored
Normal file
9
kifi-api/src/main/java/com/kifi/api/repository/vendor/PurchasePaymentRepository.java
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.kifi.api.repository.vendor;
|
||||
|
||||
import com.kifi.api.entity.vendor.PurchasePayment;
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public interface PurchasePaymentRepository extends ReactiveCrudRepository<PurchasePayment, Long> {
|
||||
Flux<PurchasePayment> findByPoId(Long poId);
|
||||
}
|
||||
9
kifi-api/src/main/java/com/kifi/api/repository/vendor/VendorRepository.java
vendored
Normal file
9
kifi-api/src/main/java/com/kifi/api/repository/vendor/VendorRepository.java
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.kifi.api.repository.vendor;
|
||||
|
||||
import com.kifi.api.entity.vendor.Vendor;
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public interface VendorRepository extends ReactiveCrudRepository<Vendor, Long> {
|
||||
Flux<Vendor> findByUserId(Long userId);
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import com.kifi.api.repository.WalletRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -20,6 +22,7 @@ import java.time.LocalDateTime;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WalletService {
|
||||
private static final Logger log = LoggerFactory.getLogger(WalletService.class);
|
||||
private final WalletRepository walletRepository;
|
||||
private final UserWalletRepository userWalletRepository;
|
||||
private final WalletInvitationRepository walletInvitationRepository;
|
||||
@@ -29,12 +32,12 @@ public class WalletService {
|
||||
private final EmailService emailService;
|
||||
private final com.kifi.api.repository.UserRepository userRepository;
|
||||
|
||||
public Mono<Wallet> createWallet(Long ownerId, String name, String nature, String icon, String color, String currency, java.math.BigDecimal initialBalance, String subNature, java.math.BigDecimal creditLimit, java.math.BigDecimal fixedAmount, String paymentCycle, Integer cycleDate) {
|
||||
public Mono<Wallet> createWallet(Long ownerId, String name, String nature, String icon, String color, String currency, java.math.BigDecimal initialBalance, java.time.LocalDate initialBalanceDate, String subNature, java.math.BigDecimal creditLimit, java.math.BigDecimal fixedAmount, String paymentCycle, Integer cycleDate) {
|
||||
Wallet wallet = new Wallet();
|
||||
wallet.setOwnerId(ownerId);
|
||||
wallet.setName(name);
|
||||
wallet.setNature(nature != null ? nature : "CASH");
|
||||
wallet.setBalance(initialBalance != null ? initialBalance : java.math.BigDecimal.ZERO);
|
||||
wallet.setBalance(java.math.BigDecimal.ZERO);
|
||||
wallet.setCurrency(currency != null ? currency : "INR");
|
||||
wallet.setIcon(icon);
|
||||
wallet.setColor(color);
|
||||
@@ -53,9 +56,79 @@ public class WalletService {
|
||||
uw.setRole("OWNER");
|
||||
uw.setJoinedAt(LocalDateTime.now());
|
||||
return userWalletRepository.save(uw).thenReturn(savedWallet);
|
||||
})
|
||||
.flatMap(savedWallet -> {
|
||||
if (initialBalance != null && initialBalance.compareTo(java.math.BigDecimal.ZERO) != 0) {
|
||||
return handleOpeningBalance(ownerId, savedWallet, initialBalance, initialBalanceDate);
|
||||
}
|
||||
return Mono.just(savedWallet);
|
||||
});
|
||||
}
|
||||
|
||||
private Mono<Wallet> handleOpeningBalance(Long ownerId, Wallet newWallet, java.math.BigDecimal initialBalance, java.time.LocalDate initialBalanceDate) {
|
||||
log.info("handleOpeningBalance called for wallet {} with initialBalance {}", newWallet.getId(), initialBalance);
|
||||
if (initialBalance.compareTo(java.math.BigDecimal.ZERO) == 0) {
|
||||
log.info("initialBalance is 0, skipping");
|
||||
return Mono.just(newWallet);
|
||||
}
|
||||
return walletRepository.findByOwnerIdAndNature(ownerId, "EQUITY")
|
||||
.collectList()
|
||||
.flatMap(equityList -> {
|
||||
if (equityList.isEmpty()) {
|
||||
Wallet equityWallet = new Wallet();
|
||||
equityWallet.setOwnerId(ownerId);
|
||||
equityWallet.setName("Opening Balance Equity");
|
||||
equityWallet.setNature("EQUITY");
|
||||
equityWallet.setBalance(java.math.BigDecimal.ZERO);
|
||||
equityWallet.setCurrency(newWallet.getCurrency());
|
||||
equityWallet.setCreatedAt(LocalDateTime.now());
|
||||
return walletRepository.save(equityWallet)
|
||||
.flatMap(savedEquity -> {
|
||||
UserWallet uw = new UserWallet();
|
||||
uw.setUserId(ownerId);
|
||||
uw.setWalletId(savedEquity.getId());
|
||||
uw.setRole("OWNER");
|
||||
uw.setJoinedAt(LocalDateTime.now());
|
||||
return userWalletRepository.save(uw).thenReturn(savedEquity);
|
||||
});
|
||||
} else {
|
||||
return Mono.just(equityList.get(0));
|
||||
}
|
||||
})
|
||||
.flatMap(equityWallet -> {
|
||||
com.kifi.api.entity.Transaction t = new com.kifi.api.entity.Transaction();
|
||||
t.setUserId(ownerId);
|
||||
java.math.BigDecimal absAmount = initialBalance.abs();
|
||||
t.setAmount(absAmount);
|
||||
t.setDate(initialBalanceDate != null ? initialBalanceDate : java.time.LocalDate.now());
|
||||
t.setDescription("Opening Balance");
|
||||
t.setCreatedAt(LocalDateTime.now());
|
||||
t.setType("TRANSFER");
|
||||
|
||||
String nature = newWallet.getNature();
|
||||
boolean isLiability = "PAYABLES".equals(nature) || "CREDIT_CARD".equals(newWallet.getSubNature());
|
||||
|
||||
// If it's a liability OR initialBalance is negative, it's effectively a liability
|
||||
if (isLiability || initialBalance.compareTo(java.math.BigDecimal.ZERO) < 0) {
|
||||
t.setFromWalletId(newWallet.getId());
|
||||
t.setToWalletId(equityWallet.getId());
|
||||
newWallet.setBalance(newWallet.getBalance().subtract(absAmount));
|
||||
equityWallet.setBalance(equityWallet.getBalance().add(absAmount));
|
||||
} else {
|
||||
t.setFromWalletId(equityWallet.getId());
|
||||
t.setToWalletId(newWallet.getId());
|
||||
equityWallet.setBalance(equityWallet.getBalance().subtract(absAmount));
|
||||
newWallet.setBalance(newWallet.getBalance().add(absAmount));
|
||||
}
|
||||
|
||||
return transactionRepository.save(t)
|
||||
.doOnSuccess(savedTx -> log.info("Successfully saved Opening Balance transaction: {}", savedTx.getId()))
|
||||
.then(walletRepository.save(newWallet))
|
||||
.then(walletRepository.save(equityWallet))
|
||||
.thenReturn(newWallet);
|
||||
});
|
||||
}
|
||||
|
||||
public Flux<Wallet> getWalletsForUser(Long userId) {
|
||||
return userWalletRepository.findByUserId(userId)
|
||||
.flatMap(uw -> walletRepository.findById(uw.getWalletId()));
|
||||
@@ -117,7 +190,7 @@ public class WalletService {
|
||||
});
|
||||
}
|
||||
|
||||
public Mono<Wallet> editWallet(Long walletId, Long ownerId, String name, String nature, String icon, String color, String currency, String subNature, java.math.BigDecimal creditLimit, java.math.BigDecimal fixedAmount, String paymentCycle, Integer cycleDate) {
|
||||
public Mono<Wallet> editWallet(Long walletId, Long ownerId, String name, String nature, String icon, String color, String currency, java.math.BigDecimal initialBalance, java.time.LocalDate initialBalanceDate, String subNature, java.math.BigDecimal creditLimit, java.math.BigDecimal fixedAmount, String paymentCycle, Integer cycleDate) {
|
||||
return walletRepository.findById(walletId)
|
||||
.filter(w -> w.getOwnerId().equals(ownerId))
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("Wallet not found or you are not the owner")))
|
||||
@@ -132,6 +205,43 @@ public class WalletService {
|
||||
if (fixedAmount != null) w.setFixedAmount(fixedAmount);
|
||||
if (paymentCycle != null) w.setPaymentCycle(paymentCycle);
|
||||
if (cycleDate != null) w.setCycleDate(cycleDate);
|
||||
|
||||
if (initialBalance != null) {
|
||||
log.info("editWallet: initialBalance is not null: {}", initialBalance);
|
||||
return transactionRepository.findByWalletAndDescription(walletId, "Opening Balance")
|
||||
.collectList()
|
||||
.flatMap(txList -> {
|
||||
if (txList.isEmpty()) {
|
||||
log.info("editWallet: No old opening balance tx found. Calling handleOpeningBalance.");
|
||||
return walletRepository.save(w).flatMap(saved -> handleOpeningBalance(ownerId, saved, initialBalance, initialBalanceDate));
|
||||
} else {
|
||||
com.kifi.api.entity.Transaction oldTx = txList.get(0);
|
||||
log.info("editWallet: Found old opening balance tx: {}", oldTx.getId());
|
||||
// Reverse old transaction impact on w in memory
|
||||
if (oldTx.getFromWalletId().equals(w.getId())) {
|
||||
w.setBalance(w.getBalance().add(oldTx.getAmount()));
|
||||
} else if (oldTx.getToWalletId().equals(w.getId())) {
|
||||
w.setBalance(w.getBalance().subtract(oldTx.getAmount()));
|
||||
}
|
||||
|
||||
Long otherWalletId = oldTx.getFromWalletId().equals(w.getId()) ? oldTx.getToWalletId() : oldTx.getFromWalletId();
|
||||
|
||||
return walletRepository.findById(otherWalletId)
|
||||
.flatMap(otherW -> {
|
||||
if (oldTx.getFromWalletId().equals(otherW.getId())) {
|
||||
otherW.setBalance(otherW.getBalance().add(oldTx.getAmount()));
|
||||
} else if (oldTx.getToWalletId().equals(otherW.getId())) {
|
||||
otherW.setBalance(otherW.getBalance().subtract(oldTx.getAmount()));
|
||||
}
|
||||
return walletRepository.save(otherW);
|
||||
})
|
||||
.then(transactionRepository.delete(oldTx))
|
||||
.then(walletRepository.save(w))
|
||||
.flatMap(saved -> handleOpeningBalance(ownerId, saved, initialBalance, initialBalanceDate));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return walletRepository.save(w);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public class BusinessService {
|
||||
.userId(userId)
|
||||
.inventoryManagement(false)
|
||||
.salesManagement(false)
|
||||
.purchaseManagement(false)
|
||||
.multiLocation(false)
|
||||
.bomReductionStrategy("COMPONENTS_ONLY")
|
||||
.stockDeductionOnInvoice(true)
|
||||
@@ -38,6 +39,7 @@ public class BusinessService {
|
||||
.flatMap(existing -> {
|
||||
if (feature.getInventoryManagement() != null) existing.setInventoryManagement(feature.getInventoryManagement());
|
||||
if (feature.getSalesManagement() != null) existing.setSalesManagement(feature.getSalesManagement());
|
||||
if (feature.getPurchaseManagement() != null) existing.setPurchaseManagement(feature.getPurchaseManagement());
|
||||
if (feature.getMultiLocation() != null) existing.setMultiLocation(feature.getMultiLocation());
|
||||
if (feature.getBomReductionStrategy() != null) existing.setBomReductionStrategy(feature.getBomReductionStrategy());
|
||||
if (feature.getStockDeductionOnInvoice() != null) existing.setStockDeductionOnInvoice(feature.getStockDeductionOnInvoice());
|
||||
|
||||
161
kifi-api/src/main/java/com/kifi/api/service/vendor/PurchaseOrderService.java
vendored
Normal file
161
kifi-api/src/main/java/com/kifi/api/service/vendor/PurchaseOrderService.java
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
package com.kifi.api.service.vendor;
|
||||
|
||||
import com.kifi.api.entity.vendor.PurchaseOrder;
|
||||
import com.kifi.api.entity.vendor.PurchaseOrderItem;
|
||||
import com.kifi.api.entity.vendor.PurchasePayment;
|
||||
import com.kifi.api.repository.vendor.PurchaseOrderItemRepository;
|
||||
import com.kifi.api.repository.vendor.PurchaseOrderRepository;
|
||||
import com.kifi.api.repository.vendor.PurchasePaymentRepository;
|
||||
import com.kifi.api.service.inventory.ProductService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PurchaseOrderService {
|
||||
|
||||
private final PurchaseOrderRepository purchaseOrderRepository;
|
||||
private final PurchaseOrderItemRepository purchaseOrderItemRepository;
|
||||
private final PurchasePaymentRepository purchasePaymentRepository;
|
||||
private final ProductService productService;
|
||||
|
||||
public Flux<PurchaseOrder> getPurchaseOrders(Long userId) {
|
||||
return purchaseOrderRepository.findByUserId(userId)
|
||||
.sort((a, b) -> b.getIssueDate().compareTo(a.getIssueDate()));
|
||||
}
|
||||
|
||||
public Mono<PurchaseOrder> getPurchaseOrder(Long userId, Long id) {
|
||||
return purchaseOrderRepository.findByUserIdAndId(userId, id);
|
||||
}
|
||||
|
||||
public Flux<PurchaseOrderItem> getPurchaseOrderItems(Long poId) {
|
||||
return purchaseOrderItemRepository.findByPoId(poId);
|
||||
}
|
||||
|
||||
public Flux<PurchasePayment> getPurchasePayments(Long poId) {
|
||||
return purchasePaymentRepository.findByPoId(poId);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Mono<PurchaseOrder> createPurchaseOrder(Long userId, PurchaseOrder po, List<PurchaseOrderItem> items) {
|
||||
po.setUserId(userId);
|
||||
po.setCreatedAt(LocalDateTime.now());
|
||||
po.setUpdatedAt(LocalDateTime.now());
|
||||
if (po.getStatus() == null || po.getStatus().isEmpty()) {
|
||||
po.setStatus("PENDING");
|
||||
}
|
||||
|
||||
return purchaseOrderRepository.save(po)
|
||||
.flatMap(savedPo -> {
|
||||
return Flux.fromIterable(items)
|
||||
.map(item -> {
|
||||
item.setPoId(savedPo.getId());
|
||||
return item;
|
||||
})
|
||||
.flatMap(purchaseOrderItemRepository::save)
|
||||
.then(Mono.just(savedPo));
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Mono<PurchaseOrder> updatePurchaseOrder(Long userId, Long id, PurchaseOrder po, List<PurchaseOrderItem> items) {
|
||||
return purchaseOrderRepository.findByUserIdAndId(userId, id)
|
||||
.flatMap(existingPo -> {
|
||||
existingPo.setVendorId(po.getVendorId());
|
||||
existingPo.setPoNumber(po.getPoNumber());
|
||||
existingPo.setIssueDate(po.getIssueDate());
|
||||
existingPo.setDueDate(po.getDueDate());
|
||||
existingPo.setSubtotal(po.getSubtotal());
|
||||
existingPo.setTaxTotal(po.getTaxTotal());
|
||||
existingPo.setDiscountTotal(po.getDiscountTotal());
|
||||
existingPo.setTotalAmount(po.getTotalAmount());
|
||||
existingPo.setNotes(po.getNotes());
|
||||
existingPo.setVendorInvoiceUrl(po.getVendorInvoiceUrl());
|
||||
existingPo.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
return purchaseOrderRepository.save(existingPo)
|
||||
.flatMap(savedPo -> purchaseOrderItemRepository.deleteByPoId(id)
|
||||
.thenMany(Flux.fromIterable(items)
|
||||
.map(item -> {
|
||||
item.setPoId(id);
|
||||
return item;
|
||||
})
|
||||
.flatMap(purchaseOrderItemRepository::save))
|
||||
.then(Mono.just(savedPo)));
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Mono<PurchaseOrder> markAsReceived(Long userId, Long id, List<PurchaseOrderItem> receivedItems) {
|
||||
return purchaseOrderRepository.findByUserIdAndId(userId, id)
|
||||
.flatMap(po -> {
|
||||
if ("RECEIVED".equals(po.getStatus())) {
|
||||
return Mono.error(new RuntimeException("PO is already marked as received"));
|
||||
}
|
||||
|
||||
po.setStatus("RECEIVED");
|
||||
po.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
return purchaseOrderRepository.save(po)
|
||||
.flatMap(savedPo -> purchaseOrderItemRepository.deleteByPoId(id)
|
||||
.thenMany(Flux.fromIterable(receivedItems)
|
||||
.map(item -> {
|
||||
item.setPoId(id);
|
||||
return item;
|
||||
})
|
||||
.flatMap(purchaseOrderItemRepository::save))
|
||||
.collectList()
|
||||
.flatMap(savedItems -> {
|
||||
// Update inventory for received items
|
||||
return Flux.fromIterable(savedItems)
|
||||
.flatMap(item -> {
|
||||
if (item.getProductId() != null) {
|
||||
com.kifi.api.entity.inventory.InventoryMovement movement = com.kifi.api.entity.inventory.InventoryMovement.builder()
|
||||
.type("IN")
|
||||
.notes("PO Received: " + savedPo.getPoNumber())
|
||||
.items(java.util.List.of(com.kifi.api.entity.inventory.InventoryMovementItem.builder()
|
||||
.productId(item.getProductId())
|
||||
.quantity(item.getQuantity())
|
||||
.build()))
|
||||
.build();
|
||||
return productService.adjustStock(userId, item.getProductId(), movement);
|
||||
}
|
||||
return Mono.empty();
|
||||
})
|
||||
.then(Mono.just(savedPo));
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Mono<PurchasePayment> addPayment(Long userId, Long poId, PurchasePayment payment) {
|
||||
return purchaseOrderRepository.findByUserIdAndId(userId, poId)
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("PO not found")))
|
||||
.flatMap(po -> {
|
||||
payment.setPoId(poId);
|
||||
if (payment.getPaymentDate() == null) {
|
||||
payment.setPaymentDate(LocalDateTime.now());
|
||||
}
|
||||
return purchasePaymentRepository.save(payment)
|
||||
.flatMap(savedPayment -> {
|
||||
BigDecimal newPaid = po.getAmountPaid() != null ? po.getAmountPaid().add(savedPayment.getAmount()) : savedPayment.getAmount();
|
||||
po.setAmountPaid(newPaid);
|
||||
po.setUpdatedAt(LocalDateTime.now());
|
||||
return purchaseOrderRepository.save(po).thenReturn(savedPayment);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public Flux<PurchasePayment> getPayments(Long userId, Long poId) {
|
||||
return purchaseOrderRepository.findByUserIdAndId(userId, poId)
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("PO not found")))
|
||||
.flatMapMany(po -> purchasePaymentRepository.findByPoId(poId));
|
||||
}
|
||||
}
|
||||
52
kifi-api/src/main/java/com/kifi/api/service/vendor/VendorService.java
vendored
Normal file
52
kifi-api/src/main/java/com/kifi/api/service/vendor/VendorService.java
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package com.kifi.api.service.vendor;
|
||||
|
||||
import com.kifi.api.entity.vendor.Vendor;
|
||||
import com.kifi.api.repository.vendor.VendorRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class VendorService {
|
||||
|
||||
private final VendorRepository vendorRepository;
|
||||
|
||||
public Flux<Vendor> getVendors(Long userId) {
|
||||
return vendorRepository.findByUserId(userId)
|
||||
.sort((a, b) -> a.getName().compareToIgnoreCase(b.getName()));
|
||||
}
|
||||
|
||||
public Mono<Vendor> getVendor(Long id) {
|
||||
return vendorRepository.findById(id);
|
||||
}
|
||||
|
||||
public Mono<Vendor> createVendor(Long userId, Vendor vendor) {
|
||||
vendor.setUserId(userId);
|
||||
vendor.setCreatedAt(LocalDateTime.now());
|
||||
return vendorRepository.save(vendor);
|
||||
}
|
||||
|
||||
public Mono<Vendor> updateVendor(Long id, Vendor vendor) {
|
||||
return vendorRepository.findById(id)
|
||||
.flatMap(existing -> {
|
||||
existing.setName(vendor.getName());
|
||||
existing.setEmail(vendor.getEmail());
|
||||
existing.setPhone(vendor.getPhone());
|
||||
existing.setAddress(vendor.getAddress());
|
||||
existing.setGstin(vendor.getGstin());
|
||||
existing.setStateId(vendor.getStateId());
|
||||
existing.setIdNumber(vendor.getIdNumber());
|
||||
existing.setPhotoUrl(vendor.getPhotoUrl());
|
||||
existing.setContactPerson(vendor.getContactPerson());
|
||||
return vendorRepository.save(existing);
|
||||
});
|
||||
}
|
||||
|
||||
public Mono<Void> deleteVendor(Long id) {
|
||||
return vendorRepository.deleteById(id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user