Fixed sales invoice issues in Ecommerce
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
package com.kifi.api.controller.sales;
|
||||
|
||||
import com.kifi.api.entity.sales.SalesChannel;
|
||||
import com.kifi.api.service.sales.SalesChannelService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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/sales-channels")
|
||||
@RequiredArgsConstructor
|
||||
public class SalesChannelController {
|
||||
|
||||
private final SalesChannelService salesChannelService;
|
||||
|
||||
@GetMapping
|
||||
public Flux<SalesChannel> getSalesChannels(Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return salesChannelService.getActiveChannels(userId);
|
||||
}
|
||||
|
||||
@GetMapping("/all")
|
||||
public Flux<SalesChannel> getAllSalesChannels(Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return salesChannelService.getAllChannels(userId);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public Mono<SalesChannel> createSalesChannel(
|
||||
Authentication authentication,
|
||||
@RequestBody SalesChannel channel) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return salesChannelService.createChannel(userId, channel);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public Mono<SalesChannel> updateSalesChannel(
|
||||
@PathVariable Long id,
|
||||
Authentication authentication,
|
||||
@RequestBody SalesChannel channel) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return salesChannelService.updateChannel(userId, id, channel);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public Mono<Void> deleteSalesChannel(
|
||||
@PathVariable Long id,
|
||||
Authentication authentication) {
|
||||
Long userId = Long.valueOf(authentication.getDetails().toString());
|
||||
return salesChannelService.deleteChannel(userId, id);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,9 @@ public class BusinessFeature {
|
||||
@Column("barcode_source")
|
||||
private String barcodeSource;
|
||||
|
||||
@Column("enable_ecommerce_channels")
|
||||
private Boolean enableEcommerceChannels;
|
||||
|
||||
@Column("created_at")
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
|
||||
@@ -80,6 +80,21 @@ public class Invoice {
|
||||
@Column("emi_start_date")
|
||||
private LocalDate emiStartDate;
|
||||
|
||||
@Column("sales_channel_id")
|
||||
private Long salesChannelId;
|
||||
|
||||
@Column("sales_channel")
|
||||
private String salesChannel;
|
||||
|
||||
@Column("marketplace_order_id")
|
||||
private String marketplaceOrderId;
|
||||
|
||||
@Column("place_of_supply_state_id")
|
||||
private Long placeOfSupplyStateId;
|
||||
|
||||
@Column("place_of_supply")
|
||||
private String placeOfSupply;
|
||||
|
||||
@Column("created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.kifi.api.entity.sales;
|
||||
|
||||
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.Column;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table("sales_channels")
|
||||
public class SalesChannel {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Column("user_id")
|
||||
private Long userId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String code;
|
||||
|
||||
private String icon;
|
||||
|
||||
@Column("default_ledger_id")
|
||||
private Long defaultLedgerId;
|
||||
|
||||
@Column("is_active")
|
||||
@Builder.Default
|
||||
private Boolean isActive = true;
|
||||
|
||||
@Column("created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Column("updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.kifi.api.repository.sales;
|
||||
|
||||
import com.kifi.api.entity.sales.SalesChannel;
|
||||
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 SalesChannelRepository extends ReactiveCrudRepository<SalesChannel, Long> {
|
||||
|
||||
@Query("SELECT * FROM sales_channels WHERE (user_id = :userId OR user_id IS NULL) AND is_active = true ORDER BY id ASC")
|
||||
Flux<SalesChannel> findActiveChannelsForUser(Long userId);
|
||||
|
||||
@Query("SELECT * FROM sales_channels WHERE (user_id = :userId OR user_id IS NULL) ORDER BY id ASC")
|
||||
Flux<SalesChannel> findAllChannelsForUser(Long userId);
|
||||
|
||||
Mono<SalesChannel> findByIdAndUserId(Long id, Long userId);
|
||||
}
|
||||
@@ -37,6 +37,7 @@ public class BusinessService {
|
||||
.multiLocation(false)
|
||||
.bomReductionStrategy("COMPONENTS_ONLY")
|
||||
.stockDeductionOnInvoice(true)
|
||||
.enableEcommerceChannels(false)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.build());
|
||||
}
|
||||
@@ -51,6 +52,7 @@ public class BusinessService {
|
||||
if (feature.getBomReductionStrategy() != null) existing.setBomReductionStrategy(feature.getBomReductionStrategy());
|
||||
if (feature.getStockDeductionOnInvoice() != null) existing.setStockDeductionOnInvoice(feature.getStockDeductionOnInvoice());
|
||||
if (feature.getBarcodeSource() != null) existing.setBarcodeSource(feature.getBarcodeSource());
|
||||
if (feature.getEnableEcommerceChannels() != null) existing.setEnableEcommerceChannels(feature.getEnableEcommerceChannels());
|
||||
return businessFeatureRepository.save(existing);
|
||||
})
|
||||
.switchIfEmpty(Mono.defer(() -> {
|
||||
|
||||
@@ -225,6 +225,16 @@ public class InvoiceService {
|
||||
if (availItems.isEmpty()) {
|
||||
return Mono.just(BigDecimal.ZERO);
|
||||
}
|
||||
// Strict FIFO: Sort by purchase/creation date & time in ASCENDING order
|
||||
availItems.sort((a, b) -> {
|
||||
if (a.getCreatedAt() == null && b.getCreatedAt() == null) {
|
||||
return Long.compare(a.getId() != null ? a.getId() : 0L, b.getId() != null ? b.getId() : 0L);
|
||||
}
|
||||
if (a.getCreatedAt() == null) return 1;
|
||||
if (b.getCreatedAt() == null) return -1;
|
||||
int cmp = a.getCreatedAt().compareTo(b.getCreatedAt());
|
||||
return cmp != 0 ? cmp : Long.compare(a.getId() != null ? a.getId() : 0L, b.getId() != null ? b.getId() : 0L);
|
||||
});
|
||||
BigDecimal needed = soldQty;
|
||||
java.util.List<Mono<Void>> saves = new java.util.ArrayList<>();
|
||||
BigDecimal totalCost = BigDecimal.ZERO;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.kifi.api.service.sales;
|
||||
|
||||
import com.kifi.api.entity.sales.SalesChannel;
|
||||
import com.kifi.api.repository.sales.SalesChannelRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional
|
||||
public class SalesChannelService {
|
||||
|
||||
private final SalesChannelRepository salesChannelRepository;
|
||||
|
||||
public Flux<SalesChannel> getActiveChannels(Long userId) {
|
||||
return salesChannelRepository.findActiveChannelsForUser(userId);
|
||||
}
|
||||
|
||||
public Flux<SalesChannel> getAllChannels(Long userId) {
|
||||
return salesChannelRepository.findAllChannelsForUser(userId);
|
||||
}
|
||||
|
||||
public Mono<SalesChannel> createChannel(Long userId, SalesChannel channel) {
|
||||
channel.setUserId(userId);
|
||||
channel.setCreatedAt(LocalDateTime.now());
|
||||
channel.setUpdatedAt(LocalDateTime.now());
|
||||
if (channel.getIsActive() == null) {
|
||||
channel.setIsActive(true);
|
||||
}
|
||||
return salesChannelRepository.save(channel);
|
||||
}
|
||||
|
||||
public Mono<SalesChannel> updateChannel(Long userId, Long id, SalesChannel updated) {
|
||||
return salesChannelRepository.findByIdAndUserId(id, userId)
|
||||
.flatMap(existing -> {
|
||||
if (updated.getName() != null) existing.setName(updated.getName());
|
||||
if (updated.getCode() != null) existing.setCode(updated.getCode());
|
||||
if (updated.getIcon() != null) existing.setIcon(updated.getIcon());
|
||||
if (updated.getDefaultLedgerId() != null) existing.setDefaultLedgerId(updated.getDefaultLedgerId());
|
||||
if (updated.getIsActive() != null) existing.setIsActive(updated.getIsActive());
|
||||
existing.setUpdatedAt(LocalDateTime.now());
|
||||
return salesChannelRepository.save(existing);
|
||||
});
|
||||
}
|
||||
|
||||
public Mono<Void> deleteChannel(Long userId, Long id) {
|
||||
return salesChannelRepository.findByIdAndUserId(id, userId)
|
||||
.flatMap(salesChannelRepository::delete);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user