Merge branch 'AttachmentsToChat'
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package com.petshop.backend.controller;
|
||||
|
||||
import com.petshop.backend.dto.common.BulkDeleteRequest;
|
||||
import com.petshop.backend.dto.common.CouponRequest;
|
||||
import com.petshop.backend.dto.common.CouponResponse;
|
||||
import com.petshop.backend.service.CouponService;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/coupons")
|
||||
@PreAuthorize("hasAnyRole('STAFF', 'ADMIN')")
|
||||
public class CouponController {
|
||||
|
||||
private final CouponService couponService;
|
||||
|
||||
public CouponController(CouponService couponService) {
|
||||
this.couponService = couponService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<Page<CouponResponse>> getAllCoupons(
|
||||
@RequestParam(required = false) String q,
|
||||
@RequestParam(required = false) Boolean active,
|
||||
Pageable pageable) {
|
||||
return ResponseEntity.ok(couponService.getAllCoupons(q, active, pageable));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<CouponResponse> getCouponById(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(couponService.getCouponById(id));
|
||||
}
|
||||
|
||||
@GetMapping("/code/{code}")
|
||||
public ResponseEntity<CouponResponse> getCouponByCode(@PathVariable String code) {
|
||||
return ResponseEntity.ok(couponService.getCouponByCode(code));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<CouponResponse> createCoupon(@Valid @RequestBody CouponRequest request) {
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(couponService.createCoupon(request));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<CouponResponse> updateCoupon(@PathVariable Long id, @Valid @RequestBody CouponRequest request) {
|
||||
return ResponseEntity.ok(couponService.updateCoupon(id, request));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<Void> deleteCoupon(@PathVariable Long id) {
|
||||
couponService.deleteCoupon(id);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public ResponseEntity<Void> bulkDeleteCoupons(@Valid @RequestBody BulkDeleteRequest request) {
|
||||
couponService.bulkDeleteCoupons(request);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,9 @@ public class SaleController {
|
||||
@RequestParam(required = false) String q,
|
||||
@RequestParam(required = false) String paymentMethod,
|
||||
@RequestParam(required = false) Long storeId,
|
||||
@RequestParam(required = false) Boolean isRefund,
|
||||
Pageable pageable) {
|
||||
return ResponseEntity.ok(saleService.getAllSales(q, paymentMethod, storeId, pageable));
|
||||
return ResponseEntity.ok(saleService.getAllSales(q, paymentMethod, storeId, isRefund, pageable));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.petshop.backend.dto.common;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class CouponRequest {
|
||||
@NotBlank(message = "Coupon code is required")
|
||||
private String couponCode;
|
||||
|
||||
@NotBlank(message = "Discount type is required")
|
||||
private String discountType;
|
||||
|
||||
@NotNull(message = "Discount value is required")
|
||||
@Positive(message = "Discount value must be positive")
|
||||
private BigDecimal discountValue;
|
||||
|
||||
private BigDecimal minOrderAmount;
|
||||
|
||||
private Boolean active = true;
|
||||
|
||||
private LocalDateTime startsAt;
|
||||
|
||||
private LocalDateTime endsAt;
|
||||
|
||||
private Integer usageLimit;
|
||||
|
||||
public String getCouponCode() { return couponCode; }
|
||||
public void setCouponCode(String couponCode) { this.couponCode = couponCode; }
|
||||
|
||||
public String getDiscountType() { return discountType; }
|
||||
public void setDiscountType(String discountType) { this.discountType = discountType; }
|
||||
|
||||
public BigDecimal getDiscountValue() { return discountValue; }
|
||||
public void setDiscountValue(BigDecimal discountValue) { this.discountValue = discountValue; }
|
||||
|
||||
public BigDecimal getMinOrderAmount() { return minOrderAmount; }
|
||||
public void setMinOrderAmount(BigDecimal minOrderAmount) { this.minOrderAmount = minOrderAmount; }
|
||||
|
||||
public Boolean getActive() { return active; }
|
||||
public void setActive(Boolean active) { this.active = active; }
|
||||
|
||||
public LocalDateTime getStartsAt() { return startsAt; }
|
||||
public void setStartsAt(LocalDateTime startsAt) { this.startsAt = startsAt; }
|
||||
|
||||
public LocalDateTime getEndsAt() { return endsAt; }
|
||||
public void setEndsAt(LocalDateTime endsAt) { this.endsAt = endsAt; }
|
||||
|
||||
public Integer getUsageLimit() { return usageLimit; }
|
||||
public void setUsageLimit(Integer usageLimit) { this.usageLimit = usageLimit; }
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.petshop.backend.dto.common;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class CouponResponse {
|
||||
private Long couponId;
|
||||
private String couponCode;
|
||||
private String discountType;
|
||||
private BigDecimal discountValue;
|
||||
private BigDecimal minOrderAmount;
|
||||
private Boolean active;
|
||||
private LocalDateTime startsAt;
|
||||
private LocalDateTime endsAt;
|
||||
private Integer usageLimit;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
public CouponResponse(Long couponId, String couponCode, String discountType, BigDecimal discountValue, BigDecimal minOrderAmount, Boolean active, LocalDateTime startsAt, LocalDateTime endsAt, Integer usageLimit, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
this.couponId = couponId;
|
||||
this.couponCode = couponCode;
|
||||
this.discountType = discountType;
|
||||
this.discountValue = discountValue;
|
||||
this.minOrderAmount = minOrderAmount;
|
||||
this.active = active;
|
||||
this.startsAt = startsAt;
|
||||
this.endsAt = endsAt;
|
||||
this.usageLimit = usageLimit;
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public Long getCouponId() { return couponId; }
|
||||
public void setCouponId(Long couponId) { this.couponId = couponId; }
|
||||
|
||||
public String getCouponCode() { return couponCode; }
|
||||
public void setCouponCode(String couponCode) { this.couponCode = couponCode; }
|
||||
|
||||
public String getDiscountType() { return discountType; }
|
||||
public void setDiscountType(String discountType) { this.discountType = discountType; }
|
||||
|
||||
public BigDecimal getDiscountValue() { return discountValue; }
|
||||
public void setDiscountValue(BigDecimal discountValue) { this.discountValue = discountValue; }
|
||||
|
||||
public BigDecimal getMinOrderAmount() { return minOrderAmount; }
|
||||
public void setMinOrderAmount(BigDecimal minOrderAmount) { this.minOrderAmount = minOrderAmount; }
|
||||
|
||||
public Boolean getActive() { return active; }
|
||||
public void setActive(Boolean active) { this.active = active; }
|
||||
|
||||
public LocalDateTime getStartsAt() { return startsAt; }
|
||||
public void setStartsAt(LocalDateTime startsAt) { this.startsAt = startsAt; }
|
||||
|
||||
public LocalDateTime getEndsAt() { return endsAt; }
|
||||
public void setEndsAt(LocalDateTime endsAt) { this.endsAt = endsAt; }
|
||||
|
||||
public Integer getUsageLimit() { return usageLimit; }
|
||||
public void setUsageLimit(Integer usageLimit) { this.usageLimit = usageLimit; }
|
||||
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
package com.petshop.backend.repository;
|
||||
|
||||
import com.petshop.backend.entity.Coupon;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -12,4 +16,8 @@ public interface CouponRepository extends JpaRepository<Coupon, Long> {
|
||||
Optional<Coupon> findByCouponCode(String couponCode);
|
||||
|
||||
Optional<Coupon> findByCouponCodeIgnoreCase(String couponCode);
|
||||
@Query("SELECT c FROM Coupon c WHERE " +
|
||||
"(:q IS NULL OR LOWER(c.couponCode) LIKE LOWER(CONCAT('%', :q, '%'))) AND " +
|
||||
"(:active IS NULL OR c.active = :active)")
|
||||
Page<Coupon> searchCoupons(@Param("q") String query, @Param("active") Boolean active, Pageable pageable);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@ public interface SaleRepository extends JpaRepository<Sale, Long> {
|
||||
"LOWER(s.store.storeName) LIKE LOWER(CONCAT('%', :q, '%'))" +
|
||||
")) AND " +
|
||||
"(:paymentMethod IS NULL OR LOWER(s.paymentMethod) = LOWER(:paymentMethod)) AND " +
|
||||
"(:isRefund IS NULL OR s.isRefund = :isRefund) AND " +
|
||||
"(:storeId IS NULL OR s.store.storeId = :storeId)")
|
||||
Page<Sale> searchSales(@Param("q") String query, @Param("paymentMethod") String paymentMethod, @Param("storeId") Long storeId, Pageable pageable);
|
||||
Page<Sale> searchSales(@Param("q") String query, @Param("paymentMethod") String paymentMethod, @Param("storeId") Long storeId, @Param("isRefund") Boolean isRefund, Pageable pageable);
|
||||
|
||||
List<Sale> findByOriginalSaleSaleId(Long originalSaleId);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public class AdoptionService {
|
||||
private static final String ADOPTION_STATUS_PENDING = "Pending";
|
||||
private static final String ADOPTION_STATUS_COMPLETED = "Completed";
|
||||
private static final String ADOPTION_STATUS_CANCELLED = "Cancelled";
|
||||
private static final String ADOPTION_STATUS_MISSED = "Missed";
|
||||
private static final String PET_STATUS_AVAILABLE = "Available";
|
||||
private static final String PET_STATUS_ADOPTED = "Adopted";
|
||||
|
||||
@@ -218,7 +219,10 @@ public class AdoptionService {
|
||||
if (ADOPTION_STATUS_CANCELLED.equalsIgnoreCase(trimmedStatus)) {
|
||||
return ADOPTION_STATUS_CANCELLED;
|
||||
}
|
||||
throw new IllegalArgumentException("Adoption status must be Pending, Completed, or Cancelled");
|
||||
if (ADOPTION_STATUS_MISSED.equalsIgnoreCase(trimmedStatus)) {
|
||||
return ADOPTION_STATUS_MISSED;
|
||||
}
|
||||
throw new IllegalArgumentException("Adoption status must be Pending, Completed, Cancelled, or Missed");
|
||||
}
|
||||
|
||||
private void validatePetAvailability(Pet pet, Long adoptionId, Long currentPetId) {
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.petshop.backend.service;
|
||||
|
||||
import com.petshop.backend.dto.common.BulkDeleteRequest;
|
||||
import com.petshop.backend.dto.common.CouponRequest;
|
||||
import com.petshop.backend.dto.common.CouponResponse;
|
||||
import com.petshop.backend.entity.Coupon;
|
||||
import com.petshop.backend.exception.ResourceNotFoundException;
|
||||
import com.petshop.backend.repository.CouponRepository;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class CouponService {
|
||||
|
||||
private final CouponRepository couponRepository;
|
||||
|
||||
public CouponService(CouponRepository couponRepository) {
|
||||
this.couponRepository = couponRepository;
|
||||
}
|
||||
|
||||
public Page<CouponResponse> getAllCoupons(String query, Boolean active, Pageable pageable) {
|
||||
return couponRepository.searchCoupons(query, active, pageable).map(this::mapToResponse);
|
||||
}
|
||||
|
||||
public CouponResponse getCouponById(Long id) {
|
||||
Coupon coupon = couponRepository.findById(id)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Coupon not found with id: " + id));
|
||||
return mapToResponse(coupon);
|
||||
}
|
||||
|
||||
public CouponResponse getCouponByCode(String code) {
|
||||
Coupon coupon = couponRepository.findByCouponCode(code)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Coupon not found with code: " + code));
|
||||
return mapToResponse(coupon);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CouponResponse createCoupon(CouponRequest request) {
|
||||
if (couponRepository.findByCouponCode(request.getCouponCode()).isPresent()) {
|
||||
throw new IllegalArgumentException("Coupon code already exists: " + request.getCouponCode());
|
||||
}
|
||||
|
||||
Coupon coupon = new Coupon();
|
||||
updateCouponFields(coupon, request);
|
||||
coupon = couponRepository.save(coupon);
|
||||
return mapToResponse(coupon);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CouponResponse updateCoupon(Long id, CouponRequest request) {
|
||||
Coupon coupon = couponRepository.findById(id)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Coupon not found with id: " + id));
|
||||
|
||||
couponRepository.findByCouponCode(request.getCouponCode()).ifPresent(existing -> {
|
||||
if (!existing.getCouponId().equals(id)) {
|
||||
throw new IllegalArgumentException("Coupon code already exists: " + request.getCouponCode());
|
||||
}
|
||||
});
|
||||
|
||||
updateCouponFields(coupon, request);
|
||||
coupon = couponRepository.save(coupon);
|
||||
return mapToResponse(coupon);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteCoupon(Long id) {
|
||||
if (!couponRepository.existsById(id)) {
|
||||
throw new ResourceNotFoundException("Coupon not found with id: " + id);
|
||||
}
|
||||
couponRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void bulkDeleteCoupons(BulkDeleteRequest request) {
|
||||
couponRepository.deleteAllById(request.getIds());
|
||||
}
|
||||
|
||||
private void updateCouponFields(Coupon coupon, CouponRequest request) {
|
||||
coupon.setCouponCode(request.getCouponCode());
|
||||
coupon.setDiscountType(request.getDiscountType());
|
||||
coupon.setDiscountValue(request.getDiscountValue());
|
||||
coupon.setMinOrderAmount(request.getMinOrderAmount());
|
||||
coupon.setActive(request.getActive());
|
||||
coupon.setStartsAt(request.getStartsAt());
|
||||
coupon.setEndsAt(request.getEndsAt());
|
||||
coupon.setUsageLimit(request.getUsageLimit());
|
||||
}
|
||||
|
||||
private CouponResponse mapToResponse(Coupon coupon) {
|
||||
return new CouponResponse(
|
||||
coupon.getCouponId(),
|
||||
coupon.getCouponCode(),
|
||||
coupon.getDiscountType(),
|
||||
coupon.getDiscountValue(),
|
||||
coupon.getMinOrderAmount(),
|
||||
coupon.getActive(),
|
||||
coupon.getStartsAt(),
|
||||
coupon.getEndsAt(),
|
||||
coupon.getUsageLimit(),
|
||||
coupon.getCreatedAt(),
|
||||
coupon.getUpdatedAt()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -39,8 +39,8 @@ public class SaleService {
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Page<SaleResponse> getAllSales(String query, String paymentMethod, Long storeId, Pageable pageable) {
|
||||
Page<Sale> sales = saleRepository.searchSales(normalizeFilter(query), normalizeFilter(paymentMethod), storeId, pageable);
|
||||
public Page<SaleResponse> getAllSales(String query, String paymentMethod, Long storeId, Boolean isRefund, Pageable pageable) {
|
||||
Page<Sale> sales = saleRepository.searchSales(normalizeFilter(query), normalizeFilter(paymentMethod), storeId, isRefund, pageable);
|
||||
return sales.map(this::mapToResponse);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user