├── README.md ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── src ├── main │ ├── java │ │ └── com │ │ │ └── icbt │ │ │ └── ap │ │ │ └── mobileaccessoriessales │ │ │ ├── controller │ │ │ ├── CommonController.java │ │ │ └── v1 │ │ │ │ ├── model │ │ │ │ ├── response │ │ │ │ │ ├── StockRequestDetailResponse.java │ │ │ │ │ ├── CustomerResponse.java │ │ │ │ │ ├── ProductResponse.java │ │ │ │ │ ├── ProductResultResponse.java │ │ │ │ │ ├── SalesAgentResponse.java │ │ │ │ │ ├── UserLoginResponse.java │ │ │ │ │ ├── OrderTotalAmountBySalesAgentResponse.java │ │ │ │ │ ├── CustomerLoginResponse.java │ │ │ │ │ ├── OrderStatusResponse.java │ │ │ │ │ ├── BranchResponse.java │ │ │ │ │ ├── StockResponse.java │ │ │ │ │ ├── OrderResultResponse.java │ │ │ │ │ └── StockRequestResponse.java │ │ │ │ └── request │ │ │ │ │ ├── ProductSaveRequest.java │ │ │ │ │ ├── StockQtyUpdateRequest.java │ │ │ │ │ ├── UserLoginRequest.java │ │ │ │ │ ├── CustomerLoginRequest.java │ │ │ │ │ ├── ProductUpdateRequest.java │ │ │ │ │ ├── BranchSaveRequest.java │ │ │ │ │ ├── StockRequestDetailRequest.java │ │ │ │ │ ├── SalesAgentSaveRequest.java │ │ │ │ │ ├── SalesAgentUpdateRequest.java │ │ │ │ │ ├── BranchUpdateRequest.java │ │ │ │ │ ├── StockRequestUpdateRequest.java │ │ │ │ │ ├── CustomerSaveRequest.java │ │ │ │ │ ├── StockRequestMakeRequest.java │ │ │ │ │ ├── CustomerUpdateRequest.java │ │ │ │ │ ├── StockSaveRequest.java │ │ │ │ │ └── StockUpdateRequest.java │ │ │ │ ├── util │ │ │ │ └── ApiConstant.java │ │ │ │ └── rest │ │ │ │ ├── UserController.java │ │ │ │ ├── ProductResultController.java │ │ │ │ └── OrderController.java │ │ │ ├── service │ │ │ ├── SalesAgentService.java │ │ │ ├── main │ │ │ │ └── CrudService.java │ │ │ ├── BranchService.java │ │ │ ├── VehicleService.java │ │ │ ├── CustomerService.java │ │ │ ├── UserService.java │ │ │ ├── ProductService.java │ │ │ ├── StockRequestService.java │ │ │ ├── StockService.java │ │ │ ├── OrderService.java │ │ │ └── impl │ │ │ │ ├── OrderServiceImpl.java │ │ │ │ ├── VehicleServiceImpl.java │ │ │ │ ├── BranchServiceImpl.java │ │ │ │ ├── SalesAgentServiceImpl.java │ │ │ │ ├── ProductServiceImpl.java │ │ │ │ ├── CustomerServiceImpl.java │ │ │ │ ├── UserServiceImpl.java │ │ │ │ └── StockServiceImpl.java │ │ │ ├── util │ │ │ ├── notification │ │ │ │ ├── NotificationSender.java │ │ │ │ ├── dto │ │ │ │ │ └── NotificationDTO.java │ │ │ │ ├── impl │ │ │ │ │ ├── SmsNotification.java │ │ │ │ │ └── EmailNotification.java │ │ │ │ └── factory │ │ │ │ │ └── NotificationFactory.java │ │ │ └── StringUtil.java │ │ │ ├── dto │ │ │ ├── ContentResponseDTO.java │ │ │ └── CommonResponseDTO.java │ │ │ ├── constant │ │ │ └── AppConstant.java │ │ │ ├── repository │ │ │ ├── UserRepository.java │ │ │ ├── VehicleRepository.java │ │ │ ├── SalesAgentRepository.java │ │ │ ├── CustomerRepository.java │ │ │ ├── main │ │ │ │ └── CrudRepository.java │ │ │ ├── BranchRepository.java │ │ │ ├── StockRequestDetailRepository.java │ │ │ ├── ProductRepository.java │ │ │ ├── StockRepository.java │ │ │ ├── StockRequestRepository.java │ │ │ ├── OrderRepository.java │ │ │ └── impl │ │ │ │ ├── VehicleRepositoryImpl.java │ │ │ │ ├── SalesAgentRepositoryRepositoryImpl.java │ │ │ │ ├── UserRepositoryImpl.java │ │ │ │ ├── CustomerRepositoryImpl.java │ │ │ │ ├── BranchRepositoryImpl.java │ │ │ │ ├── StockRequestDetailRepositoryImpl.java │ │ │ │ ├── ProductRepositoryImpl.java │ │ │ │ ├── StockRepositoryImpl.java │ │ │ │ └── OrderRepositoryImpl.java │ │ │ ├── entity │ │ │ ├── query │ │ │ │ ├── StockResult.java │ │ │ │ ├── ProductResult.java │ │ │ │ ├── OrderTotalAmountBySalesAgent.java │ │ │ │ ├── StockRequestResult.java │ │ │ │ ├── OrderResult.java │ │ │ │ └── OrderStatus.java │ │ │ ├── StockRequestDetail.java │ │ │ ├── OrderDetail.java │ │ │ ├── Vehicle.java │ │ │ ├── Order.java │ │ │ ├── Customer.java │ │ │ ├── Stock.java │ │ │ ├── User.java │ │ │ ├── Product.java │ │ │ ├── Branch.java │ │ │ └── StockRequest.java │ │ │ ├── MobileAccessoriesSalesServerApplication.java │ │ │ ├── exception │ │ │ ├── CustomAuthException.java │ │ │ ├── CustomServiceException.java │ │ │ └── AppExceptionHandler.java │ │ │ ├── ServletInitializer.java │ │ │ ├── enums │ │ │ ├── BranchType.java │ │ │ ├── BranchStatus.java │ │ │ ├── ProductStatus.java │ │ │ ├── UserRole.java │ │ │ ├── StockRequestStatus.java │ │ │ └── OrderRequestStatus.java │ │ │ └── config │ │ │ └── AppConfig.java │ └── resources │ │ ├── application.properties │ │ └── messages │ │ ├── success-message.properties │ │ └── exception-message.properties └── test │ └── java │ └── com │ └── icbt │ └── ap │ └── mobileaccessoriessales │ ├── MobileAccessoriesSalesServerApplicationTests.java │ ├── repository │ └── impl │ │ ├── VehicleRepositoryImplTest.java │ │ ├── UserRepositoryImplTest.java │ │ ├── StockRequestDetailRepositoryImplTest.java │ │ ├── StockRequestRepositoryImplTest.java │ │ ├── ProductRepositoryImplTest.java │ │ ├── BranchRepositoryImplTest.java │ │ └── StockRepositoryImplTest.java │ ├── service │ └── impl │ │ ├── UserServiceImplTest.java │ │ ├── VehicleServiceImplTest.java │ │ ├── ProductServiceImplTest.java │ │ ├── BranchServiceImplTest.java │ │ ├── StockServiceImplTest.java │ │ └── StockRequestServiceImplTest.java │ └── controller │ └── v1 │ └── rest │ └── ProductControllerTest.java ├── .gitignore └── pom.xml /README.md: -------------------------------------------------------------------------------- 1 | # mobile_accessories_sales_server 2 | Mobile accessories sales backend using spring boot - java 3 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supuna97/mobile_accessories_sales_server/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/CommonController.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller; 2 | 3 | import org.springframework.web.bind.annotation.CrossOrigin; 4 | 5 | @CrossOrigin 6 | public interface CommonController { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/SalesAgentService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.User; 4 | import com.icbt.ap.mobileaccessoriessales.service.main.CrudService; 5 | 6 | public interface SalesAgentService extends CrudService { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/util/notification/NotificationSender.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.util.notification; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.util.notification.dto.NotificationDTO; 4 | 5 | public interface NotificationSender { 6 | void sendNotification(NotificationDTO notificationDTO); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/dto/ContentResponseDTO.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.dto; 2 | 3 | import lombok.*; 4 | 5 | @AllArgsConstructor 6 | @Getter 7 | @Setter 8 | @Builder 9 | @ToString(callSuper = true) 10 | public class ContentResponseDTO { 11 | private boolean success; 12 | private T data; 13 | } -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/constant/AppConstant.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.constant; 2 | 3 | public class AppConstant { 4 | public static final String DEFAULT_SUCCESS_CODE = "200"; 5 | public static final String DEFAULT_SUCCESS_MESSAGE = "Operation is successful"; 6 | 7 | private AppConstant() { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/main/CrudService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.main; 2 | 3 | import java.util.List; 4 | 5 | public interface CrudService { 6 | void add(T t); 7 | 8 | void update(T t); 9 | 10 | void delete(K id); 11 | 12 | T getById(K id); 13 | 14 | List getAll(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/dto/CommonResponseDTO.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.dto; 2 | 3 | import lombok.*; 4 | 5 | @AllArgsConstructor 6 | @Getter 7 | @Setter 8 | @Builder 9 | @ToString(callSuper = true) 10 | public class CommonResponseDTO { 11 | private boolean success; 12 | private String code; 13 | private String message; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.User; 4 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 5 | 6 | public interface UserRepository extends CrudRepository { 7 | User findByUserName(String username); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/VehicleRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Vehicle; 4 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 5 | 6 | public interface VehicleRepository extends CrudRepository { 7 | Vehicle findByRegNo(String regNo); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/SalesAgentRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.User; 4 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 5 | 6 | public interface SalesAgentRepository extends CrudRepository { 7 | User findByUserName(String username); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Customer; 4 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 5 | 6 | public interface CustomerRepository extends CrudRepository { 7 | Customer findByCustomerName(String name); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/BranchService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 4 | import com.icbt.ap.mobileaccessoriessales.service.main.CrudService; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service 8 | public interface BranchService extends CrudService { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/VehicleService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Vehicle; 4 | import com.icbt.ap.mobileaccessoriessales.service.main.CrudService; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service 8 | public interface VehicleService extends CrudService { 9 | 10 | } -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.util; 2 | 3 | public class StringUtil { 4 | private StringUtil() { 5 | } 6 | 7 | public static boolean isBlank(String value) { 8 | return value == null || value.isBlank(); 9 | } 10 | 11 | public static boolean isNotBlank(String value) { 12 | return !isBlank(value); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/main/CrudRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.main; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | public interface CrudRepository { 7 | List findAll(); 8 | 9 | Optional findById(K id); 10 | 11 | void save(T entity); 12 | 13 | void update(T entity); 14 | 15 | void delete(K id); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/BranchRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 4 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 5 | 6 | public interface BranchRepository extends CrudRepository { 7 | 8 | Branch findByName(String name); 9 | 10 | Branch findByTel(String tel); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/util/notification/dto/NotificationDTO.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.util.notification.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | @AllArgsConstructor 8 | @Data 9 | @SuperBuilder 10 | public class NotificationDTO { 11 | private String message; 12 | private String topic; 13 | private String destination; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/query/StockResult.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity.query; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Stock; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | @SuperBuilder 11 | public class StockResult extends Stock { 12 | private String branchName; 13 | private String productName; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/StockRequestDetail.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @SuperBuilder 10 | public class StockRequestDetail { 11 | private String id; 12 | private Integer qty; 13 | /*FKs*/ 14 | private String stockRequestId; 15 | private String productId; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/OrderDetail.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class OrderDetail { 13 | private String id; 14 | private LocalDateTime createdAt; 15 | private String orderId; 16 | private String stockId; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/MobileAccessoriesSalesServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MobileAccessoriesSalesServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MobileAccessoriesSalesServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/CustomerService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.request.CustomerLoginRequest; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Customer; 5 | import com.icbt.ap.mobileaccessoriessales.service.main.CrudService; 6 | 7 | public interface CustomerService extends CrudService { 8 | Customer authenticate(CustomerLoginRequest loginRequest); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/StockRequestDetailResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @SuperBuilder 10 | public class StockRequestDetailResponse { 11 | private String id; 12 | private String productId; 13 | private String productName; 14 | private Integer qty; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/CustomerResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @SuperBuilder 10 | public class CustomerResponse { 11 | private String id; 12 | private String name; 13 | private String mobile; 14 | private String address; 15 | private String username; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/ProductResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @SuperBuilder 10 | public class ProductResponse { 11 | private String id; 12 | private String name; 13 | private String status; 14 | private Integer statusId; 15 | private String createdAt; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/Vehicle.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class Vehicle { 13 | private String id; 14 | private String regNo; 15 | private String driverId; 16 | private LocalDateTime createdAt; 17 | /*FKs*/ 18 | private String branchId; 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/exception/CustomAuthException.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.exception; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class CustomAuthException extends RuntimeException{ 7 | private final String code; 8 | private final String message; 9 | private final String[] args; 10 | 11 | public CustomAuthException(String code, String message, String[] args) { 12 | this.code = code; 13 | this.message = message; 14 | this.args = args; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.request.UserLoginRequest; 4 | import com.icbt.ap.mobileaccessoriessales.entity.User; 5 | import com.icbt.ap.mobileaccessoriessales.service.main.CrudService; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service 9 | public interface UserService extends CrudService { 10 | 11 | User authenticate(UserLoginRequest loginRequest); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(MobileAccessoriesSalesServerApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/Order.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class Order { 13 | private String id; 14 | private String totalAmount; 15 | private LocalDateTime createdAt; 16 | private String status; 17 | private String customerId; 18 | private String salesRepId; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/query/ProductResult.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity.query; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class ProductResult { 13 | private String id; 14 | private String name; 15 | private Integer qty; 16 | private String price; 17 | private String description; 18 | private String status; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/ProductResultResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @SuperBuilder 10 | public class ProductResultResponse { 11 | private String id; 12 | private String name; 13 | private Integer qty; 14 | private String price; 15 | private String description; 16 | private String status; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/SalesAgentResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.enums.UserRole; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | @SuperBuilder 11 | public class SalesAgentResponse { 12 | private String id; 13 | private String username; 14 | private UserRole userRole; 15 | private String branchId; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/UserLoginResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.enums.UserRole; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | @SuperBuilder 11 | public class UserLoginResponse { 12 | private String id; 13 | private String username; 14 | private UserRole userRole; 15 | private String branchId; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/StockRequestDetailRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.StockRequestDetail; 4 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface StockRequestDetailRepository extends CrudRepository { 9 | List findAllByStockRequest(String stockRequestId); 10 | 11 | void saveAll(List stocks); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/Customer.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.enums.UserRole; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class Customer { 13 | private String id; 14 | private String name; 15 | private String mobile; 16 | private String address; 17 | private String username; 18 | private String password; 19 | private UserRole userRole; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/query/OrderTotalAmountBySalesAgent.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity.query; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class OrderTotalAmountBySalesAgent { 13 | private String repId; 14 | private String repName; 15 | private String branchId; 16 | private String branchName; 17 | private String totalOrder; 18 | private String totalAmount; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/ProductSaveRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import javax.validation.constraints.NotBlank; 8 | 9 | import static com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant.Validation; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | @SuperBuilder 14 | public class ProductSaveRequest { 15 | @NotBlank(message = Validation.NAME_REQUIRED) 16 | private String name; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/OrderTotalAmountBySalesAgentResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @SuperBuilder 10 | public class OrderTotalAmountBySalesAgentResponse { 11 | private String repId; 12 | private String repName; 13 | private String branchId; 14 | private String branchName; 15 | private String totalOrder; 16 | private String totalAmount; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/Stock.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.math.BigDecimal; 8 | import java.time.LocalDateTime; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class Stock { 14 | private String id; 15 | private String description; 16 | private Integer qty; 17 | private BigDecimal price; 18 | private String branchId; 19 | private String productId; 20 | private LocalDateTime createdAt; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.enums.UserRole; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | @Data 9 | @NoArgsConstructor //default constructor 10 | @SuperBuilder //builder design pattern -> object creation readable 11 | public class User { 12 | private String id; 13 | private String username; 14 | private String password; 15 | private UserRole userRole; 16 | /*FKs*/ 17 | private String branchId; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/query/StockRequestResult.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity.query; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.StockRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.NoArgsConstructor; 7 | import lombok.experimental.SuperBuilder; 8 | 9 | @EqualsAndHashCode(callSuper = true) 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class StockRequestResult extends StockRequest { 14 | private String byBranchName; 15 | private String forBranchName; 16 | private String vehicleReg; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/query/OrderResult.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity.query; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class OrderResult { 13 | private String id; 14 | private String totalAmount; 15 | private LocalDateTime createdAt; 16 | private String status; 17 | private String customerName; 18 | private String customerMobile; 19 | private String salesAgentName; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/CustomerLoginResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.enums.UserRole; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | @SuperBuilder 11 | public class CustomerLoginResponse { 12 | private String id; 13 | private String name; 14 | private String mobile; 15 | private String address; 16 | private String username; 17 | private UserRole userRole; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/OrderStatusResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class OrderStatusResponse { 13 | private String id; 14 | private String totalAmount; 15 | private LocalDateTime createdAt; 16 | private String status; 17 | private String customerName; 18 | private String customerMobile; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/Product.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.enums.ProductStatus; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.NoArgsConstructor; 7 | import lombok.experimental.SuperBuilder; 8 | 9 | import java.time.LocalDateTime; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | @SuperBuilder 14 | public class Product { 15 | private String id; 16 | @EqualsAndHashCode.Exclude 17 | private String name; 18 | private ProductStatus status; 19 | private LocalDateTime createdAt; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.ProductResult; 5 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 6 | 7 | import java.util.List; 8 | 9 | public interface ProductRepository extends CrudRepository { 10 | 11 | Product findByName(String name); 12 | 13 | List findAllByIdsIn(List productIds); 14 | 15 | List findAllProductDetails(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/BranchResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @SuperBuilder 10 | public class BranchResponse { 11 | private String id; 12 | private String name; 13 | private String address; 14 | private String tel; 15 | private String type; 16 | private Integer typeId; 17 | private String status; 18 | private Integer statusId; 19 | private String createdAt; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.ProductResult; 5 | import com.icbt.ap.mobileaccessoriessales.service.main.CrudService; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.List; 9 | 10 | @Service 11 | public interface ProductService extends CrudService { 12 | 13 | List validateAndGetProductsByIds(List productIds); 14 | 15 | List getAllProductDetails(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/StockResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @SuperBuilder 10 | public class StockResponse { 11 | private String id; 12 | private String description; 13 | private String qty; 14 | private String price; 15 | private String branchId; 16 | private String branchName; 17 | private String productId; 18 | private String productName; 19 | private String createdAt; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/OrderResultResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class OrderResultResponse { 13 | private String id; 14 | private String totalAmount; 15 | private LocalDateTime createdAt; 16 | private String status; 17 | private String customerName; 18 | private String customerMobile; 19 | private String salesAgentName; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/query/OrderStatus.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity.query; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.enums.OrderRequestStatus; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class OrderStatus { 14 | private String id; 15 | private String totalAmount; 16 | private LocalDateTime createdAt; 17 | private OrderRequestStatus status; 18 | private String customerName; 19 | private String customerMobile; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/StockQtyUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class StockQtyUpdateRequest { 14 | @NotBlank(message = ApiConstant.Validation.ID_REQUIRED) 15 | private String id; 16 | @NotBlank(message = ApiConstant.Validation.QTY_REQUIRED) 17 | private Integer qty; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/StockRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Stock; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.StockResult; 5 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 6 | 7 | import java.util.List; 8 | 9 | public interface StockRepository extends CrudRepository { 10 | List findAllByBranch(String branchId); 11 | 12 | List findAllByProduct(String productId); 13 | 14 | List findAllByIdsIn(List stockIds); 15 | 16 | void updateListQty(List stocks); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/UserLoginRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class UserLoginRequest { 14 | @NotBlank(message = ApiConstant.Validation.USERNAME_REQUIRED) 15 | private String username; 16 | @NotBlank(message = ApiConstant.Validation.PASSWORD_REQUIRED) 17 | private String password; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/Branch.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.enums.BranchStatus; 4 | import com.icbt.ap.mobileaccessoriessales.enums.BranchType; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | import lombok.experimental.SuperBuilder; 8 | 9 | import java.time.LocalDateTime; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | @SuperBuilder 14 | public class Branch { 15 | private String id; 16 | private String name; 17 | private String address; 18 | private String tel; 19 | private BranchType type; 20 | private BranchStatus status; 21 | private LocalDateTime createdAt; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/CustomerLoginRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class CustomerLoginRequest { 14 | @NotBlank(message = ApiConstant.Validation.USERNAME_REQUIRED) 15 | private String username; 16 | @NotBlank(message = ApiConstant.Validation.PASSWORD_REQUIRED) 17 | private String password; 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/MobileAccessoriesSalesServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.extension.ExtendWith; 6 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.junit.jupiter.SpringExtension; 9 | 10 | @Slf4j 11 | @ExtendWith(SpringExtension.class) 12 | @SpringBootTest 13 | @AutoConfigureMockMvc 14 | class MobileAccessoriesSalesServerApplicationTests { 15 | 16 | @Test 17 | void contextLoads() { 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/ProductUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class ProductUpdateRequest { 14 | @NotBlank(message = ApiConstant.Validation.ID_REQUIRED) 15 | private String id; 16 | @NotBlank(message = ApiConstant.Validation.NAME_REQUIRED) 17 | private String name; 18 | private Integer statusId; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/BranchSaveRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class BranchSaveRequest { 14 | @NotBlank(message = ApiConstant.Validation.NAME_REQUIRED) 15 | private String name; 16 | @NotBlank(message = ApiConstant.Validation.ADDRESS_REQUIRED) 17 | private String address; 18 | @NotBlank(message = ApiConstant.Validation.TEL_REQUIRED) 19 | private String tel; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/StockRequestDetailRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.Min; 9 | import javax.validation.constraints.NotBlank; 10 | import javax.validation.constraints.NotNull; 11 | 12 | @Data 13 | @NoArgsConstructor 14 | @SuperBuilder 15 | public class StockRequestDetailRequest { 16 | private String id; 17 | @NotBlank(message = ApiConstant.Validation.PRODUCT_ID_REQUIRED) 18 | private String productId; 19 | @NotNull 20 | @Min(1) 21 | private Integer qty; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/response/StockRequestResponse.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.response; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.List; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @SuperBuilder 12 | public class StockRequestResponse { 13 | private String id; 14 | private String byBranchId; 15 | private String forBranchId; 16 | private String vehicleId; 17 | private String byBranchName; 18 | private String forBranchName; 19 | private String vehicleReg; 20 | private String status; 21 | private String createdAt; 22 | private String updatedAt; 23 | private List stockRequestDetails; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/entity/StockRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.entity; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.enums.StockRequestStatus; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.List; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | @SuperBuilder 14 | public class StockRequest { 15 | private String id; 16 | private StockRequestStatus status; 17 | private LocalDateTime createdAt; 18 | private LocalDateTime updatedAt; 19 | /*FKs*/ 20 | private String byBranchId; 21 | private String forBranchId; 22 | private String vehicleId; 23 | /*Child tables*/ 24 | private List stockRequestDetails; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/SalesAgentSaveRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class SalesAgentSaveRequest { 14 | @NotBlank(message = ApiConstant.Validation.USERNAME_REQUIRED) 15 | private String username; 16 | @NotBlank(message = ApiConstant.Validation.PASSWORD_REQUIRED) 17 | private String password; 18 | @NotBlank(message = ApiConstant.Validation.BRANCH_REQUIRED) 19 | private String branchId; 20 | private String userRole; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/StockRequestRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.StockRequest; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.StockRequestResult; 5 | import com.icbt.ap.mobileaccessoriessales.enums.StockRequestStatus; 6 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 7 | 8 | import java.util.List; 9 | 10 | public interface StockRequestRepository extends CrudRepository { 11 | String saveAndGetId(StockRequest stock); 12 | 13 | void updateStatus(String id, StockRequestStatus status); 14 | 15 | List findAllByRequestByBranch(String byBranchId); 16 | 17 | List findAllByRequestToBranch(String toBranchId); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/StockRequestService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.StockRequest; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.StockRequestResult; 5 | import com.icbt.ap.mobileaccessoriessales.enums.StockRequestStatus; 6 | import com.icbt.ap.mobileaccessoriessales.service.main.CrudService; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public interface StockRequestService extends CrudService { 13 | 14 | List getAllByRequestedByBranch(String branchId); 15 | 16 | List getAllByRequestedForBranch(String branchId); 17 | 18 | void updateStatus(String stockRequestId, StockRequestStatus status); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/enums/BranchType.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | @Getter 10 | @AllArgsConstructor 11 | public enum BranchType { 12 | 13 | HEAD_OFFICE(1, "Head Office"), BRANCH(2, "Branch"); 14 | 15 | private final Integer id; 16 | private final String description; 17 | 18 | public static List getList() { 19 | return Arrays.asList(BranchType.values().clone()); 20 | } 21 | 22 | public static BranchType getById(Integer id) { 23 | return getList() 24 | .stream() 25 | .filter(branchType -> branchType.id.equals(id)) 26 | .findFirst() 27 | .orElse(null); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/StockService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.request.StockQtyUpdateRequest; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Stock; 5 | import com.icbt.ap.mobileaccessoriessales.entity.query.StockResult; 6 | import com.icbt.ap.mobileaccessoriessales.service.main.CrudService; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public interface StockService extends CrudService { 13 | 14 | List getAllByBranch(String branchId); 15 | 16 | List getAllByProduct(String productId); 17 | 18 | void updateStockQty(List qtyUpdateRequests); 19 | 20 | List validateAndGetStocksByIds(List stockIds); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/enums/BranchStatus.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | @Getter 10 | @AllArgsConstructor 11 | public enum BranchStatus { 12 | 13 | ACTIVE(1, "Active"), INACTIVE(0, "Inactive"), DELETED(-1, "Deleted"); 14 | 15 | private final Integer id; 16 | private final String description; 17 | 18 | public static List getList() { 19 | return Arrays.asList(BranchStatus.values().clone()); 20 | } 21 | 22 | public static BranchStatus getById(Integer id) { 23 | return getList() 24 | .stream() 25 | .filter(branchStatus -> branchStatus.id.equals(id)) 26 | .findFirst() 27 | .orElse(null); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/enums/ProductStatus.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | @Getter 10 | @AllArgsConstructor 11 | public enum ProductStatus { 12 | 13 | ACTIVE(1, "Active"), INACTIVE(0, "Inactive"), DELETED(-1, "Deleted"); 14 | 15 | private final Integer id; 16 | private final String description; 17 | 18 | public static List getList() { 19 | return Arrays.asList(ProductStatus.values().clone()); 20 | } 21 | 22 | public static ProductStatus getById(Integer id) { 23 | return getList() 24 | .stream() 25 | .filter(productStatus -> productStatus.id.equals(id)) 26 | .findFirst() 27 | .orElse(null); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/SalesAgentUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class SalesAgentUpdateRequest { 14 | @NotBlank(message = ApiConstant.Validation.ID_REQUIRED) 15 | private String id; 16 | @NotBlank(message = ApiConstant.Validation.USERNAME_REQUIRED) 17 | private String username; 18 | @NotBlank(message = ApiConstant.Validation.PASSWORD_REQUIRED) 19 | private String password; 20 | @NotBlank(message = ApiConstant.Validation.BRANCH_REQUIRED) 21 | private String branchId; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/BranchUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class BranchUpdateRequest { 14 | @NotBlank(message = ApiConstant.Validation.ID_REQUIRED) 15 | private String id; 16 | @NotBlank(message = ApiConstant.Validation.NAME_REQUIRED) 17 | private String name; 18 | @NotBlank(message = ApiConstant.Validation.ADDRESS_REQUIRED) 19 | private String address; 20 | @NotBlank(message = ApiConstant.Validation.TEL_REQUIRED) 21 | private String tel; 22 | private Integer statusId; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Order; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderResult; 5 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderTotalAmountBySalesAgent; 6 | import com.icbt.ap.mobileaccessoriessales.enums.OrderRequestStatus; 7 | import com.icbt.ap.mobileaccessoriessales.enums.StockRequestStatus; 8 | import com.icbt.ap.mobileaccessoriessales.service.main.CrudService; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.List; 12 | 13 | @Service 14 | public interface OrderService extends CrudService { 15 | List findAllOrder(); 16 | 17 | List findAllTotalAmountSaleByAgent(); 18 | 19 | void updateStatus(String orderId, OrderRequestStatus status); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/enums/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | @Getter 10 | @AllArgsConstructor 11 | public enum UserRole { 12 | 13 | HEAD_OFFICE_ADMIN(1, "Admin"), BRANCH_ADMIN(2, "Sales Agent"), 14 | SUPPLIER(3,"Supplier"), DELETED(-1, "Deleted"), CUSTOMER(4, "Customer"); 15 | 16 | private final Integer id; 17 | private final String description; 18 | 19 | public static List getList() { 20 | return Arrays.asList(UserRole.values().clone()); 21 | } 22 | 23 | public static UserRole getById(Integer id) { 24 | return getList() 25 | .stream() 26 | .filter(userRole -> userRole.id.equals(id)) 27 | .findFirst() 28 | .orElse(null); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/StockRequestUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | import java.util.List; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | @SuperBuilder 14 | public class StockRequestUpdateRequest { 15 | @NotBlank(message = ApiConstant.Validation.ID_REQUIRED) 16 | private String id; 17 | @NotBlank(message = ApiConstant.Validation.BY_BRANCH_REQUIRED) 18 | private String byBranchId; 19 | @NotBlank(message = ApiConstant.Validation.FOR_BRANCH_REQUIRED) 20 | private String forBranchId; 21 | private String vehicleId; 22 | private List stockRequestDetails; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | ## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) 3 | spring.datasource.url=jdbc:mysql://localhost:3306/sales_db?useSSL=false 4 | spring.datasource.username=root 5 | spring.datasource.password=1234 6 | ## Hibernate Properties 7 | #The SQL dialect makes Hibernate generate better SQL for the chosen database 8 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect 9 | # Hibernate ddl auto (create, create-drop, validate, update) 10 | spring.jpa.hibernate.ddl-auto=update 11 | logging.level.org.hibernate.stat=debug 12 | # Show all queries 13 | spring.jpa.show-sql=true 14 | spring.jpa.properties.hibernate.format_sql=true 15 | logging.level.org.hibernate.type=trace 16 | server.servlet.context-path=/api 17 | # HikariCP settings 18 | # spring.datasource.hikari.* 19 | #60 sec 20 | spring.datasource.hikari.connection-timeout=60000 21 | # max 10 22 | spring.datasource.hikari.maximum-pool-size=10 -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/enums/StockRequestStatus.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | @Getter 10 | @AllArgsConstructor 11 | public enum StockRequestStatus { 12 | 13 | PENDING(0, "Pending"), DONE(1, "Done"), 14 | REJECTED(2, "Rejected"), ON_DELIVERY(3, "On Delivery"); 15 | 16 | private final Integer id; 17 | private final String description; 18 | 19 | public static List getList() { 20 | return Arrays.asList(StockRequestStatus.values().clone()); 21 | } 22 | 23 | public static StockRequestStatus getById(Integer id) { 24 | return getList() 25 | .stream() 26 | .filter(stockRequestStatus -> stockRequestStatus.id.equals(id)) 27 | .findFirst() 28 | .orElse(null); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/enums/OrderRequestStatus.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | @Getter 10 | @AllArgsConstructor 11 | public enum OrderRequestStatus { 12 | ORDER_PENDING(0, "Pending"), ORDER_DONE(1, "Done"), 13 | ORDER_REJECTED(2, "Rejected"), ORDER_DELIVERY(3, "On Delivery"); 14 | 15 | private final Integer id; 16 | private final String description; 17 | 18 | public static List getList() { 19 | return Arrays.asList(OrderRequestStatus.values().clone()); 20 | } 21 | 22 | public static OrderRequestStatus getById(Integer id) { 23 | return getList() 24 | .stream() 25 | .filter(orderRequestStatus -> orderRequestStatus.id.equals(id)) 26 | .findFirst() 27 | .orElse(null); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/CustomerSaveRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class CustomerSaveRequest { 14 | @NotBlank(message = ApiConstant.Validation.NAME_REQUIRED) 15 | private String name; 16 | @NotBlank(message = ApiConstant.Validation.TEL_REQUIRED) 17 | private String mobile; 18 | @NotBlank(message = ApiConstant.Validation.ADDRESS_REQUIRED) 19 | private String address; 20 | @NotBlank(message = ApiConstant.Validation.USERNAME_REQUIRED) 21 | private String username; 22 | @NotBlank(message = ApiConstant.Validation.PASSWORD_REQUIRED) 23 | private String password; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Order; 4 | import com.icbt.ap.mobileaccessoriessales.entity.OrderDetail; 5 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderResult; 6 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderTotalAmountBySalesAgent; 7 | import com.icbt.ap.mobileaccessoriessales.enums.OrderRequestStatus; 8 | import com.icbt.ap.mobileaccessoriessales.repository.main.CrudRepository; 9 | 10 | import java.util.List; 11 | 12 | public interface OrderRepository extends CrudRepository { 13 | List findAllByOrderBySalesAgent(String bySalesAgentId); 14 | 15 | List findAllOrder(); 16 | 17 | List findAllOrderDetails(); 18 | 19 | List findAllTotalAmountSaleByAgent(); 20 | 21 | void updateStatus(String id, OrderRequestStatus status); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/StockRequestMakeRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.Valid; 9 | import javax.validation.constraints.NotBlank; 10 | import javax.validation.constraints.NotEmpty; 11 | import java.util.List; 12 | 13 | @Data 14 | @NoArgsConstructor 15 | @SuperBuilder 16 | public class StockRequestMakeRequest { 17 | @NotBlank(message = ApiConstant.Validation.BY_BRANCH_REQUIRED) 18 | private String byBranchId; 19 | @NotBlank(message = ApiConstant.Validation.FOR_BRANCH_REQUIRED) 20 | private String forBranchId; 21 | private String vehicleId; 22 | @Valid 23 | @NotEmpty(message = ApiConstant.Validation.PRODUCT_DETAILS_REQUIRED) 24 | private List stockRequestDetails; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/CustomerUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @SuperBuilder 13 | public class CustomerUpdateRequest { 14 | @NotBlank(message = ApiConstant.Validation.ID_REQUIRED) 15 | private String id; 16 | @NotBlank(message = ApiConstant.Validation.NAME_REQUIRED) 17 | private String name; 18 | @NotBlank(message = ApiConstant.Validation.TEL_REQUIRED) 19 | private String mobile; 20 | @NotBlank(message = ApiConstant.Validation.ADDRESS_REQUIRED) 21 | private String address; 22 | @NotBlank(message = ApiConstant.Validation.USERNAME_REQUIRED) 23 | private String username; 24 | @NotBlank(message = ApiConstant.Validation.PASSWORD_REQUIRED) 25 | private String password; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/StockSaveRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | import javax.validation.constraints.NotNull; 10 | import javax.validation.constraints.Pattern; 11 | 12 | @Data 13 | @NoArgsConstructor 14 | @SuperBuilder 15 | public class StockSaveRequest { 16 | private String description; 17 | @NotNull 18 | @Pattern(message = "branchId must be a number", regexp = ApiConstant.Validation.PATTERN_NUMBER) 19 | private String qty; 20 | @Pattern(message = "Price must be a number", regexp = ApiConstant.Validation.PATTERN_DECIMAL) 21 | private String price; 22 | @NotBlank(message = ApiConstant.Validation.BRANCH_REQUIRED) 23 | private String branchId; 24 | @NotBlank(message = ApiConstant.Validation.PRODUCT_REQUIRED) 25 | private String productId; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.config; 2 | 3 | import org.springframework.context.MessageSource; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.support.ReloadableResourceBundleMessageSource; 7 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 8 | import org.springframework.security.crypto.password.PasswordEncoder; 9 | 10 | @Configuration 11 | public class AppConfig { 12 | 13 | @Bean 14 | public MessageSource messageSource() { 15 | ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); 16 | messageSource.setBasenames("classpath:messages/exception-message", "classpath:messages/success-message"); 17 | messageSource.setCacheSeconds(60); //reload messages every 60 seconds 18 | return messageSource; 19 | } 20 | 21 | @Bean 22 | public PasswordEncoder passwordEncoder() { 23 | return new BCryptPasswordEncoder(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/messages/success-message.properties: -------------------------------------------------------------------------------- 1 | success.confirmation.common.added.code=201 2 | success.confirmation.common.updated.code=200 3 | success.confirmation.product.added.message=Product is added successfully! 4 | success.confirmation.product.updated.message=Product is updated successfully! 5 | success.confirmation.product.deleted.message=Product is deleted successfully! 6 | success.confirmation.branch.added.message=Branch is added successfully! 7 | success.confirmation.branch.updated.message=Branch is updated successfully! 8 | success.confirmation.branch.deleted.message=Branch is deleted successfully! 9 | success.confirmation.stock.added.message=Stock is added successfully! 10 | success.confirmation.stock.updated.message=Stock is updated successfully! 11 | success.confirmation.stock.qty.updated.message=Stock qty is updated successfully! 12 | success.confirmation.stock.deleted.message=Stock is deleted successfully! 13 | success.confirmation.stock.request.added.message=Stock request is added successfully! 14 | success.confirmation.stock.request.updated.message=Stock request is updated successfully! 15 | success.confirmation.stock.request.deleted.message=Stock request is deleted successfully! -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/util/notification/impl/SmsNotification.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.util.notification.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.util.notification.NotificationSender; 4 | import com.icbt.ap.mobileaccessoriessales.util.notification.dto.NotificationDTO; 5 | 6 | public class SmsNotification implements NotificationSender { 7 | private static SmsNotification smsNotification; 8 | 9 | /** 10 | * private constrictor to initialize properties related to email configurations. 11 | */ 12 | private SmsNotification() { 13 | } 14 | 15 | 16 | /** 17 | * @return the SmsNotification instance which is initialized only once. 18 | */ 19 | public static SmsNotification getInstance() { 20 | if (smsNotification == null) { 21 | smsNotification = new SmsNotification(); 22 | } 23 | return smsNotification; 24 | } 25 | 26 | /** 27 | * @param notificationDTO send notification details 28 | */ 29 | @Override 30 | public void sendNotification(NotificationDTO notificationDTO) { 31 | throw new UnsupportedOperationException("SMS notification is not implemented yet!"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/util/notification/impl/EmailNotification.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.util.notification.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.util.notification.NotificationSender; 4 | import com.icbt.ap.mobileaccessoriessales.util.notification.dto.NotificationDTO; 5 | 6 | 7 | public class EmailNotification implements NotificationSender { 8 | private static EmailNotification emailNotification; 9 | 10 | /** 11 | * private constrictor to initialize properties related to email configurations. 12 | */ 13 | private EmailNotification() { 14 | /*TODO 15 | *Initialize the java mail sender*/ 16 | } 17 | 18 | /** 19 | * @return the EmailNotification instance which is initialized only once. 20 | */ 21 | public static EmailNotification getInstance() { 22 | if (emailNotification == null) { 23 | emailNotification = new EmailNotification(); 24 | } 25 | return emailNotification; 26 | } 27 | 28 | /** 29 | * @param notificationDTO send notification details 30 | */ 31 | @Override 32 | public void sendNotification(NotificationDTO notificationDTO) { 33 | throw new UnsupportedOperationException("Email notification is not implemented yet!"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/exception/CustomServiceException.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.exception; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class CustomServiceException extends RuntimeException{ 7 | private final String code; 8 | private final String message; 9 | private final Throwable throwable; 10 | private final String[] args; 11 | 12 | public CustomServiceException(String code, String message) { 13 | this.code = code; 14 | this.message = message; 15 | this.throwable = null; 16 | this.args = new String[0]; 17 | } 18 | 19 | public CustomServiceException(String code, String message, String[] args) { 20 | this.code = code; 21 | this.message = message; 22 | this.args = args; 23 | this.throwable = null; 24 | } 25 | 26 | public CustomServiceException(String code, String message, Throwable throwable) { 27 | this.code = code; 28 | this.message = message; 29 | this.throwable = throwable; 30 | this.args = new String[0]; 31 | } 32 | 33 | public CustomServiceException(String code, String message, Throwable throwable, String[] args) { 34 | this.code = code; 35 | this.message = message; 36 | this.throwable = throwable; 37 | this.args = args; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/model/request/StockUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.model.request; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | import javax.validation.constraints.NotNull; 10 | import javax.validation.constraints.Pattern; 11 | 12 | import static com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant.Validation.PATTERN_DECIMAL; 13 | import static com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant.Validation.PATTERN_NUMBER; 14 | 15 | @Data 16 | @NoArgsConstructor 17 | @SuperBuilder 18 | public class StockUpdateRequest { 19 | @NotBlank(message = ApiConstant.Validation.ID_REQUIRED) 20 | private String id; 21 | private String description; 22 | @NotNull 23 | @Pattern(message = "branchId must be a number", regexp = PATTERN_NUMBER) 24 | private String qty; 25 | @Pattern(message = "Price must be a number", regexp = PATTERN_DECIMAL) 26 | private String price; 27 | @NotBlank(message = ApiConstant.Validation.BRANCH_REQUIRED) 28 | private String branchId; 29 | @NotBlank(message = ApiConstant.Validation.PRODUCT_REQUIRED) 30 | private String productId; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/messages/exception-message.properties: -------------------------------------------------------------------------------- 1 | error.validation.common.already.exist.code=409 2 | error.validation.common.not.found.code=404 3 | error.validation.unauthorized.code=401 4 | error.validation.forbidden.code=401 5 | error.validation.common.status.not.found.message=Invalid statusId in the request! 6 | error.validation.product.name.already.exist.message=Product name already exists! 7 | error.validation.product.not.found.message=Product does not exist! 8 | error.validation.branch.name.already.exist.message=Branch name already exists! 9 | error.validation.branch.tel.already.exist.message=Branch tel already exists! 10 | error.validation.branch.not.found.message=Branch does not exist! 11 | error.validation.stock.not.found.message=Stock does not exist! 12 | error.validation.stock.id.not.found.message=Stock does not exist for ID: {0} 13 | error.validation.vehicle.not.found.message=Vehicle does not exist! 14 | error.validation.vehicle.regno.already.exist.message=Vehicle reg no already exists! 15 | error.validation.stock.request.not.found.message=Stock request does not exist! 16 | error.validation.product.id.not.found.message=Product does not exist for ID: {0} 17 | error.validation.user.name.already.exist.message=Username already exists! 18 | error.validation.username.not.found.message=User does not exist for username: {0} 19 | error.validation.userid.not.found.message=User does not exist for id: {0} 20 | error.validation.invalid.password.message=Invalid password! -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/util/notification/factory/NotificationFactory.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.util.notification.factory; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.util.notification.NotificationSender; 4 | import com.icbt.ap.mobileaccessoriessales.util.notification.impl.EmailNotification; 5 | import com.icbt.ap.mobileaccessoriessales.util.notification.impl.SmsNotification; 6 | 7 | public class NotificationFactory { 8 | private static NotificationFactory notificationFactory; 9 | 10 | private NotificationFactory() { 11 | } 12 | 13 | public static NotificationFactory getInstance() { 14 | if (notificationFactory == null) { 15 | notificationFactory = new NotificationFactory(); 16 | } 17 | return notificationFactory; 18 | } 19 | 20 | /** 21 | * @param type the notification type 22 | * @return the notification concrete instance of the given type. 23 | */ 24 | public NotificationSender getNotificationSender(NotificationType type) { 25 | switch (type) { 26 | case SMS: 27 | return SmsNotification.getInstance(); 28 | case EMAIL: 29 | return EmailNotification.getInstance(); 30 | default: 31 | throw new UnsupportedOperationException("Given type is not implemented yet"); 32 | } 33 | } 34 | 35 | public enum NotificationType { 36 | SMS, EMAIL 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/util/ApiConstant.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.util; 2 | 3 | import java.time.format.DateTimeFormatter; 4 | 5 | public final class ApiConstant { 6 | private ApiConstant() { 7 | } 8 | 9 | public static final String VERSION = "/v1"; 10 | public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; 11 | public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); 12 | 13 | public static final class Validation { 14 | public static final String ID_REQUIRED = "Id is mandatory"; 15 | public static final String NAME_REQUIRED = "Name is mandatory"; 16 | public static final String ADDRESS_REQUIRED = "Address is mandatory"; 17 | public static final String TEL_REQUIRED = "Tel is mandatory"; 18 | public static final String QTY_REQUIRED = "QTY is mandatory"; 19 | public static final String PRICE_REQUIRED = "Price is mandatory"; 20 | public static final String BRANCH_REQUIRED = "Branch is mandatory"; 21 | public static final String PRODUCT_REQUIRED = "Product is mandatory"; 22 | public static final String BY_BRANCH_REQUIRED = "By branch is mandatory"; 23 | public static final String FOR_BRANCH_REQUIRED = "By branch is mandatory"; 24 | public static final String PRODUCT_DETAILS_REQUIRED = "Product details are mandatory"; 25 | public static final String PRODUCT_ID_REQUIRED = "Product id is mandatory"; 26 | public static final String USERNAME_REQUIRED = "Username is mandatory"; 27 | public static final String PASSWORD_REQUIRED = "Password is mandatory"; 28 | 29 | public static final String PATTERN_NUMBER = "^[0-9]*$"; 30 | public static final String PATTERN_DECIMAL = "\\d*\\.?\\d+"; 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/repository/impl/VehicleRepositoryImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Vehicle; 4 | import com.icbt.ap.mobileaccessoriessales.repository.VehicleRepository; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.jdbc.core.JdbcTemplate; 11 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 12 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 13 | import org.springframework.test.context.junit.jupiter.SpringExtension; 14 | 15 | import javax.sql.DataSource; 16 | import java.util.List; 17 | 18 | import static org.junit.jupiter.api.Assertions.assertTrue; 19 | import static org.junit.jupiter.api.Assertions.*; 20 | 21 | @Slf4j 22 | @ExtendWith(SpringExtension.class) 23 | @SpringBootTest 24 | @AutoConfigureMockMvc 25 | class VehicleRepositoryImplTest { 26 | 27 | private final VehicleRepository branchRepository; 28 | 29 | public VehicleRepositoryImplTest() { 30 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 31 | .addScript("classpath:test/sales_db_test.sql") 32 | .build(); 33 | branchRepository = new VehicleRepositoryImpl(new JdbcTemplate(dataSource)); 34 | } 35 | 36 | @Test 37 | void findAll() { 38 | final List branches = branchRepository.findAll(); 39 | log.info("Vehicles: {}", branches); 40 | assertTrue(branches.size() > 0); 41 | } 42 | 43 | @Test 44 | void findById() { 45 | } 46 | 47 | @Test 48 | void save() { 49 | } 50 | 51 | @Test 52 | void update() { 53 | } 54 | 55 | @Test 56 | void delete() { 57 | } 58 | 59 | @Test 60 | void findByRegNo() { 61 | } 62 | } -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/repository/impl/UserRepositoryImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.User; 4 | import com.icbt.ap.mobileaccessoriessales.repository.UserRepository; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.jdbc.core.JdbcTemplate; 11 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 12 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 13 | import org.springframework.test.context.junit.jupiter.SpringExtension; 14 | 15 | import javax.sql.DataSource; 16 | import java.util.List; 17 | 18 | import static org.junit.jupiter.api.Assertions.assertTrue; 19 | import static org.junit.jupiter.api.Assertions.*; 20 | 21 | @Slf4j 22 | @ExtendWith(SpringExtension.class) 23 | @SpringBootTest 24 | @AutoConfigureMockMvc 25 | class UserRepositoryImplTest { 26 | 27 | private final UserRepository userRepository; 28 | 29 | public UserRepositoryImplTest() { 30 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 31 | .addScript("classpath:test/sales_db_test.sql") 32 | .build(); 33 | userRepository = new UserRepositoryImpl(new JdbcTemplate(dataSource)); 34 | } 35 | 36 | @Test 37 | void findAll() { 38 | final List users = userRepository.findAll(); 39 | log.info("Users: {}", users); 40 | assertTrue(users.size() > 0); 41 | } 42 | 43 | @Test 44 | void findById() { 45 | } 46 | 47 | @Test 48 | void save() { 49 | } 50 | 51 | @Test 52 | void update() { 53 | } 54 | 55 | @Test 56 | void delete() { 57 | } 58 | 59 | @Test 60 | void findByUserName() { 61 | String username = "super"; 62 | final User user = userRepository.findByUserName(username); 63 | assertTrue(user != null && username.equals(user.getUsername())); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/repository/impl/StockRequestDetailRepositoryImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.StockRequestDetail; 4 | import com.icbt.ap.mobileaccessoriessales.repository.StockRequestDetailRepository; 5 | import com.icbt.ap.mobileaccessoriessales.repository.StockRequestRepository; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.extension.ExtendWith; 9 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.jdbc.core.JdbcTemplate; 12 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 13 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 14 | import org.springframework.test.context.junit.jupiter.SpringExtension; 15 | 16 | import javax.sql.DataSource; 17 | import java.util.List; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertTrue; 20 | import static org.junit.jupiter.api.Assertions.*; 21 | 22 | @Slf4j 23 | @ExtendWith(SpringExtension.class) 24 | @SpringBootTest 25 | @AutoConfigureMockMvc 26 | class StockRequestDetailRepositoryImplTest { 27 | 28 | private final StockRequestRepository stockRequestRepository; 29 | private final StockRequestDetailRepository stockRequestDetailRepository; 30 | 31 | public StockRequestDetailRepositoryImplTest() { 32 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 33 | .addScript("classpath:test/sales_db_test.sql") 34 | .build(); 35 | stockRequestRepository = new StockRequestRepositoryImpl(new JdbcTemplate(dataSource)); 36 | stockRequestDetailRepository = new StockRequestDetailRepositoryImpl(new JdbcTemplate(dataSource)); 37 | } 38 | 39 | @Test 40 | void findAll() { 41 | final List stockRequestDetails = stockRequestDetailRepository.findAll(); 42 | log.info("Stocks Request Details: {}", stockRequestDetails); 43 | assertTrue(stockRequestDetails.size() > 0); 44 | } 45 | 46 | @Test 47 | void findById() { 48 | } 49 | 50 | @Test 51 | void save() { 52 | } 53 | 54 | @Test 55 | void update() { 56 | } 57 | 58 | @Test 59 | void delete() { 60 | } 61 | 62 | @Test 63 | void findAllByStockRequest() { 64 | } 65 | } -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/repository/impl/StockRequestRepositoryImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.StockRequest; 4 | import com.icbt.ap.mobileaccessoriessales.repository.StockRepository; 5 | import com.icbt.ap.mobileaccessoriessales.repository.StockRequestRepository; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.extension.ExtendWith; 9 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.jdbc.core.JdbcTemplate; 12 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 13 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 14 | import org.springframework.test.context.junit.jupiter.SpringExtension; 15 | 16 | import javax.sql.DataSource; 17 | import java.util.List; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertTrue; 20 | import static org.junit.jupiter.api.Assertions.*; 21 | 22 | @Slf4j 23 | @ExtendWith(SpringExtension.class) 24 | @SpringBootTest 25 | @AutoConfigureMockMvc 26 | class StockRequestRepositoryImplTest { 27 | 28 | private final StockRequestRepository stockRequestRepository; 29 | private final StockRepository stockRepository; 30 | 31 | public StockRequestRepositoryImplTest() { 32 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 33 | .addScript("classpath:test/sales_db_test.sql") 34 | .build(); 35 | stockRepository = new StockRepositoryImpl(new JdbcTemplate(dataSource)); 36 | stockRequestRepository = new StockRequestRepositoryImpl(new JdbcTemplate(dataSource)); 37 | } 38 | 39 | @Test 40 | void findAll() { 41 | final List stockRequests = stockRequestRepository.findAll(); 42 | log.info("Stocks Requests: {}", stockRequests); 43 | assertTrue(stockRequests.size() > 0); 44 | } 45 | 46 | @Test 47 | void findById() { 48 | } 49 | 50 | @Test 51 | void save() { 52 | } 53 | 54 | @Test 55 | void update() { 56 | } 57 | 58 | @Test 59 | void updateStatus() { 60 | } 61 | 62 | @Test 63 | void delete() { 64 | } 65 | 66 | @Test 67 | void findAllByRequestByBranch() { 68 | } 69 | 70 | @Test 71 | void findAllByRequestToBranch() { 72 | } 73 | } -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/impl/OrderServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Order; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderResult; 5 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderTotalAmountBySalesAgent; 6 | import com.icbt.ap.mobileaccessoriessales.enums.OrderRequestStatus; 7 | import com.icbt.ap.mobileaccessoriessales.enums.ProductStatus; 8 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 9 | import com.icbt.ap.mobileaccessoriessales.repository.OrderRepository; 10 | import com.icbt.ap.mobileaccessoriessales.repository.impl.ProductRepositoryImpl; 11 | import com.icbt.ap.mobileaccessoriessales.service.OrderService; 12 | import lombok.RequiredArgsConstructor; 13 | import lombok.extern.slf4j.Slf4j; 14 | import org.springframework.dao.EmptyResultDataAccessException; 15 | import org.springframework.stereotype.Service; 16 | import org.springframework.transaction.annotation.Transactional; 17 | 18 | import java.util.List; 19 | import java.util.Optional; 20 | 21 | @Service 22 | @RequiredArgsConstructor 23 | @Slf4j 24 | public class OrderServiceImpl implements OrderService { 25 | private final OrderRepository orderRepository; 26 | 27 | @Override 28 | public void add(Order order) { 29 | 30 | } 31 | 32 | @Override 33 | public void update(Order order) { 34 | 35 | } 36 | 37 | @Override 38 | public void delete(String id) { 39 | 40 | } 41 | 42 | @Override 43 | public Order getById(String id) { 44 | return orderRepository.findById(id).orElseThrow(() -> new CustomServiceException( 45 | "error.validation.common.not.found.code", 46 | "error.validation.product.not.found.message" 47 | )); 48 | } 49 | 50 | @Override 51 | public List getAll() { 52 | return orderRepository.findAll(); 53 | } 54 | 55 | @Override 56 | public List findAllOrder() { 57 | return orderRepository.findAllOrder(); 58 | } 59 | 60 | @Override 61 | public List findAllTotalAmountSaleByAgent() { 62 | return orderRepository.findAllTotalAmountSaleByAgent(); 63 | } 64 | 65 | @Override 66 | public void updateStatus(String orderId, OrderRequestStatus status) { 67 | /*validates the incoming data*/ 68 | final Order orderResult = getById(orderId); 69 | // if (orderResult == null) { 70 | // System.out.println("hello");; 71 | // } 72 | orderRepository.updateStatus(orderResult.getId(), status); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/rest/UserController.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.rest; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.CommonController; 4 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.request.UserLoginRequest; 5 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.response.UserLoginResponse; 6 | import com.icbt.ap.mobileaccessoriessales.entity.User; 7 | import com.icbt.ap.mobileaccessoriessales.service.UserService; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.context.MessageSource; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestBody; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | import javax.validation.Valid; 18 | import java.time.LocalDateTime; 19 | import java.util.Locale; 20 | 21 | import static com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant.DATE_TIME_FORMATTER; 22 | import static com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant.VERSION; 23 | 24 | @RestController 25 | @RequestMapping(value = VERSION + "/user") 26 | @Slf4j 27 | @RequiredArgsConstructor 28 | public class UserController implements CommonController { 29 | 30 | private final UserService userService; 31 | 32 | private final MessageSource messageSource; 33 | 34 | @PostMapping(path = "/auth") 35 | public ResponseEntity authenticate(@Valid @RequestBody UserLoginRequest request) { 36 | log.info("User login request, Username: {}", request.getUsername()); 37 | return authenticateUser(request); 38 | } 39 | 40 | private ResponseEntity authenticateUser(UserLoginRequest request) { 41 | final User user = userService.authenticate(request); 42 | return ResponseEntity.ok(UserLoginResponse.builder() 43 | .id(user.getId()) 44 | .username(user.getUsername()) 45 | .userRole(user.getUserRole()) 46 | .branchId(user.getBranchId()) 47 | .build() 48 | ); 49 | } 50 | 51 | private String getFormattedDateTime(LocalDateTime dateTime) { 52 | return DATE_TIME_FORMATTER.format(dateTime); 53 | } 54 | 55 | private String getCode(String key) { 56 | return messageSource.getMessage(key, new Object[0], Locale.getDefault()); 57 | } 58 | 59 | private String getMessage(String key) { 60 | return messageSource.getMessage(key, new Object[0], Locale.getDefault()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/repository/impl/ProductRepositoryImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 4 | import com.icbt.ap.mobileaccessoriessales.enums.ProductStatus; 5 | import com.icbt.ap.mobileaccessoriessales.repository.ProductRepository; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.extension.ExtendWith; 9 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.jdbc.core.JdbcTemplate; 12 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 13 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 14 | import org.springframework.test.context.junit.jupiter.SpringExtension; 15 | 16 | import javax.sql.DataSource; 17 | import java.util.List; 18 | import java.util.Optional; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertTrue; 21 | import static org.junit.jupiter.api.Assertions.*; 22 | 23 | @Slf4j 24 | @ExtendWith(SpringExtension.class) 25 | @SpringBootTest 26 | @AutoConfigureMockMvc 27 | class ProductRepositoryImplTest { 28 | 29 | private final ProductRepository productRepository; 30 | 31 | private ProductRepositoryImplTest() { 32 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 33 | .addScript("classpath:test/sales_db_test.sql") 34 | .build(); 35 | productRepository = new ProductRepositoryImpl(new JdbcTemplate(dataSource)); 36 | } 37 | 38 | @Test 39 | void findAll() { 40 | final List products = productRepository.findAll(); 41 | log.info("Products: {}", products); 42 | } 43 | 44 | @Test 45 | void findById() { 46 | String id = "12cbc2ca-69d8-11eb-8f8a-a81e849e9ba1"; 47 | final Optional optionalProduct = productRepository.findById(id); 48 | assertTrue(optionalProduct.isPresent() && id.equals(optionalProduct.get().getId())); 49 | } 50 | 51 | @Test 52 | void save() { 53 | Product product = Product.builder().name("Pineapple").status(ProductStatus.ACTIVE).build(); 54 | productRepository.save(product); 55 | product = productRepository.findByName(product.getName()); 56 | assertEquals("Pineapple", product.getName()); 57 | } 58 | 59 | @Test 60 | void update() { 61 | } 62 | 63 | @Test 64 | void delete() { 65 | } 66 | 67 | @Test 68 | void setDataSource() { 69 | } 70 | 71 | @Test 72 | void findByName() { 73 | } 74 | 75 | public ProductRepository getProductRepository() { 76 | return productRepository; 77 | } 78 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.6.4 9 | 10 | 11 | com.icbt.ap.mobileaccessoriessales 12 | mobile_accessories_sales_server 13 | 0.0.1-SNAPSHOT 14 | war 15 | mobile_accessories_sales_server 16 | Demo project for Spring Boot 17 | 18 | 11 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-data-jdbc 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-mail 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-web 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-validation 36 | 37 | 38 | org.springframework.security 39 | spring-security-crypto 40 | 41 | 42 | 43 | com.h2database 44 | h2 45 | test 46 | 47 | 48 | mysql 49 | mysql-connector-java 50 | runtime 51 | 52 | 53 | org.projectlombok 54 | lombok 55 | true 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-starter-tomcat 60 | provided 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-test 65 | test 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.springframework.boot 73 | spring-boot-maven-plugin 74 | 75 | 76 | 77 | org.projectlombok 78 | lombok 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/impl/VehicleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Vehicle; 5 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 6 | import com.icbt.ap.mobileaccessoriessales.repository.VehicleRepository; 7 | import com.icbt.ap.mobileaccessoriessales.service.BranchService; 8 | import com.icbt.ap.mobileaccessoriessales.service.VehicleService; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | 15 | @Service 16 | @RequiredArgsConstructor 17 | @Slf4j 18 | public class VehicleServiceImpl implements VehicleService { 19 | 20 | private final VehicleRepository vehicleRepository; 21 | private final BranchService branchService; 22 | 23 | @Override 24 | public void add(Vehicle vehicle) { 25 | /*checks whether the vehicle reg no already exists*/ 26 | final Vehicle vehicleByNo = vehicleRepository.findByRegNo(vehicle.getRegNo()); 27 | if (vehicleByNo != null) throwVehicleNameAlreadyExistException(); 28 | /*validates the branch and explicitly sets the queried branch id*/ 29 | final Branch branch = branchService.getById(vehicle.getBranchId()); 30 | vehicle.setBranchId(branch.getId()); 31 | vehicleRepository.save(vehicle); 32 | } 33 | 34 | @Override 35 | public void update(Vehicle vehicle) { 36 | /*validates the incoming data*/ 37 | final Vehicle vehicleById = getById(vehicle.getId()); 38 | /*checks whether the vehicle name already exists*/ 39 | final Vehicle vehicleByNo = vehicleRepository.findByRegNo(vehicle.getRegNo()); 40 | if ((vehicleByNo != null) && (!vehicleByNo.getId().equals(vehicle.getId()))) 41 | throwVehicleNameAlreadyExistException(); 42 | 43 | vehicleById.setRegNo(vehicle.getRegNo()); 44 | vehicleById.setBranchId(vehicle.getBranchId()); 45 | vehicleById.setDriverId(vehicle.getDriverId()); 46 | vehicleById.setBranchId(vehicle.getBranchId()); 47 | 48 | vehicleRepository.update(vehicleById); 49 | } 50 | 51 | @Override 52 | public void delete(String id) { 53 | final Vehicle vehicle = getById(id); 54 | vehicleRepository.delete(vehicle.getId()); 55 | } 56 | 57 | @Override 58 | public Vehicle getById(String id) { 59 | return vehicleRepository.findById(id).orElseThrow(() -> new CustomServiceException( 60 | "error.validation.common.not.found.code", 61 | "error.validation.vehicle.not.found.message" 62 | )); 63 | } 64 | 65 | @Override 66 | public List getAll() { 67 | return vehicleRepository.findAll(); 68 | } 69 | 70 | 71 | /*Internal functions below*/ 72 | 73 | private void throwVehicleNameAlreadyExistException() { 74 | throw new CustomServiceException( 75 | "error.validation.common.already.exist.code", 76 | "error.validation.vehicle.regno.already.exist.message" 77 | ); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/rest/ProductResultController.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.rest; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.CommonController; 4 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.response.ProductResultResponse; 5 | import com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant; 6 | import com.icbt.ap.mobileaccessoriessales.dto.ContentResponseDTO; 7 | import com.icbt.ap.mobileaccessoriessales.entity.query.ProductResult; 8 | import com.icbt.ap.mobileaccessoriessales.service.ProductService; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.context.MessageSource; 12 | import org.springframework.http.ResponseEntity; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | import java.time.LocalDateTime; 18 | import java.util.List; 19 | import java.util.Locale; 20 | import java.util.stream.Collectors; 21 | 22 | @RestController 23 | @RequestMapping(value = ApiConstant.VERSION + "/product_list") 24 | @Slf4j 25 | @RequiredArgsConstructor 26 | public class ProductResultController implements CommonController { 27 | 28 | private final ProductService productService; 29 | 30 | private final MessageSource messageSource; 31 | 32 | @GetMapping(path = "") 33 | public ResponseEntity>> getProductResults() { 34 | log.info("Get all products details"); 35 | return getAllProductDetails(); 36 | } 37 | 38 | /*Internal functions*/ 39 | 40 | private ResponseEntity>> getAllProductDetails() { 41 | return ResponseEntity.ok(new ContentResponseDTO<>(true, 42 | getProductResultResponseList(productService.getAllProductDetails()))); 43 | } 44 | 45 | private List getProductResultResponseList(List productResults) { 46 | return productResults 47 | .stream() 48 | .map(this::getProductResultResponse) 49 | .collect(Collectors.toList()); 50 | } 51 | 52 | private ProductResultResponse getProductResultResponse(ProductResult productResult) { 53 | return ProductResultResponse.builder() 54 | .id(productResult.getId()) 55 | .name(productResult.getName()) 56 | .status(productResult.getStatus()) 57 | .qty(productResult.getQty()) 58 | .price(productResult.getPrice()) 59 | .description(productResult.getDescription()) 60 | .build(); 61 | } 62 | 63 | private String getFormattedDateTime(LocalDateTime dateTime) { 64 | return ApiConstant.DATE_TIME_FORMATTER.format(dateTime); 65 | } 66 | 67 | private String getCode(String key) { 68 | return messageSource.getMessage(key, new Object[0], Locale.getDefault()); 69 | } 70 | 71 | private String getMessage(String key) { 72 | return messageSource.getMessage(key, new Object[0], Locale.getDefault()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/impl/VehicleRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Vehicle; 4 | import com.icbt.ap.mobileaccessoriessales.repository.VehicleRepository; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.dao.EmptyResultDataAccessException; 8 | import org.springframework.jdbc.core.JdbcTemplate; 9 | import org.springframework.jdbc.core.RowMapper; 10 | import org.springframework.stereotype.Repository; 11 | 12 | import java.sql.ResultSet; 13 | import java.sql.SQLException; 14 | import java.util.List; 15 | import java.util.Optional; 16 | 17 | @Repository 18 | @RequiredArgsConstructor 19 | @Slf4j 20 | public class VehicleRepositoryImpl implements VehicleRepository { 21 | 22 | private final JdbcTemplate jdbcTemplate; 23 | 24 | @Override 25 | public List findAll() { 26 | return jdbcTemplate.query("SELECT * FROM vehicle ", 27 | new VehicleRowMapper()); 28 | } 29 | 30 | @Override 31 | public Optional findById(String id) { 32 | 33 | String sql = "SELECT * FROM vehicle WHERE id = ? "; 34 | 35 | try { 36 | return Optional.ofNullable(jdbcTemplate 37 | .queryForObject(sql, new VehicleRowMapper(), id)); 38 | } catch (EmptyResultDataAccessException ex) { 39 | return Optional.empty(); 40 | } 41 | } 42 | 43 | @Override 44 | public void save(Vehicle vehicle) { 45 | jdbcTemplate.update("INSERT INTO vehicle (id, reg_no, driver_id, branch_id) " 46 | + "VALUES (UUID(), ?, ?, ?)", 47 | vehicle.getRegNo(), vehicle.getDriverId(), vehicle.getBranchId()); 48 | } 49 | 50 | @Override 51 | public void update(Vehicle vehicle) { 52 | jdbcTemplate.update("UPDATE vehicle " + " SET reg_no = ?, driver_id = ? , branch_id = ? " + " WHERE id = ?", 53 | vehicle.getRegNo(), vehicle.getDriverId(), vehicle.getBranchId(), vehicle.getId()); 54 | } 55 | 56 | @Override 57 | public void delete(String id) { 58 | jdbcTemplate.update("UPDATE vehicle " + " SET reg_no = ? " + " WHERE id = ?", 59 | null, id); 60 | } 61 | 62 | @Override 63 | public Vehicle findByRegNo(String regNo) { 64 | 65 | String sql = "SELECT * FROM vehicle WHERE reg_no = ?"; 66 | 67 | try { 68 | return jdbcTemplate.queryForObject(sql, new VehicleRowMapper(), regNo); 69 | } catch (EmptyResultDataAccessException ex) { 70 | return null; 71 | } 72 | } 73 | 74 | 75 | private static class VehicleRowMapper implements RowMapper { 76 | @Override 77 | public Vehicle mapRow(ResultSet resultSet, int rowNum) throws SQLException { 78 | return Vehicle.builder() 79 | .id(resultSet.getString("id")) 80 | .regNo(resultSet.getString("reg_no")) 81 | .driverId(resultSet.getString("driver_id")) 82 | .branchId(resultSet.getString("branch_id")) 83 | .createdAt(resultSet.getTimestamp("created_at").toLocalDateTime()) 84 | .build(); 85 | } 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/service/impl/UserServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.config.AppConfig; 4 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.request.UserLoginRequest; 5 | import com.icbt.ap.mobileaccessoriessales.entity.User; 6 | import com.icbt.ap.mobileaccessoriessales.repository.BranchRepository; 7 | import com.icbt.ap.mobileaccessoriessales.repository.UserRepository; 8 | import com.icbt.ap.mobileaccessoriessales.repository.impl.BranchRepositoryImpl; 9 | import com.icbt.ap.mobileaccessoriessales.repository.impl.UserRepositoryImpl; 10 | import com.icbt.ap.mobileaccessoriessales.service.BranchService; 11 | import com.icbt.ap.mobileaccessoriessales.service.UserService; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.extension.ExtendWith; 15 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.context.annotation.Import; 18 | import org.springframework.jdbc.core.JdbcTemplate; 19 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 20 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 21 | import org.springframework.security.crypto.password.PasswordEncoder; 22 | import org.springframework.test.context.junit.jupiter.SpringExtension; 23 | 24 | import javax.sql.DataSource; 25 | 26 | import static org.junit.jupiter.api.Assertions.*; 27 | 28 | @Import(AppConfig.class) 29 | @Slf4j 30 | @ExtendWith(SpringExtension.class) 31 | @SpringBootTest 32 | @AutoConfigureMockMvc 33 | class UserServiceImplTest { 34 | 35 | private final UserService userService; 36 | 37 | private final UserRepository userRepository; 38 | private final BranchService branchService; 39 | private final BranchRepository branchRepository; 40 | private final PasswordEncoder passwordEncoder; 41 | 42 | private UserServiceImplTest() { 43 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 44 | .addScript("classpath:test/sales_db_test.sql") 45 | .build(); 46 | branchRepository = new BranchRepositoryImpl(new JdbcTemplate(dataSource)); 47 | branchService = new BranchServiceImpl(branchRepository); 48 | userRepository = new UserRepositoryImpl(new JdbcTemplate(dataSource)); 49 | passwordEncoder = new AppConfig().passwordEncoder(); 50 | userService = new UserServiceImpl(userRepository, branchService, passwordEncoder); 51 | } 52 | 53 | 54 | @Test 55 | void add() { 56 | } 57 | 58 | @Test 59 | void update() { 60 | } 61 | 62 | @Test 63 | void delete() { 64 | } 65 | 66 | @Test 67 | void getById() { 68 | } 69 | 70 | @Test 71 | void getAll() { 72 | } 73 | 74 | @Test 75 | void authenticate() { 76 | final UserLoginRequest loginRequest = UserLoginRequest.builder() 77 | .username("super") 78 | .password("123") 79 | .build(); 80 | final User user = userService.authenticate(loginRequest); 81 | log.info("Logged user: {}", user); 82 | assertEquals(loginRequest.getUsername(), user.getUsername()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/impl/SalesAgentRepositoryRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.User; 4 | import com.icbt.ap.mobileaccessoriessales.enums.UserRole; 5 | import com.icbt.ap.mobileaccessoriessales.repository.SalesAgentRepository; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.dao.EmptyResultDataAccessException; 9 | import org.springframework.jdbc.core.RowMapper; 10 | import org.springframework.stereotype.Repository; 11 | import org.springframework.jdbc.core.JdbcTemplate; 12 | 13 | import java.sql.ResultSet; 14 | import java.sql.SQLException; 15 | import java.util.List; 16 | import java.util.Optional; 17 | 18 | @Repository 19 | @RequiredArgsConstructor 20 | @Slf4j 21 | public class SalesAgentRepositoryRepositoryImpl implements SalesAgentRepository { 22 | private final JdbcTemplate jdbcTemplate; 23 | 24 | @Override 25 | public List findAll() { 26 | return jdbcTemplate.query("SELECT * FROM user WHERE user_role =2", new SalesAgentRepositoryRepositoryImpl.SalesAgentRowMapper()); 27 | } 28 | 29 | @Override 30 | public Optional findById(String id) { 31 | String sql = "SELECT * FROM user WHERE id = ?"; 32 | 33 | try { 34 | return Optional.ofNullable(jdbcTemplate 35 | .queryForObject(sql, new SalesAgentRepositoryRepositoryImpl.SalesAgentRowMapper(), id)); 36 | } catch (EmptyResultDataAccessException ex) { 37 | return Optional.empty(); 38 | } 39 | } 40 | 41 | @Override 42 | public void save(User user) { 43 | jdbcTemplate.update("INSERT INTO user (id, username, password, user_role, branch_id) " 44 | + "VALUES (UUID(), ?, ?, ?, ?)", 45 | user.getUsername(), user.getPassword(), user.getUserRole().getId(), user.getBranchId()); 46 | } 47 | 48 | @Override 49 | public void update(User user) { 50 | jdbcTemplate.update("UPDATE user " + " SET username = ?, password = ? , user_role = ? , branch_id = ? " + " WHERE id = ?", 51 | user.getUsername(), user.getPassword(), user.getUserRole().getId(), user.getBranchId(), user.getId()); 52 | } 53 | 54 | @Override 55 | public void delete(String id) { 56 | jdbcTemplate.update("DELETE FROM user WHERE id = ?", id); 57 | } 58 | 59 | @Override 60 | public User findByUserName(String username) { 61 | String sql = "SELECT * FROM user WHERE user.username = ?"; 62 | 63 | try { 64 | return jdbcTemplate.queryForObject(sql, new SalesAgentRepositoryRepositoryImpl.SalesAgentRowMapper(), username); 65 | } catch (EmptyResultDataAccessException ex) { 66 | return null; 67 | } 68 | } 69 | 70 | private static class SalesAgentRowMapper implements RowMapper { 71 | @Override 72 | public User mapRow(ResultSet resultSet, int rowNum) throws SQLException { 73 | return User.builder() 74 | .id(resultSet.getString("id")) 75 | .username(resultSet.getString("username")) 76 | .password(resultSet.getString("password")) 77 | .userRole(UserRole.getById(resultSet.getInt("user_role"))) 78 | .branchId(resultSet.getString("branch_id")) 79 | .build(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/impl/BranchServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 4 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 5 | import com.icbt.ap.mobileaccessoriessales.repository.BranchRepository; 6 | import com.icbt.ap.mobileaccessoriessales.service.BranchService; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.List; 12 | 13 | @Service 14 | @RequiredArgsConstructor 15 | @Slf4j 16 | public class BranchServiceImpl implements BranchService { 17 | 18 | private final BranchRepository branchRepository; 19 | 20 | @Override 21 | public void add(Branch branch) { 22 | /*checks whether the branch name already exists*/ 23 | final Branch branchByName = branchRepository.findByName(branch.getName()); 24 | if (branchByName != null) throwBranchNameAlreadyExistException(); 25 | final Branch branchByTel = branchRepository.findByTel(branch.getTel()); 26 | if (branchByTel != null) throwBranchTelAlreadyExistException(); 27 | 28 | branchRepository.save(branch); 29 | } 30 | 31 | @Override 32 | public void update(Branch branch) { 33 | /*validates the incoming data*/ 34 | final Branch branchById = getById(branch.getId()); 35 | /*checks whether the branch name already exists*/ 36 | final Branch branchByName = branchRepository.findByName(branch.getName()); 37 | if ((branchByName != null) && (!branchByName.getId().equals(branch.getId()))) 38 | throwBranchNameAlreadyExistException(); 39 | final Branch branchByTel = branchRepository.findByTel(branch.getTel()); 40 | if ((branchByTel != null) && (!branchByTel.getId().equals(branch.getId()))) 41 | throwBranchTelAlreadyExistException(); 42 | 43 | branchById.setName(branch.getName()); 44 | branchById.setAddress(branch.getAddress()); 45 | branchById.setTel(branch.getTel()); 46 | if (branch.getStatus() != null) 47 | branchById.setStatus(branch.getStatus()); 48 | 49 | branchRepository.update(branchById); 50 | } 51 | 52 | @Override 53 | public void delete(String id) { 54 | final Branch branch = getById(id); 55 | branchRepository.delete(branch.getId()); 56 | } 57 | 58 | @Override 59 | public Branch getById(String id) { 60 | return branchRepository.findById(id).orElseThrow(() -> new CustomServiceException( 61 | "error.validation.common.not.found.code", 62 | "error.validation.branch.not.found.message" 63 | )); 64 | } 65 | 66 | @Override 67 | public List getAll() { 68 | return branchRepository.findAll(); 69 | } 70 | 71 | 72 | /*Internal functions below*/ 73 | 74 | private void throwBranchNameAlreadyExistException() { 75 | throw new CustomServiceException( 76 | "error.validation.common.already.exist.code", 77 | "error.validation.branch.name.already.exist.message" 78 | ); 79 | } 80 | 81 | private void throwBranchTelAlreadyExistException() { 82 | throw new CustomServiceException( 83 | "error.validation.common.already.exist.code", 84 | "error.validation.branch.tel.already.exist.message" 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/impl/UserRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.User; 4 | import com.icbt.ap.mobileaccessoriessales.enums.UserRole; 5 | import com.icbt.ap.mobileaccessoriessales.repository.UserRepository; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.dao.EmptyResultDataAccessException; 9 | import org.springframework.jdbc.core.JdbcTemplate; 10 | import org.springframework.jdbc.core.RowMapper; 11 | import org.springframework.stereotype.Repository; 12 | 13 | import java.sql.ResultSet; 14 | import java.sql.SQLException; 15 | import java.util.List; 16 | import java.util.Optional; 17 | 18 | @Repository 19 | @RequiredArgsConstructor 20 | @Slf4j //Causes lombok to generate a logger field 21 | //lombok - java library that automatically plugs into your editor and build tools, spicing up your java. 22 | public class UserRepositoryImpl implements UserRepository { 23 | 24 | private final JdbcTemplate jdbcTemplate; 25 | 26 | @Override 27 | public List findAll() { 28 | return jdbcTemplate.query("SELECT * FROM user", new UserRowMapper()); 29 | } 30 | 31 | @Override 32 | public Optional findById(String id) { 33 | 34 | String sql = "SELECT * FROM user WHERE id = ?"; 35 | 36 | try { 37 | return Optional.ofNullable(jdbcTemplate 38 | .queryForObject(sql, new UserRowMapper(), id)); 39 | } catch (EmptyResultDataAccessException ex) { 40 | return Optional.empty(); 41 | } 42 | } 43 | 44 | @Override 45 | public void save(User user) { 46 | jdbcTemplate.update("INSERT INTO user (id, username, password, user_role, branch_id) " 47 | + "VALUES (UUID(), ?, ?, ?, ?)", 48 | user.getUsername(), user.getPassword(), user.getUserRole().getId(), user.getBranchId()); 49 | } 50 | 51 | @Override 52 | public void update(User user) { 53 | jdbcTemplate.update("UPDATE user " + " SET username = ?, password = ? , user_role = ? , branch_id = ? " + " WHERE id = ?", 54 | user.getUsername(), user.getPassword(), user.getUserRole().getId(), user.getBranchId(), user.getId()); 55 | } 56 | 57 | @Override 58 | public void delete(String id) { 59 | jdbcTemplate.update("UPDATE user " + " SET username = null " + " WHERE id = ?", id); 60 | } 61 | 62 | @Override 63 | public User findByUserName(String username) { 64 | 65 | String sql = "SELECT * FROM user WHERE user.username = ?"; 66 | 67 | try { 68 | return jdbcTemplate.queryForObject(sql, new UserRowMapper(), username); 69 | } catch (EmptyResultDataAccessException ex) { 70 | return null; 71 | } 72 | } 73 | 74 | private static class UserRowMapper implements RowMapper { 75 | @Override 76 | public User mapRow(ResultSet resultSet, int rowNum) throws SQLException { 77 | return User.builder() 78 | .id(resultSet.getString("id")) 79 | .username(resultSet.getString("username")) 80 | .password(resultSet.getString("password")) 81 | .userRole(UserRole.getById(resultSet.getInt("user_role"))) 82 | .branchId(resultSet.getString("branch_id")) 83 | .build(); 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/service/impl/VehicleServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.config.AppConfig; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 5 | import com.icbt.ap.mobileaccessoriessales.entity.Vehicle; 6 | import com.icbt.ap.mobileaccessoriessales.repository.BranchRepository; 7 | import com.icbt.ap.mobileaccessoriessales.repository.VehicleRepository; 8 | import com.icbt.ap.mobileaccessoriessales.repository.impl.BranchRepositoryImpl; 9 | import com.icbt.ap.mobileaccessoriessales.repository.impl.VehicleRepositoryImpl; 10 | import com.icbt.ap.mobileaccessoriessales.service.BranchService; 11 | import com.icbt.ap.mobileaccessoriessales.service.VehicleService; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.extension.ExtendWith; 15 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.context.annotation.Import; 18 | import org.springframework.jdbc.core.JdbcTemplate; 19 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 20 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 21 | import org.springframework.test.context.junit.jupiter.SpringExtension; 22 | 23 | import javax.sql.DataSource; 24 | 25 | import static org.junit.jupiter.api.Assertions.assertTrue; 26 | import static org.junit.jupiter.api.Assertions.*; 27 | 28 | @Import(AppConfig.class) 29 | @Slf4j 30 | @ExtendWith(SpringExtension.class) 31 | @SpringBootTest 32 | @AutoConfigureMockMvc 33 | class VehicleServiceImplTest { 34 | 35 | private VehicleService vehicleService; 36 | private BranchService branchService; 37 | 38 | private final VehicleRepository vehicleRepository; 39 | private final BranchRepository branchRepository; 40 | 41 | private VehicleServiceImplTest() { 42 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 43 | .addScript("classpath:test/sales_db_test.sql") 44 | .build(); 45 | vehicleRepository = new VehicleRepositoryImpl(new JdbcTemplate(dataSource)); 46 | branchRepository = new BranchRepositoryImpl(new JdbcTemplate(dataSource)); 47 | branchService = new BranchServiceImpl(branchRepository); 48 | vehicleService = new VehicleServiceImpl(vehicleRepository, branchService); 49 | } 50 | 51 | @Test 52 | void add() { 53 | String branchId = "323432"; 54 | final Branch branch = branchService.getById(branchId); 55 | assertTrue(branch != null && branchId.equals(branch.getId())); 56 | 57 | Vehicle vehicle = Vehicle.builder() 58 | .regNo("JH-1209") 59 | .driverId("D0101") 60 | .branchId(branchId) 61 | .build(); 62 | vehicleService.add(vehicle); 63 | Vehicle vehicleByNo = vehicleRepository.findByRegNo(vehicle.getRegNo()); 64 | assertEquals(vehicle.getRegNo(), vehicleByNo.getRegNo()); 65 | assertEquals(vehicle.getDriverId(), vehicleByNo.getDriverId()); 66 | assertEquals(vehicle.getBranchId(), vehicleByNo.getBranchId()); 67 | } 68 | 69 | @Test 70 | void update() { 71 | } 72 | 73 | @Test 74 | void delete() { 75 | } 76 | 77 | @Test 78 | void getById() { 79 | } 80 | 81 | @Test 82 | void getAll() { 83 | } 84 | } -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/service/impl/ProductServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 4 | import com.icbt.ap.mobileaccessoriessales.enums.ProductStatus; 5 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 6 | import com.icbt.ap.mobileaccessoriessales.repository.ProductRepository; 7 | import com.icbt.ap.mobileaccessoriessales.repository.impl.ProductRepositoryImpl; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.extension.ExtendWith; 11 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.jdbc.core.JdbcTemplate; 14 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 15 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 16 | import org.springframework.test.context.junit.jupiter.SpringExtension; 17 | 18 | import javax.sql.DataSource; 19 | import java.util.List; 20 | import java.util.Optional; 21 | 22 | import static org.junit.jupiter.api.Assertions.*; 23 | 24 | @Slf4j 25 | @ExtendWith(SpringExtension.class) 26 | @SpringBootTest 27 | @AutoConfigureMockMvc 28 | class ProductServiceImplTest { 29 | 30 | private ProductServiceImpl productService; 31 | 32 | private final ProductRepository productRepository; 33 | 34 | private ProductServiceImplTest() { 35 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 36 | .addScript("classpath:test/sales_db_test.sql") 37 | .build(); 38 | productRepository = new ProductRepositoryImpl(new JdbcTemplate(dataSource)); 39 | productService = new ProductServiceImpl(productRepository); 40 | } 41 | 42 | @Test 43 | void add() { 44 | String name = "Sugar"; 45 | final Product product = Product.builder().name(name).status(ProductStatus.ACTIVE).build(); 46 | productService.add(product); 47 | final Product productByName = productRepository.findByName(name); 48 | assertEquals(product.getName(), productByName.getName()); 49 | assertEquals(product.getStatus(), productByName.getStatus()); 50 | } 51 | 52 | @Test 53 | void update() { 54 | String id = "12cbc2ca-69d8-11eb-8f8a-a81e849e9ba1"; 55 | final Optional optionalProduct = productRepository.findById(id); 56 | assertTrue(optionalProduct.isPresent()); 57 | final Product product = optionalProduct.get(); 58 | product.setName("Tea"); 59 | product.setStatus(ProductStatus.INACTIVE); 60 | productService.update(product); 61 | 62 | final Optional updatedOptionalProduct = productRepository.findById(id); 63 | assertTrue(updatedOptionalProduct.isPresent()); 64 | assertEquals(product, updatedOptionalProduct.get()); 65 | } 66 | 67 | @Test 68 | void delete() { 69 | String id = "12cbc2ca-69d8-11eb-8f8a-a81e849e9ba"; 70 | productService.delete(id); 71 | assertThrows(CustomServiceException.class, () -> { 72 | final Product product = productService.getById(id); 73 | }); 74 | } 75 | 76 | @Test 77 | void getById() { 78 | String id = "12cbc2ca-69d8-11eb-8f8a-a81e849e9ba"; 79 | final Product product = productService.getById(id); 80 | assertEquals(id, product.getId()); 81 | } 82 | 83 | @Test 84 | void getAll() { 85 | final List products = productService.getAll(); 86 | assertFalse(products.isEmpty()); 87 | } 88 | } -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/impl/SalesAgentServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 4 | import com.icbt.ap.mobileaccessoriessales.entity.User; 5 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 6 | import com.icbt.ap.mobileaccessoriessales.repository.SalesAgentRepository; 7 | import com.icbt.ap.mobileaccessoriessales.service.BranchService; 8 | import com.icbt.ap.mobileaccessoriessales.service.SalesAgentService; 9 | import com.icbt.ap.mobileaccessoriessales.util.StringUtil; 10 | import lombok.RequiredArgsConstructor; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.security.crypto.password.PasswordEncoder; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.util.List; 16 | 17 | @Service 18 | @RequiredArgsConstructor 19 | @Slf4j 20 | public class SalesAgentServiceImpl implements SalesAgentService { 21 | private final SalesAgentRepository salesAgentRepository; 22 | private final BranchService branchService; 23 | private final PasswordEncoder passwordEncoder; 24 | 25 | @Override 26 | public void add(User user) { 27 | /*checks whether the sales agent name already exists*/ 28 | final User userByUserName = salesAgentRepository.findByUserName(user.getUsername()); 29 | if (userByUserName != null) throwUserNameAlreadyExistException(); 30 | /*checks whether the given branch id exists and sets explicitly*/ 31 | final Branch branch = branchService.getById(user.getBranchId()); 32 | user.setBranchId(branch.getId()); 33 | user.setPassword(passwordEncoder.encode(user.getPassword())); 34 | salesAgentRepository.save(user); 35 | } 36 | 37 | @Override 38 | public void update(User user) { 39 | /*validates the incoming data*/ 40 | final User userById = getById(user.getId()); 41 | /*checks whether the sales agent name already exists*/ 42 | final User userByUserName = salesAgentRepository.findByUserName(user.getUsername()); 43 | if ((userByUserName != null) && (!userByUserName.getId().equals(user.getId()))) 44 | throwUserNameAlreadyExistException(); 45 | if (StringUtil.isNotBlank(user.getBranchId())) { 46 | final Branch branch = branchService.getById(user.getBranchId()); 47 | user.setBranchId(branch.getId()); 48 | } 49 | 50 | userById.setUsername(user.getUsername()); 51 | userById.setPassword(passwordEncoder.encode(user.getPassword())); 52 | userById.setUserRole(user.getUserRole()); 53 | userById.setBranchId(user.getBranchId()); 54 | 55 | salesAgentRepository.update(userById); 56 | } 57 | 58 | @Override 59 | public void delete(String id) { 60 | final User user = getById(id); 61 | salesAgentRepository.delete(user.getId()); 62 | } 63 | 64 | @Override 65 | public User getById(String id) { 66 | return salesAgentRepository.findById(id).orElseThrow(() -> new CustomServiceException( 67 | "error.validation.common.not.found.code", 68 | "error.validation.userid.not.found.message", 69 | new String[]{id} 70 | )); 71 | } 72 | 73 | @Override 74 | public List getAll() { 75 | return salesAgentRepository.findAll(); 76 | } 77 | 78 | /*Internal functions below*/ 79 | 80 | private void throwUserNameAlreadyExistException() { 81 | throw new CustomServiceException( 82 | "error.validation.common.already.exist.code", 83 | "error.validation.user.name.already.exist.message" 84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/impl/CustomerRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Customer; 4 | import com.icbt.ap.mobileaccessoriessales.entity.User; 5 | import com.icbt.ap.mobileaccessoriessales.enums.ProductStatus; 6 | import com.icbt.ap.mobileaccessoriessales.enums.UserRole; 7 | import com.icbt.ap.mobileaccessoriessales.repository.CustomerRepository; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.dao.EmptyResultDataAccessException; 11 | import org.springframework.jdbc.core.JdbcTemplate; 12 | import org.springframework.jdbc.core.RowMapper; 13 | import org.springframework.stereotype.Repository; 14 | 15 | import java.sql.ResultSet; 16 | import java.sql.SQLException; 17 | import java.util.List; 18 | import java.util.Optional; 19 | 20 | @Repository 21 | @RequiredArgsConstructor 22 | @Slf4j 23 | public class CustomerRepositoryImpl implements CustomerRepository { 24 | private final JdbcTemplate jdbcTemplate; 25 | 26 | @Override 27 | public Customer findByCustomerName(String name) { 28 | String sql = "SELECT * FROM customer WHERE customer.name = ?"; 29 | 30 | try { 31 | return jdbcTemplate.queryForObject(sql, new CustomerRepositoryImpl.CustomerRowMapper(), name); 32 | } catch (EmptyResultDataAccessException ex) { 33 | return null; 34 | } 35 | } 36 | 37 | @Override 38 | public List findAll() { 39 | return jdbcTemplate.query("SELECT * FROM customer", 40 | new CustomerRepositoryImpl.CustomerRowMapper()); 41 | } 42 | 43 | @Override 44 | public Optional findById(String id) { 45 | String sql = "SELECT * FROM customer WHERE id = ?"; 46 | 47 | try { 48 | return Optional.ofNullable(jdbcTemplate.queryForObject(sql, new CustomerRepositoryImpl.CustomerRowMapper(),id)); 49 | } catch (EmptyResultDataAccessException ex) { 50 | return Optional.empty(); 51 | } 52 | } 53 | 54 | @Override 55 | public void save(Customer customer) { 56 | jdbcTemplate.update("INSERT INTO customer (id, name, mobile, address, username, password) " + "VALUES (UUID(), ?, ?, ?, ?, ?)", 57 | customer.getName(), customer.getMobile(), customer.getAddress(), customer.getUsername(), customer.getPassword()); 58 | } 59 | 60 | @Override 61 | public void update(Customer customer) { 62 | jdbcTemplate.update("UPDATE customer " + " SET name = ?, mobile = ?, address = ?, username = ?, password = ? " + " WHERE id = ?", 63 | customer.getName(), customer.getMobile(), customer.getAddress(), customer.getUsername(), customer.getPassword(), customer.getId()); 64 | } 65 | 66 | @Override 67 | public void delete(String id) { 68 | jdbcTemplate.update("DELETE FROM customer WHERE id = ?", id); 69 | } 70 | 71 | private static class CustomerRowMapper implements RowMapper { 72 | @Override 73 | public Customer mapRow(ResultSet resultSet, int rowNum) throws SQLException { 74 | return Customer.builder() 75 | .id(resultSet.getString("id")) 76 | .name(resultSet.getString("name")) 77 | .mobile(resultSet.getString("mobile")) 78 | .address(resultSet.getString("address")) 79 | .username(resultSet.getString("username")) 80 | .password(resultSet.getString("password")) 81 | .userRole(UserRole.getById(resultSet.getInt("user_role"))) 82 | .build(); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/service/impl/BranchServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.config.AppConfig; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 5 | import com.icbt.ap.mobileaccessoriessales.enums.BranchStatus; 6 | import com.icbt.ap.mobileaccessoriessales.enums.BranchType; 7 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 8 | import com.icbt.ap.mobileaccessoriessales.repository.BranchRepository; 9 | import com.icbt.ap.mobileaccessoriessales.repository.impl.BranchRepositoryImpl; 10 | import com.icbt.ap.mobileaccessoriessales.service.BranchService; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.junit.jupiter.api.Test; 13 | import org.junit.jupiter.api.extension.ExtendWith; 14 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 15 | import org.springframework.boot.test.context.SpringBootTest; 16 | import org.springframework.context.annotation.Import; 17 | import org.springframework.jdbc.core.JdbcTemplate; 18 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 19 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 20 | import org.springframework.test.context.junit.jupiter.SpringExtension; 21 | 22 | import javax.sql.DataSource; 23 | import java.util.List; 24 | 25 | import static org.junit.jupiter.api.Assertions.*; 26 | 27 | @Import(AppConfig.class) 28 | @Slf4j 29 | @ExtendWith(SpringExtension.class) 30 | @SpringBootTest 31 | @AutoConfigureMockMvc 32 | class BranchServiceImplTest { 33 | 34 | private BranchService branchService; 35 | 36 | private final BranchRepository branchRepository; 37 | 38 | private BranchServiceImplTest() { 39 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 40 | .addScript("classpath:test/sales_db_test.sql") 41 | .build(); 42 | branchRepository = new BranchRepositoryImpl(new JdbcTemplate(dataSource)); 43 | branchService = new BranchServiceImpl(branchRepository); 44 | } 45 | 46 | @Test 47 | void add() { 48 | Branch branch = Branch.builder() 49 | .name("Matara Branch") 50 | .address("Matara") 51 | .tel("0770114545") 52 | .type(BranchType.BRANCH).build(); 53 | branchService.add(branch); 54 | Branch branchByName = branchRepository.findByName(branch.getName()); 55 | assertEquals(branch.getName(), branchByName.getName()); 56 | assertEquals(branch.getAddress(), branchByName.getAddress()); 57 | assertEquals(branch.getTel(), branchByName.getTel()); 58 | } 59 | 60 | @Test 61 | void update() { 62 | String id = "323432"; 63 | final Branch branch = branchService.getById(id); 64 | assertTrue(branch != null && id.equals(branch.getId())); 65 | 66 | branch.setName("JAffna branch"); 67 | branch.setAddress("Jaffna"); 68 | branch.setTel("0787878440"); 69 | branch.setStatus(BranchStatus.INACTIVE); 70 | branchRepository.update(branch); 71 | 72 | final Branch updatedBranch = branchService.getById(id); 73 | assertTrue(updatedBranch != null && id.equals(updatedBranch.getId())); 74 | assertEquals(branch, updatedBranch); 75 | } 76 | 77 | @Test 78 | void delete() { 79 | String id = "323432"; 80 | branchService.delete(id); 81 | assertThrows(CustomServiceException.class, () -> { 82 | final Branch branch = branchService.getById(id); 83 | }); 84 | } 85 | 86 | @Test 87 | void getById() { 88 | String id = "323432"; 89 | final Branch branch = branchService.getById(id); 90 | assertTrue(branch != null && id.equals(branch.getId())); 91 | } 92 | 93 | @Test 94 | void getAll() { 95 | final List branches = branchService.getAll(); 96 | assertFalse(branches.isEmpty()); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/impl/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.ProductResult; 5 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 6 | import com.icbt.ap.mobileaccessoriessales.repository.ProductRepository; 7 | import com.icbt.ap.mobileaccessoriessales.service.ProductService; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.List; 13 | 14 | @Service 15 | @RequiredArgsConstructor 16 | @Slf4j 17 | public class ProductServiceImpl implements ProductService { 18 | 19 | private final ProductRepository productRepository; 20 | 21 | @Override 22 | public void add(Product product) { 23 | /*checks whether the product name already exists*/ 24 | final Product productByName = productRepository.findByName(product.getName()); 25 | if (productByName != null) throwProductAlreadyExistException(); 26 | productRepository.save(product); 27 | } 28 | 29 | @Override 30 | public void update(Product product) { 31 | /*validates the incoming data*/ 32 | final Product productById = getById(product.getId()); 33 | /*checks whether the product name already exists*/ 34 | final Product productByName = productRepository.findByName(product.getName()); 35 | if ((productByName != null) && (!productByName.getId().equals(product.getId()))) 36 | throwProductAlreadyExistException(); 37 | 38 | productById.setName(product.getName()); 39 | if (product.getStatus() != null) 40 | productById.setStatus(product.getStatus()); 41 | productRepository.update(product); 42 | } 43 | 44 | @Override 45 | public void delete(String id) { 46 | final Product product = getById(id); 47 | productRepository.delete(product.getId()); 48 | } 49 | 50 | @Override 51 | public Product getById(String id) { 52 | return productRepository.findById(id).orElseThrow(() -> new CustomServiceException( 53 | "error.validation.common.not.found.code", 54 | "error.validation.product.not.found.message" 55 | )); 56 | } 57 | 58 | @Override 59 | public List getAll() { 60 | return productRepository.findAll(); 61 | } 62 | 63 | @Override 64 | public List validateAndGetProductsByIds(List productIds) { 65 | final List productListByIds = productRepository.findAllByIdsIn(productIds); 66 | 67 | /*validates whether all the requested ids are available in the result*/ 68 | validateStockReqAndResult(productIds, productListByIds); 69 | return productListByIds; 70 | } 71 | 72 | @Override 73 | public List getAllProductDetails() { 74 | return productRepository.findAllProductDetails(); 75 | } 76 | 77 | 78 | /*Internal functions below*/ 79 | 80 | private void validateStockReqAndResult(List productIdsReq, List products) { 81 | productIdsReq.forEach(productId -> { 82 | if (products.stream().noneMatch(product -> product.getId().equals(productId))) { 83 | throw new CustomServiceException( 84 | "error.validation.common.not.found.code", 85 | "error.validation.product.id.not.found.message", 86 | new String[]{productId} 87 | ); 88 | } 89 | }); 90 | } 91 | 92 | private void throwProductAlreadyExistException() { 93 | throw new CustomServiceException( 94 | "error.validation.common.already.exist.code", 95 | "error.validation.product.name.already.exist.message" 96 | ); 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/impl/BranchRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 4 | import com.icbt.ap.mobileaccessoriessales.enums.BranchStatus; 5 | import com.icbt.ap.mobileaccessoriessales.enums.BranchType; 6 | import com.icbt.ap.mobileaccessoriessales.repository.BranchRepository; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.dao.EmptyResultDataAccessException; 10 | import org.springframework.jdbc.core.JdbcTemplate; 11 | import org.springframework.jdbc.core.RowMapper; 12 | import org.springframework.stereotype.Repository; 13 | 14 | import java.sql.ResultSet; 15 | import java.sql.SQLException; 16 | import java.util.List; 17 | import java.util.Optional; 18 | 19 | @Repository 20 | @RequiredArgsConstructor 21 | @Slf4j 22 | public class BranchRepositoryImpl implements BranchRepository { 23 | 24 | private final JdbcTemplate jdbcTemplate; 25 | 26 | @Override 27 | public List findAll() { 28 | return jdbcTemplate.query("SELECT * FROM branch WHERE status <> ?", 29 | new BranchRowMapper(), BranchStatus.DELETED.getId()); 30 | } 31 | 32 | @Override 33 | public Optional findById(String id) { 34 | 35 | String sql = "SELECT * FROM branch WHERE id = ? AND status <> ?"; 36 | 37 | try { 38 | return Optional.ofNullable(jdbcTemplate 39 | .queryForObject(sql, new BranchRowMapper(), id, BranchStatus.DELETED.getId())); 40 | } catch (EmptyResultDataAccessException ex) { 41 | return Optional.empty(); 42 | } 43 | } 44 | 45 | @Override 46 | public void save(Branch branch) { 47 | jdbcTemplate.update("INSERT INTO branch (id, name, address, tel, type) " 48 | + "VALUES (UUID(), ?, ?, ?, ?)", 49 | branch.getName(), branch.getAddress(), branch.getTel(), branch.getType().getId()); 50 | } 51 | 52 | @Override 53 | public void update(Branch branch) { 54 | jdbcTemplate.update("UPDATE branch " + " SET name = ?, address = ? , tel = ? , status = ? " + " WHERE id = ?", 55 | branch.getName(), branch.getAddress(), branch.getTel(), branch.getStatus().getId(), branch.getId()); 56 | } 57 | 58 | @Override 59 | public void delete(String id) { 60 | jdbcTemplate.update("UPDATE branch " + " SET status = ? " + " WHERE id = ?", 61 | BranchStatus.DELETED.getId(), id); 62 | } 63 | 64 | @Override 65 | public Branch findByName(String name) { 66 | 67 | String sql = "SELECT * FROM branch WHERE status <> ? AND name = ?"; 68 | 69 | try { 70 | return jdbcTemplate.queryForObject(sql, new BranchRowMapper(), 71 | BranchStatus.DELETED.getId(), name); 72 | } catch (EmptyResultDataAccessException ex) { 73 | return null; 74 | } 75 | } 76 | 77 | @Override 78 | public Branch findByTel(String tel) { 79 | 80 | String sql = "SELECT * FROM branch WHERE status <> ? AND tel = ?"; 81 | 82 | try { 83 | return jdbcTemplate.queryForObject(sql, new BranchRowMapper(), 84 | BranchStatus.DELETED.getId(), tel); 85 | } catch (EmptyResultDataAccessException ex) { 86 | return null; 87 | } 88 | } 89 | 90 | private static class BranchRowMapper implements RowMapper { 91 | @Override 92 | public Branch mapRow(ResultSet resultSet, int rowNum) throws SQLException { 93 | return Branch.builder() 94 | .id(resultSet.getString("id")) 95 | .name(resultSet.getString("name")) 96 | .address(resultSet.getString("address")) 97 | .tel(resultSet.getString("tel")) 98 | .type(BranchType.getById(resultSet.getInt("type"))) 99 | .status(BranchStatus.getById(resultSet.getInt("status"))) 100 | .createdAt(resultSet.getTimestamp("created_at").toLocalDateTime()) 101 | .build(); 102 | } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/impl/CustomerServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.request.CustomerLoginRequest; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Customer; 5 | import com.icbt.ap.mobileaccessoriessales.exception.CustomAuthException; 6 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 7 | import com.icbt.ap.mobileaccessoriessales.repository.CustomerRepository; 8 | import com.icbt.ap.mobileaccessoriessales.service.CustomerService; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.security.crypto.password.PasswordEncoder; 12 | import org.springframework.stereotype.Service; 13 | 14 | import java.util.List; 15 | 16 | @Service 17 | @RequiredArgsConstructor 18 | @Slf4j 19 | public class CustomerServiceImpl implements CustomerService { 20 | private final CustomerRepository customerRepository; 21 | private final PasswordEncoder passwordEncoder; 22 | 23 | @Override 24 | public Customer authenticate(CustomerLoginRequest loginRequest) { 25 | final Customer customer = customerRepository.findByCustomerName(loginRequest.getUsername()); 26 | if (customer == null) throw new CustomAuthException( 27 | "error.validation.unauthorized.code", 28 | "error.validation.username.not.found.message", 29 | new String[]{loginRequest.getUsername()} 30 | ); 31 | if (!passwordEncoder.matches(loginRequest.getPassword(), customer.getPassword())) 32 | throw new CustomAuthException( 33 | "error.validation.unauthorized.code", 34 | "error.validation.invalid.password.message", 35 | new String[]{} 36 | ); 37 | customer.setPassword(null); 38 | return customer; 39 | } 40 | 41 | @Override 42 | public void add(Customer customer) { 43 | /*checks whether the user name already exists*/ 44 | final Customer customerByUserName = customerRepository.findByCustomerName(customer.getUsername()); 45 | if (customerByUserName != null) throwUserNameAlreadyExistException(); 46 | /*checks whether the given branch id exists and sets explicitly*/ 47 | customer.setPassword(passwordEncoder.encode(customer.getPassword())); 48 | customerRepository.save(customer); 49 | } 50 | 51 | @Override 52 | public void update(Customer customer) { 53 | /*validates the incoming data*/ 54 | final Customer customerById = getById(customer.getId()); 55 | /*checks whether the user name already exists*/ 56 | final Customer customerByUserName = customerRepository.findByCustomerName(customer.getUsername()); 57 | if ((customerByUserName != null) && (!customerByUserName.getId().equals(customer.getId()))) 58 | throwUserNameAlreadyExistException(); 59 | 60 | customerById.setName(customer.getName()); 61 | customerById.setMobile(customer.getMobile()); 62 | customerById.setAddress(customer.getAddress()); 63 | customerById.setUsername(customer.getUsername()); 64 | customerById.setPassword(passwordEncoder.encode(customer.getPassword())); 65 | 66 | customerRepository.update(customerById); 67 | } 68 | 69 | @Override 70 | public void delete(String id) { 71 | final Customer customer = getById(id); 72 | customerRepository.delete(customer.getId()); 73 | } 74 | 75 | @Override 76 | public Customer getById(String id) { 77 | return customerRepository.findById(id).orElseThrow(() -> new CustomServiceException( 78 | "error.validation.common.not.found.code", 79 | "error.validation.userid.not.found.message", 80 | new String[]{id} 81 | )); 82 | } 83 | 84 | @Override 85 | public List getAll() { 86 | return customerRepository.findAll(); 87 | } 88 | 89 | /*Internal functions below*/ 90 | 91 | private void throwUserNameAlreadyExistException() { 92 | throw new CustomServiceException( 93 | "error.validation.common.already.exist.code", 94 | "error.validation.user.name.already.exist.message" 95 | ); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.request.UserLoginRequest; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 5 | import com.icbt.ap.mobileaccessoriessales.entity.User; 6 | import com.icbt.ap.mobileaccessoriessales.exception.CustomAuthException; 7 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 8 | import com.icbt.ap.mobileaccessoriessales.repository.UserRepository; 9 | import com.icbt.ap.mobileaccessoriessales.service.BranchService; 10 | import com.icbt.ap.mobileaccessoriessales.service.UserService; 11 | import com.icbt.ap.mobileaccessoriessales.util.StringUtil; 12 | import lombok.RequiredArgsConstructor; 13 | import lombok.extern.slf4j.Slf4j; 14 | import org.springframework.security.crypto.password.PasswordEncoder; 15 | import org.springframework.stereotype.Service; 16 | 17 | import java.util.List; 18 | 19 | @Service 20 | @RequiredArgsConstructor 21 | @Slf4j 22 | public class UserServiceImpl implements UserService { 23 | 24 | private final UserRepository userRepository; 25 | private final BranchService branchService; 26 | private final PasswordEncoder passwordEncoder; 27 | 28 | @Override 29 | public void add(User user) { 30 | /*checks whether the user name already exists*/ 31 | final User userByUserName = userRepository.findByUserName(user.getUsername()); 32 | if (userByUserName != null) throwUserNameAlreadyExistException(); 33 | /*checks whether the given branch id exists and sets explicitly*/ 34 | final Branch branch = branchService.getById(user.getBranchId()); 35 | user.setBranchId(branch.getId()); 36 | userRepository.save(user); 37 | } 38 | 39 | @Override 40 | public void update(User user) { 41 | /*validates the incoming data*/ 42 | final User userById = getById(user.getId()); 43 | /*checks whether the user name already exists*/ 44 | final User userByUserName = userRepository.findByUserName(user.getUsername()); 45 | if ((userByUserName != null) && (!userByUserName.getId().equals(user.getId()))) 46 | throwUserNameAlreadyExistException(); 47 | if (StringUtil.isNotBlank(user.getBranchId())) { 48 | final Branch branch = branchService.getById(user.getBranchId()); 49 | user.setBranchId(branch.getId()); 50 | } 51 | 52 | userById.setUsername(user.getUsername()); 53 | userById.setPassword(user.getPassword()); 54 | userById.setUserRole(user.getUserRole()); 55 | 56 | userRepository.update(userById); 57 | } 58 | 59 | @Override 60 | public void delete(String id) { 61 | final User user = getById(id); 62 | userRepository.delete(user.getId()); 63 | } 64 | 65 | @Override 66 | public User getById(String id) { 67 | return userRepository.findById(id).orElseThrow(() -> new CustomServiceException( 68 | "error.validation.common.not.found.code", 69 | "error.validation.userid.not.found.message", 70 | new String[]{id} 71 | )); 72 | } 73 | 74 | @Override 75 | public List getAll() { 76 | return userRepository.findAll(); 77 | } 78 | 79 | @Override 80 | public User authenticate(UserLoginRequest loginRequest) { 81 | final User user = userRepository.findByUserName(loginRequest.getUsername()); 82 | if (user == null) throw new CustomAuthException( 83 | "error.validation.unauthorized.code", 84 | "error.validation.username.not.found.message", 85 | new String[]{loginRequest.getUsername()} 86 | ); 87 | if (!passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) 88 | throw new CustomAuthException( 89 | "error.validation.unauthorized.code", 90 | "error.validation.invalid.password.message", 91 | new String[]{} 92 | ); 93 | user.setPassword(null); 94 | return user; 95 | } 96 | 97 | 98 | /*Internal functions below*/ 99 | 100 | private void throwUserNameAlreadyExistException() { 101 | throw new CustomServiceException( 102 | "error.validation.common.already.exist.code", 103 | "error.validation.user.name.already.exist.message" 104 | ); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/impl/StockRequestDetailRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.StockRequestDetail; 4 | import com.icbt.ap.mobileaccessoriessales.repository.StockRequestDetailRepository; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.dao.EmptyResultDataAccessException; 8 | import org.springframework.jdbc.core.BatchPreparedStatementSetter; 9 | import org.springframework.jdbc.core.JdbcTemplate; 10 | import org.springframework.jdbc.core.RowMapper; 11 | import org.springframework.stereotype.Repository; 12 | 13 | import java.sql.PreparedStatement; 14 | import java.sql.ResultSet; 15 | import java.sql.SQLException; 16 | import java.util.List; 17 | import java.util.Optional; 18 | 19 | @Repository 20 | @RequiredArgsConstructor 21 | @Slf4j 22 | public class StockRequestDetailRepositoryImpl implements StockRequestDetailRepository { 23 | 24 | private final JdbcTemplate jdbcTemplate; 25 | 26 | private static final String STOCK_REQUEST_SELECT = "SELECT * FROM stock_request_detail srd "; 27 | 28 | @Override 29 | public List findAll() { 30 | return jdbcTemplate.query(STOCK_REQUEST_SELECT, new StockRequestDetailRowMapper()); 31 | } 32 | 33 | @Override 34 | public Optional findById(String id) { 35 | 36 | String sql = STOCK_REQUEST_SELECT + " WHERE srd.id = ? "; 37 | 38 | try { 39 | return Optional.ofNullable(jdbcTemplate 40 | .queryForObject(sql, new StockRequestDetailRowMapper(), id)); 41 | } catch (EmptyResultDataAccessException ex) { 42 | return Optional.empty(); 43 | } 44 | } 45 | 46 | @Override 47 | public void save(StockRequestDetail stockRequestDetail) { 48 | jdbcTemplate.update("INSERT INTO stock_request_detail (`id`, `stock_request_id`, `product_id`, `qty`) " 49 | + "VALUES (UUID(), ?, ?, ?)", 50 | stockRequestDetail.getStockRequestId(), stockRequestDetail.getProductId(), stockRequestDetail.getQty()); 51 | } 52 | 53 | @Override 54 | public void update(StockRequestDetail stockRequestDetail) { 55 | jdbcTemplate.update("UPDATE stock_request_detail " + " SET stock_request_id = ?, product_id = ?, qty = ? " + 56 | " WHERE id = ?", 57 | stockRequestDetail.getStockRequestId(), stockRequestDetail.getProductId(), stockRequestDetail.getQty(), 58 | stockRequestDetail.getId()); 59 | } 60 | 61 | @Override 62 | public void delete(String id) { 63 | jdbcTemplate.update("UPDATE stock_request_detail " + " SET qty = ? WHERE id = ?", 0, id); 64 | } 65 | 66 | @Override 67 | public List findAllByStockRequest(String stockRequestId) { 68 | 69 | String sql = STOCK_REQUEST_SELECT + " WHERE srd.stock_request_id = ?"; 70 | 71 | return jdbcTemplate.query(sql, new StockRequestDetailRowMapper(), stockRequestId); 72 | } 73 | 74 | @Override 75 | public void saveAll(List stocks) { 76 | jdbcTemplate.batchUpdate("INSERT INTO stock_request_detail (`id`, `stock_request_id`, `product_id`, `qty`) " 77 | + "VALUES (UUID(), ?, ?, ?)", 78 | new BatchPreparedStatementSetter() { 79 | public void setValues(PreparedStatement ps, int i) 80 | throws SQLException { 81 | ps.setString(1, stocks.get(i).getStockRequestId()); 82 | ps.setString(2, stocks.get(i).getProductId()); 83 | ps.setInt(3, stocks.get(i).getQty()); 84 | } 85 | 86 | public int getBatchSize() { 87 | return stocks.size(); 88 | } 89 | }); 90 | } 91 | 92 | private static class StockRequestDetailRowMapper implements RowMapper { 93 | @Override 94 | public StockRequestDetail mapRow(ResultSet resultSet, int rowNum) throws SQLException { 95 | return StockRequestDetail.builder() 96 | .id(resultSet.getString("id")) 97 | .stockRequestId(resultSet.getString("stock_request_id")) 98 | .productId(resultSet.getString("product_id")) 99 | .qty(resultSet.getInt("qty")) 100 | .build(); 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/repository/impl/BranchRepositoryImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 4 | import com.icbt.ap.mobileaccessoriessales.enums.BranchStatus; 5 | import com.icbt.ap.mobileaccessoriessales.enums.BranchType; 6 | import com.icbt.ap.mobileaccessoriessales.repository.BranchRepository; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.jdbc.core.JdbcTemplate; 13 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 14 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 15 | import org.springframework.test.context.junit.jupiter.SpringExtension; 16 | 17 | import javax.sql.DataSource; 18 | import java.util.List; 19 | import java.util.Optional; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertFalse; 22 | import static org.junit.jupiter.api.Assertions.assertTrue; 23 | import static org.junit.jupiter.api.Assertions.*; 24 | 25 | @Slf4j 26 | @ExtendWith(SpringExtension.class) 27 | @SpringBootTest 28 | @AutoConfigureMockMvc 29 | class BranchRepositoryImplTest { 30 | 31 | private final BranchRepository branchRepository; 32 | 33 | public BranchRepositoryImplTest() { 34 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 35 | .addScript("classpath:test/sales_db_test.sql") 36 | .build(); 37 | branchRepository = new BranchRepositoryImpl(new JdbcTemplate(dataSource)); 38 | } 39 | 40 | @Test 41 | void findAll() { 42 | final List branches = branchRepository.findAll(); 43 | log.info("Branches: {}", branches); 44 | assertTrue(branches.size() > 0); 45 | } 46 | 47 | @Test 48 | void findById() { 49 | String id = "323432"; 50 | final Optional optionalBranch = branchRepository.findById(id); 51 | assertTrue(optionalBranch.isPresent() && id.equals(optionalBranch.get().getId())); 52 | } 53 | 54 | @Test 55 | void save() { 56 | Branch branch = Branch.builder() 57 | .name("Matara Branch") 58 | .address("Matara") 59 | .tel("0770114545") 60 | .type(BranchType.BRANCH).build(); 61 | branchRepository.save(branch); 62 | Branch branchByName = branchRepository.findByName(branch.getName()); 63 | assertEquals(branch.getName(), branchByName.getName()); 64 | assertEquals(branch.getAddress(), branchByName.getAddress()); 65 | assertEquals(branch.getTel(), branchByName.getTel()); 66 | } 67 | 68 | @Test 69 | void update() { 70 | String id = "323432"; 71 | final Optional optionalBranch = branchRepository.findById(id); 72 | assertTrue(optionalBranch.isPresent() && id.equals(optionalBranch.get().getId())); 73 | final Branch branch = optionalBranch.get(); 74 | branch.setName("JAffna branch"); 75 | branch.setAddress("Jaffna"); 76 | branch.setTel("0787878440"); 77 | branch.setStatus(BranchStatus.INACTIVE); 78 | branchRepository.update(branch); 79 | 80 | final Optional optionalUpdatedBranch = branchRepository.findById(id); 81 | assertTrue(optionalUpdatedBranch.isPresent() && id.equals(optionalUpdatedBranch.get().getId())); 82 | final Branch updatedBranch = optionalUpdatedBranch.get(); 83 | assertEquals(branch, updatedBranch); 84 | } 85 | 86 | @Test 87 | void delete() { 88 | String id = "323432"; 89 | final Optional optionalBranch = branchRepository.findById(id); 90 | assertTrue(optionalBranch.isPresent() && id.equals(optionalBranch.get().getId())); 91 | final Branch branch = optionalBranch.get(); 92 | branchRepository.delete(branch.getId()); 93 | 94 | final Optional optionalDeletedBranch = branchRepository.findById(id); 95 | assertFalse(optionalDeletedBranch.isPresent() && id.equals(optionalDeletedBranch.get().getId())); 96 | } 97 | 98 | @Test 99 | void findByName() { 100 | String name = "Colombo Branch"; 101 | final Branch branch = branchRepository.findByName(name); 102 | assertTrue(branch != null && name.equals(branch.getName())); 103 | } 104 | 105 | @Test 106 | void findByTel() { 107 | String tel = "0774935895"; 108 | final Branch branch = branchRepository.findByTel(tel); 109 | assertTrue(branch != null && tel.equals(branch.getTel())); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/service/impl/StockServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.config.AppConfig; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 5 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 6 | import com.icbt.ap.mobileaccessoriessales.entity.Stock; 7 | import com.icbt.ap.mobileaccessoriessales.entity.query.StockResult; 8 | import com.icbt.ap.mobileaccessoriessales.repository.StockRepository; 9 | import com.icbt.ap.mobileaccessoriessales.repository.impl.BranchRepositoryImpl; 10 | import com.icbt.ap.mobileaccessoriessales.repository.impl.ProductRepositoryImpl; 11 | import com.icbt.ap.mobileaccessoriessales.repository.impl.StockRepositoryImpl; 12 | import com.icbt.ap.mobileaccessoriessales.service.BranchService; 13 | import com.icbt.ap.mobileaccessoriessales.service.ProductService; 14 | import com.icbt.ap.mobileaccessoriessales.service.StockService; 15 | import lombok.extern.slf4j.Slf4j; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.extension.ExtendWith; 18 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 19 | import org.springframework.boot.test.context.SpringBootTest; 20 | import org.springframework.context.annotation.Import; 21 | import org.springframework.jdbc.core.JdbcTemplate; 22 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 23 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 24 | import org.springframework.test.context.junit.jupiter.SpringExtension; 25 | 26 | import javax.sql.DataSource; 27 | import java.math.BigDecimal; 28 | import java.util.List; 29 | import java.util.Optional; 30 | 31 | import static org.junit.jupiter.api.Assertions.assertFalse; 32 | import static org.junit.jupiter.api.Assertions.assertTrue; 33 | import static org.junit.jupiter.api.Assertions.*; 34 | 35 | @Import(AppConfig.class) 36 | @Slf4j 37 | @ExtendWith(SpringExtension.class) 38 | @SpringBootTest 39 | @AutoConfigureMockMvc 40 | class StockServiceImplTest { 41 | 42 | private final StockService stockService; 43 | 44 | private final ProductService productService; 45 | private final BranchService branchService; 46 | 47 | private final StockRepository stockRepository; 48 | 49 | private StockServiceImplTest() { 50 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 51 | .addScript("classpath:test/sales_db_test.sql") 52 | .build(); 53 | stockRepository = new StockRepositoryImpl(new JdbcTemplate(dataSource)); 54 | 55 | productService = new ProductServiceImpl(new ProductRepositoryImpl(new JdbcTemplate(dataSource))); 56 | branchService = new BranchServiceImpl(new BranchRepositoryImpl(new JdbcTemplate(dataSource))); 57 | stockService = new StockServiceImpl(stockRepository, productService, branchService); 58 | } 59 | 60 | @Test 61 | void add() { 62 | String branchId = "323432"; 63 | final Branch branch = branchService.getById(branchId); 64 | assertTrue(branch != null && branchId.equals(branch.getId())); 65 | 66 | String productId = "12cbc2ca-69d8-11eb-8f8a-a81e849e9ba1"; 67 | final Product product = productService.getById(productId); 68 | assertTrue(product != null && productId.equals(product.getId())); 69 | 70 | Stock stock = Stock.builder() 71 | .description("my stock") 72 | .qty(50) 73 | .price(BigDecimal.TEN.multiply(BigDecimal.TEN)) 74 | .productId(product.getId()) 75 | .branchId(branch.getId()) 76 | .build(); 77 | stockService.add(stock); 78 | } 79 | 80 | @Test 81 | void update() { 82 | String id = "643344fregt4t1"; 83 | final Stock stock = stockService.getById(id); 84 | stock.setPrice(BigDecimal.TEN); 85 | stock.setQty(30); 86 | stock.setDescription("Desc"); 87 | stock.setBranchId("323432"); 88 | stock.setProductId("12cbc2ca-69d8-11eb-8f8a-a81e849e9ba2"); 89 | stockService.update(stock); 90 | 91 | final Optional optionalStock = stockRepository.findById(id); 92 | assertTrue(optionalStock.isPresent()); 93 | assertEquals(optionalStock.get().getId(), stock.getId()); 94 | } 95 | 96 | @Test 97 | void delete() { 98 | } 99 | 100 | @Test 101 | void getById() { 102 | } 103 | 104 | @Test 105 | void getAll() { 106 | final List stocks = stockService.getAll(); 107 | assertFalse(stocks.isEmpty()); 108 | } 109 | 110 | @Test 111 | void getAllByBranch() { 112 | final List stockResults = stockService.getAllByBranch("43242324"); 113 | assertFalse(stockResults.isEmpty()); 114 | } 115 | 116 | @Test 117 | void getAllByProduct() { 118 | } 119 | } -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/impl/ProductRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.ProductResult; 5 | import com.icbt.ap.mobileaccessoriessales.enums.ProductStatus; 6 | import com.icbt.ap.mobileaccessoriessales.repository.ProductRepository; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.dao.EmptyResultDataAccessException; 10 | import org.springframework.jdbc.core.JdbcTemplate; 11 | import org.springframework.jdbc.core.RowMapper; 12 | import org.springframework.stereotype.Repository; 13 | 14 | import java.sql.ResultSet; 15 | import java.sql.SQLException; 16 | import java.util.Collections; 17 | import java.util.List; 18 | import java.util.Optional; 19 | 20 | @Repository 21 | @RequiredArgsConstructor 22 | @Slf4j 23 | public class ProductRepositoryImpl implements ProductRepository { 24 | 25 | private final JdbcTemplate jdbcTemplate; 26 | 27 | @Override 28 | public List findAll() { 29 | return jdbcTemplate.query("SELECT * FROM product WHERE status <> ?", 30 | new ProductRowMapper(), ProductStatus.DELETED.getId()); 31 | } 32 | 33 | @Override 34 | public Optional findById(String id) { 35 | 36 | String sql = "SELECT * FROM product WHERE status <> ? AND id = ?"; 37 | 38 | try { 39 | return Optional.ofNullable(jdbcTemplate.queryForObject(sql, new ProductRowMapper(), 40 | ProductStatus.DELETED.getId(), id)); 41 | } catch (EmptyResultDataAccessException ex) { 42 | return Optional.empty(); 43 | } 44 | } 45 | 46 | @Override 47 | public void save(Product product) { 48 | jdbcTemplate.update("INSERT INTO product (id, name, status) " + "VALUES (UUID(), ?, ?)", 49 | product.getName(), product.getStatus().getId()); 50 | } 51 | 52 | @Override 53 | public void update(Product product) { 54 | jdbcTemplate.update("UPDATE product " + " SET name = ?, status = ? " + " WHERE id = ?", 55 | product.getName(), product.getStatus().getId(), product.getId()); 56 | } 57 | 58 | @Override 59 | public void delete(String id) { 60 | jdbcTemplate.update("UPDATE product " + " SET status = ? " + " WHERE id = ?", 61 | ProductStatus.DELETED.getId(), id); 62 | } 63 | 64 | @Override 65 | public Product findByName(String name) { 66 | 67 | String sql = "SELECT * FROM product WHERE status <> ? AND name = ?"; 68 | 69 | try { 70 | return jdbcTemplate.queryForObject(sql, new ProductRowMapper(), 71 | ProductStatus.DELETED.getId(), name); 72 | } catch (EmptyResultDataAccessException ex) { 73 | return null; 74 | } 75 | } 76 | 77 | @Override 78 | public List findAllByIdsIn(List productIds) { 79 | String sql = "SELECT * FROM product WHERE id IN (%s)"; 80 | String inSql = String.join(",", Collections.nCopies(productIds.size(), "?")); 81 | 82 | return jdbcTemplate.query(String.format(sql, inSql), new ProductRowMapper(), productIds.toArray()); 83 | } 84 | 85 | @Override 86 | public List findAllProductDetails() { 87 | return jdbcTemplate.query("SELECT p.id as id, p.name as name, SUM(s.price) as price, s.qty as qty, s.description as description, p.status as status FROM stock s " + 88 | "INNER JOIN product p on s.product_id=p.id WHERE p.status = 1 GROUP BY p.id", 89 | new ProductResultRowMapper()); 90 | } 91 | 92 | private static class ProductRowMapper implements RowMapper { 93 | @Override 94 | public Product mapRow(ResultSet resultSet, int rowNum) throws SQLException { 95 | return Product.builder() 96 | .id(resultSet.getString("id")) 97 | .name(resultSet.getString("name")) 98 | .status(ProductStatus.getById(resultSet.getInt("status"))) 99 | .createdAt(resultSet.getTimestamp("created_at").toLocalDateTime()) 100 | .build(); 101 | } 102 | } 103 | 104 | private static class ProductResultRowMapper implements RowMapper { 105 | @Override 106 | public ProductResult mapRow(ResultSet resultSet, int rowNum) throws SQLException { 107 | return ProductResult.builder() 108 | .id(resultSet.getString("id")) 109 | .name(resultSet.getString("name")) 110 | .price(resultSet.getString("price")) 111 | .qty(resultSet.getInt("qty")) 112 | .status(resultSet.getString("status")) 113 | .description(resultSet.getString("description")) 114 | .build(); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/exception/AppExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.exception; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.dto.CommonResponseDTO; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.context.MessageSource; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.http.converter.HttpMessageNotReadableException; 10 | import org.springframework.validation.BindingResult; 11 | import org.springframework.web.bind.MethodArgumentNotValidException; 12 | import org.springframework.web.bind.annotation.ControllerAdvice; 13 | import org.springframework.web.bind.annotation.ExceptionHandler; 14 | import org.springframework.web.context.request.WebRequest; 15 | import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.Locale; 20 | 21 | @ControllerAdvice 22 | @Slf4j 23 | @RequiredArgsConstructor 24 | public class AppExceptionHandler { 25 | private final MessageSource messageSource; 26 | 27 | @ExceptionHandler(value = {CustomServiceException.class}) 28 | public ResponseEntity handleInvalidInputException(CustomServiceException ex, Locale locale) { 29 | log.error("Business Exception: " + ex.getMessage(), ex); 30 | return getBusinessError(ex, ex.getCode(), locale); 31 | } 32 | 33 | @ExceptionHandler(value = {CustomAuthException.class}) 34 | public ResponseEntity handleAuthException(CustomAuthException ex, Locale locale) { 35 | log.error("Business Exception: " + ex.getMessage(), ex); 36 | return getAuthError(ex, ex.getCode(), locale); 37 | } 38 | 39 | @ExceptionHandler(value = {Exception.class}) 40 | public ResponseEntity handleInvalidInputException(Exception ex, Locale locale) { 41 | log.error("Server Exception: " + ex.getMessage(), ex); 42 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) 43 | .body(new CommonResponseDTO(false, HttpStatus.INTERNAL_SERVER_ERROR.name(), 44 | "Something went wrong! ")); 45 | } 46 | 47 | @ExceptionHandler(MethodArgumentTypeMismatchException.class) 48 | public final ResponseEntity handleArgumentTypeMismatchException( 49 | MethodArgumentTypeMismatchException ex, Locale locale) { 50 | 51 | return getBadRequestError(ex, HttpStatus.BAD_REQUEST.name(), locale); 52 | } 53 | 54 | @ExceptionHandler(HttpMessageNotReadableException.class) 55 | public final ResponseEntity handleArgumentTypeMismatchException( 56 | HttpMessageNotReadableException ex, Locale locale) { 57 | 58 | return getBadRequestError(ex, HttpStatus.BAD_REQUEST.name(), locale); 59 | } 60 | 61 | @ExceptionHandler(MethodArgumentNotValidException.class) 62 | public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) { 63 | log.error("Method arguments are not valid", ex); 64 | BindingResult result = ex.getBindingResult(); 65 | 66 | List errorList = new ArrayList<>(); 67 | result.getFieldErrors().forEach(fieldError -> errorList.add(fieldError.getField() + " : " + fieldError.getDefaultMessage() 68 | + " : rejected value: " + fieldError.getRejectedValue() + "")); 69 | 70 | result.getGlobalErrors().forEach(fieldError -> errorList.add(fieldError.getDefaultMessage())); 71 | 72 | return ResponseEntity.status(HttpStatus.BAD_REQUEST) 73 | .body(new CommonResponseDTO(false, HttpStatus.BAD_REQUEST.name(), 74 | errorList.isEmpty() ? "Invalid request data" : errorList.get(0))); 75 | } 76 | 77 | private ResponseEntity getBusinessError(CustomServiceException ex, String code, Locale locale) { 78 | log.error("Bad request Exception: " + ex.getMessage(), ex); 79 | return ResponseEntity.status(HttpStatus.BAD_REQUEST) 80 | .body(new CommonResponseDTO(false, 81 | messageSource.getMessage(code, ex.getArgs(), locale), 82 | messageSource.getMessage(ex.getMessage(), ex.getArgs(), locale)) 83 | ); 84 | } 85 | 86 | private ResponseEntity getAuthError(CustomAuthException ex, String code, Locale locale) { 87 | log.error("Auth Exception: " + ex.getMessage(), ex); 88 | return ResponseEntity.status(HttpStatus.UNAUTHORIZED) 89 | .body(new CommonResponseDTO(false, 90 | messageSource.getMessage(code, ex.getArgs(), locale), 91 | messageSource.getMessage(ex.getMessage(), ex.getArgs(), locale)) 92 | ); 93 | } 94 | 95 | private ResponseEntity getBadRequestError(Exception ex, String code, Locale locale) { 96 | log.error("Bad request Exception: " + ex.getMessage(), ex); 97 | return ResponseEntity.status(HttpStatus.BAD_REQUEST) 98 | .body(new CommonResponseDTO(false, code, ex.getMessage())); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/service/impl/StockRequestServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.config.AppConfig; 4 | import com.icbt.ap.mobileaccessoriessales.entity.*; 5 | import com.icbt.ap.mobileaccessoriessales.enums.StockRequestStatus; 6 | import com.icbt.ap.mobileaccessoriessales.repository.StockRepository; 7 | import com.icbt.ap.mobileaccessoriessales.repository.StockRequestDetailRepository; 8 | import com.icbt.ap.mobileaccessoriessales.repository.StockRequestRepository; 9 | import com.icbt.ap.mobileaccessoriessales.repository.VehicleRepository; 10 | import com.icbt.ap.mobileaccessoriessales.repository.impl.*; 11 | import com.icbt.ap.mobileaccessoriessales.service.*; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.extension.ExtendWith; 15 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.context.annotation.Import; 18 | import org.springframework.jdbc.core.JdbcTemplate; 19 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 20 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 21 | import org.springframework.test.context.junit.jupiter.SpringExtension; 22 | import static org.junit.jupiter.api.Assertions.*; 23 | 24 | import javax.sql.DataSource; 25 | import java.util.Arrays; 26 | 27 | @Import(AppConfig.class) 28 | @Slf4j 29 | @ExtendWith(SpringExtension.class) 30 | @SpringBootTest 31 | @AutoConfigureMockMvc 32 | class StockRequestServiceImplTest { 33 | 34 | private final StockRequestService stockRequestService; 35 | private final StockRequestRepository stockRequestRepository; 36 | private final StockRequestDetailRepository stockRequestDetailRepository; 37 | private final VehicleRepository vehicleRepository; 38 | private final StockRepository stockRepository; 39 | 40 | private final StockService stockService; 41 | private final ProductService productService; 42 | private final BranchService branchService; 43 | private VehicleService vehicleService; 44 | 45 | 46 | private StockRequestServiceImplTest() { 47 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 48 | .addScript("classpath:test/sales_db_test.sql") 49 | .build(); 50 | final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 51 | stockRepository = new StockRepositoryImpl(jdbcTemplate); 52 | final BranchRepositoryImpl branchRepository = new BranchRepositoryImpl(jdbcTemplate); 53 | 54 | stockRequestRepository = new StockRequestRepositoryImpl(jdbcTemplate); 55 | stockRequestDetailRepository = new StockRequestDetailRepositoryImpl(jdbcTemplate); 56 | vehicleRepository = new VehicleRepositoryImpl(jdbcTemplate); 57 | 58 | branchService = new BranchServiceImpl(branchRepository); 59 | vehicleService = new VehicleServiceImpl(vehicleRepository, branchService); 60 | productService = new ProductServiceImpl(new ProductRepositoryImpl(jdbcTemplate)); 61 | stockService = new StockServiceImpl(stockRepository, productService, branchService); 62 | stockRequestService = new StockRequestServiceImpl(stockRequestRepository, stockRequestDetailRepository, 63 | vehicleRepository, branchRepository, stockRepository, branchService, vehicleService, stockService, 64 | productService); 65 | } 66 | 67 | @Test 68 | void add() { 69 | String byBranchId = "323432"; 70 | String forBranchId = "43242324"; 71 | String vehicleId = "43432"; 72 | String productId = "12cbc2ca-69d8-11eb-8f8a-a81e849e9ba1"; 73 | 74 | StockRequestDetail stockRequestDetail = StockRequestDetail.builder() 75 | .productId(productId) 76 | .qty(10) 77 | .build(); 78 | StockRequestDetail stockRequestDetail2 = StockRequestDetail.builder() 79 | .productId(productId) 80 | .qty(20) 81 | .build(); 82 | 83 | StockRequest stockRequest = StockRequest.builder() 84 | .byBranchId(byBranchId) 85 | .forBranchId(forBranchId) 86 | .vehicleId(vehicleId) 87 | .stockRequestDetails(Arrays.asList(stockRequestDetail, stockRequestDetail2)) 88 | .build(); 89 | stockRequestService.add(stockRequest); 90 | } 91 | 92 | @Test 93 | void update() { 94 | } 95 | 96 | @Test 97 | void delete() { 98 | } 99 | 100 | @Test 101 | void getById() { 102 | } 103 | 104 | @Test 105 | void getAll() { 106 | } 107 | 108 | @Test 109 | void getAllByRequestedByBranch() { 110 | } 111 | 112 | @Test 113 | void getAllByRequestedForBranch() { 114 | } 115 | 116 | @Test 117 | void updateStatus() { 118 | final String stockReqId = "fer324324"; 119 | final StockRequestStatus status = StockRequestStatus.REJECTED; 120 | stockRequestService.updateStatus(stockReqId, status); 121 | final StockRequest stockRequest = stockRequestService.getById(stockReqId); 122 | assertEquals(status, stockRequest.getStatus()); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/service/impl/StockServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.service.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.request.StockQtyUpdateRequest; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 5 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 6 | import com.icbt.ap.mobileaccessoriessales.entity.Stock; 7 | import com.icbt.ap.mobileaccessoriessales.entity.query.StockResult; 8 | import com.icbt.ap.mobileaccessoriessales.exception.CustomServiceException; 9 | import com.icbt.ap.mobileaccessoriessales.repository.StockRepository; 10 | import com.icbt.ap.mobileaccessoriessales.service.BranchService; 11 | import com.icbt.ap.mobileaccessoriessales.service.ProductService; 12 | import com.icbt.ap.mobileaccessoriessales.service.StockService; 13 | import lombok.RequiredArgsConstructor; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.springframework.stereotype.Service; 16 | 17 | import java.util.List; 18 | import java.util.Optional; 19 | import java.util.stream.Collectors; 20 | 21 | @Service 22 | @RequiredArgsConstructor 23 | @Slf4j 24 | public class StockServiceImpl implements StockService { 25 | 26 | private final StockRepository stockRepository; 27 | 28 | private final ProductService productService; 29 | private final BranchService branchService; 30 | 31 | @Override 32 | public void add(Stock stock) { 33 | /*checks whether the requested stock foreign table data exists*/ 34 | final Branch branch = branchService.getById(stock.getBranchId()); 35 | final Product product = productService.getById(stock.getProductId()); 36 | 37 | /*explicitly re-assigns the FK ids*/ 38 | stock.setBranchId(branch.getId()); 39 | stock.setProductId(product.getId()); 40 | 41 | stockRepository.save(stock); 42 | } 43 | 44 | @Override 45 | public void update(Stock stock) { 46 | /*validates the incoming data*/ 47 | final Stock stockById = getById(stock.getId()); 48 | 49 | stockById.setDescription(stock.getDescription()); 50 | stockById.setPrice(stock.getPrice()); 51 | stockById.setQty(stock.getQty()); 52 | /*checks and validates whether the foreign tables are requested to change*/ 53 | if (stock.getBranchId() != null) { 54 | final Branch branch = branchService.getById(stock.getBranchId()); 55 | stockById.setBranchId(branch.getId()); 56 | } 57 | if (stock.getProductId() != null) { 58 | final Product product = productService.getById(stock.getProductId()); 59 | stock.setProductId(product.getId()); 60 | } 61 | 62 | stockRepository.update(stockById); 63 | } 64 | 65 | @Override 66 | public void delete(String id) { 67 | final Stock stock = getById(id); 68 | stockRepository.delete(stock.getId()); 69 | } 70 | 71 | @Override 72 | public Stock getById(String id) { 73 | return stockRepository.findById(id).orElseThrow(() -> new CustomServiceException("error.validation.common.not.found.code", "error.validation.stock.not.found.message")); 74 | } 75 | 76 | @Override 77 | public List getAll() { 78 | return stockRepository.findAll(); 79 | } 80 | 81 | @Override 82 | public List getAllByBranch(String branchId) { 83 | return stockRepository.findAllByBranch(branchId); 84 | } 85 | 86 | @Override 87 | public List getAllByProduct(String productId) { 88 | return stockRepository.findAllByProduct(productId); 89 | } 90 | 91 | /** 92 | * @param qtyUpdateRequests the stock id and the qty that needs to increase/decrease from existing qty. 93 | */ 94 | @Override 95 | public void updateStockQty(List qtyUpdateRequests) { 96 | final List stockIds = qtyUpdateRequests.stream().map(StockQtyUpdateRequest::getId).collect(Collectors.toList()); 97 | final List stockListByIds = validateAndGetStocksByIds(stockIds); 98 | 99 | /*filters and sets qty for the corresponding id*/ 100 | stockListByIds.forEach(stock -> { 101 | final Optional updateRequestOptional = qtyUpdateRequests.stream().filter(qtyUpdateRequest -> qtyUpdateRequest.getId().equals(stock.getId())).findFirst(); 102 | if (updateRequestOptional.isEmpty()) return; 103 | 104 | /*calculation is always a plus (+) operation, 105 | therefore a qty decrease request should send minus values*/ 106 | stock.setQty(stock.getQty() + updateRequestOptional.get().getQty()); 107 | }); 108 | /*updates entire list*/ 109 | stockRepository.updateListQty(stockListByIds); 110 | } 111 | 112 | @Override 113 | public List validateAndGetStocksByIds(List stockIds) { 114 | final List stockListByIds = stockRepository.findAllByIdsIn(stockIds); 115 | 116 | /*validates whether all the requested ids are available in the result*/ 117 | validateStockReqAndResult(stockIds, stockListByIds); 118 | return stockListByIds; 119 | } 120 | 121 | /*Internal functions below*/ 122 | 123 | private void validateStockReqAndResult(List stockIdsReq, List stocks) { 124 | stockIdsReq.forEach(stockId -> { 125 | if (stocks.stream().noneMatch(stock -> stock.getId().equals(stockId))) { 126 | throw new CustomServiceException("error.validation.common.not.found.code", "error.validation.stock.id.not.found.message", new String[]{stockId}); 127 | } 128 | }); 129 | } 130 | 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/controller/v1/rest/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.rest; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.controller.CommonController; 4 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.response.OrderResultResponse; 5 | import com.icbt.ap.mobileaccessoriessales.controller.v1.model.response.OrderTotalAmountBySalesAgentResponse; 6 | import com.icbt.ap.mobileaccessoriessales.dto.CommonResponseDTO; 7 | import com.icbt.ap.mobileaccessoriessales.dto.ContentResponseDTO; 8 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderResult; 9 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderTotalAmountBySalesAgent; 10 | import com.icbt.ap.mobileaccessoriessales.enums.OrderRequestStatus; 11 | import com.icbt.ap.mobileaccessoriessales.service.OrderService; 12 | import lombok.RequiredArgsConstructor; 13 | import lombok.extern.slf4j.Slf4j; 14 | import org.springframework.context.MessageSource; 15 | import org.springframework.http.HttpStatus; 16 | import org.springframework.http.ResponseEntity; 17 | import org.springframework.web.bind.annotation.*; 18 | 19 | import java.util.List; 20 | import java.util.Locale; 21 | import java.util.stream.Collectors; 22 | 23 | import static com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant.VERSION; 24 | 25 | @RestController 26 | @RequestMapping(value = VERSION + "/orders") 27 | @Slf4j 28 | @RequiredArgsConstructor 29 | public class OrderController implements CommonController { 30 | private final OrderService orderService; 31 | private final MessageSource messageSource; 32 | 33 | @GetMapping(path = "") 34 | public ResponseEntity>> getOrderResults() { 35 | log.info("Get all order details"); 36 | return getAllOrderResults(); 37 | } 38 | 39 | @GetMapping(path = "/total_sales_by_sales_agents") 40 | public ResponseEntity>> getOrderTotalAmountBySalesAgentResults() { 41 | log.info("Get all order details by sales agent wise"); 42 | return getAllOrderTotalAmountBySalesAgentResults(); 43 | } 44 | 45 | @PatchMapping(path = "/{orderRequestId}/status/{status}") 46 | public ResponseEntity updateStatus( 47 | @PathVariable(name = "orderRequestId") String orderRequestId, 48 | @PathVariable(name = "status") OrderRequestStatus status) { 49 | log.info("Update order request status by id, OrderRequest id: {}", orderRequestId); 50 | return updateOrderRequestStatus(orderRequestId, status); 51 | } 52 | 53 | /*Internal functions*/ 54 | 55 | private ResponseEntity>> getAllOrderResults() { 56 | return ResponseEntity.ok(new ContentResponseDTO<>(true, 57 | getOrderResultResponseList(orderService.findAllOrder()))); 58 | } 59 | 60 | private ResponseEntity>> getAllOrderTotalAmountBySalesAgentResults() { 61 | return ResponseEntity.ok(new ContentResponseDTO<>(true, 62 | getOrderTotalAmountBySalesAgentResultResponseList(orderService.findAllTotalAmountSaleByAgent()))); 63 | } 64 | 65 | private List getOrderResultResponseList(List orderResults) { 66 | return orderResults 67 | .stream() 68 | .map(this::getOrderResultResponse) 69 | .collect(Collectors.toList()); 70 | } 71 | 72 | private ResponseEntity updateOrderRequestStatus( 73 | String orderRequestId, OrderRequestStatus status) { 74 | orderService.updateStatus(orderRequestId, status); 75 | return new ResponseEntity<>(new CommonResponseDTO(true, 76 | getCode("success.confirmation.common.updated.code"), 77 | getMessage("success.confirmation.stock.request.updated.message")), 78 | HttpStatus.OK); 79 | } 80 | 81 | private OrderResultResponse getOrderResultResponse(OrderResult orderResult) { 82 | return OrderResultResponse.builder() 83 | .id(orderResult.getId()) 84 | .totalAmount(orderResult.getTotalAmount()) 85 | .status(orderResult.getStatus()) 86 | .customerName(orderResult.getCustomerName()) 87 | .customerMobile(orderResult.getCustomerMobile()) 88 | .salesAgentName(orderResult.getSalesAgentName()) 89 | .createdAt(orderResult.getCreatedAt()) 90 | .build(); 91 | } 92 | 93 | private List getOrderTotalAmountBySalesAgentResultResponseList(List orderResults) { 94 | return orderResults 95 | .stream() 96 | .map(this::getOrderTotalAmountBySalesAgentResultResponse) 97 | .collect(Collectors.toList()); 98 | } 99 | 100 | private OrderTotalAmountBySalesAgentResponse getOrderTotalAmountBySalesAgentResultResponse(OrderTotalAmountBySalesAgent orderResult) { 101 | return OrderTotalAmountBySalesAgentResponse.builder() 102 | .repId(orderResult.getRepId()) 103 | .repName(orderResult.getRepName()) 104 | .branchId(orderResult.getBranchId()) 105 | .branchName(orderResult.getBranchName()) 106 | .totalOrder(orderResult.getTotalOrder()) 107 | .totalAmount(orderResult.getTotalAmount()) 108 | .build(); 109 | } 110 | 111 | private String getCode(String key) { 112 | return messageSource.getMessage(key, new Object[0], Locale.getDefault()); 113 | } 114 | 115 | private String getMessage(String key) { 116 | return messageSource.getMessage(key, new Object[0], Locale.getDefault()); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/repository/impl/StockRepositoryImplTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Branch; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 5 | import com.icbt.ap.mobileaccessoriessales.entity.Stock; 6 | import com.icbt.ap.mobileaccessoriessales.entity.query.StockResult; 7 | import com.icbt.ap.mobileaccessoriessales.repository.BranchRepository; 8 | import com.icbt.ap.mobileaccessoriessales.repository.ProductRepository; 9 | import com.icbt.ap.mobileaccessoriessales.repository.StockRepository; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.extension.ExtendWith; 13 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.jdbc.core.JdbcTemplate; 16 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 17 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 18 | import org.springframework.test.context.junit.jupiter.SpringExtension; 19 | 20 | import javax.sql.DataSource; 21 | import java.math.BigDecimal; 22 | import java.util.List; 23 | import java.util.Optional; 24 | 25 | import static org.junit.jupiter.api.Assertions.assertTrue; 26 | import static org.junit.jupiter.api.Assertions.*; 27 | 28 | @Slf4j 29 | @ExtendWith(SpringExtension.class) 30 | @SpringBootTest 31 | @AutoConfigureMockMvc 32 | class StockRepositoryImplTest { 33 | 34 | private final StockRepository stockRepository; 35 | private final BranchRepository branchRepository; 36 | private final ProductRepository productRepository; 37 | 38 | public StockRepositoryImplTest() { 39 | DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) 40 | .addScript("classpath:test/sales_db_test.sql") 41 | .build(); 42 | stockRepository = new StockRepositoryImpl(new JdbcTemplate(dataSource)); 43 | branchRepository = new BranchRepositoryImpl(new JdbcTemplate(dataSource)); 44 | productRepository = new ProductRepositoryImpl(new JdbcTemplate(dataSource)); 45 | } 46 | 47 | @Test 48 | void findAll() { 49 | final List stocks = stockRepository.findAll(); 50 | log.info("Stocks: {}", stocks); 51 | assertTrue(stocks.size() > 0); 52 | } 53 | 54 | @Test 55 | void findById() { 56 | String id = "643344fregt4t"; 57 | final Optional optionalStock = stockRepository.findById(id); 58 | assertTrue(optionalStock.isPresent() && id.equals(optionalStock.get().getId())); 59 | } 60 | 61 | @Test 62 | void save() { 63 | String branchId = "323432"; 64 | final Optional optionalBranch = branchRepository.findById(branchId); 65 | assertTrue(optionalBranch.isPresent() && branchId.equals(optionalBranch.get().getId())); 66 | 67 | String productId = "12cbc2ca-69d8-11eb-8f8a-a81e849e9ba1"; 68 | final Optional optionalProduct = productRepository.findById(productId); 69 | assertTrue(optionalProduct.isPresent() && productId.equals(optionalProduct.get().getId())); 70 | 71 | Stock stock = Stock.builder() 72 | .description("my stock") 73 | .qty(50) 74 | .price(BigDecimal.TEN.multiply(BigDecimal.TEN)) 75 | .productId(optionalProduct.get().getId()) 76 | .branchId(optionalBranch.get().getId()) 77 | .build(); 78 | 79 | stockRepository.save(stock); 80 | } 81 | 82 | @Test 83 | void update() { 84 | String id = "643344fregt4t"; 85 | 86 | String branchId = "323432"; 87 | final Optional optionalBranch = branchRepository.findById(branchId); 88 | assertTrue(optionalBranch.isPresent() && branchId.equals(optionalBranch.get().getId())); 89 | 90 | String productId = "12cbc2ca-69d8-11eb-8f8a-a81e849e9ba1"; 91 | final Optional optionalProduct = productRepository.findById(productId); 92 | assertTrue(optionalProduct.isPresent() && productId.equals(optionalProduct.get().getId())); 93 | 94 | 95 | final Optional optionalStock = stockRepository.findById(id); 96 | assertTrue(optionalStock.isPresent() && id.equals(optionalStock.get().getId())); 97 | final Stock stock = optionalStock.get(); 98 | stock.setDescription("test desc"); 99 | stock.setQty(12); 100 | stock.setPrice(new BigDecimal("160.00")); 101 | stock.setProductId(optionalProduct.get().getId()); 102 | stock.setBranchId(optionalBranch.get().getId()); 103 | stockRepository.update(stock); 104 | 105 | final Optional optionalUpdatedStock = stockRepository.findById(id); 106 | assertTrue(optionalUpdatedStock.isPresent() && id.equals(optionalUpdatedStock.get().getId())); 107 | final Stock updatedStock = optionalUpdatedStock.get(); 108 | assertEquals(stock, updatedStock); 109 | } 110 | 111 | @Test 112 | void delete() { 113 | 114 | } 115 | 116 | @Test 117 | void findAllByBranch() { 118 | 119 | String branchId = "323432"; 120 | final Optional optionalBranch = branchRepository.findById(branchId); 121 | assertTrue(optionalBranch.isPresent() && branchId.equals(optionalBranch.get().getId())); 122 | 123 | final List stocks = stockRepository.findAllByBranch(optionalBranch.get().getId()); 124 | assertTrue(stocks.stream().allMatch(stock -> stock.getBranchId().equals(branchId))); 125 | } 126 | 127 | @Test 128 | void findAllByProduct() { 129 | 130 | String productId = "12cbc2ca-69d8-11eb-8f8a-a81e849e9ba1"; 131 | final Optional optionalProduct = productRepository.findById(productId); 132 | assertTrue(optionalProduct.isPresent() && productId.equals(optionalProduct.get().getId())); 133 | 134 | final List stocks = stockRepository.findAllByProduct(optionalProduct.get().getId()); 135 | assertTrue(stocks.stream().allMatch(stock -> stock.getProductId().equals(productId))); 136 | } 137 | } -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/impl/StockRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Stock; 4 | import com.icbt.ap.mobileaccessoriessales.entity.query.StockResult; 5 | import com.icbt.ap.mobileaccessoriessales.enums.BranchStatus; 6 | import com.icbt.ap.mobileaccessoriessales.enums.ProductStatus; 7 | import com.icbt.ap.mobileaccessoriessales.repository.StockRepository; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.dao.EmptyResultDataAccessException; 11 | import org.springframework.jdbc.core.BatchPreparedStatementSetter; 12 | import org.springframework.jdbc.core.JdbcTemplate; 13 | import org.springframework.jdbc.core.RowMapper; 14 | import org.springframework.stereotype.Repository; 15 | 16 | import java.sql.PreparedStatement; 17 | import java.sql.ResultSet; 18 | import java.sql.SQLException; 19 | import java.util.Collections; 20 | import java.util.List; 21 | import java.util.Optional; 22 | 23 | @Repository 24 | @RequiredArgsConstructor 25 | @Slf4j 26 | public class StockRepositoryImpl implements StockRepository { 27 | 28 | private final JdbcTemplate jdbcTemplate; 29 | 30 | private static final String BRANCH_AND_PRODUCT_SELECT = "SELECT s.*, b.`name` AS branch_name, p.`name` AS product_name " + 31 | "FROM stock s INNER JOIN product p on s.product_id = p.id AND p.status = " + ProductStatus.ACTIVE.getId() + " " + 32 | "INNER JOIN branch b on s.branch_id = b.id AND b.status = " + BranchStatus.ACTIVE.getId(); 33 | 34 | @Override 35 | public List findAll() { 36 | return jdbcTemplate.query(BRANCH_AND_PRODUCT_SELECT, new StockRowMapper()); 37 | } 38 | 39 | @Override 40 | public Optional findById(String id) { 41 | 42 | String sql = BRANCH_AND_PRODUCT_SELECT + " WHERE s.id = ? "; 43 | 44 | try { 45 | return Optional.ofNullable(jdbcTemplate 46 | .queryForObject(sql, new StockResultRowMapper(), id)); 47 | } catch (EmptyResultDataAccessException ex) { 48 | return Optional.empty(); 49 | } 50 | } 51 | 52 | @Override 53 | public void save(Stock stock) { 54 | jdbcTemplate.update("INSERT INTO stock (`id`, `description`, `qty`, `price`, `branch_id`, `product_id`) " 55 | + "VALUES (UUID(), ?, ?, ?, ?, ?)", 56 | stock.getDescription(), stock.getQty(), stock.getPrice(), stock.getBranchId(), stock.getProductId()); 57 | } 58 | 59 | @Override 60 | public void update(Stock stock) { 61 | jdbcTemplate.update("UPDATE stock " + " SET description = ?, qty = ?, price = ? , " + 62 | "branch_id = ? , product_id = ? " + " WHERE id = ?", 63 | stock.getDescription(), stock.getQty(), stock.getPrice(), 64 | stock.getBranchId(), stock.getProductId(), stock.getId()); 65 | } 66 | 67 | @Override 68 | public void delete(String id) { 69 | jdbcTemplate.update("UPDATE stock " + " SET qty = ? WHERE id = ?", 0, id); 70 | } 71 | 72 | @Override 73 | public List findAllByBranch(String branchId) { 74 | 75 | String sql = BRANCH_AND_PRODUCT_SELECT + " WHERE s.branch_id = ?"; 76 | 77 | return jdbcTemplate.query(sql, new StockResultRowMapper(), branchId); 78 | } 79 | 80 | @Override 81 | public List findAllByProduct(String productId) { 82 | String sql = BRANCH_AND_PRODUCT_SELECT + " WHERE product_id = ?"; 83 | 84 | return jdbcTemplate.query(sql, new StockResultRowMapper(), productId); 85 | } 86 | 87 | @Override 88 | public List findAllByIdsIn(List stockIds) { 89 | String sql = "SELECT * FROM stock WHERE id IN (%s)"; 90 | String inSql = String.join(",", Collections.nCopies(stockIds.size(), "?")); 91 | 92 | return jdbcTemplate.query(String.format(sql, inSql), new StockRowMapper(), stockIds.toArray()); 93 | } 94 | 95 | @Override 96 | public void updateListQty(List stocks) { 97 | jdbcTemplate.batchUpdate("UPDATE stock SET qty = ? WHERE id = ? ", 98 | new BatchPreparedStatementSetter() { 99 | public void setValues(PreparedStatement ps, int i) 100 | throws SQLException { 101 | ps.setInt(1, stocks.get(i).getQty()); 102 | ps.setString(2, stocks.get(i).getId()); 103 | } 104 | 105 | public int getBatchSize() { 106 | return stocks.size(); 107 | } 108 | }); 109 | } 110 | 111 | private static class StockRowMapper implements RowMapper { 112 | @Override 113 | public Stock mapRow(ResultSet resultSet, int rowNum) throws SQLException { 114 | return StockResult.builder() 115 | .id(resultSet.getString("id")) 116 | .description(resultSet.getString("description")) 117 | .qty(resultSet.getInt("qty")) 118 | .price(resultSet.getBigDecimal("price")) 119 | .branchId(resultSet.getString("branch_id")) 120 | .productId(resultSet.getString("product_id")) 121 | .createdAt(resultSet.getTimestamp("created_at").toLocalDateTime()) 122 | .build(); 123 | } 124 | } 125 | 126 | private static class StockResultRowMapper implements RowMapper { 127 | @Override 128 | public StockResult mapRow(ResultSet resultSet, int rowNum) throws SQLException { 129 | return StockResult.builder() 130 | .id(resultSet.getString("id")) 131 | .description(resultSet.getString("description")) 132 | .qty(resultSet.getInt("qty")) 133 | .price(resultSet.getBigDecimal("price")) 134 | .branchId(resultSet.getString("branch_id")) 135 | .branchName(resultSet.getString("branch_name")) 136 | .productId(resultSet.getString("product_id")) 137 | .productName(resultSet.getString("product_name")) 138 | .createdAt(resultSet.getTimestamp("created_at").toLocalDateTime()) 139 | .build(); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/com/icbt/ap/mobileaccessoriessales/repository/impl/OrderRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.repository.impl; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.entity.Order; 4 | import com.icbt.ap.mobileaccessoriessales.entity.OrderDetail; 5 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderResult; 6 | import com.icbt.ap.mobileaccessoriessales.entity.query.OrderTotalAmountBySalesAgent; 7 | import com.icbt.ap.mobileaccessoriessales.enums.OrderRequestStatus; 8 | import com.icbt.ap.mobileaccessoriessales.enums.ProductStatus; 9 | import com.icbt.ap.mobileaccessoriessales.repository.OrderRepository; 10 | import lombok.RequiredArgsConstructor; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.dao.EmptyResultDataAccessException; 13 | import org.springframework.jdbc.core.JdbcTemplate; 14 | import org.springframework.stereotype.Repository; 15 | import org.springframework.jdbc.core.RowMapper; 16 | 17 | import java.sql.ResultSet; 18 | import java.sql.SQLException; 19 | import java.util.List; 20 | import java.util.Optional; 21 | 22 | @Repository 23 | @RequiredArgsConstructor 24 | @Slf4j 25 | public class OrderRepositoryImpl implements OrderRepository { 26 | 27 | private final JdbcTemplate jdbcTemplate; 28 | 29 | @Override 30 | public List findAllByOrderBySalesAgent(String bySalesAgentId) { 31 | String sql = "SELECT o.*, od.*, c.`name` AS customer_name, c.`mobile` AS customer_mobile, c.`address` AS customer_address, u.username AS sale_rep_name" + 32 | "FROM orders o INNER JOIN customer c on o.customer_id =c.id " + 33 | "INNER JOIN user u on o.sales_rep_id = u.id" + 34 | "WHERE o.sales_rep_id = ?"; 35 | // String inSql = String.join(",", Collections.nCopies(bySalesAgentId.size(), "?")); 36 | return null; 37 | } 38 | 39 | @Override 40 | public List findAll() { 41 | 42 | return jdbcTemplate.query("SELECT * FROM orders", new OrderRowMapper()); 43 | } 44 | 45 | @Override 46 | public List findAllOrder() { 47 | return jdbcTemplate.query("SELECT o.id AS order_id, o.status AS status, o.total_amount AS total_amount, o.created_at AS order_date, \n" + 48 | " c.name AS customer_name, c.mobile AS customer_mobile, u.username AS sales_agent_name \n" + 49 | " FROM orders o INNER JOIN customer c on o.customer_id=c.id\n" + 50 | " INNER JOIN user u on o.sales_rep_id=u.id", new OrderResultRowMapper()); 51 | } 52 | 53 | @Override 54 | public List findAllOrderDetails() { 55 | return null; 56 | } 57 | 58 | @Override 59 | public List findAllTotalAmountSaleByAgent() { 60 | return jdbcTemplate.query("SELECT u.id AS id, u.username AS agent_name, u.branch_id AS branch_id,\n" + 61 | " b.name AS branch_name, COUNT(o.id) AS total_order, SUM(o.total_amount) AS total_amount\n" + 62 | " FROM orders o INNER JOIN user u on o.sales_rep_id=u.id\n" + 63 | " INNER JOIN branch b on u.branch_id = b.id\n" + 64 | " GROUP BY o.sales_rep_id" 65 | , new OrderTotalBySalesAgentRowMapper()); 66 | } 67 | 68 | @Override 69 | public void updateStatus(String id, OrderRequestStatus status) { 70 | jdbcTemplate.update("UPDATE orders " + " SET status = ? WHERE id = ?", 71 | status.getId(), id); 72 | } 73 | 74 | @Override 75 | public Optional findById(String id) { 76 | 77 | String sql = "SELECT * FROM orders WHERE id = ?"; 78 | 79 | try { 80 | return Optional.ofNullable(jdbcTemplate.queryForObject(sql, new OrderRepositoryImpl.OrderRowMapper(), id)); 81 | } catch (EmptyResultDataAccessException ex) { 82 | return Optional.empty(); 83 | } 84 | } 85 | 86 | @Override 87 | public void save(Order entity) { 88 | 89 | } 90 | 91 | @Override 92 | public void update(Order entity) { 93 | 94 | } 95 | 96 | @Override 97 | public void delete(String id) { 98 | 99 | } 100 | 101 | private static class OrderResultRowMapper implements RowMapper { 102 | @Override 103 | public OrderResult mapRow(ResultSet resultSet, int rowNum) throws SQLException { 104 | return OrderResult.builder() 105 | .id(resultSet.getString("order_id")) 106 | .totalAmount(resultSet.getString("total_amount")) 107 | .createdAt(resultSet.getTimestamp("order_date").toLocalDateTime()) 108 | .status(resultSet.getString("status")) 109 | .customerName(resultSet.getString("customer_name")) 110 | .customerMobile(resultSet.getString("customer_mobile")) 111 | .salesAgentName(resultSet.getString("sales_agent_name")) 112 | .build(); 113 | } 114 | } 115 | 116 | private static class OrderRowMapper implements RowMapper { 117 | @Override 118 | public Order mapRow(ResultSet resultSet, int rowNum) throws SQLException { 119 | return Order.builder() 120 | .id(resultSet.getString("id")) 121 | .totalAmount(resultSet.getString("total_amount")) 122 | .createdAt(resultSet.getTimestamp("created_at").toLocalDateTime()) 123 | .status(resultSet.getString("status")) 124 | .customerId(resultSet.getString("customer_id")) 125 | .salesRepId(resultSet.getString("sales_rep_id")) 126 | .build(); 127 | } 128 | } 129 | 130 | private static class OrderTotalBySalesAgentRowMapper implements RowMapper { 131 | @Override 132 | public OrderTotalAmountBySalesAgent mapRow(ResultSet resultSet, int rowNum) throws SQLException { 133 | return OrderTotalAmountBySalesAgent.builder() 134 | .repId(resultSet.getString("id")) 135 | .repName(resultSet.getString("agent_name")) 136 | .branchId(resultSet.getString("branch_id")) 137 | .branchName(resultSet.getString("branch_name")) 138 | .totalOrder(resultSet.getString("total_order")) 139 | .totalAmount(resultSet.getString("total_amount")) 140 | .build(); 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/test/java/com/icbt/ap/mobileaccessoriessales/controller/v1/rest/ProductControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.icbt.ap.mobileaccessoriessales.controller.v1.rest; 2 | 3 | import com.icbt.ap.mobileaccessoriessales.config.AppConfig; 4 | import com.icbt.ap.mobileaccessoriessales.entity.Product; 5 | import com.icbt.ap.mobileaccessoriessales.enums.ProductStatus; 6 | import com.icbt.ap.mobileaccessoriessales.service.ProductService; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.junit.jupiter.api.Test; 9 | import org.mockito.Mockito; 10 | import org.skyscreamer.jsonassert.JSONAssert; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 13 | import org.springframework.boot.test.mock.mockito.MockBean; 14 | import org.springframework.context.MessageSource; 15 | import org.springframework.context.annotation.Import; 16 | import org.springframework.http.HttpStatus; 17 | import org.springframework.http.MediaType; 18 | import org.springframework.mock.web.MockHttpServletResponse; 19 | import org.springframework.test.web.servlet.MockMvc; 20 | import org.springframework.test.web.servlet.MvcResult; 21 | import org.springframework.test.web.servlet.RequestBuilder; 22 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 23 | 24 | import java.time.LocalDateTime; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import static com.icbt.ap.mobileaccessoriessales.controller.v1.util.ApiConstant.DATE_TIME_FORMATTER; 29 | import static org.junit.jupiter.api.Assertions.assertEquals; 30 | import static org.mockito.Mockito.when; 31 | 32 | 33 | @Slf4j 34 | @Import(AppConfig.class) 35 | @WebMvcTest(value = ProductController.class) 36 | class ProductControllerTest { 37 | 38 | @Autowired 39 | private MockMvc mockMvc; 40 | 41 | @MockBean 42 | private ProductService productService; 43 | 44 | @Autowired 45 | private MessageSource messageSource; 46 | 47 | private static final String PRODUCT_PATH = "/v1/product"; 48 | 49 | 50 | @Test 51 | void getProducts() throws Exception { 52 | final LocalDateTime now = LocalDateTime.now(); 53 | List products = new ArrayList<>(); 54 | products.add(Product.builder() 55 | .id("64db6f2b-6ab1-11eb-888a-a81e849e9ba4") 56 | .name("Apple") 57 | .status(ProductStatus.ACTIVE) 58 | .createdAt(now) 59 | .build()); 60 | products.add(Product.builder() 61 | .id("64db6f2b-6ab1-11eb-888a-a4324234324") 62 | .name("Orange") 63 | .status(ProductStatus.ACTIVE) 64 | .createdAt(now) 65 | .build()); 66 | 67 | when(productService.getAll()) 68 | .thenReturn(products); 69 | 70 | RequestBuilder requestBuilder = MockMvcRequestBuilders 71 | .get(PRODUCT_PATH) 72 | .accept(MediaType.APPLICATION_JSON); 73 | 74 | MvcResult result = mockMvc.perform(requestBuilder) 75 | .andReturn(); 76 | 77 | log.info("Response: {}", result.getResponse().getContentAsString()); 78 | String expected = "{'success':true,'data':[{'id':'64db6f2b-6ab1-11eb-888a-a81e849e9ba4'," + 79 | "'name':'Apple','status':'Active','createdAt':'" 80 | + DATE_TIME_FORMATTER.format(now) + "'}," + 81 | "{'id':'64db6f2b-6ab1-11eb-888a-a4324234324'," + 82 | "'name':'Orange','status':'Active','createdAt':'" 83 | + DATE_TIME_FORMATTER.format(now) + "'}]}"; 84 | 85 | JSONAssert.assertEquals(expected, result.getResponse().getContentAsString(), false); 86 | } 87 | 88 | @Test 89 | void getProduct() throws Exception { 90 | Product mockProduct = Product.builder() 91 | .id("64db6f2b-6ab1-11eb-888a-a81e849e9ba4") 92 | .name("Apple") 93 | .status(ProductStatus.ACTIVE) 94 | .createdAt(LocalDateTime.now()) 95 | .build(); 96 | 97 | when(productService.getById(Mockito.anyString())) 98 | .thenReturn(mockProduct); 99 | 100 | RequestBuilder requestBuilder = MockMvcRequestBuilders 101 | .get(PRODUCT_PATH + "/121212") 102 | .accept(MediaType.APPLICATION_JSON); 103 | 104 | MvcResult result = mockMvc.perform(requestBuilder) 105 | .andReturn(); 106 | 107 | log.info("Response: {}", result.getResponse().getContentAsString()); 108 | String expected = "{'success':true,'data':{'id':'64db6f2b-6ab1-11eb-888a-a81e849e9ba4'," + 109 | "'name':'Apple','status':'Active','createdAt':'" 110 | + DATE_TIME_FORMATTER.format(mockProduct.getCreatedAt()) + "'}}"; 111 | 112 | JSONAssert.assertEquals(expected, result.getResponse().getContentAsString(), false); 113 | } 114 | 115 | @Test 116 | void saveProduct() throws Exception { 117 | 118 | // Send course as body to /students/Student1/courses 119 | RequestBuilder requestBuilder = MockMvcRequestBuilders 120 | .post(PRODUCT_PATH) 121 | .accept(MediaType.APPLICATION_JSON) 122 | .content("{\n" + 123 | " \"name\": \"Apple\"\n" + 124 | "}") 125 | .contentType(MediaType.APPLICATION_JSON); 126 | 127 | MvcResult result = mockMvc.perform(requestBuilder).andReturn(); 128 | 129 | MockHttpServletResponse response = result.getResponse(); 130 | 131 | assertEquals(HttpStatus.CREATED.value(), response.getStatus()); 132 | } 133 | 134 | @Test 135 | void updateProduct() throws Exception { 136 | // Send course as body to /students/Student1/courses 137 | RequestBuilder requestBuilder = MockMvcRequestBuilders 138 | .put(PRODUCT_PATH) 139 | .accept(MediaType.APPLICATION_JSON) 140 | .content("{\n" + 141 | " \"id\": \"12\",\n" + 142 | " \"name\": \"Apple\"\n" + 143 | "}") 144 | .contentType(MediaType.APPLICATION_JSON); 145 | 146 | MvcResult result = mockMvc.perform(requestBuilder).andReturn(); 147 | 148 | MockHttpServletResponse response = result.getResponse(); 149 | 150 | assertEquals(HttpStatus.OK.value(), response.getStatus()); 151 | } 152 | 153 | @Test 154 | void deleteProduct() throws Exception { 155 | 156 | RequestBuilder requestBuilder = MockMvcRequestBuilders 157 | .delete(PRODUCT_PATH + "/121212") 158 | .accept(MediaType.APPLICATION_JSON) 159 | .contentType(MediaType.APPLICATION_JSON); 160 | 161 | MvcResult result = mockMvc.perform(requestBuilder).andReturn(); 162 | 163 | MockHttpServletResponse response = result.getResponse(); 164 | 165 | assertEquals(HttpStatus.OK.value(), response.getStatus()); 166 | } 167 | } --------------------------------------------------------------------------------