diff --git a/book-my-show/backend/java/bms-monolith/pom.xml b/book-my-show/backend/java/bms-monolith/pom.xml index a695f1f..296d940 100644 --- a/book-my-show/backend/java/bms-monolith/pom.xml +++ b/book-my-show/backend/java/bms-monolith/pom.xml @@ -75,6 +75,13 @@ 2.18.0 + + org.apache.commons + commons-lang3 + 3.12.0 + + + diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/BmsMonolithApplication.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/BmsMonolithApplication.java index f43b60d..85f8c87 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/BmsMonolithApplication.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/BmsMonolithApplication.java @@ -9,5 +9,4 @@ public class BmsMonolithApplication { public static void main(String[] args) { SpringApplication.run(BmsMonolithApplication.class, args); } - } diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/constants/BMSConstants.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/constants/BMSConstants.java new file mode 100644 index 0000000..025da37 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/constants/BMSConstants.java @@ -0,0 +1,14 @@ +package org.lbcc.bms.bms_monolith.admin.constants; + +public final class BMSConstants { + + private BMSConstants() { + } + + public static final String VENDOR_SERVICE_ERROR = "VENDOR_SERVICE_ERROR"; + public static final String VENDOR_SUCCESS_MESSAGE = "Vendors fetched successfully"; + public static final String VENDOR_UPDATE_SUCCESS_MESSAGE = "Vendor status updated successfully"; + + public static final String VENDOR_NOT_FOUND = "VENDOR_NOT_FOUND"; + public static final String INVALID_REQUEST = "INVALID_REQUEST"; +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/AdminVendorOnboardingController.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/AdminVendorOnboardingController.java new file mode 100644 index 0000000..72d3d87 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/AdminVendorOnboardingController.java @@ -0,0 +1,72 @@ +package org.lbcc.bms.bms_monolith.admin.controller; + +import jakarta.annotation.Nullable; +import jakarta.websocket.server.PathParam; +import org.lbcc.bms.bms_monolith.admin.dto.VendorOnboardResponse; +import org.lbcc.bms.bms_monolith.admin.constants.BMSConstants; +import org.lbcc.bms.bms_monolith.admin.dto.VendorSearchRequest; +import org.lbcc.bms.bms_monolith.common.entity.Vendor; +import org.lbcc.bms.bms_monolith.common.enums.VendorStatus; +import org.lbcc.bms.bms_monolith.admin.dto.VendorOnboardRequest; +import org.lbcc.bms.bms_monolith.admin.service.AdminService; +import org.lbcc.bms.bms_monolith.common.response.ApiListResponse; +import org.lbcc.bms.bms_monolith.common.response.ApiResponse; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.data.web.SortDefault; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +//TODO: all these endpoints will be allowed only by ADMIN + +@RequestMapping("/vendors") +@RestController +public class AdminVendorOnboardingController { + + private final AdminService adminService; + + public AdminVendorOnboardingController(AdminService adminService) { + this.adminService = adminService; + } + + @PostMapping() + public ResponseEntity> onboardNewVendor(@RequestBody VendorOnboardRequest vendorOnboardRequest) { + VendorOnboardResponse response = adminService.onboardNewVendor(vendorOnboardRequest); + ApiResponse apiResponse = ApiResponse.builder() + .success(true) + .message(BMSConstants.VENDOR_SUCCESS_MESSAGE) + .data(response) + .build(); + return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse); + } + + @PutMapping("/{vendorId}/{status}") + public ResponseEntity> updateVendorStatus(@PathVariable String vendorId, @PathVariable VendorStatus status) { + Vendor vendor = adminService.updatedVendorStatus(vendorId, status); + ApiResponse response = ApiResponse.builder() + .success(true) + .message(BMSConstants.VENDOR_UPDATE_SUCCESS_MESSAGE) + .data(vendor.getId().toString()) + .build(); + return ResponseEntity.ok(response); + } + + @GetMapping + public ResponseEntity> getAllVendors( + @Nullable @ModelAttribute() VendorSearchRequest searchRequest, + @PageableDefault(page = 0, size = 10) + @SortDefault(sort = "name", direction = Sort.Direction.ASC) Pageable pageable) { + + Page vendorsPage = adminService.searchVendors(searchRequest, pageable); + ApiListResponse response = ApiListResponse.builder() + .setPage(vendorsPage) + .success(true) + .message(BMSConstants.VENDOR_SUCCESS_MESSAGE) + .build(); + return ResponseEntity.ok(response); + } + +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/SeatTypeController.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/SeatTypeController.java new file mode 100644 index 0000000..1f12f69 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/SeatTypeController.java @@ -0,0 +1,36 @@ +package org.lbcc.bms.bms_monolith.admin.controller; + +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatTypeResponse; +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatTypesRequestDto; +import org.lbcc.bms.bms_monolith.common.entity.SeatType; +import org.lbcc.bms.bms_monolith.common.response.ApiListResponse; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/seat-types") +public class SeatTypeController { + + private final SeatTypeService seatTypeService; + + public SeatTypeController(SeatTypeService seatTypeService) { + this.seatTypeService = seatTypeService; + } + + @PostMapping + public ResponseEntity> createSeatType(@RequestBody SeatTypesRequestDto seatTypesRequestDto) { + SeatTypeResponse response = seatTypeService.createSeatType(seatTypesRequestDto); + ApiListResponse apiResponse = ApiListResponse.builder() + .success(true).message("Seat types created successfully") + .data(response.getSeatTypeIds().stream() + .map(id -> new SeatTypeResponse(List.of(id))) + .collect(Collectors.toList())).build(); + return ResponseEntity.ok(apiResponse); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/SeatTypeService.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/SeatTypeService.java new file mode 100644 index 0000000..f8fae7d --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/SeatTypeService.java @@ -0,0 +1,41 @@ +package org.lbcc.bms.bms_monolith.admin.controller; + +import lombok.extern.slf4j.Slf4j; +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatTypeDto; +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatTypeResponse; +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatTypesRequestDto; +import org.lbcc.bms.bms_monolith.admin.repository.SeatTypeRepository; +import org.lbcc.bms.bms_monolith.common.entity.SeatType; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class SeatTypeService { + + private final SeatTypeRepository seatTypeRepository; + + SeatTypeService(SeatTypeRepository seatTypeRepository) { + this.seatTypeRepository = seatTypeRepository; + } + + public SeatTypeResponse createSeatType(SeatTypesRequestDto seatTypesRequestDto) { + log.info("Creating seat type"); + List seatTypeDtos = seatTypesRequestDto.getSeatTypes(); + List seatTypes = seatTypeDtos.stream().map(SeatTypeDto::toEntity).toList(); + log.info("Saving seat types: {}", seatTypes); + List savedSeatTypes = seatTypeRepository.saveAll(seatTypes); + log.info("Seat types created successfully"); + return SeatTypeResponse.from(savedSeatTypes); + } + + public List getSeatTypes(List seatTypeIds) { + List uuidList = seatTypeIds.stream() + .map(UUID::fromString) + .collect(Collectors.toList()); + return seatTypeRepository.findAllById(uuidList); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/VenueController.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/VenueController.java new file mode 100644 index 0000000..1f77ea9 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/controller/VenueController.java @@ -0,0 +1,45 @@ +package org.lbcc.bms.bms_monolith.admin.controller; + +import org.lbcc.bms.bms_monolith.admin.dto.venue.VenueAddSeatsRequest; +import org.lbcc.bms.bms_monolith.admin.dto.venue.VenueDto; +import org.lbcc.bms.bms_monolith.admin.dto.venue.VenueOnboardResponse; +import org.lbcc.bms.bms_monolith.admin.service.VenueService; +import org.lbcc.bms.bms_monolith.common.entity.Venue; +import org.lbcc.bms.bms_monolith.common.response.ApiResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/venues") +public class VenueController { + + private final VenueService venueService; + + public VenueController(VenueService venueService) { + this.venueService = venueService; + } + + //onboard venue + @PostMapping() + public ResponseEntity onboardVenue(@RequestBody VenueDto venueDto) { + VenueOnboardResponse response = venueService.createVenue(venueDto); + ApiResponse apiResponse = ApiResponse.builder() + .success(true).message("Venue onboarded successfully") + .data(response).build(); + return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse); + } + + //add seats to venue + @PostMapping("/seats") + public ResponseEntity> addSeatsToVenue(@RequestBody VenueAddSeatsRequest request) { + Venue response = venueService.addSeatsToVenue(request.getVenueId(), request.getSeatDtos()); + ApiResponse apiResponse = ApiResponse.builder() + .success(true).message("Seats added successfully") + .data(response).build(); + return ResponseEntity.ok(apiResponse); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorDto.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorDto.java new file mode 100644 index 0000000..a95ec9e --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorDto.java @@ -0,0 +1,26 @@ +package org.lbcc.bms.bms_monolith.admin.dto; + +import lombok.Builder; +import lombok.Data; +import org.lbcc.bms.bms_monolith.common.dto.AddressDto; +import org.lbcc.bms.bms_monolith.common.enums.VendorStatus; + +import java.util.UUID; + +@Data +@Builder +public class VendorDto { + + private UUID id; + private String name; + private String contactNumber; + private String email; + private AddressDto address; + private String website; + private String gstNo; + private String panNo; + private VendorStatus status; + private String registrationDate; + private String logoUrl; + +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorOnboardRequest.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorOnboardRequest.java new file mode 100644 index 0000000..17b8cf2 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorOnboardRequest.java @@ -0,0 +1,66 @@ +package org.lbcc.bms.bms_monolith.admin.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Builder; +import lombok.Data; +import org.lbcc.bms.bms_monolith.common.dto.AddressDto; +import org.lbcc.bms.bms_monolith.common.entity.Vendor; +import org.lbcc.bms.bms_monolith.common.enums.VendorStatus; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDateTime; + +@Data +@Builder +public class VendorOnboardRequest { + + @NotBlank(message = "Vendor name is required") + @Size(min = 3, max = 30, message = "Vendor name must be at most 30 characters") + private String name; + + @NotBlank(message = "Contact is required") + @Pattern(regexp = "^[0-9]{10}$", message = "Invalid contact number. Please provide a 10 digit number.") + private String contactNumber; + + @NotBlank(message = "Email is required") + @Pattern(regexp = "^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+$", message = "Invalid email format. Please provide a valid email.") + private String email; + + @NotBlank(message = "Address is required") + private AddressDto address; + + @NotBlank(message = "Website is required") + private String website; + + @NotBlank(message = "GST number is required") + @Pattern(regexp = "^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[0-9]{1}[Z]{1}[0-9]{1}$", message = "Invalid GST number. Please provide a valid GST number.") + private String gstNo; + + @NotBlank(message = "PAN number is required") + @Pattern(regexp = "^[A-Z]{5}[0-9]{4}[A-Z]{1}$", message = "Invalid PAN number. Please provide a valid PAN number.") + private String panNo; + + @NotBlank(message = "Registration date is required") + @Pattern(regexp = "^[0-9]{2}-[0-9]{2}-[0-9]{4}$", message = "Invalid date format. Please use dd-MM-yyyy.") + private String registrationDate; + +// @NotNull(message = "Logo is required") + private MultipartFile logoFile; + + public static Vendor buildVendorFromDto(VendorOnboardRequest vendorOnboardRequest) { + return Vendor.builder() + .name(vendorOnboardRequest.getName()) + .contactNumber(vendorOnboardRequest.getContactNumber()) + .email(vendorOnboardRequest.getEmail()) + .address(AddressDto.addressDtoToAddress(vendorOnboardRequest.getAddress())) + .website(vendorOnboardRequest.getWebsite()) + .gstNo(vendorOnboardRequest.getGstNo()) + .panNo(vendorOnboardRequest.getPanNo()) + .registrationDate(LocalDateTime.parse(vendorOnboardRequest.getRegistrationDate())) + .logoUrl("logo-url-logo-url-logo-url-logo-url") + .status(VendorStatus.ACTIVE) + .build(); + } +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorOnboardResponse.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorOnboardResponse.java new file mode 100644 index 0000000..f82742b --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorOnboardResponse.java @@ -0,0 +1,15 @@ +package org.lbcc.bms.bms_monolith.admin.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.lbcc.bms.bms_monolith.common.enums.VendorStatus; + +@Data +@AllArgsConstructor +public class VendorOnboardResponse { + + private String vendorId; + private String vendorName; + private VendorStatus vendorStatus; + +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorSearchRequest.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorSearchRequest.java new file mode 100644 index 0000000..2e37eef --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorSearchRequest.java @@ -0,0 +1,18 @@ +package org.lbcc.bms.bms_monolith.admin.dto; + +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +@Data +public class VendorSearchRequest { + + private String vendorName; + private String vendorStatus; + private String registrationDate; + + public boolean hasSearchCriteria() { + return !StringUtils.isBlank(vendorName) || + !StringUtils.isBlank(vendorStatus) || + !StringUtils.isBlank(registrationDate); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorSearchResponse.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorSearchResponse.java new file mode 100644 index 0000000..d3c848e --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/VendorSearchResponse.java @@ -0,0 +1,28 @@ +package org.lbcc.bms.bms_monolith.admin.dto; + +import lombok.AllArgsConstructor; +import org.lbcc.bms.bms_monolith.common.dto.AddressDto; +import org.lbcc.bms.bms_monolith.common.entity.Vendor; + +import java.util.List; + +@AllArgsConstructor +public class VendorSearchResponse { + private List vendorDtoList; + + public static VendorDto buildVendorDtoFromVendor(Vendor vendor) { + return VendorDto.builder() + .id(vendor.getId()).name(vendor.getName()) + .contactNumber(vendor.getContactNumber()).email(vendor.getEmail()) + .address(AddressDto.addressToAddressDto(vendor.getAddress())) + .website(vendor.getWebsite()).gstNo(vendor.getGstNo()) + .panNo(vendor.getPanNo()).status(vendor.getStatus()) + .registrationDate(String.valueOf(vendor.getRegistrationDate())) + .logoUrl(vendor.getLogoUrl()) + .build(); + } + + public static List buildVendorDtoListFromVendorList(List vendorList) { + return vendorList.stream().map(VendorSearchResponse::buildVendorDtoFromVendor).toList(); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatDto.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatDto.java new file mode 100644 index 0000000..56a6742 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatDto.java @@ -0,0 +1,29 @@ +package org.lbcc.bms.bms_monolith.admin.dto.seat; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.lbcc.bms.bms_monolith.common.entity.Seat; +import org.lbcc.bms.bms_monolith.common.entity.SeatType; +import org.lbcc.bms.bms_monolith.common.entity.Venue; +import org.lbcc.bms.bms_monolith.common.enums.OperationalStatus; + +import java.util.List; +import java.util.Map; + +@AllArgsConstructor +@Data +public class SeatDto { + + private String seatTypeId; + private String label; // seat number like A1, B22, etc. + + public static Seat toEntity(SeatDto seatDto, Venue venue, Map seatTypeMap) { + SeatType seatType = seatTypeMap.get(seatDto.getSeatTypeId()); + return new Seat(seatType, venue, OperationalStatus.OPERATIONAL, seatDto.getLabel()); + } + + public static List seatDtoListToSeatList(List seatDtoList, Venue venue, Map seatTypeMap) { + return seatDtoList.stream().map(seatDto -> toEntity(seatDto, venue, seatTypeMap)).toList(); + } + +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypeDto.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypeDto.java new file mode 100644 index 0000000..c4451e0 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypeDto.java @@ -0,0 +1,19 @@ +package org.lbcc.bms.bms_monolith.admin.dto.seat; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.lbcc.bms.bms_monolith.common.entity.SeatType; + +import java.math.BigDecimal; + +@AllArgsConstructor +@Data +public class SeatTypeDto { + + private String label; + private BigDecimal price; + + public static SeatType toEntity(SeatTypeDto seatTypeDto) { + return new SeatType(seatTypeDto.getLabel(), seatTypeDto.getPrice()); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypeInShowDTO.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypeInShowDTO.java new file mode 100644 index 0000000..b67a9ce --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypeInShowDTO.java @@ -0,0 +1,24 @@ +package org.lbcc.bms.bms_monolith.admin.dto.seat; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +import java.math.BigDecimal; + +@Getter +@Setter +@AllArgsConstructor +@SuperBuilder +public class SeatTypeInShowDTO { + + @NotNull(message = "Seat type ID is required.") + private String seatTypeId; // ID of the seat type + + @NotNull(message = "label/type name is required.") + private String typeName; // E.g., Regular, VIP + + private BigDecimal price; // Price for this seat type +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypeResponse.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypeResponse.java new file mode 100644 index 0000000..1ec5973 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypeResponse.java @@ -0,0 +1,18 @@ +package org.lbcc.bms.bms_monolith.admin.dto.seat; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.lbcc.bms.bms_monolith.common.entity.SeatType; + +import java.util.List; + +@AllArgsConstructor +@Getter +public class SeatTypeResponse { + + private List seatTypeIds; + + public static SeatTypeResponse from(List seatTypes) { + return new SeatTypeResponse(seatTypes.stream().map(x -> x.getId().toString()).toList()); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypesRequestDto.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypesRequestDto.java new file mode 100644 index 0000000..6c5dfbb --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/seat/SeatTypesRequestDto.java @@ -0,0 +1,12 @@ +package org.lbcc.bms.bms_monolith.admin.dto.seat; + +import lombok.Data; + +import java.util.List; + +@Data +public class SeatTypesRequestDto { + + private List seatTypes; + +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/venue/VenueAddSeatsRequest.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/venue/VenueAddSeatsRequest.java new file mode 100644 index 0000000..755fd20 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/venue/VenueAddSeatsRequest.java @@ -0,0 +1,12 @@ +package org.lbcc.bms.bms_monolith.admin.dto.venue; + +import lombok.Data; +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatDto; + +import java.util.List; + +@Data +public class VenueAddSeatsRequest { + private String venueId; + private List seatDtos; +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/venue/VenueDto.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/venue/VenueDto.java new file mode 100644 index 0000000..d29802c --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/venue/VenueDto.java @@ -0,0 +1,37 @@ +package org.lbcc.bms.bms_monolith.admin.dto.venue; + +import lombok.Data; +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatDto; +import org.lbcc.bms.bms_monolith.common.dto.AddressDto; +import org.lbcc.bms.bms_monolith.common.entity.SeatType; +import org.lbcc.bms.bms_monolith.common.entity.Venue; +import org.lbcc.bms.bms_monolith.common.enums.OperationalStatus; +import org.lbcc.bms.bms_monolith.common.enums.VenueType; + +import java.util.List; +import java.util.Map; + +@Data +public class VenueDto { + private String id; + private String name; + private AddressDto address; + private String phone; + private String email; + private String website; + private String description; + private Integer totalSeatingCapacity; + private VenueType venueType; + private List seats; + + public static Venue toEntity(VenueDto venueDto, Map seatTypeMap) { + Venue venue = new Venue(); + venue.setName(venueDto.getName()); + venue.setAddress(AddressDto.addressDtoToAddress(venueDto.getAddress())); + venue.setTotalSeatingCapacity(venueDto.getTotalSeatingCapacity()); + venue.setOperationalStatus(OperationalStatus.OPERATIONAL); + venue.setVenueType(venueDto.getVenueType()); + venue.setSeats(SeatDto.seatDtoListToSeatList(venueDto.getSeats(), venue ,seatTypeMap)); + return venue; + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/venue/VenueOnboardResponse.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/venue/VenueOnboardResponse.java new file mode 100644 index 0000000..b4fb670 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/dto/venue/VenueOnboardResponse.java @@ -0,0 +1,11 @@ +package org.lbcc.bms.bms_monolith.admin.dto.venue; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class VenueOnboardResponse { + private String venueId; + private String venueName; +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/exceptions/AdminExceptionHandler.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/exceptions/AdminExceptionHandler.java new file mode 100644 index 0000000..c5e5caa --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/exceptions/AdminExceptionHandler.java @@ -0,0 +1,35 @@ +package org.lbcc.bms.bms_monolith.admin.exceptions; + +import lombok.extern.slf4j.Slf4j; +import org.lbcc.bms.bms_monolith.admin.controller.AdminVendorOnboardingController; +import org.lbcc.bms.bms_monolith.admin.constants.BMSConstants; +import org.lbcc.bms.bms_monolith.admin.controller.VenueController; +import org.lbcc.bms.bms_monolith.common.exception.GlobalExceptionHandler; +import org.lbcc.bms.bms_monolith.common.response.ApiErrorResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@Slf4j +@ControllerAdvice(assignableTypes = {AdminVendorOnboardingController.class, VenueController.class}) +public class AdminExceptionHandler { + + @ExceptionHandler(value = {Exception.class, RuntimeException.class}) + public ResponseEntity handleEventServiceException(Exception ex) { + log.error("Exception occurred in vendor operation ", ex); + return GlobalExceptionHandler.buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage(), BMSConstants.VENDOR_SERVICE_ERROR); + } + + @ExceptionHandler(VendorNotFoundException.class) + public ResponseEntity handleVendorNotFoundException(VendorNotFoundException ex) { + log.error("Vendor not found ", ex); + return GlobalExceptionHandler.buildErrorResponse(HttpStatus.NOT_FOUND, ex.getMessage(), BMSConstants.VENDOR_NOT_FOUND); + } + + @ExceptionHandler(InvalidRequest.class) + public ResponseEntity handleInvalidVendorRequest(InvalidRequest ex) { + log.error("Invalid vendor request ", ex); + return GlobalExceptionHandler.buildErrorResponse(HttpStatus.BAD_REQUEST, ex.getMessage(), BMSConstants.INVALID_REQUEST); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/exceptions/InvalidRequest.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/exceptions/InvalidRequest.java new file mode 100644 index 0000000..638808f --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/exceptions/InvalidRequest.java @@ -0,0 +1,8 @@ +package org.lbcc.bms.bms_monolith.admin.exceptions; + +public class InvalidRequest extends RuntimeException { + + public InvalidRequest(String message) { + super(message); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/exceptions/VendorNotFoundException.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/exceptions/VendorNotFoundException.java new file mode 100644 index 0000000..a39af73 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/exceptions/VendorNotFoundException.java @@ -0,0 +1,8 @@ +package org.lbcc.bms.bms_monolith.admin.exceptions; + +public class VendorNotFoundException extends RuntimeException { + + public VendorNotFoundException(String message) { + super(message); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/repository/SeatTypeRepository.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/repository/SeatTypeRepository.java new file mode 100644 index 0000000..815ed0c --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/repository/SeatTypeRepository.java @@ -0,0 +1,11 @@ +package org.lbcc.bms.bms_monolith.admin.repository; + +import org.lbcc.bms.bms_monolith.common.entity.SeatType; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface SeatTypeRepository extends JpaRepository { +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/repository/VendorRepository.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/repository/VendorRepository.java new file mode 100644 index 0000000..4a03aa3 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/repository/VendorRepository.java @@ -0,0 +1,18 @@ +package org.lbcc.bms.bms_monolith.admin.repository; + +import org.lbcc.bms.bms_monolith.common.entity.Vendor; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface VendorRepository extends JpaRepository , JpaSpecificationExecutor { + + List findByNameContaining(String vendorName); + + Optional findById(UUID vendorId); +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/repository/VenueRepository.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/repository/VenueRepository.java new file mode 100644 index 0000000..a0e4ccd --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/repository/VenueRepository.java @@ -0,0 +1,12 @@ +package org.lbcc.bms.bms_monolith.admin.repository; + +import org.lbcc.bms.bms_monolith.common.entity.Venue; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface VenueRepository extends JpaRepository { + +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/service/AdminService.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/service/AdminService.java new file mode 100644 index 0000000..54a8f4d --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/service/AdminService.java @@ -0,0 +1,88 @@ +package org.lbcc.bms.bms_monolith.admin.service; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.lbcc.bms.bms_monolith.admin.dto.*; +import org.lbcc.bms.bms_monolith.admin.exceptions.InvalidRequest; +import org.lbcc.bms.bms_monolith.common.entity.Vendor; +import org.lbcc.bms.bms_monolith.common.enums.VendorStatus; +import org.lbcc.bms.bms_monolith.common.response.ApiResponse; +import org.lbcc.bms.bms_monolith.admin.exceptions.VendorNotFoundException; +import org.lbcc.bms.bms_monolith.admin.repository.VendorRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; + +@Service +@Slf4j +public class AdminService { + + private final VendorRepository vendorRepository; + + public AdminService(VendorRepository vendorRepository) { + this.vendorRepository = vendorRepository; + } + + public VendorOnboardResponse onboardNewVendor(VendorOnboardRequest vendorOnboardRequest) { + log.info("Onboarding new vendor {}", vendorOnboardRequest.getName()); + //TODO: will save the logoFile to file storage like s3 and get the URL and then update the vendor object before saving + Vendor vendor = vendorRepository.save(VendorOnboardRequest.buildVendorFromDto(vendorOnboardRequest)); + log.info("Vendor onboarded successfully with id {}", vendor.getId()); + + return new VendorOnboardResponse(vendor.getId().toString(), vendor.getName(), vendor.getStatus()); + } + + public List searchVendor(String vendorName) { + if (StringUtils.isEmpty(vendorName)) { + throw new InvalidRequest("Vendor name cannot be empty"); + } + + log.info("Searching for vendor with name {}", vendorName); + List vendorList = vendorRepository.findByNameContaining(vendorName); + log.info("total vendors found {}", vendorList.size()); + return vendorList.isEmpty() ? List.of() : + VendorSearchResponse.buildVendorDtoListFromVendorList(vendorList); + + + } + + public Vendor findVendorById(UUID vendorId) { + if (vendorId == null) { + throw new InvalidRequest("Vendor id cannot be empty"); + } + return vendorRepository.findById(vendorId).orElseThrow(() -> new VendorNotFoundException("Vendor not found")); + } + + public Vendor updatedVendorStatus(String vendorId, VendorStatus vendorStatus) { + validateVendorUpdateRequest(vendorId, vendorStatus); + log.info("updating vendor with id {} to {} ", vendorId, vendorStatus); + Vendor vendor = findVendorById(UUID.fromString(vendorId)); + vendor.setStatus(vendorStatus); + vendorRepository.save(vendor); + log.info("Vendor id {} suspended successfully", vendorId); + return vendor; + } + + public Page searchVendors(VendorSearchRequest searchRequest, Pageable pageable) { + try { + Specification spec = VendorSpecifications.createSpecification(searchRequest); + return vendorRepository.findAll(spec, pageable); + } catch (Exception e) { + log.error("Error in searching vendors", e); + return Page.empty(); + } + } + + private void validateVendorUpdateRequest(String vendorId, VendorStatus vendorStatus) { + if (StringUtils.isEmpty(vendorId)) { + throw new InvalidRequest("Vendor id cannot be empty"); + } + if (vendorStatus == null || StringUtils.isEmpty(vendorStatus.name())) { + throw new InvalidRequest("Vendor status cannot be empty"); + } + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/service/VendorSpecifications.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/service/VendorSpecifications.java new file mode 100644 index 0000000..8b094da --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/service/VendorSpecifications.java @@ -0,0 +1,42 @@ +package org.lbcc.bms.bms_monolith.admin.service; + +import org.apache.commons.lang3.StringUtils; +import org.lbcc.bms.bms_monolith.admin.dto.VendorSearchRequest; +import org.lbcc.bms.bms_monolith.common.entity.Vendor; +import org.springframework.data.jpa.domain.Specification; + +import jakarta.persistence.criteria.Predicate; + +import java.util.ArrayList; +import java.util.List; + +public class VendorSpecifications { + + public static Specification createSpecification(VendorSearchRequest searchRequest) { + if (searchRequest == null) { + // return all vendors without applying any filters (Conjunction) + return (root, query, criteriaBuilder) -> criteriaBuilder.conjunction(); + } + + return (root, query, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + + if (StringUtils.isNotBlank(searchRequest.getVendorName())) { + predicates.add(criteriaBuilder.like( + criteriaBuilder.lower(root.get("vendorName")), + "%" + searchRequest.getVendorName().toLowerCase() + "%" + )); + } + if (StringUtils.isNotBlank(searchRequest.getVendorStatus())) { + predicates.add(criteriaBuilder.equal(root.get("vendorStatus"), searchRequest.getVendorStatus())); + } + if (searchRequest.getRegistrationDate() != null) { + predicates.add(criteriaBuilder.equal(root.get("registrationDate"), searchRequest.getRegistrationDate())); + } + + return predicates.isEmpty() + ? criteriaBuilder.conjunction() + : criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/service/VenueService.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/service/VenueService.java new file mode 100644 index 0000000..442ed58 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/admin/service/VenueService.java @@ -0,0 +1,66 @@ +package org.lbcc.bms.bms_monolith.admin.service; + +import lombok.extern.slf4j.Slf4j; +import org.lbcc.bms.bms_monolith.admin.controller.SeatTypeService; +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatDto; +import org.lbcc.bms.bms_monolith.admin.dto.venue.VenueDto; +import org.lbcc.bms.bms_monolith.admin.dto.venue.VenueOnboardResponse; +import org.lbcc.bms.bms_monolith.admin.repository.VenueRepository; +import org.lbcc.bms.bms_monolith.common.entity.Seat; +import org.lbcc.bms.bms_monolith.common.entity.SeatType; +import org.lbcc.bms.bms_monolith.common.entity.Venue; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class VenueService { + + private final VenueRepository venueRepository; + private final SeatTypeService seatTypeService; + + @Autowired + public VenueService(VenueRepository venueRepository, SeatTypeService seatTypeService) { + this.venueRepository = venueRepository; + this.seatTypeService = seatTypeService; + } + + public VenueOnboardResponse createVenue(VenueDto venueDto) { + List seatTypeIds = venueDto.getSeats().stream().map(SeatDto::getSeatTypeId).toList(); + List seatTypes = seatTypeService.getSeatTypes(seatTypeIds); + Map seatTypeMap = seatTypes.stream() + .collect(Collectors.toMap(seatType -> seatType.getId().toString(), seatType -> seatType)); + Venue venue = VenueDto.toEntity(venueDto, seatTypeMap); + log.info("Creating venue: {}", venue); + venueRepository.save(venue); + log.info("Venue created successfully: {}", venue); + return new VenueOnboardResponse(venue.getId().toString(), venue.getName()); + } + + public Venue getVenueById(String venueId) { + if (venueId == null) { + throw new RuntimeException("Venue id cannot be null"); + } + return venueRepository.findById(UUID.fromString(venueId)).orElseThrow(() -> new RuntimeException("Venue not found")); + } + + public Venue addSeatsToVenue(String venueId, List seatDtos) { + Venue venue = getVenueById(venueId); + List seatTypes = seatTypeService.getSeatTypes(seatDtos.stream().map(SeatDto::getSeatTypeId).toList()); + Map seatTypeMap = seatTypes.stream() + .collect(Collectors.toMap(seatType -> seatType.getId().toString(), seatType -> seatType)); + List addedSeats = seatDtos.stream().map(seatDto -> SeatDto.toEntity(seatDto, venue, seatTypeMap)).toList(); + venue.getSeats().addAll(addedSeats); + + if (venue.getSeats().size() > 100) { + throw new RuntimeException("Cannot add more than 100 seats"); + } + + return venueRepository.save(venue); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/config/JpaConfig.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/config/JpaConfig.java index ca00d90..f0559cb 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/config/JpaConfig.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/config/JpaConfig.java @@ -1,12 +1,14 @@ package org.lbcc.bms.bms_monolith.common.config; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.AuditorAware; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import java.util.Optional; @EnableJpaAuditing +@Configuration public class JpaConfig { @Bean diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/constants/BMSConstants.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/constants/BMSConstants.java index b691851..5764f39 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/constants/BMSConstants.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/constants/BMSConstants.java @@ -11,4 +11,7 @@ private BMSConstants() { public static final String UNEXPECTED_ERROR_MESSAGE = "An unexpected error occurred"; public static final String UNEXPECTED_ERROR_CODE = "UNEXPECTED_ERROR"; public static final String EVENT_SERVICE_ERROR = "EVENT_SERVICE_ERROR"; + + public static final String VENDOR_NOT_FOUND = "VENDOR_NOT_FOUND"; + public static final String INVALID_VENDOR_REQUEST = "INVALID_VENDOR_REQUEST"; } diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/dto/AddressDto.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/dto/AddressDto.java new file mode 100644 index 0000000..ef06012 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/dto/AddressDto.java @@ -0,0 +1,26 @@ +package org.lbcc.bms.bms_monolith.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.lbcc.bms.bms_monolith.common.entity.Address; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AddressDto { + + private String street; + private String city; + private String state; + private String zipCode; + private String country; + + public static AddressDto addressToAddressDto(Address address) { + return new AddressDto(address.getStreet(), address.getCity(), address.getState(), address.getZipCode(), address.getCountry()); + } + + public static Address addressDtoToAddress(AddressDto addressDto) { + return new Address(null, addressDto.getStreet(), addressDto.getCity(), addressDto.getState(), addressDto.getZipCode(), addressDto.getCountry()); + } +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Address.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Address.java new file mode 100644 index 0000000..c441349 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Address.java @@ -0,0 +1,24 @@ +package org.lbcc.bms.bms_monolith.common.entity; + +import jakarta.persistence.*; +import lombok.*; + + +@Entity +@Table(name = "addresses") +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class Address { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String street; + private String city; + private String state; + private String zipCode; + private String country; +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/BaseAuditingEntity.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/BaseAuditingEntity.java index 83b1dd5..6f29972 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/BaseAuditingEntity.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/BaseAuditingEntity.java @@ -31,7 +31,7 @@ public abstract class BaseAuditingEntity { @Id @GeneratedValue(strategy = GenerationType.UUID) - @Column(columnDefinition = "CHAR(36)") + @Column(columnDefinition = "CHAR(36)", nullable = false, updatable = false) private UUID id; @CreatedDate diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/EventShow.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/EventShow.java index b7652a1..4c3695b 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/EventShow.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/EventShow.java @@ -12,9 +12,10 @@ import jakarta.persistence.EnumType; import jakarta.persistence.CascadeType; import jakarta.persistence.FetchType; -import jakarta.validation.constraints.NotNull; import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import lombok.experimental.SuperBuilder; import org.lbcc.bms.bms_monolith.common.enums.Genre; @@ -24,7 +25,9 @@ @Entity @Table(name = "event_shows") @Getter +@Setter @SuperBuilder +@NoArgsConstructor public class EventShow extends BaseAuditingEntity { @ElementCollection(targetClass = Genre.class) @@ -33,10 +36,10 @@ public class EventShow extends BaseAuditingEntity { @Enumerated(EnumType.STRING) private List genres; - @NotNull + @Column(nullable = false) private Instant startDate; - @NotNull + @Column(nullable = false) private Instant endDate; @ManyToOne diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Seat.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Seat.java index 536fb65..cc057aa 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Seat.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Seat.java @@ -11,6 +11,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.experimental.SuperBuilder; + import org.lbcc.bms.bms_monolith.common.enums.OperationalStatus; @Entity @@ -19,6 +21,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor +@SuperBuilder public class Seat extends BaseAuditingEntity { @ManyToOne diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatInShow.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatInShow.java index 1c5851e..0d3dcae 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatInShow.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatInShow.java @@ -1,14 +1,11 @@ package org.lbcc.bms.bms_monolith.common.entity; -import jakarta.persistence.Entity; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.Enumerated; -import jakarta.persistence.EnumType; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.experimental.SuperBuilder; import org.lbcc.bms.bms_monolith.common.enums.BookingStatus; @Entity @@ -16,12 +13,17 @@ @Setter @AllArgsConstructor @NoArgsConstructor +@SuperBuilder public class SeatInShow extends BaseAuditingEntity { @ManyToOne @JoinColumn(name = "seat_type_in_show_id") private SeatTypeInShow seatTypeInShow; + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "seat_id", nullable = false) + private Seat seat; + @ManyToOne @JoinColumn(name = "show_id") private EventShow show; diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatType.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatType.java index 50d26ff..cfd1205 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatType.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatType.java @@ -18,10 +18,10 @@ @NoArgsConstructor public class SeatType extends BaseAuditingEntity { - @Column(length = 15) + @Column(length = 15, nullable = false) private String label; - @Column(precision = 10, scale = 2) + @Column(precision = 10, scale = 2, nullable = false) private BigDecimal price; } diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatTypeInShow.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatTypeInShow.java index 581241e..1029bef 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatTypeInShow.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/SeatTypeInShow.java @@ -5,6 +5,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.JoinColumn; import jakarta.persistence.Column; +import lombok.Data; import lombok.Getter; import lombok.experimental.SuperBuilder; @@ -14,6 +15,7 @@ @Table(name = "seat_type_in_shows") @Getter @SuperBuilder +@Data public class SeatTypeInShow extends BaseAuditingEntity { @ManyToOne diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Vendor.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Vendor.java index 94e32ff..18f5f10 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Vendor.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Vendor.java @@ -3,17 +3,18 @@ import jakarta.persistence.Entity; import jakarta.persistence.Table; import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.EnumType; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; -import jakarta.validation.constraints.Size; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.Pattern; -import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.experimental.SuperBuilder; + import org.lbcc.bms.bms_monolith.common.enums.VendorStatus; import java.time.LocalDateTime; @@ -24,6 +25,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor +@SuperBuilder public class Vendor extends BaseAuditingEntity { @Column(nullable = false, length = 20) @@ -33,11 +35,14 @@ public class Vendor extends BaseAuditingEntity { @Column(nullable = false, length = 100) private String email; - @Column(nullable = false) - private String address; + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "address_id") + private Address address; @Column(nullable = true, length = 100) private String website; + private String gstNo; + private String panNo; @Enumerated(EnumType.STRING) @Column(nullable = false, length = 20) diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Venue.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Venue.java index 97d9bea..2599955 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Venue.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/entity/Venue.java @@ -6,10 +6,10 @@ import jakarta.persistence.EnumType; import jakarta.persistence.CascadeType; import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Column; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -30,7 +30,11 @@ public class Venue extends BaseAuditingEntity { @Column(nullable = false, unique = true) private String name; - private String address; + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "address_id") + private Address address; + private BigDecimal latitude; private BigDecimal longitude; private Integer totalSeatingCapacity; diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/exception/GlobalExceptionHandler.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/exception/GlobalExceptionHandler.java index b0de11d..8d6b673 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/exception/GlobalExceptionHandler.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/common/exception/GlobalExceptionHandler.java @@ -1,5 +1,6 @@ package org.lbcc.bms.bms_monolith.common.exception; +import lombok.extern.slf4j.Slf4j; import org.lbcc.bms.bms_monolith.common.constants.BMSConstants; import org.lbcc.bms.bms_monolith.common.response.ApiErrorResponse; import org.springframework.http.HttpStatus; @@ -8,9 +9,12 @@ import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice +@Slf4j public class GlobalExceptionHandler { + @ExceptionHandler(Exception.class) public ResponseEntity handleGlobalException(Exception ex) { + log.error("Unexpected error occurred", ex); return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, BMSConstants.UNEXPECTED_ERROR_MESSAGE, BMSConstants.UNEXPECTED_ERROR_CODE); } diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/controller/EventController.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/controller/EventController.java index 8318d96..b47e8bd 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/controller/EventController.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/controller/EventController.java @@ -1,8 +1,14 @@ package org.lbcc.bms.bms_monolith.eventservice.controller; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; import org.lbcc.bms.bms_monolith.common.constants.BMSConstants; import org.lbcc.bms.bms_monolith.common.response.ApiListResponse; +import org.lbcc.bms.bms_monolith.common.response.ApiResponse; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventDTO; import org.lbcc.bms.bms_monolith.eventservice.dto.EventResponse; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventTypeRequestDto; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventTypeResponse; import org.lbcc.bms.bms_monolith.eventservice.service.IEventService; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -12,8 +18,11 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequestMapping(path="/events") +@Slf4j public class EventController { private final IEventService iEventService; @@ -38,4 +47,38 @@ public ResponseEntity> getAllEvents( return ResponseEntity.ok(response); } + @PostMapping("/event-types") + public ResponseEntity addEventTypes(@RequestBody EventTypeRequestDto eventTypeRequestDto) { + EventTypeResponse eventTypeResponse = iEventService.addEventTypes(eventTypeRequestDto); + ApiListResponse response = ApiListResponse.builder() + .success(true) + .message("event types added successfully") + .data(List.of(eventTypeResponse)) + .build(); + return ResponseEntity.ok(response); + } + + @PostMapping("/host") + public ResponseEntity hostEvent(@RequestBody @Valid EventDTO event) { + EventResponse hostedEvent = iEventService.hostEvent(event); + log.info("Event hosted successfully"); + ApiResponse response = ApiResponse.builder() + .success(true) + .message("event hosted successfully") + .data(hostedEvent) + .build(); + return ResponseEntity.ok(response); + } + + @PostMapping("/shows") //adding more shows to an event + public ResponseEntity addShows(@RequestBody @Valid EventDTO event) { + EventResponse hostedEvent = iEventService.addShowsToEvent(event); + ApiResponse response = ApiResponse.builder() + .success(true) + .message("Shows added successfully to event") + .data(hostedEvent) + .build(); + return ResponseEntity.ok(response); + } + } diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventDTO.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventDTO.java new file mode 100644 index 0000000..64bcd25 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventDTO.java @@ -0,0 +1,44 @@ +package org.lbcc.bms.bms_monolith.eventservice.dto; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Builder; +import lombok.Data; + +import java.time.Instant; +import java.util.List; + +@Data +@Builder +public class EventDTO { + + private String id; + + @Size(min = 10, max = 50, message = "Title must be between 10 and 50 characters.") + private String title; + + @Size(max = 100, message = "Description must be less than 100 characters.") + private String description; + + //vendor details + @NotNull(message = "Vendor id is required.") + private String vendorId; + + //venue details + @NotNull(message = "Venue id is required.") + private String venueId; + + //available shows + private List shows; + + //event type details + @NotNull(message = "Event type id is required.") + private String eventTypeId; + + @NotNull(message = "Start date is required.") + private Instant startDate; + + @NotNull(message = "End date is required.") + private Instant endDate; + +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventResponse.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventResponse.java index 6aba519..5592aa0 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventResponse.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventResponse.java @@ -5,12 +5,12 @@ import org.lbcc.bms.bms_monolith.common.entity.Event; import java.util.List; -import java.util.stream.Collectors; @Getter @Builder public class EventResponse { + private String id; private String title; private String description; private String vendorName; @@ -23,6 +23,7 @@ public class EventResponse { public static EventResponse fromEntity(Event event) { return new EventResponse( + event.getId().toString(), event.getTitle(), event.getDescription(), event.getVendor() != null ? event.getVendor().getName() : null, diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventShowDTO.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventShowDTO.java new file mode 100644 index 0000000..6fe7bf2 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventShowDTO.java @@ -0,0 +1,44 @@ +package org.lbcc.bms.bms_monolith.eventservice.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatTypeInShowDTO; +import org.lbcc.bms.bms_monolith.common.entity.*; +import org.lbcc.bms.bms_monolith.common.enums.Genre; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class EventShowDTO { + + private String id; + + @NotNull(message = "Show date is required.") + private Instant showDate; + + @NotNull(message = "Start time is required.") + private Instant startTime; + + @NotNull(message = "End time is required.") + private Instant endTime; + + private List genres; + + private List seatTypeInShows; + + //hiding below fields from client side + @JsonIgnore + private List seats; + + @JsonIgnore + private Map seatTypeMap; +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventShowResponse.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventShowResponse.java index c764df7..b33fb1d 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventShowResponse.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventShowResponse.java @@ -1,10 +1,16 @@ package org.lbcc.bms.bms_monolith.eventservice.dto; +import lombok.AllArgsConstructor; +import lombok.Data; import lombok.Getter; import org.lbcc.bms.bms_monolith.common.entity.EventShow; +import org.lbcc.bms.bms_monolith.eventservice.dto.seat.SeatInShowResponse; +import org.lbcc.bms.bms_monolith.eventservice.dto.seat.SeatTypeInShowResponse; import java.util.List; +@Data +@AllArgsConstructor @Getter public class EventShowResponse { @@ -14,16 +20,6 @@ public class EventShowResponse { private List seatInShows; private List seatTypeInShows; - // Constructors, Getters, and Setters - - public EventShowResponse(List genres, String startDate, String endDate, - List seatInShows, List seatTypeInShows) { - this.genres = genres; - this.startDate = startDate; - this.endDate = endDate; - this.seatInShows = seatInShows; - this.seatTypeInShows = seatTypeInShows; - } // Static factory method for conversion from EventShow entity to EventShowResponse DTO public static EventShowResponse fromEntity(EventShow show) { diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventTypeDto.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventTypeDto.java new file mode 100644 index 0000000..c457d57 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventTypeDto.java @@ -0,0 +1,26 @@ +package org.lbcc.bms.bms_monolith.eventservice.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.lbcc.bms.bms_monolith.common.entity.EventType; + +import java.util.List; + +@Data +@AllArgsConstructor +public class EventTypeDto { + private String id; + private String label; + + public static EventTypeDto fromEntity(EventType eventType) { + return new EventTypeDto( + eventType.getId().toString(), + eventType.getLabel() + ); + } + + public static List fromEntities(List eventTypes) { + return eventTypes.stream().map(EventTypeDto::fromEntity).toList(); + } + +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventTypeRequestDto.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventTypeRequestDto.java new file mode 100644 index 0000000..d65e25e --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventTypeRequestDto.java @@ -0,0 +1,16 @@ +package org.lbcc.bms.bms_monolith.eventservice.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.lbcc.bms.bms_monolith.common.entity.EventType; + +import java.util.List; + +@Data +public class EventTypeRequestDto { + private List eventTypes; + + public static List toEntities(List eventTypes) { + return eventTypes.stream().map(EventType::new).toList(); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventTypeResponse.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventTypeResponse.java new file mode 100644 index 0000000..ebe8fb6 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/EventTypeResponse.java @@ -0,0 +1,12 @@ +package org.lbcc.bms.bms_monolith.eventservice.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.List; + +@AllArgsConstructor +@Data +public class EventTypeResponse { + private List evenTypes; +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatInShowRequest.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatInShowRequest.java new file mode 100644 index 0000000..8c6a3dd --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatInShowRequest.java @@ -0,0 +1,9 @@ +package org.lbcc.bms.bms_monolith.eventservice.dto; + +import lombok.Data; + +@Data +public class SeatInShowRequest { + private String seatTypeInShowId; + private String bookingStatus; +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatTypeInShowRequest.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatTypeInShowRequest.java new file mode 100644 index 0000000..f29da12 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatTypeInShowRequest.java @@ -0,0 +1,11 @@ +package org.lbcc.bms.bms_monolith.eventservice.dto; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class SeatTypeInShowRequest { + private String seatTypeId; + private BigDecimal price; +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatInShowResponse.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/seat/SeatInShowResponse.java similarity index 91% rename from book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatInShowResponse.java rename to book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/seat/SeatInShowResponse.java index 6184e9a..52951af 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatInShowResponse.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/seat/SeatInShowResponse.java @@ -1,10 +1,12 @@ -package org.lbcc.bms.bms_monolith.eventservice.dto; +package org.lbcc.bms.bms_monolith.eventservice.dto.seat; +import lombok.Data; import lombok.Getter; import org.lbcc.bms.bms_monolith.common.entity.SeatInShow; import java.util.UUID; +@Data @Getter public class SeatInShowResponse { diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatTypeInShowResponse.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/seat/SeatTypeInShowResponse.java similarity index 91% rename from book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatTypeInShowResponse.java rename to book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/seat/SeatTypeInShowResponse.java index c5601d1..7b95b25 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/SeatTypeInShowResponse.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/dto/seat/SeatTypeInShowResponse.java @@ -1,11 +1,13 @@ -package org.lbcc.bms.bms_monolith.eventservice.dto; +package org.lbcc.bms.bms_monolith.eventservice.dto.seat; +import lombok.Data; import lombok.Getter; import org.lbcc.bms.bms_monolith.common.entity.SeatTypeInShow; import java.math.BigDecimal; import java.util.UUID; +@Data @Getter public class SeatTypeInShowResponse { diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/helpers/EventHelpers.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/helpers/EventHelpers.java new file mode 100644 index 0000000..669d179 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/helpers/EventHelpers.java @@ -0,0 +1,90 @@ +package org.lbcc.bms.bms_monolith.eventservice.helpers; + +import lombok.extern.slf4j.Slf4j; +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatTypeInShowDTO; +import org.lbcc.bms.bms_monolith.common.entity.*; +import org.lbcc.bms.bms_monolith.common.enums.BookingStatus; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventShowDTO; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +public class EventHelpers { + + public static EventShow mapEventShowDTOToEntity(EventShowDTO eventShowDTO) { + EventShow eventShow = EventShow.builder() + .genres(eventShowDTO.getGenres()) + .startDate(eventShowDTO.getStartTime()) + .endDate(eventShowDTO.getEndTime()) + .build(); + + List seatInShows = getSeatInShows(eventShowDTO.getSeats()); + seatInShows.forEach(seat -> seat.setShow(eventShow)); + eventShow.setSeatInShows(seatInShows); + + List seatTypes = getSeatTypes(eventShowDTO.getSeatTypeMap()); + Map seatTypePriceMap = buildSeatTypePriceMap(eventShowDTO, seatTypes); + + List seatTypesInShow = getSeatTypeInShows(seatTypePriceMap, seatTypes); + seatInShows.forEach(seat -> seat.setSeatTypeInShow(getSeatTypeId(seat, seatTypesInShow))); + seatTypesInShow.forEach(seatType -> seatType.setShow(eventShow)); + eventShow.setSeatTypeInShows(seatTypesInShow); + + return eventShow; + } + + private static Map buildSeatTypePriceMap(EventShowDTO eventShowDTO, List seatTypes) { + Map seatTypePriceMap = null; + //while onboarding shows admin can provide price for each seat type based on the show + //price can be altered for each show based on demand and show timings + if (eventShowDTO.getSeatTypeInShows() != null) { + seatTypePriceMap = eventShowDTO.getSeatTypeInShows().stream() + .collect(Collectors.toMap(SeatTypeInShowDTO::getSeatTypeId, SeatTypeInShowDTO::getPrice)); + } else { + //in case admin does not want to change the price for each show will pick the default price from seat type + seatTypePriceMap = seatTypes.stream() + .collect(Collectors.toMap(seatType -> seatType.getId().toString(), SeatType::getPrice)); + } + return seatTypePriceMap; + } + + private static List getSeatInShows(List seats) { + return seats.stream() + .map(EventHelpers::createSeatInShow) + .collect(Collectors.toList()); + } + + private static List getSeatTypes(Map seatTypeMap) { + return new ArrayList<>(seatTypeMap.values()); + } + + private static List getSeatTypeInShows(Map seatTypePriceMap, List seatTypes) { + return seatTypes.stream() + .map(seatType -> createSeatTypeInShow(seatTypePriceMap, seatType)) + .collect(Collectors.toList()); + } + + private static SeatTypeInShow getSeatTypeId(SeatInShow seat, List seatTypeInShows) { + return seatTypeInShows.stream() + .filter(seatType -> seatType.getSeatType().getId().equals(seat.getSeat().getSeatType().getId())) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Invalid seat type ID " + seat.getSeat().getSeatType().getId())); + } + + //creation methods + private static SeatTypeInShow createSeatTypeInShow(Map seatTypePriceMap, SeatType seatType) { + return SeatTypeInShow.builder() + .seatType(seatType) + .price(seatTypePriceMap.getOrDefault(seatType.getId().toString(), seatType.getPrice())) + .build(); + } + + private static SeatInShow createSeatInShow(Seat seat) { + return SeatInShow.builder() + .seat(seat).bookingStatus(BookingStatus.AVAILABLE) + .build(); + } + +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/repository/EventTypeRepository.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/repository/EventTypeRepository.java new file mode 100644 index 0000000..2335c33 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/repository/EventTypeRepository.java @@ -0,0 +1,13 @@ +package org.lbcc.bms.bms_monolith.eventservice.repository; + +import org.lbcc.bms.bms_monolith.common.entity.EventType; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.UUID; + +public interface EventTypeRepository extends JpaRepository { + + EventType findByLabel(String label); + List findByIdIn(List ids); +} diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/repository/IEventRepository.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/repository/IEventRepository.java index aa7939c..90725b6 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/repository/IEventRepository.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/repository/IEventRepository.java @@ -4,12 +4,19 @@ 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.stereotype.Repository; +import java.util.Optional; import java.util.UUID; @Repository public interface IEventRepository extends JpaRepository { + @Query("SELECT e FROM Event e JOIN FETCH e.vendor JOIN FETCH e.venue JOIN FETCH e.eventType ORDER BY e.startDate DESC") + Page findAllWithDetails(Pageable pageable); + + @Override + Optional findById(UUID uuid); Page findAll(Pageable pageable); } \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/service/IEventService.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/service/IEventService.java index 5ea592d..482b0cf 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/service/IEventService.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/service/IEventService.java @@ -1,10 +1,20 @@ package org.lbcc.bms.bms_monolith.eventservice.service; +import org.lbcc.bms.bms_monolith.common.entity.Event; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventDTO; import org.lbcc.bms.bms_monolith.eventservice.dto.EventResponse; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventTypeRequestDto; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventTypeResponse; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; public interface IEventService { - Page getAllEvents(Pageable pageable); + Page getAllEvents(Pageable pageable); + + EventResponse hostEvent(EventDTO eventDTO); + + EventTypeResponse addEventTypes(EventTypeRequestDto eventTypeRequestDto); + + EventResponse addShowsToEvent(EventDTO eventDTO); } diff --git a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/service/impl/EventServiceImpl.java b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/service/impl/EventServiceImpl.java index 268630f..26bf1db 100644 --- a/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/service/impl/EventServiceImpl.java +++ b/book-my-show/backend/java/bms-monolith/src/main/java/org/lbcc/bms/bms_monolith/eventservice/service/impl/EventServiceImpl.java @@ -1,23 +1,47 @@ package org.lbcc.bms.bms_monolith.eventservice.service.impl; import lombok.extern.slf4j.Slf4j; +import org.lbcc.bms.bms_monolith.admin.repository.SeatTypeRepository; +import org.lbcc.bms.bms_monolith.admin.service.AdminService; +import org.lbcc.bms.bms_monolith.admin.service.VenueService; +import org.lbcc.bms.bms_monolith.common.entity.*; +import org.lbcc.bms.bms_monolith.eventservice.dto.*; import org.lbcc.bms.bms_monolith.common.entity.Event; import org.lbcc.bms.bms_monolith.eventservice.dto.EventResponse; import org.lbcc.bms.bms_monolith.eventservice.exception.EventServiceException; +import org.lbcc.bms.bms_monolith.eventservice.helpers.EventHelpers; +import org.lbcc.bms.bms_monolith.eventservice.repository.EventTypeRepository; import org.lbcc.bms.bms_monolith.eventservice.repository.IEventRepository; import org.lbcc.bms.bms_monolith.eventservice.service.IEventService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import java.util.*; +import java.util.stream.Collectors; + @Service @Slf4j public class EventServiceImpl implements IEventService { private final IEventRepository IEventRepository; + private final EventTypeRepository eventTypeRepository; + private final SeatTypeRepository seatTypeRepository; + private final VenueService venueService; + private final AdminService adminService; - public EventServiceImpl(IEventRepository IEventRepository) { + @Autowired + public EventServiceImpl(IEventRepository IEventRepository, + EventTypeRepository eventTypeRepository, + SeatTypeRepository seatTypeRepository, + VenueService venueService, + AdminService adminService) { this.IEventRepository = IEventRepository; + this.eventTypeRepository = eventTypeRepository; + this.seatTypeRepository = seatTypeRepository; + this.venueService = venueService; + this.adminService = adminService; } @Override @@ -32,4 +56,91 @@ public Page getAllEvents(Pageable pageable) { throw new EventServiceException("Failed to fetch events", e); } } + + @Override + public EventResponse hostEvent(EventDTO request) { + //TODO: add additional validations to check if timings are correct + //Example: adding back dated shows should not be allowed + // end date should be greater than start date + Event event = mapEventDTOToEntity(request); + + Event savedEvent = IEventRepository.save(event); //save the event + log.info("Event hosted successfully: {}", savedEvent); + return EventResponse.fromEntity(savedEvent); + } + + public Event mapEventDTOToEntity(EventDTO eventDTO) { + Vendor vendor = adminService.findVendorById(UUID.fromString(eventDTO.getVendorId())); + Venue venue = venueService.getVenueById(eventDTO.getVenueId()); + + EventType eventType = eventTypeRepository.findById(UUID.fromString(eventDTO.getEventTypeId())) + .orElse(null); + + Event event = Event.builder() + .title(eventDTO.getTitle()).description(eventDTO.getDescription()) + .vendor(vendor).venue(venue).eventType(eventType) + .startDate(eventDTO.getStartDate()).endDate(eventDTO.getEndDate()) + .build(); + + addSeatsData(eventDTO, venue); + + List eventShows = eventDTO.getShows() != null ? eventDTO.getShows().stream() + .map(EventHelpers::mapEventShowDTOToEntity) + .toList() : List.of(); + + eventShows.forEach(show -> show.setEvent(event)); + + event.setShow(eventShows); + + return event; + } + + + @Override + public EventResponse addShowsToEvent(EventDTO eventDTO) { + Event event = IEventRepository.findById(UUID.fromString(eventDTO.getId())) + .orElseThrow(() -> new EventServiceException("Event not found", new Throwable())); + Venue venue = venueService.getVenueById(eventDTO.getVenueId()); + + addSeatsData(eventDTO, venue); + + if (eventDTO.getShows() == null || eventDTO.getShows().isEmpty()) { + throw new EventServiceException("No shows found in request", new Throwable()); + } + + List eventShows = eventDTO.getShows().stream() + .map(EventHelpers::mapEventShowDTOToEntity) + .toList(); + + eventShows.forEach(show -> show.setEvent(event)); + event.setShow(event.getShow() == null ? new ArrayList<>() : event.getShow()); + event.getShow().addAll(eventShows); + + Event updatedEvent = IEventRepository.save(event); + log.info("Shows added to event successfully: {}", updatedEvent); + return EventResponse.fromEntity(updatedEvent); + } + + @Override + public EventTypeResponse addEventTypes(EventTypeRequestDto eventTypeRequestDto) { + log.info("Adding event types: {}", eventTypeRequestDto.getEventTypes()); + List eventTypesList = eventTypeRequestDto.getEventTypes(); + List eventTypes = EventTypeRequestDto.toEntities(eventTypesList); + List savedEventTypes = eventTypeRepository.saveAll(eventTypes); + log.info("Event types added successfully: {}", savedEventTypes); + return new EventTypeResponse(EventTypeDto.fromEntities(savedEventTypes)); + } + + //Adds seats data (seatType and available seats) based on venue + private void addSeatsData(EventDTO eventDTO, Venue venue) { + eventDTO.getShows().forEach(show -> { + show.setSeats(venue.getSeats()); + show.setSeatTypeMap(getSeatTypeMap()); + }); + } + + private Map getSeatTypeMap() { + List seatTypes = seatTypeRepository.findAll(); //TODO: can be cached later + return seatTypes.stream().collect(Collectors.toMap(x -> x.getId().toString(), x -> x)); + } } diff --git a/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/admin/controller/AdminVendorOnboardingControllerTest.java b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/admin/controller/AdminVendorOnboardingControllerTest.java new file mode 100644 index 0000000..859ff48 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/admin/controller/AdminVendorOnboardingControllerTest.java @@ -0,0 +1,105 @@ +package org.lbcc.bms.bms_monolith.admin.controller; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.lbcc.bms.bms_monolith.admin.constants.BMSConstants; +import org.lbcc.bms.bms_monolith.admin.dto.VendorOnboardRequest; +import org.lbcc.bms.bms_monolith.admin.dto.VendorOnboardResponse; +import org.lbcc.bms.bms_monolith.admin.exceptions.InvalidRequest; +import org.lbcc.bms.bms_monolith.admin.exceptions.VendorNotFoundException; +import org.lbcc.bms.bms_monolith.admin.service.AdminService; +import org.lbcc.bms.bms_monolith.common.entity.Vendor; +import org.lbcc.bms.bms_monolith.common.enums.VendorStatus; +import org.lbcc.bms.bms_monolith.common.response.ApiResponse; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import java.util.UUID; + +public class AdminVendorOnboardingControllerTest { + + @Mock + private AdminService adminService; + + @InjectMocks + private AdminVendorOnboardingController controller; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void updateVendorStatus_shouldReturnOk_whenVendorStatusUpdatedSuccessfully() { + String vendorId = "1ad50f91-fcf1-4d80-b54e-fada5b6ad973"; + VendorStatus status = VendorStatus.ACTIVE; + Vendor vendor = Vendor.builder().id(UUID.fromString(vendorId)).status(status).build(); + when(adminService.updatedVendorStatus(vendorId, status)).thenReturn(vendor); //expected behaviour + + ResponseEntity> result = controller.updateVendorStatus(vendorId, status); + + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals("Vendor status updated successfully", result.getBody().getMessage()); + } + + @Test + void updateVendorStatus_shouldReturnError_whenVendorNotFound() { + String vendorId = "123"; + VendorStatus status = VendorStatus.ACTIVE; + + when(adminService.updatedVendorStatus(vendorId, status)).thenThrow(new VendorNotFoundException("Vendor not found")); + + assertThrows(VendorNotFoundException.class, () -> { + controller.updateVendorStatus(vendorId, status); + }); + } + + @Test + void updateVendorStatus_shouldReturnError_whenInvalidVendorRequest() { + String vendorId = ""; + VendorStatus status = VendorStatus.ACTIVE; + + when(adminService.updatedVendorStatus(vendorId, status)).thenThrow(new InvalidRequest("Vendor id cannot be empty")); + + assertThrows(InvalidRequest.class, () -> { + controller.updateVendorStatus(vendorId, status); + }); + } + + + //onboarding tests + @Test + void onboardNewVendor_shouldReturnCreated_whenVendorOnboardedSuccessfully() { + VendorOnboardRequest request = VendorOnboardRequest.builder() + .name("VendorName") + .contactNumber("1234567890") + .email("test@gmail.com").build(); + VendorOnboardResponse response = new VendorOnboardResponse("123", "VendorName", VendorStatus.ACTIVE); + + when(adminService.onboardNewVendor(request)).thenReturn(response); + ResponseEntity> result = controller.onboardNewVendor(request); + + assertEquals(HttpStatus.CREATED, result.getStatusCode()); + assertEquals(BMSConstants.VENDOR_SUCCESS_MESSAGE, result.getBody().getMessage()); + } + + @Test + void onboardNewVendor_shouldReturnError_whenInvalidVendorRequest() { + VendorOnboardRequest request = VendorOnboardRequest.builder() + .name("VendorName") + .contactNumber("1234567890") + .email("test@gmail.com").build(); + + when(adminService.onboardNewVendor(request)).thenThrow(new InvalidRequest("Invalid request")); + + assertThrows(InvalidRequest.class, () -> { + controller.onboardNewVendor(request); + }); + } +} \ No newline at end of file diff --git a/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/admin/helpers/AdminServiceTestHelper.java b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/admin/helpers/AdminServiceTestHelper.java new file mode 100644 index 0000000..c25b3ca --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/admin/helpers/AdminServiceTestHelper.java @@ -0,0 +1,44 @@ +package org.lbcc.bms.bms_monolith.admin.helpers; + +import org.lbcc.bms.bms_monolith.admin.dto.VendorOnboardRequest; +import org.lbcc.bms.bms_monolith.common.dto.AddressDto; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +public class AdminServiceTestHelper { + + public VendorOnboardRequest buildVendorOnboardRequest() { + MultipartFile logoFile = new MockMultipartFile("logoFile", "logo.png", "image/png", "Sample logo".getBytes()); + + AddressDto addressDto = new AddressDto("123, Sample Street", "Sample City", "Sample State", "123456", "Sample Country"); + return VendorOnboardRequest.builder() + .name("Sample Vendor") + .contactNumber("1234567890") + .email("sample@example.com") + .address(addressDto) + .website("https://www.sample.com") + .gstNo("GST123456") + .panNo("PAN123456") + .registrationDate("12-12-2022") + .logoFile(logoFile) + .build(); + } + + public VendorOnboardRequest buildInvalidVendorOnboardRequest() { + + AddressDto addressDto = new AddressDto("123, Sample Street", "Sample City", "Sample State", "123456", "Sample Country"); + return VendorOnboardRequest.builder() + .name("Sample Vendor") + .contactNumber("1234567890") + .email("sample@example.com") + .address(addressDto) + .website("https://www.sample.com") + .gstNo("GST123456") + .panNo("PAN123456") + .registrationDate("12-12-2022") + .logoFile(null) + .build(); + } +} diff --git a/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/admin/service/AdminServiceTest.java b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/admin/service/AdminServiceTest.java new file mode 100644 index 0000000..72eda8a --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/admin/service/AdminServiceTest.java @@ -0,0 +1,170 @@ +package org.lbcc.bms.bms_monolith.admin.service; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import org.lbcc.bms.bms_monolith.admin.dto.VendorDto; +import org.lbcc.bms.bms_monolith.admin.exceptions.InvalidRequest; +import org.lbcc.bms.bms_monolith.common.dto.AddressDto; +import org.lbcc.bms.bms_monolith.common.entity.Vendor; +import org.lbcc.bms.bms_monolith.common.enums.VendorStatus; +import org.lbcc.bms.bms_monolith.common.response.ApiResponse; + +import org.lbcc.bms.bms_monolith.admin.dto.VendorOnboardRequest; +import org.lbcc.bms.bms_monolith.admin.dto.VendorOnboardResponse; +import org.lbcc.bms.bms_monolith.admin.dto.VendorSearchResponse; +import org.lbcc.bms.bms_monolith.admin.exceptions.VendorNotFoundException; +import org.lbcc.bms.bms_monolith.admin.helpers.AdminServiceTestHelper; +import org.lbcc.bms.bms_monolith.admin.repository.VendorRepository; + + +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +@SpringBootTest +public class AdminServiceTest { + + @Mock + private VendorRepository vendorRepository; + + @InjectMocks + private AdminService adminService; + + private Vendor vendor; + + @Autowired + private AdminServiceTestHelper adminServiceTestHelper; + + @BeforeEach + void setUp() { + AddressDto addressDto = new AddressDto("123, Sample Street", "Sample City", "Sample State", "123456", "Sample Country"); + vendor = new Vendor(); + vendor.setId(UUID.randomUUID()); + vendor.setName("Test Vendor"); + vendor.setAddress(AddressDto.addressDtoToAddress(addressDto)); + } + + @Test + @DisplayName("Search vendor with valid name returns vendor list") + void searchVendorWithValidNameReturnsVendorList() { + when(vendorRepository.findByNameContaining("Test Vendor")).thenReturn(List.of(vendor)); + + List vendorDtoList = adminService.searchVendor("Test Vendor"); + ApiResponse response = ApiResponse.builder() + .success(true) + .message("Vendor found successfully") + .data(new VendorSearchResponse(vendorDtoList)) + .build(); + + assertTrue(response.isSuccess()); + assertEquals("Vendor found successfully", response.getMessage()); + assertNotNull(response.getData()); + verify(vendorRepository, times(1)).findByNameContaining("Test Vendor"); + } + + @Test + @DisplayName("Search vendor with empty name throws InvalidRequest") + void searchVendorWithEmptyNameThrowsInvalidVendorRequest() { + assertThrows(InvalidRequest.class, () -> adminService.searchVendor("")); + } + + @Test + @DisplayName("Search vendor with null name throws InvalidRequest") + void searchVendorWithNullNameThrowsInvalidVendorRequest() { + assertThrows(InvalidRequest.class, () -> adminService.searchVendor(null)); + } + + @Test + @DisplayName("Search vendor with non-existing name returns no vendor found") + void searchVendorWithNonExistingNameReturnsNoVendorFound() { + when(vendorRepository.findByNameContaining("Non Existing Vendor")).thenReturn(Collections.emptyList()); + + List vendorDtoList = adminService.searchVendor("Non Existing Vendor"); + ApiResponse response = ApiResponse.builder() + .success(false) + .message("No vendor found with given name") + .data(new VendorSearchResponse(vendorDtoList)) + .build(); + assertFalse(response.isSuccess()); + assertEquals("No vendor found with given name", response.getMessage()); + assertEquals(0, vendorDtoList.size()); + verify(vendorRepository, times(1)).findByNameContaining("Non Existing Vendor"); + } + + @Test + @DisplayName("Update vendor status with valid id and status updates successfully") + void updateVendorStatusWithValidIdAndStatusUpdatesSuccessfully() { + UUID vendorId = UUID.randomUUID(); + Vendor vendor = new Vendor(); + vendor.setId(vendorId); + vendor.setStatus(VendorStatus.ACTIVE); + + when(vendorRepository.findById(vendorId)).thenReturn(Optional.of(vendor)); + + Vendor updatedVendor = adminService.updatedVendorStatus(vendorId.toString(), VendorStatus.SUSPENDED); + + assertEquals(vendorId, updatedVendor.getId()); + assertEquals(VendorStatus.SUSPENDED, updatedVendor.getStatus()); + verify(vendorRepository, times(1)).findById(vendorId); + verify(vendorRepository, times(1)).save(vendor); + } + + @Test + @DisplayName("Update vendor status with null id throws InvalidRequest") + void updateVendorStatusWithNullIdThrowsInvalidVendorRequest() { + assertThrows(InvalidRequest.class, () -> adminService.updatedVendorStatus(null, VendorStatus.SUSPENDED)); + } + + @Test + @DisplayName("Update vendor status with empty id throws InvalidRequest") + void updateVendorStatusWithEmptyIdThrowsInvalidVendorRequest() { + assertThrows(InvalidRequest.class, () -> adminService.updatedVendorStatus("", VendorStatus.SUSPENDED)); + } + + @Test + @DisplayName("Update vendor status with null status throws InvalidRequest") + void updateVendorStatusWithNullStatusThrowsInvalidVendorRequest() { + UUID vendorId = UUID.randomUUID(); + assertThrows(InvalidRequest.class, () -> adminService.updatedVendorStatus(vendorId.toString(), null)); + } + + @Test + @DisplayName("Update vendor status with non-existing id throws VendorNotFoundException") + void updateVendorStatusWithNonExistingIdThrowsVendorNotFoundException() { + UUID vendorId = UUID.randomUUID(); + when(vendorRepository.findById(vendorId)).thenReturn(Optional.empty()); + + assertThrows(VendorNotFoundException.class, () -> adminService.updatedVendorStatus(vendorId.toString(), VendorStatus.SUSPENDED)); + verify(vendorRepository, times(1)).findById(vendorId); + } + + @Test + @DisplayName("Onboard new vendor with valid request returns success response") + void onboardNewVendorWithValidRequestReturnsSuccessResponse() { + VendorOnboardRequest requestDto = adminServiceTestHelper.buildVendorOnboardRequest(); + Vendor vendor = new Vendor(); + vendor.setId(UUID.randomUUID()); + vendor.setName("New Vendor"); + vendor.setStatus(VendorStatus.ACTIVE); + + when(vendorRepository.save(any(Vendor.class))).thenReturn(vendor); + + VendorOnboardResponse response = adminService.onboardNewVendor(requestDto); + + assertEquals(vendor.getId().toString(), response.getVendorId()); + verify(vendorRepository, times(1)).save(any(Vendor.class)); + } + +} diff --git a/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/service/EventServiceImplTest.java b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/service/EventServiceImplTest.java index e747df5..c4db7ac 100644 --- a/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/service/EventServiceImplTest.java +++ b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/service/EventServiceImplTest.java @@ -1,13 +1,19 @@ package org.lbcc.bms.bms_monolith.service; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.lbcc.bms.bms_monolith.admin.repository.SeatTypeRepository; +import org.lbcc.bms.bms_monolith.admin.service.AdminService; +import org.lbcc.bms.bms_monolith.admin.service.VenueService; +import org.lbcc.bms.bms_monolith.common.entity.*; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventDTO; import org.lbcc.bms.bms_monolith.common.entity.Event; import org.lbcc.bms.bms_monolith.eventservice.dto.EventResponse; import org.lbcc.bms.bms_monolith.eventservice.exception.EventServiceException; +import org.lbcc.bms.bms_monolith.eventservice.repository.EventTypeRepository; import org.lbcc.bms.bms_monolith.eventservice.repository.IEventRepository; import org.lbcc.bms.bms_monolith.eventservice.service.impl.EventServiceImpl; +import org.lbcc.bms.bms_monolith.service.helpers.EventHelpers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -17,7 +23,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import java.util.Collections; +import java.util.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -31,12 +37,26 @@ class EventServiceImplTest { @Mock private IEventRepository IEventRepository; + @Mock + private EventTypeRepository eventTypeRepository; + @InjectMocks private EventServiceImpl eventService; + @Mock + private AdminService adminService; + + @Mock + private VenueService venueService; + + @Mock + private SeatTypeRepository seatTypeRepository; + + @Test void testGetAllEventsSuccess() { Event event = new Event(); + event.setId(UUID.randomUUID()); event.setTitle("Sample Event"); event.setDescription("Sample Description"); @@ -64,4 +84,65 @@ void testGetAllEventsExceptionHandling() { assertEquals("Failed to fetch events", exception.getMessage()); } + + @Test + void mapEventDTOToEntitySuccess() { + EventDTO eventDTO = EventHelpers.createEventDTO(); + + Vendor vendor = new Vendor(); + vendor.setId(UUID.fromString(eventDTO.getVendorId())); + + Venue venue = EventHelpers.createVenue(eventDTO); + List seatTypes = EventHelpers.createSeatTypes(); + + EventType eventType = new EventType(); + eventType.setId(UUID.fromString(eventDTO.getEventTypeId())); + + when(adminService.findVendorById(UUID.fromString(eventDTO.getVendorId()))).thenReturn(vendor); + when(venueService.getVenueById(String.valueOf(UUID.fromString(eventDTO.getVenueId())))).thenReturn(venue); + when(eventTypeRepository.findById(UUID.fromString(eventDTO.getEventTypeId()))).thenReturn(Optional.of(eventType)); + when(seatTypeRepository.findAll()).thenReturn(seatTypes); + + Event event = eventService.mapEventDTOToEntity(eventDTO); + + assertNotNull(event); + assertEquals(EventHelpers.EVENT_TITLE, event.getTitle()); + assertEquals(EventHelpers.EVENT_DESCRIPTION, event.getDescription()); + assertEquals(vendor, event.getVendor()); + assertEquals(venue, event.getVenue()); + assertEquals(eventType, event.getEventType()); + assertEquals(venue.getSeats().size(), event.getVenue().getSeats().size()); + assertEquals(event.getShow().size(), eventDTO.getShows().size()); + } + + @Test + void mapEventDTOToEntityThrowsExceptionWhenVendorNotFound() { + EventDTO eventDTO = EventHelpers.createEventDTO(); + + when(adminService.findVendorById(UUID.fromString(eventDTO.getVendorId()))).thenThrow(new IllegalArgumentException("Vendor not found")); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + eventService.mapEventDTOToEntity(eventDTO); + }); + + assertEquals("Vendor not found", exception.getMessage()); + } + + @Test + void mapEventDTOToEntityThrowsExceptionWhenVenueNotFound() { + EventDTO eventDTO = EventHelpers.createEventDTO(); + + Vendor vendor = new Vendor(); + vendor.setId(UUID.fromString(eventDTO.getVendorId())); + + when(adminService.findVendorById(UUID.fromString(eventDTO.getVendorId()))).thenReturn(vendor); + when(venueService.getVenueById(String.valueOf(UUID.fromString(eventDTO.getVenueId())))).thenThrow(new IllegalArgumentException("Invalid venue ID")); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + eventService.mapEventDTOToEntity(eventDTO); + }); + + assertEquals("Invalid venue ID", exception.getMessage()); + } + } diff --git a/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/service/helpers/EventHelpers.java b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/service/helpers/EventHelpers.java new file mode 100644 index 0000000..ee9b3d7 --- /dev/null +++ b/book-my-show/backend/java/bms-monolith/src/test/java/org/lbcc/bms/bms_monolith/service/helpers/EventHelpers.java @@ -0,0 +1,126 @@ +package org.lbcc.bms.bms_monolith.service.helpers; + +import org.lbcc.bms.bms_monolith.admin.dto.seat.SeatTypeInShowDTO; +import org.lbcc.bms.bms_monolith.common.entity.Seat; +import org.lbcc.bms.bms_monolith.common.entity.SeatType; +import org.lbcc.bms.bms_monolith.common.entity.Venue; +import org.lbcc.bms.bms_monolith.common.enums.Genre; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventDTO; +import org.lbcc.bms.bms_monolith.eventservice.dto.EventShowDTO; + +import java.math.BigDecimal; +import java.time.Instant; +import java.util.*; + +public class EventHelpers { + + public static final String EVENT_TITLE = "Circus Festival 2024"; + public static final String EVENT_DESCRIPTION = "A two-day music festival featuring top artists."; + + //List of all seat type IDs(Regular, VIP, GOLD) + private static final String SEAT_TYPE_ID1 = "2d72c22e-951d-42fc-b570-a5c99d6a7fc0"; + private static final String SEAT_TYPE_ID2 = "7fe67850-56a9-45ae-a0e4-c04cda82b895"; + private static final String SEAT_TYPE_ID3 = "1ad50f91-fcf1-4d80-b54e-fada5b6ad973"; + + // Constants for SeatType + private static final String REGULAR_LABEL = "Regular"; + private static final String VIP_LABEL = "VIP"; + private static final String GOLD_LABEL = "GOLD"; + + + public static List createSeats() { + List seats = new ArrayList<>(); + List seatTypes = createSeatTypes(); + + String[] seatLabels = {"A1", "A2", "B1", "B2"}; + for (int i = 0; i < seatLabels.length; i++) { + seats.add(createSeat(seatLabels[i], seatTypes.get(i % seatTypes.size()))); + } + return seats; + } + + private static Seat createSeat(String label, SeatType seatType) { + return Seat.builder() + .id(UUID.randomUUID()).label(label) + .seatType(seatType).build(); + } + + private static SeatTypeInShowDTO createSeatTypeInShowDTO(String seatTypeId, BigDecimal price) { + return SeatTypeInShowDTO.builder() + .seatTypeId(seatTypeId) + .price(price) + .build(); + } + + private static EventShowDTO createEventShowDTO(Instant showDate, Instant startTime, Instant endTime, + List genres, List seatTypeInShows) { + return EventShowDTO.builder() + .showDate(showDate) + .startTime(startTime) + .endTime(endTime) + .genres(genres) + .seatTypeInShows(seatTypeInShows) + .build(); + } + + public static EventDTO createEventDTO() { + // Create seat types for the shows + SeatTypeInShowDTO seatType1Show1 = createSeatTypeInShowDTO(SEAT_TYPE_ID1, new BigDecimal("150.00")); + SeatTypeInShowDTO seatType2Show1 = createSeatTypeInShowDTO(SEAT_TYPE_ID2, new BigDecimal("250.00")); + SeatTypeInShowDTO seatType1Show2 = createSeatTypeInShowDTO(SEAT_TYPE_ID2, new BigDecimal("300.00")); + + // Create EventShowDTOs + EventShowDTO show1 = createEventShowDTO( + Instant.parse("2024-06-15T00:00:00.000Z"), + Instant.parse("2024-06-15T10:00:00.000Z"), + Instant.parse("2024-06-15T22:00:00.000Z"), + Arrays.asList(Genre.COMEDY, Genre.DRAMA), + Arrays.asList(seatType1Show1, seatType2Show1) + ); + + EventShowDTO show2 = createEventShowDTO( + Instant.parse("2024-06-16T00:00:00.000Z"), + Instant.parse("2024-06-16T10:00:00.000Z"), + Instant.parse("2024-06-16T22:00:00.000Z"), + Arrays.asList(Genre.ACTION, Genre.THRILLER), + List.of(seatType1Show2) + ); + + // Create the main EventDTO + return EventDTO.builder() + .title("Circus Festival 2024") + .description("A two-day music festival featuring top artists.") + .vendorId("79984c71-6080-4251-adcc-254c8939a8bc") + .venueId("8d05ee6c-2f69-4650-b5a5-0aa7ebfd9909") + .eventTypeId("2172e49a-ba32-4e52-9814-6d6ed043c6ee") + .startDate(Instant.parse("2024-06-15T00:00:00.000Z")) + .endDate(Instant.parse("2024-06-16T23:59:59.000Z")) + .shows(Arrays.asList(show1, show2)) + .build(); + } + + private static SeatType createSeatType(String uuid, String label, BigDecimal price) { + SeatType seatType = new SeatType(); + seatType.setId(UUID.fromString(uuid)); + seatType.setLabel(label); + seatType.setPrice(price); + return seatType; + } + + public static List createSeatTypes() { + return List.of( + createSeatType(SEAT_TYPE_ID1, REGULAR_LABEL, BigDecimal.valueOf(100)), + createSeatType(SEAT_TYPE_ID2, VIP_LABEL, BigDecimal.valueOf(200)), + createSeatType(SEAT_TYPE_ID3, GOLD_LABEL, BigDecimal.valueOf(300)) + ); + } + + public static Venue createVenue(EventDTO eventDTO) { + Venue venue = new Venue(); + venue.setId(UUID.fromString(eventDTO.getVenueId())); + List seats = EventHelpers.createSeats(); + venue.setSeats(seats); + + return venue; + } +}