diff --git a/semestr_2/Lab. 2/qpick-shop/.gitignore b/semestr_2/Lab. 2/qpick-shop/.gitignore
new file mode 100644
index 0000000..c2065bc
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/.gitignore
@@ -0,0 +1,37 @@
+HELP.md
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
diff --git a/semestr_2/Lab. 2/qpick-shop/build.gradle b/semestr_2/Lab. 2/qpick-shop/build.gradle
new file mode 100644
index 0000000..9779452
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/build.gradle
@@ -0,0 +1,29 @@
+plugins {
+ id 'java'
+ id 'org.springframework.boot' version '3.2.3'
+ id 'io.spring.dependency-management' version '1.1.4'
+}
+
+group = 'com.example'
+version = '0.0.1-SNAPSHOT'
+
+java {
+ sourceCompatibility = '17'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter-web'
+ implementation 'org.springframework.boot:spring-boot-starter-validation'
+ implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
+ implementation 'org.modelmapper:modelmapper:3.2.0'
+
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+}
+
+tasks.named('test') {
+ useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/semestr_2/Lab. 2/qpick-shop/gradle/wrapper/gradle-wrapper.jar b/semestr_2/Lab. 2/qpick-shop/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..d64cd49
Binary files /dev/null and b/semestr_2/Lab. 2/qpick-shop/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/semestr_2/Lab. 2/qpick-shop/gradle/wrapper/gradle-wrapper.properties b/semestr_2/Lab. 2/qpick-shop/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1af9e09
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/semestr_2/Lab. 2/qpick-shop/gradlew b/semestr_2/Lab. 2/qpick-shop/gradlew
new file mode 100644
index 0000000..1aa94a4
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/gradlew
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/semestr_2/Lab. 2/qpick-shop/gradlew.bat b/semestr_2/Lab. 2/qpick-shop/gradlew.bat
new file mode 100644
index 0000000..93e3f59
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/semestr_2/Lab. 2/qpick-shop/index.html b/semestr_2/Lab. 2/qpick-shop/index.html
new file mode 100644
index 0000000..3191a87
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/index.html
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+ Document
+
+
+
+ Push the button
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/semestr_2/Lab. 2/qpick-shop/settings.gradle b/semestr_2/Lab. 2/qpick-shop/settings.gradle
new file mode 100644
index 0000000..82cfb67
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'qpick-shop'
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/QpickShopApplication.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/QpickShopApplication.java
new file mode 100644
index 0000000..90ee882
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/QpickShopApplication.java
@@ -0,0 +1,50 @@
+package com.example.qpickshop;
+
+import java.util.Objects;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+// import com.example.demo.items.model.ItemEntity;
+// import com.example.demo.items.service.ItemService;
+// import com.example.demo.types.model.TypeEntity;
+// import com.example.demo.types.service.TypeService;
+
+@SpringBootApplication
+public class QpickShopApplication implements CommandLineRunner {
+ private final Logger log = LoggerFactory.getLogger(QpickShopApplication.class);
+
+ // private final TypeService typeService;
+ // private final ItemService itemService;
+
+ // public DemoApplication(TypeService typeService, ItemService itemService) {
+ // this.typeService = typeService;
+ // this.itemService = itemService;
+ // }
+
+ public static void main(String[] args) {
+ SpringApplication.run(QpickShopApplication.class, args);
+ }
+
+ @Override
+ public void run(String... args) throws Exception {
+ // if (args.length > 0 && Objects.equals("--populate", args[0])) {
+ // log.info("Create default types values");
+ // final var type1 = typeService.create(new TypeEntity(null, "Мясная"));
+ // final var type2 = typeService.create(new TypeEntity(null, "Пепперони"));
+ // final var type3 = typeService.create(new TypeEntity(null, "Сырная"));
+
+ // log.info("Create default items values");
+ // itemService.create(new ItemEntity(null, type1, 399.00, 20));
+ // itemService.create(new ItemEntity(null, type1, 499.00, 3));
+ // itemService.create(new ItemEntity(null, type2, 450.50, 30));
+ // itemService.create(new ItemEntity(null, type2, 900.50, 10));
+ // itemService.create(new ItemEntity(null, type2, 600.00, 6));
+ // itemService.create(new ItemEntity(null, type3, 750.00, 6));
+ // itemService.create(new ItemEntity(null, type3, 670.00, 3));
+ // }
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/WebConfig.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/WebConfig.java
new file mode 100644
index 0000000..fa50808
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/WebConfig.java
@@ -0,0 +1,14 @@
+package com.example.qpickshop;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.lang.NonNull;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+ @Override
+ public void addCorsMappings(@NonNull CorsRegistry registry) {
+ registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE");
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/api/CartItemController.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/api/CartItemController.java
new file mode 100644
index 0000000..47550aa
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/api/CartItemController.java
@@ -0,0 +1,75 @@
+package com.example.qpickshop.cartItems.api;
+
+import java.util.List;
+
+import org.modelmapper.ModelMapper;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.example.qpickshop.cartItems.model.CartItemEntity;
+import com.example.qpickshop.cartItems.service.CartItemService;
+import com.example.qpickshop.core.configuration.Constants;
+import com.example.qpickshop.products.service.ProductService;
+import com.example.qpickshop.users.service.UserService;
+
+import jakarta.validation.Valid;
+
+@RestController
+@RequestMapping(Constants.API_URL + "/basket")
+public class CartItemController {
+ private final CartItemService cartItemService;
+ private final ProductService productService;
+ private final UserService userService;
+ private final ModelMapper modelMapper;
+
+ public CartItemController(CartItemService cartItemService, ProductService productService, UserService userService,
+ ModelMapper modelMapper) {
+ this.cartItemService = cartItemService;
+ this.productService = productService;
+ this.userService = userService;
+ this.modelMapper = modelMapper;
+ }
+
+ private CartItemDto toDto(CartItemEntity entity) {
+ return modelMapper.map(entity, CartItemDto.class);
+ }
+
+ private CartItemEntity toEntity(CartItemDto dto) {
+ CartItemEntity entity = modelMapper.map(dto, CartItemEntity.class);
+ entity.setProduct(productService.get(dto.getProductId()));
+ entity.setUser(userService.get(dto.getUserId()));
+ return entity;
+ }
+
+ @GetMapping
+ public List getAll(@RequestParam(name = "userId", defaultValue = "0") Long userId) {
+ return cartItemService.getAll(userId).stream().map(this::toDto).toList();
+ }
+
+ @GetMapping("/{id}")
+ public CartItemDto get(@PathVariable(name = "id") Long id) {
+ return toDto(cartItemService.get(id));
+ }
+
+ @PostMapping
+ public CartItemDto create(@RequestBody @Valid CartItemDto dto) {
+ return toDto(cartItemService.create(toEntity(dto)));
+ }
+
+ @PutMapping("/{id}")
+ public CartItemDto update(@PathVariable(name = "id") Long id, @RequestBody CartItemDto dto) {
+ return toDto(cartItemService.update(id, toEntity(dto)));
+ }
+
+ @DeleteMapping("/{id}")
+ public CartItemDto delete(@PathVariable(name = "id") Long id) {
+ return toDto(cartItemService.delete(id));
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/api/CartItemDto.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/api/CartItemDto.java
new file mode 100644
index 0000000..052283c
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/api/CartItemDto.java
@@ -0,0 +1,55 @@
+package com.example.qpickshop.cartItems.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+
+public class CartItemDto {
+ private Long id;
+
+ @NotNull
+ @Min(1)
+ private Long productId;
+
+ @NotNull
+ @Min(1)
+ private Long userId;
+
+ @NotNull
+ @Min(1)
+ private Integer quantity;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getProductId() {
+ return productId;
+ }
+
+ public void setProductId(Long productId) {
+ this.productId = productId;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public Integer getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(Integer quantity) {
+ this.quantity = quantity;
+ }
+}
\ No newline at end of file
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/model/CartItemEntity.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/model/CartItemEntity.java
new file mode 100644
index 0000000..10bd50a
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/model/CartItemEntity.java
@@ -0,0 +1,66 @@
+package com.example.qpickshop.cartItems.model;
+
+import java.util.Objects;
+
+import com.example.qpickshop.core.model.BaseEntity;
+import com.example.qpickshop.products.model.ProductEntity;
+import com.example.qpickshop.users.model.UserEntity;
+
+public class CartItemEntity extends BaseEntity {
+ private UserEntity user;
+ private ProductEntity product;
+ private Integer quantity;
+
+ public CartItemEntity() {
+ super();
+ }
+
+ public CartItemEntity(Long id, UserEntity user, ProductEntity product, Integer quantity) {
+ super(id);
+ this.user = user;
+ this.product = product;
+ this.quantity = quantity;
+ }
+
+ public UserEntity getUser() {
+ return user;
+ }
+
+ public void setUser(UserEntity user) {
+ this.user = user;
+ }
+
+ public ProductEntity getProduct() {
+ return product;
+ }
+
+ public void setProduct(ProductEntity product) {
+ this.product = product;
+ }
+
+ public Integer getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(Integer quantity) {
+ this.quantity = quantity;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, user, product, quantity);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ final CartItemEntity other = (CartItemEntity) obj;
+ return Objects.equals(other.getId(), id)
+ && Objects.equals(other.getUser(), user)
+ && Objects.equals(other.getProduct(), product)
+ && Objects.equals(other.getQuantity(), quantity);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/repository/CartItemRepository.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/repository/CartItemRepository.java
new file mode 100644
index 0000000..8c9e694
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/repository/CartItemRepository.java
@@ -0,0 +1,10 @@
+package com.example.qpickshop.cartItems.repository;
+
+import org.springframework.stereotype.Repository;
+
+import com.example.qpickshop.cartItems.model.CartItemEntity;
+import com.example.qpickshop.core.repository.MapRepository;
+
+@Repository
+public class CartItemRepository extends MapRepository {
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/service/CartItemService.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/service/CartItemService.java
new file mode 100644
index 0000000..5c19b42
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/cartItems/service/CartItemService.java
@@ -0,0 +1,52 @@
+package com.example.qpickshop.cartItems.service;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+
+import com.example.qpickshop.cartItems.model.CartItemEntity;
+import com.example.qpickshop.cartItems.repository.CartItemRepository;
+import com.example.qpickshop.core.error.NotFoundException;
+
+@Service
+public class CartItemService {
+ private final CartItemRepository repository;
+
+ public CartItemService(CartItemRepository repository) {
+ this.repository = repository;
+ }
+
+ public List getAll(Long userId) {
+ if (Objects.equals(userId, 0L)) {
+ return repository.getAll();
+ }
+
+ return repository.getAll().stream()
+ .filter(cartItem -> cartItem.getUser().getId().equals(userId))
+ .toList();
+ }
+
+ public CartItemEntity get(Long id) {
+ return Optional.ofNullable(repository.get(id))
+ .orElseThrow(() -> new NotFoundException(id));
+ }
+
+ public CartItemEntity create(CartItemEntity entity) {
+ return repository.create(entity);
+ }
+
+ public CartItemEntity update(Long id, CartItemEntity entity) {
+ final CartItemEntity existsEntity = get(id);
+ existsEntity.setUser(entity.getUser());
+ existsEntity.setProduct(entity.getProduct());
+ existsEntity.setQuantity(entity.getQuantity());
+ return repository.update(existsEntity);
+ }
+
+ public CartItemEntity delete(Long id) {
+ final CartItemEntity existsEntity = get(id);
+ return repository.delete(existsEntity);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/api/CategoryController.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/api/CategoryController.java
new file mode 100644
index 0000000..d248d05
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/api/CategoryController.java
@@ -0,0 +1,64 @@
+package com.example.qpickshop.categories.api;
+
+import java.util.List;
+
+import org.modelmapper.ModelMapper;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.example.qpickshop.core.configuration.Constants;
+import com.example.qpickshop.categories.model.CategoryEntity;
+import com.example.qpickshop.categories.service.CategoryService;
+
+import jakarta.validation.Valid;
+
+@RestController
+@RequestMapping(Constants.API_URL + "/category")
+public class CategoryController {
+ private final CategoryService categoryService;
+ private final ModelMapper modelMapper;
+
+ public CategoryController(CategoryService categoryService, ModelMapper modelMapper) {
+ this.categoryService = categoryService;
+ this.modelMapper = modelMapper;
+ }
+
+ private CategoryDto toDto(CategoryEntity entity) {
+ return modelMapper.map(entity, CategoryDto.class);
+ }
+
+ private CategoryEntity toEntity(CategoryDto dto) {
+ return modelMapper.map(dto, CategoryEntity.class);
+ }
+
+ @GetMapping
+ public List getAll() {
+ return categoryService.getAll().stream().map(this::toDto).toList();
+ }
+
+ @GetMapping("/{id}")
+ public CategoryDto get(@PathVariable(name = "id") Long id) {
+ return toDto(categoryService.get(id));
+ }
+
+ @PostMapping
+ public CategoryDto create(@RequestBody @Valid CategoryDto dto) {
+ return toDto(categoryService.create(toEntity(dto)));
+ }
+
+ @PutMapping("/{id}")
+ public CategoryDto update(@PathVariable(name = "id") Long id, @RequestBody CategoryDto dto) {
+ return toDto(categoryService.update(id, toEntity(dto)));
+ }
+
+ @DeleteMapping("/{id}")
+ public CategoryDto delete(@PathVariable(name = "id") Long id) {
+ return toDto(categoryService.delete(id));
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/api/CategoryDto.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/api/CategoryDto.java
new file mode 100644
index 0000000..fdb3a3f
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/api/CategoryDto.java
@@ -0,0 +1,28 @@
+package com.example.qpickshop.categories.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import jakarta.validation.constraints.NotBlank;
+
+public class CategoryDto {
+ private Long id;
+ @NotBlank
+ private String name;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/model/CategoryEntity.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/model/CategoryEntity.java
new file mode 100644
index 0000000..2531d6d
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/model/CategoryEntity.java
@@ -0,0 +1,42 @@
+package com.example.qpickshop.categories.model;
+
+import java.util.Objects;
+
+import com.example.qpickshop.core.model.BaseEntity;
+
+public class CategoryEntity extends BaseEntity {
+ private String name;
+
+ public CategoryEntity() {
+ super();
+ }
+
+ public CategoryEntity(Long id, String name) {
+ super(id);
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ final CategoryEntity other = (CategoryEntity) obj;
+ return Objects.equals(other.getId(), id)
+ && Objects.equals(other.getName(), name);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/repository/CategoryRepository.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/repository/CategoryRepository.java
new file mode 100644
index 0000000..a28912a
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/repository/CategoryRepository.java
@@ -0,0 +1,10 @@
+package com.example.qpickshop.categories.repository;
+
+import org.springframework.stereotype.Repository;
+
+import com.example.qpickshop.core.repository.MapRepository;
+import com.example.qpickshop.categories.model.CategoryEntity;
+
+@Repository
+public class CategoryRepository extends MapRepository {
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/service/CategoryService.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/service/CategoryService.java
new file mode 100644
index 0000000..c733437
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/categories/service/CategoryService.java
@@ -0,0 +1,43 @@
+package com.example.qpickshop.categories.service;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.categories.model.CategoryEntity;
+import com.example.qpickshop.categories.repository.CategoryRepository;
+
+@Service
+public class CategoryService {
+ private final CategoryRepository repository;
+
+ public CategoryService(CategoryRepository repository) {
+ this.repository = repository;
+ }
+
+ public List getAll() {
+ return repository.getAll();
+ }
+
+ public CategoryEntity get(Long id) {
+ return Optional.ofNullable(repository.get(id))
+ .orElseThrow(() -> new NotFoundException(id));
+ }
+
+ public CategoryEntity create(CategoryEntity entity) {
+ return repository.create(entity);
+ }
+
+ public CategoryEntity update(Long id, CategoryEntity entity) {
+ final CategoryEntity existsEntity = get(id);
+ existsEntity.setName(entity.getName());
+ return repository.update(existsEntity);
+ }
+
+ public CategoryEntity delete(Long id) {
+ final CategoryEntity existsEntity = get(id);
+ return repository.delete(existsEntity);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/configuration/Constants.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/configuration/Constants.java
new file mode 100644
index 0000000..6605807
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/configuration/Constants.java
@@ -0,0 +1,8 @@
+package com.example.qpickshop.core.configuration;
+
+public class Constants {
+ public static final String API_URL = "/api/1.0";
+
+ private Constants() {
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/configuration/MapperConfiguration.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/configuration/MapperConfiguration.java
new file mode 100644
index 0000000..db38ea6
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/configuration/MapperConfiguration.java
@@ -0,0 +1,13 @@
+package com.example.qpickshop.core.configuration;
+
+import org.modelmapper.ModelMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MapperConfiguration {
+ @Bean
+ ModelMapper modelMapper() {
+ return new ModelMapper();
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/configuration/WebConfiguration.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/configuration/WebConfiguration.java
new file mode 100644
index 0000000..762ff01
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/configuration/WebConfiguration.java
@@ -0,0 +1,15 @@
+package com.example.qpickshop.core.configuration;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.lang.NonNull;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfiguration implements WebMvcConfigurer {
+ @Override
+ public void addCorsMappings(@NonNull CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedMethods("GET", "POST", "PUT", "DELETE");
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/error/NotFoundException.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/error/NotFoundException.java
new file mode 100644
index 0000000..afe6d44
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/error/NotFoundException.java
@@ -0,0 +1,7 @@
+package com.example.qpickshop.core.error;
+
+public class NotFoundException extends RuntimeException {
+ public NotFoundException(Long id) {
+ super(String.format("Entity with id [%s] is not found or not exists", id));
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/model/BaseEntity.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/model/BaseEntity.java
new file mode 100644
index 0000000..57b9d6c
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/model/BaseEntity.java
@@ -0,0 +1,20 @@
+package com.example.qpickshop.core.model;
+
+public abstract class BaseEntity {
+ protected Long id;
+
+ protected BaseEntity() {
+ }
+
+ protected BaseEntity(Long id) {
+ this.id = id;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/repository/CommonRepository.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/repository/CommonRepository.java
new file mode 100644
index 0000000..121e17f
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/repository/CommonRepository.java
@@ -0,0 +1,17 @@
+package com.example.qpickshop.core.repository;
+
+import java.util.List;
+
+public interface CommonRepository {
+ List getAll();
+
+ E get(T id);
+
+ E create(E entity);
+
+ E update(E entity);
+
+ E delete(E entity);
+
+ void deleteAll();
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/repository/MapRepository.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/repository/MapRepository.java
new file mode 100644
index 0000000..63a5231
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/core/repository/MapRepository.java
@@ -0,0 +1,57 @@
+package com.example.qpickshop.core.repository;
+
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import com.example.qpickshop.core.model.BaseEntity;
+
+public abstract class MapRepository implements CommonRepository {
+ private final Map entities = new TreeMap<>();
+ private Long lastId = 0L;
+
+ protected MapRepository() {
+ }
+
+ @Override
+ public List getAll() {
+ return entities.values().stream().toList();
+ }
+
+ @Override
+ public E get(Long id) {
+ return entities.get(id);
+ }
+
+ @Override
+ public E create(E entity) {
+ lastId++;
+ entity.setId(lastId);
+ entities.put(lastId, entity);
+ return entity;
+ }
+
+ @Override
+ public E update(E entity) {
+ if (get(entity.getId()) == null) {
+ return null;
+ }
+ entities.put(entity.getId(), entity);
+ return entity;
+ }
+
+ @Override
+ public E delete(E entity) {
+ if (get(entity.getId()) == null) {
+ return null;
+ }
+ entities.remove(entity.getId());
+ return entity;
+ }
+
+ @Override
+ public void deleteAll() {
+ lastId = 0L;
+ entities.clear();
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/api/FavouriteProductController.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/api/FavouriteProductController.java
new file mode 100644
index 0000000..a186fa1
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/api/FavouriteProductController.java
@@ -0,0 +1,75 @@
+package com.example.qpickshop.favouriteProducts.api;
+
+import java.util.List;
+
+import org.modelmapper.ModelMapper;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.example.qpickshop.core.configuration.Constants;
+import com.example.qpickshop.favouriteProducts.model.FavouriteProductEntity;
+import com.example.qpickshop.favouriteProducts.service.FavouriteProductService;
+import com.example.qpickshop.products.service.ProductService;
+import com.example.qpickshop.users.service.UserService;
+
+import jakarta.validation.Valid;
+
+@RestController
+@RequestMapping(Constants.API_URL + "/favourites")
+public class FavouriteProductController {
+ private final FavouriteProductService favouriteProductService;
+ private final ProductService productService;
+ private final UserService userService;
+ private final ModelMapper modelMapper;
+
+ public FavouriteProductController(FavouriteProductService favouriteProductService, ProductService productService, UserService userService,
+ ModelMapper modelMapper) {
+ this.favouriteProductService = favouriteProductService;
+ this.productService = productService;
+ this.userService = userService;
+ this.modelMapper = modelMapper;
+ }
+
+ private FavouriteProductDto toDto(FavouriteProductEntity entity) {
+ return modelMapper.map(entity, FavouriteProductDto.class);
+ }
+
+ private FavouriteProductEntity toEntity(FavouriteProductDto dto) {
+ FavouriteProductEntity entity = modelMapper.map(dto, FavouriteProductEntity.class);
+ entity.setProduct(productService.get(dto.getProductId()));
+ entity.setUser(userService.get(dto.getUserId()));
+ return entity;
+ }
+
+ @GetMapping
+ public List getAll(@RequestParam(name = "userId", defaultValue = "0") Long userId) {
+ return favouriteProductService.getAll(userId).stream().map(this::toDto).toList();
+ }
+
+ @GetMapping("/{id}")
+ public FavouriteProductDto get(@PathVariable(name = "id") Long id) {
+ return toDto(favouriteProductService.get(id));
+ }
+
+ @PostMapping
+ public FavouriteProductDto create(@RequestBody @Valid FavouriteProductDto dto) {
+ return toDto(favouriteProductService.create(toEntity(dto)));
+ }
+
+ @PutMapping("/{id}")
+ public FavouriteProductDto update(@PathVariable(name = "id") Long id, @RequestBody FavouriteProductDto dto) {
+ return toDto(favouriteProductService.update(id, toEntity(dto)));
+ }
+
+ @DeleteMapping("/{id}")
+ public FavouriteProductDto delete(@PathVariable(name = "id") Long id) {
+ return toDto(favouriteProductService.delete(id));
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/api/FavouriteProductDto.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/api/FavouriteProductDto.java
new file mode 100644
index 0000000..1109d1c
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/api/FavouriteProductDto.java
@@ -0,0 +1,43 @@
+package com.example.qpickshop.favouriteProducts.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+
+public class FavouriteProductDto {
+ private Long id;
+
+ @NotNull
+ @Min(1)
+ private Long productId;
+
+ @NotNull
+ @Min(1)
+ private Long userId;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getProductId() {
+ return productId;
+ }
+
+ public void setProductId(Long productId) {
+ this.productId = productId;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+}
\ No newline at end of file
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/model/FavouriteProductEntity.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/model/FavouriteProductEntity.java
new file mode 100644
index 0000000..81d3630
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/model/FavouriteProductEntity.java
@@ -0,0 +1,55 @@
+package com.example.qpickshop.favouriteProducts.model;
+
+import java.util.Objects;
+
+import com.example.qpickshop.core.model.BaseEntity;
+import com.example.qpickshop.products.model.ProductEntity;
+import com.example.qpickshop.users.model.UserEntity;
+
+public class FavouriteProductEntity extends BaseEntity {
+ private UserEntity user;
+ private ProductEntity product;
+
+ public FavouriteProductEntity() {
+ super();
+ }
+
+ public FavouriteProductEntity(Long id, UserEntity user, ProductEntity product) {
+ super(id);
+ this.user = user;
+ this.product = product;
+ }
+
+ public UserEntity getUser() {
+ return user;
+ }
+
+ public void setUser(UserEntity user) {
+ this.user = user;
+ }
+
+ public ProductEntity getProduct() {
+ return product;
+ }
+
+ public void setProduct(ProductEntity product) {
+ this.product = product;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, user, product);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ final FavouriteProductEntity other = (FavouriteProductEntity) obj;
+ return Objects.equals(other.getId(), id)
+ && Objects.equals(other.getUser(), user)
+ && Objects.equals(other.getProduct(), product);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/repository/FavouriteProductRepository.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/repository/FavouriteProductRepository.java
new file mode 100644
index 0000000..5c90166
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/repository/FavouriteProductRepository.java
@@ -0,0 +1,10 @@
+package com.example.qpickshop.favouriteProducts.repository;
+
+import org.springframework.stereotype.Repository;
+
+import com.example.qpickshop.core.repository.MapRepository;
+import com.example.qpickshop.favouriteProducts.model.FavouriteProductEntity;
+
+@Repository
+public class FavouriteProductRepository extends MapRepository {
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/service/FavouriteProductService.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/service/FavouriteProductService.java
new file mode 100644
index 0000000..3b22fe9
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/favouriteProducts/service/FavouriteProductService.java
@@ -0,0 +1,51 @@
+package com.example.qpickshop.favouriteProducts.service;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.favouriteProducts.model.FavouriteProductEntity;
+import com.example.qpickshop.favouriteProducts.repository.FavouriteProductRepository;
+
+@Service
+public class FavouriteProductService {
+ private final FavouriteProductRepository repository;
+
+ public FavouriteProductService(FavouriteProductRepository repository) {
+ this.repository = repository;
+ }
+
+ public List getAll(Long userId) {
+ if (Objects.equals(userId, 0L)) {
+ return repository.getAll();
+ }
+
+ return repository.getAll().stream()
+ .filter(favourite -> favourite.getUser().getId().equals(userId))
+ .toList();
+ }
+
+ public FavouriteProductEntity get(Long id) {
+ return Optional.ofNullable(repository.get(id))
+ .orElseThrow(() -> new NotFoundException(id));
+ }
+
+ public FavouriteProductEntity create(FavouriteProductEntity entity) {
+ return repository.create(entity);
+ }
+
+ public FavouriteProductEntity update(Long id, FavouriteProductEntity entity) {
+ final FavouriteProductEntity existsEntity = get(id);
+ existsEntity.setUser(entity.getUser());
+ existsEntity.setProduct(entity.getProduct());
+ return repository.update(existsEntity);
+ }
+
+ public FavouriteProductEntity delete(Long id) {
+ final FavouriteProductEntity existsEntity = get(id);
+ return repository.delete(existsEntity);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/api/OrderController.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/api/OrderController.java
new file mode 100644
index 0000000..fa437dc
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/api/OrderController.java
@@ -0,0 +1,86 @@
+package com.example.qpickshop.orders.api;
+
+import java.util.List;
+
+import org.modelmapper.ModelMapper;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.example.qpickshop.core.configuration.Constants;
+import com.example.qpickshop.orders.model.OrderEntity;
+import com.example.qpickshop.orders.model.OrderItemEntity;
+import com.example.qpickshop.orders.service.OrderService;
+import com.example.qpickshop.products.service.ProductService;
+import com.example.qpickshop.users.service.UserService;
+
+import jakarta.validation.Valid;
+
+@RestController
+@RequestMapping(Constants.API_URL + "/order")
+public class OrderController {
+ private final OrderService orderService;
+ private final ProductService productService;
+ private final UserService userService;
+ private final ModelMapper modelMapper;
+
+ public OrderController(OrderService orderService, UserService userService, ProductService productService,
+ ModelMapper modelMapper) {
+ this.orderService = orderService;
+ this.productService = productService;
+ this.userService = userService;
+ this.modelMapper = modelMapper;
+ }
+
+ private OrderItemEntity getOrderItemEntity(OrderItemDto dto) {
+ OrderItemEntity orderItem = modelMapper.map(dto, OrderItemEntity.class);
+ orderItem.setProduct(productService.get(orderItem.getProduct().getId()));
+ return orderItem;
+ }
+
+ private List getOrderItems(OrderDto dto) {
+ return dto.getOrderItems().stream().map(this::getOrderItemEntity).toList();
+ }
+
+ private OrderDto toDto(OrderEntity entity) {
+ return modelMapper.map(entity, OrderDto.class);
+ }
+
+ private OrderEntity toEntity(OrderDto dto) {
+ OrderEntity entity = modelMapper.map(dto, OrderEntity.class);
+ entity.setUser(userService.get(dto.getUserId()));
+ entity.setItems(getOrderItems(dto));
+ return entity;
+ }
+
+ @GetMapping
+ public List getAll(@RequestParam(name = "userId", defaultValue = "0") Long userId) {
+ return orderService.getAll(userId).stream().map(this::toDto).toList();
+ }
+
+ @GetMapping("/{id}")
+ public OrderDto get(@PathVariable(name = "id") Long id) {
+ return toDto(orderService.get(id));
+ }
+
+ @PostMapping
+ public OrderDto create(@RequestBody @Valid OrderDto dto) {
+ return toDto(orderService.create(toEntity(dto)));
+ }
+
+ @PutMapping("/{id}")
+ public OrderDto update(@PathVariable(name = "id") Long id, @RequestBody OrderDto dto) {
+ return toDto(orderService.update(id, toEntity(dto)));
+ }
+
+ @DeleteMapping("/{id}")
+ public OrderDto delete(@PathVariable(name = "id") Long id) {
+ return toDto(orderService.delete(id));
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/api/OrderDto.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/api/OrderDto.java
new file mode 100644
index 0000000..b4a4cd0
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/api/OrderDto.java
@@ -0,0 +1,46 @@
+package com.example.qpickshop.orders.api;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+
+public class OrderDto {
+ private Long id;
+
+ @NotNull
+ @Min(1)
+ private Long userId;
+
+ @NotNull
+ @Size(min = 1)
+ private List orderItems;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public List getOrderItems() {
+ return orderItems;
+ }
+
+ public void setOrderItems(List orderItems) {
+ this.orderItems = orderItems;
+ }
+}
\ No newline at end of file
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/api/OrderItemDto.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/api/OrderItemDto.java
new file mode 100644
index 0000000..ac659d6
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/api/OrderItemDto.java
@@ -0,0 +1,43 @@
+package com.example.qpickshop.orders.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+
+public class OrderItemDto {
+ private Long id;
+
+ @NotNull
+ @Min(1)
+ private Long productId;
+
+ @NotNull
+ @Min(1)
+ private Integer quantity;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getProductId() {
+ return productId;
+ }
+
+ public void setProductId(Long productId) {
+ this.productId = productId;
+ }
+
+ public Integer getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(Integer quantity) {
+ this.quantity = quantity;
+ }
+}
\ No newline at end of file
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/model/OrderEntity.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/model/OrderEntity.java
new file mode 100644
index 0000000..7690abf
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/model/OrderEntity.java
@@ -0,0 +1,67 @@
+package com.example.qpickshop.orders.model;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+import com.example.qpickshop.core.model.BaseEntity;
+import com.example.qpickshop.users.model.UserEntity;
+
+public class OrderEntity extends BaseEntity {
+ private UserEntity user;
+ private Date date;
+ private List items;
+
+ public OrderEntity() {
+ super();
+ }
+
+ public OrderEntity(Long id, UserEntity user, List items) {
+ super(id);
+ this.user = user;
+ this.date = new Date();
+ this.items = items;
+ }
+
+ public UserEntity getUser() {
+ return user;
+ }
+
+ public void setUser(UserEntity user) {
+ this.user = user;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public List getItems() {
+ return items;
+ }
+
+ public void setItems(List items) {
+ this.items = items;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, user, items, date);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ final OrderEntity other = (OrderEntity) obj;
+ return Objects.equals(other.getId(), id)
+ && Objects.equals(other.getItems(), items)
+ && Objects.equals(other.getDate(), date)
+ && Objects.equals(other.getUser(), user);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/model/OrderItemEntity.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/model/OrderItemEntity.java
new file mode 100644
index 0000000..de3e5aa
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/model/OrderItemEntity.java
@@ -0,0 +1,65 @@
+package com.example.qpickshop.orders.model;
+
+import java.util.Objects;
+
+import com.example.qpickshop.core.model.BaseEntity;
+import com.example.qpickshop.products.model.ProductEntity;
+
+public class OrderItemEntity extends BaseEntity {
+ private ProductEntity product;
+ private OrderEntity order;
+ private Integer quantity;
+
+ public OrderItemEntity() {
+ super();
+ }
+
+ public OrderItemEntity(Long id, OrderEntity order, ProductEntity product, Integer quantity) {
+ super(id);
+ this.order = order;
+ this.product = product;
+ this.quantity = quantity;
+ }
+
+ public OrderEntity getOrder() {
+ return order;
+ }
+
+ public void setOrder(OrderEntity order) {
+ this.order = order;
+ }
+
+ public ProductEntity getProduct() {
+ return product;
+ }
+
+ public void setProduct(ProductEntity product) {
+ this.product = product;
+ }
+
+ public Integer getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(Integer quantity) {
+ this.quantity = quantity;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, order, product, quantity);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ final OrderItemEntity other = (OrderItemEntity) obj;
+ return Objects.equals(other.getId(), id)
+ && Objects.equals(other.getOrder(), order)
+ && Objects.equals(other.getProduct(), product)
+ && Objects.equals(other.getQuantity(), quantity);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/repository/OrderItemRepository.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/repository/OrderItemRepository.java
new file mode 100644
index 0000000..ba5de22
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/repository/OrderItemRepository.java
@@ -0,0 +1,10 @@
+package com.example.qpickshop.orders.repository;
+
+import org.springframework.stereotype.Repository;
+
+import com.example.qpickshop.core.repository.MapRepository;
+import com.example.qpickshop.orders.model.OrderItemEntity;
+
+@Repository
+public class OrderItemRepository extends MapRepository {
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/repository/OrderRepository.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/repository/OrderRepository.java
new file mode 100644
index 0000000..c250b73
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/repository/OrderRepository.java
@@ -0,0 +1,10 @@
+package com.example.qpickshop.orders.repository;
+
+import org.springframework.stereotype.Repository;
+
+import com.example.qpickshop.core.repository.MapRepository;
+import com.example.qpickshop.orders.model.OrderEntity;
+
+@Repository
+public class OrderRepository extends MapRepository {
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/service/OrderItemService.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/service/OrderItemService.java
new file mode 100644
index 0000000..f89e03f
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/service/OrderItemService.java
@@ -0,0 +1,52 @@
+package com.example.qpickshop.orders.service;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.orders.model.OrderItemEntity;
+import com.example.qpickshop.orders.repository.OrderItemRepository;
+
+@Service
+public class OrderItemService {
+ private final OrderItemRepository repository;
+
+ public OrderItemService(OrderItemRepository repository) {
+ this.repository = repository;
+ }
+
+ public List getAll(Long orderId) {
+ if (Objects.equals(orderId, 0L)) {
+ return repository.getAll();
+ }
+
+ return repository.getAll().stream()
+ .filter(orderItem -> orderItem.getOrder().getId().equals(orderId))
+ .toList();
+ }
+
+ public OrderItemEntity get(Long id) {
+ return Optional.ofNullable(repository.get(id))
+ .orElseThrow(() -> new NotFoundException(id));
+ }
+
+ public OrderItemEntity create(OrderItemEntity entity) {
+ return repository.create(entity);
+ }
+
+ public OrderItemEntity update(Long id, OrderItemEntity entity) {
+ final OrderItemEntity existsEntity = get(id);
+ existsEntity.setOrder(entity.getOrder());
+ existsEntity.setProduct(entity.getProduct());
+ existsEntity.setQuantity(entity.getQuantity());
+ return repository.update(existsEntity);
+ }
+
+ public OrderItemEntity delete(Long id) {
+ final OrderItemEntity existsEntity = get(id);
+ return repository.delete(existsEntity);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/service/OrderService.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/service/OrderService.java
new file mode 100644
index 0000000..f0c0f32
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/orders/service/OrderService.java
@@ -0,0 +1,59 @@
+package com.example.qpickshop.orders.service;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.orders.model.OrderEntity;
+import com.example.qpickshop.orders.model.OrderItemEntity;
+import com.example.qpickshop.orders.repository.OrderRepository;
+
+@Service
+public class OrderService {
+ private final OrderRepository repository;
+ private final OrderItemService orderItemService;
+
+ public OrderService(OrderRepository repository, OrderItemService orderItemService) {
+ this.repository = repository;
+ this.orderItemService = orderItemService;
+ }
+
+ public List getAll(Long userId) {
+ if (Objects.equals(userId, 0L)) {
+ return repository.getAll();
+ }
+
+ return repository.getAll().stream()
+ .filter(order -> order.getUser().getId().equals(userId))
+ .toList();
+ }
+
+ public OrderEntity get(Long id) {
+ return Optional.ofNullable(repository.get(id))
+ .orElseThrow(() -> new NotFoundException(id));
+ }
+
+ public OrderEntity create(OrderEntity entity) {
+ for (int i = 0; i < entity.getItems().size(); i++) {
+ final OrderItemEntity orderItem = entity.getItems().get(i);
+ orderItem.setOrder(entity);
+ orderItemService.create(orderItem);
+ }
+
+ return repository.create(entity);
+ }
+
+ public OrderEntity update(Long id, OrderEntity entity) {
+ final OrderEntity existsEntity = get(id);
+ existsEntity.setUser(entity.getUser());
+ return repository.update(existsEntity);
+ }
+
+ public OrderEntity delete(Long id) {
+ final OrderEntity existsEntity = get(id);
+ return repository.delete(existsEntity);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/api/ProductController.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/api/ProductController.java
new file mode 100644
index 0000000..93bfa7b
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/api/ProductController.java
@@ -0,0 +1,71 @@
+package com.example.qpickshop.products.api;
+
+import java.util.List;
+
+import org.modelmapper.ModelMapper;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.example.qpickshop.core.configuration.Constants;
+import com.example.qpickshop.products.model.ProductEntity;
+import com.example.qpickshop.products.service.ProductService;
+import com.example.qpickshop.categories.service.CategoryService;
+
+import jakarta.validation.Valid;
+
+@RestController
+@RequestMapping(Constants.API_URL + "/product")
+public class ProductController {
+ private final ProductService productService;
+ private final CategoryService categoryService;
+ private final ModelMapper modelMapper;
+
+ public ProductController(ProductService productService, CategoryService typeService,
+ ModelMapper modelMapper) {
+ this.productService = productService;
+ this.categoryService = typeService;
+ this.modelMapper = modelMapper;
+ }
+
+ private ProductDto toDto(ProductEntity entity) {
+ return modelMapper.map(entity, ProductDto.class);
+ }
+
+ private ProductEntity toEntity(ProductDto dto) {
+ final ProductEntity entity = modelMapper.map(dto, ProductEntity.class);
+ entity.setCategory(categoryService.get(dto.getCategoryId()));
+ return entity;
+ }
+
+ @GetMapping
+ public List getAll(@RequestParam(name = "categoryId", defaultValue = "0") Long categoryId) {
+ return productService.getAll(categoryId).stream().map(this::toDto).toList();
+ }
+
+ @GetMapping("/{id}")
+ public ProductDto get(@PathVariable(name = "id") Long id) {
+ return toDto(productService.get(id));
+ }
+
+ @PostMapping
+ public ProductDto create(@RequestBody @Valid ProductDto dto) {
+ return toDto(productService.create(toEntity(dto)));
+ }
+
+ @PutMapping("/{id}")
+ public ProductDto update(@PathVariable(name = "id") Long id, @RequestBody ProductDto dto) {
+ return toDto(productService.update(id, toEntity(dto)));
+ }
+
+ @DeleteMapping("/{id}")
+ public ProductDto delete(@PathVariable(name = "id") Long id) {
+ return toDto(productService.delete(id));
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/api/ProductDto.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/api/ProductDto.java
new file mode 100644
index 0000000..650d530
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/api/ProductDto.java
@@ -0,0 +1,78 @@
+package com.example.qpickshop.products.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
+public class ProductDto {
+ private Long id;
+
+ @NotBlank
+ private String name;
+
+ @NotNull
+ @Min(1)
+ private Long categoryId;
+
+ @NotNull
+ @Min(1)
+ private Double price;
+
+ @NotNull
+ @Min(0)
+ private Double rating;
+
+ @NotBlank
+ private String description;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Long getCategoryId() {
+ return categoryId;
+ }
+
+ public void setCategoryId(Long categoryId) {
+ this.categoryId = categoryId;
+ }
+
+ public Double getPrice() {
+ return price;
+ }
+
+ public void setPrice(Double price) {
+ this.price = price;
+ }
+
+ public Double getRating() {
+ return rating;
+ }
+
+ public void setRating(Double rating) {
+ this.rating = rating;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setProductInfos(String description) {
+ this.description = description;
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/model/ProductEntity.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/model/ProductEntity.java
new file mode 100644
index 0000000..db1a6b9
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/model/ProductEntity.java
@@ -0,0 +1,88 @@
+package com.example.qpickshop.products.model;
+
+import java.util.Objects;
+
+import com.example.qpickshop.core.model.BaseEntity;
+import com.example.qpickshop.categories.model.CategoryEntity;
+
+public class ProductEntity extends BaseEntity {
+ private String name;
+ private CategoryEntity category;
+ private String description;
+ private Double price;
+ private Double rating;
+
+ public ProductEntity() {
+ super();
+ }
+
+ public ProductEntity(Long id, String name, CategoryEntity category,
+ String description, Double price, Double rating) {
+ super(id);
+ this.name = name;
+ this.category = category;
+ this.price = price;
+ this.rating = rating;
+ this.description = description;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public CategoryEntity getCategory() {
+ return category;
+ }
+
+ public void setCategory(CategoryEntity category) {
+ this.category = category;
+ }
+
+ public Double getPrice() {
+ return price;
+ }
+
+ public void setPrice(Double price) {
+ this.price = price;
+ }
+
+ public Double getRating() {
+ return rating;
+ }
+
+ public void setRating(Double rating) {
+ this.rating = rating;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name, category, price, rating, description);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ final ProductEntity other = (ProductEntity) obj;
+ return Objects.equals(other.getId(), id)
+ && Objects.equals(other.getName(), name)
+ && Objects.equals(other.getCategory(), category)
+ && Objects.equals(other.getPrice(), price)
+ && Objects.equals(other.getRating(), rating)
+ && Objects.equals(other.getDescription(), description);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/repository/ProductRepository.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/repository/ProductRepository.java
new file mode 100644
index 0000000..2efa6cf
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/repository/ProductRepository.java
@@ -0,0 +1,10 @@
+package com.example.qpickshop.products.repository;
+
+import org.springframework.stereotype.Repository;
+
+import com.example.qpickshop.core.repository.MapRepository;
+import com.example.qpickshop.products.model.ProductEntity;
+
+@Repository
+public class ProductRepository extends MapRepository {
+}
\ No newline at end of file
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/service/ProductService.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/service/ProductService.java
new file mode 100644
index 0000000..0f168c0
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/products/service/ProductService.java
@@ -0,0 +1,53 @@
+package com.example.qpickshop.products.service;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.products.model.ProductEntity;
+import com.example.qpickshop.products.repository.ProductRepository;
+
+@Service
+public class ProductService {
+ private final ProductRepository repository;
+
+ public ProductService(ProductRepository repository) {
+ this.repository = repository;
+ }
+
+ public List getAll(Long categoryId) {
+ if (Objects.equals(categoryId, 0L)) {
+ return repository.getAll();
+ }
+
+ return repository.getAll().stream()
+ .filter(product -> product.getCategory().getId().equals(categoryId))
+ .toList();
+ }
+
+ public ProductEntity get(Long id) {
+ return Optional.ofNullable(repository.get(id))
+ .orElseThrow(() -> new NotFoundException(id));
+ }
+
+ public ProductEntity create(ProductEntity entity) {
+ return repository.create(entity);
+ }
+
+ public ProductEntity update(Long id, ProductEntity entity) {
+ final ProductEntity existsEntity = get(id);
+ existsEntity.setCategory(entity.getCategory());
+ existsEntity.setPrice(entity.getPrice());
+ existsEntity.setRating(entity.getRating());
+ existsEntity.setDescription(entity.getDescription());
+ return repository.update(existsEntity);
+ }
+
+ public ProductEntity delete(Long id) {
+ final ProductEntity existsEntity = get(id);
+ return repository.delete(existsEntity);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/api/UserController.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/api/UserController.java
new file mode 100644
index 0000000..c9e1d78
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/api/UserController.java
@@ -0,0 +1,64 @@
+package com.example.qpickshop.users.api;
+
+import java.util.List;
+
+import org.modelmapper.ModelMapper;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.example.qpickshop.core.configuration.Constants;
+import com.example.qpickshop.users.model.UserEntity;
+import com.example.qpickshop.users.service.UserService;
+
+import jakarta.validation.Valid;
+
+@RestController
+@RequestMapping(Constants.API_URL + "/user")
+public class UserController {
+ private final UserService userService;
+ private final ModelMapper modelMapper;
+
+ public UserController(UserService userService, ModelMapper modelMapper) {
+ this.userService = userService;
+ this.modelMapper = modelMapper;
+ }
+
+ private UserDto toDto(UserEntity entity) {
+ return modelMapper.map(entity, UserDto.class);
+ }
+
+ private UserEntity toEntity(UserDto dto) {
+ return modelMapper.map(dto, UserEntity.class);
+ }
+
+ @GetMapping
+ public List getAll() {
+ return userService.getAll().stream().map(this::toDto).toList();
+ }
+
+ @GetMapping("/{id}")
+ public UserDto get(@PathVariable(name = "id") Long id) {
+ return toDto(userService.get(id));
+ }
+
+ @PostMapping
+ public UserDto create(@RequestBody @Valid UserDto dto) {
+ return toDto(userService.create(toEntity(dto)));
+ }
+
+ @PutMapping("/{id}")
+ public UserDto update(@PathVariable(name = "id") Long id, @RequestBody UserDto dto) {
+ return toDto(userService.update(id, toEntity(dto)));
+ }
+
+ @DeleteMapping("/{id}")
+ public UserDto delete(@PathVariable(name = "id") Long id) {
+ return toDto(userService.delete(id));
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/api/UserDto.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/api/UserDto.java
new file mode 100644
index 0000000..1c070fc
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/api/UserDto.java
@@ -0,0 +1,43 @@
+package com.example.qpickshop.users.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+
+public class UserDto {
+ private Long id;
+
+ @NotNull
+ @Min(1)
+ private String email;
+
+ @NotNull
+ @Min(1)
+ private String password;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
\ No newline at end of file
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/model/UserEntity.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/model/UserEntity.java
new file mode 100644
index 0000000..dad358d
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/model/UserEntity.java
@@ -0,0 +1,53 @@
+package com.example.qpickshop.users.model;
+
+import java.util.Objects;
+
+import com.example.qpickshop.core.model.BaseEntity;
+
+public class UserEntity extends BaseEntity {
+ private String email;
+ private String password;
+
+ public UserEntity() {
+ super();
+ }
+
+ public UserEntity(Long id, String email, String password) {
+ super(id);
+ this.email = email;
+ this.password = password;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, email, password);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ final UserEntity other = (UserEntity) obj;
+ return Objects.equals(other.getId(), id)
+ && Objects.equals(other.getEmail(), email)
+ && Objects.equals(other.getPassword(), password);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/repository/UserRepository.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/repository/UserRepository.java
new file mode 100644
index 0000000..181bfcc
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/repository/UserRepository.java
@@ -0,0 +1,10 @@
+package com.example.qpickshop.users.repository;
+
+import org.springframework.stereotype.Repository;
+
+import com.example.qpickshop.core.repository.MapRepository;
+import com.example.qpickshop.users.model.UserEntity;
+
+@Repository
+public class UserRepository extends MapRepository {
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/service/UserService.java b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/service/UserService.java
new file mode 100644
index 0000000..6427cfb
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/java/com/example/qpickshop/users/service/UserService.java
@@ -0,0 +1,44 @@
+package com.example.qpickshop.users.service;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.users.model.UserEntity;
+import com.example.qpickshop.users.repository.UserRepository;
+
+@Service
+public class UserService {
+ private final UserRepository repository;
+
+ public UserService(UserRepository repository) {
+ this.repository = repository;
+ }
+
+ public List getAll() {
+ return repository.getAll();
+ }
+
+ public UserEntity get(Long id) {
+ return Optional.ofNullable(repository.get(id))
+ .orElseThrow(() -> new NotFoundException(id));
+ }
+
+ public UserEntity create(UserEntity entity) {
+ return repository.create(entity);
+ }
+
+ public UserEntity update(Long id, UserEntity entity) {
+ final UserEntity existsEntity = get(id);
+ existsEntity.setEmail(entity.getEmail());
+ existsEntity.setPassword(entity.getPassword());
+ return repository.update(existsEntity);
+ }
+
+ public UserEntity delete(Long id) {
+ final UserEntity existsEntity = get(id);
+ return repository.delete(existsEntity);
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/main/resources/application.properties b/semestr_2/Lab. 2/qpick-shop/src/main/resources/application.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/CartItemServiceTests.java b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/CartItemServiceTests.java
new file mode 100644
index 0000000..fb66dec
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/CartItemServiceTests.java
@@ -0,0 +1,110 @@
+package com.example.qpickshop;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.products.model.ProductEntity;
+import com.example.qpickshop.products.repository.ProductRepository;
+import com.example.qpickshop.products.service.ProductService;
+import com.example.qpickshop.cartItems.model.CartItemEntity;
+import com.example.qpickshop.cartItems.service.CartItemService;
+import com.example.qpickshop.categories.model.CategoryEntity;
+import com.example.qpickshop.categories.repository.CategoryRepository;
+import com.example.qpickshop.categories.service.CategoryService;
+import com.example.qpickshop.users.model.UserEntity;
+import com.example.qpickshop.users.repository.UserRepository;
+import com.example.qpickshop.users.service.UserService;
+
+@SpringBootTest
+@TestMethodOrder(OrderAnnotation.class)
+public class CartItemServiceTests {
+ @Autowired
+ private CartItemService cartItemService;
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private CategoryService categoryService;
+
+ @Autowired
+ private ProductRepository productRepository;
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private CategoryRepository categoryRepository;
+
+ @Autowired
+ private ProductService productService;
+
+ @Test
+ void getTest() {
+ Assertions.assertThrows(NotFoundException.class, () -> cartItemService.get(0L));
+ }
+
+ @Test
+ @Order(1)
+ void createTest() {
+ final UserEntity user = userService.create(new UserEntity(null, "test@mail.ru", "test"));
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "test"));
+ final ProductEntity product = productService
+ .create(new ProductEntity(null, "test", category, "description", 100.00, 5.00));
+
+ cartItemService.create(new CartItemEntity(null, user, product, 5));
+ cartItemService.create(new CartItemEntity(null, user, product, 6));
+
+ final CartItemEntity last = cartItemService.create(new CartItemEntity(null, user, product, 7));
+
+ Assertions.assertEquals(3, cartItemService.getAll(0L).size());
+ Assertions.assertEquals(last, cartItemService.get(3L));
+ }
+
+ @Test
+ @Order(2)
+ void updateTest() {
+ final UserEntity user = userService.create(new UserEntity(null, "test1@mail.ru", "test"));
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "test"));
+ final ProductEntity product = productService
+ .create(new ProductEntity(null, "test1", category, "description", 100.00, 2.00));
+
+ final CartItemEntity cartItem = cartItemService.get(3L);
+ final Integer oldQuantity = cartItem.getQuantity();
+
+ final CartItemEntity newCartItem = cartItemService.update(3L, new CartItemEntity(null, user, product, 10));
+
+ Assertions.assertEquals(3, cartItemService.getAll(0L).size());
+ Assertions.assertEquals(newCartItem, cartItemService.get(3L));
+ Assertions.assertEquals(10, newCartItem.getQuantity());
+ Assertions.assertNotEquals(oldQuantity, newCartItem.getQuantity());
+ }
+
+ @Test
+ @Order(3)
+ void deleteTest() {
+ cartItemService.delete(3L);
+
+ Assertions.assertEquals(2, cartItemService.getAll(0L).size());
+ Assertions.assertThrows(NotFoundException.class, () -> cartItemService.get(3L));
+
+ final UserEntity user = userService.get(2L);
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "test"));
+ final ProductEntity product = productService
+ .create(new ProductEntity(null, "test", category, "descr", 100.00, 1.22));
+ final CartItemEntity newCartItem = cartItemService.create(new CartItemEntity(null, user, product, 15));
+
+ Assertions.assertEquals(3, cartItemService.getAll(0L).size());
+ Assertions.assertEquals(4L, newCartItem.getId());
+
+ productRepository.deleteAll();
+ userRepository.deleteAll();
+ categoryRepository.deleteAll();
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/CategoryServiceTests.java b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/CategoryServiceTests.java
new file mode 100644
index 0000000..81cb5b8
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/CategoryServiceTests.java
@@ -0,0 +1,67 @@
+package com.example.qpickshop;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.categories.model.CategoryEntity;
+import com.example.qpickshop.categories.repository.CategoryRepository;
+import com.example.qpickshop.categories.service.CategoryService;
+
+@SpringBootTest
+@TestMethodOrder(OrderAnnotation.class)
+class CategoryServiceTests {
+ @Autowired
+ private CategoryService categoryService;
+
+ @Autowired
+ private CategoryRepository categoryRepository;
+
+ @Test
+ void getTest() {
+ Assertions.assertThrows(NotFoundException.class, () -> categoryService.get(0L));
+ }
+
+ @Test
+ @Order(1)
+ void createTest() {
+ categoryService.create(new CategoryEntity(null, "Телефоны"));
+ categoryService.create(new CategoryEntity(null, "Ноутбуки"));
+ final CategoryEntity last = categoryService.create(new CategoryEntity(null, "Процессоры"));
+ Assertions.assertEquals(3, categoryService.getAll().size());
+ Assertions.assertEquals(last, categoryService.get(3L));
+ }
+
+ @Test
+ @Order(2)
+ void updateTest() {
+ final String test = "TEST";
+ final CategoryEntity entity = categoryService.get(3L);
+ final String oldName = entity.getName();
+ final CategoryEntity newEntity = categoryService.update(3L, new CategoryEntity(1L, test));
+ Assertions.assertEquals(3, categoryService.getAll().size());
+ Assertions.assertEquals(newEntity, categoryService.get(3L));
+ Assertions.assertEquals(test, newEntity.getName());
+ Assertions.assertNotEquals(oldName, newEntity.getName());
+ }
+
+ @Test
+ @Order(3)
+ void deleteTest() {
+ categoryService.delete(3L);
+ Assertions.assertEquals(2, categoryService.getAll().size());
+ final CategoryEntity last = categoryService.get(2L);
+ Assertions.assertEquals(2L, last.getId());
+
+ final CategoryEntity newEntity = categoryService.create(new CategoryEntity(null, "Клавиатуры"));
+ Assertions.assertEquals(3, categoryService.getAll().size());
+ Assertions.assertEquals(4L, newEntity.getId());
+
+ categoryRepository.deleteAll();
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/FavouriteServiceTests.java b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/FavouriteServiceTests.java
new file mode 100644
index 0000000..6dc144c
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/FavouriteServiceTests.java
@@ -0,0 +1,110 @@
+package com.example.qpickshop;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.products.model.ProductEntity;
+import com.example.qpickshop.products.repository.ProductRepository;
+import com.example.qpickshop.products.service.ProductService;
+import com.example.qpickshop.favouriteProducts.model.FavouriteProductEntity;
+import com.example.qpickshop.favouriteProducts.service.FavouriteProductService;
+import com.example.qpickshop.categories.model.CategoryEntity;
+import com.example.qpickshop.categories.repository.CategoryRepository;
+import com.example.qpickshop.categories.service.CategoryService;
+import com.example.qpickshop.users.model.UserEntity;
+import com.example.qpickshop.users.repository.UserRepository;
+import com.example.qpickshop.users.service.UserService;
+
+@SpringBootTest
+@TestMethodOrder(OrderAnnotation.class)
+public class FavouriteServiceTests {
+ @Autowired
+ private FavouriteProductService favouriteProductService;
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private CategoryService categoryService;
+
+ @Autowired
+ private ProductRepository productRepository;
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private CategoryRepository categoryRepository;
+
+ @Autowired
+ private ProductService productService;
+
+ @Test
+ void getTest() {
+ Assertions.assertThrows(NotFoundException.class, () -> favouriteProductService.get(0L));
+ }
+
+ @Test
+ @Order(1)
+ void createTest() {
+ final UserEntity user = userService.create(new UserEntity(null, "test@mail.ru", "test"));
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "test"));
+ final ProductEntity product = productService
+ .create(new ProductEntity(null, "test", category, "description", 100.00, 5.00));
+
+ favouriteProductService.create(new FavouriteProductEntity(null, user, product));
+ favouriteProductService.create(new FavouriteProductEntity(null, user, product));
+
+ final FavouriteProductEntity last = favouriteProductService.create(new FavouriteProductEntity(null, user, product));
+
+ Assertions.assertEquals(3, favouriteProductService.getAll(0L).size());
+ Assertions.assertEquals(last, favouriteProductService.get(3L));
+ }
+
+ @Test
+ @Order(2)
+ void updateTest() {
+ final UserEntity user = userService.create(new UserEntity(null, "test1@mail.ru", "test"));
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "test"));
+ final ProductEntity product = productService
+ .create(new ProductEntity(null, "test1", category, "description", 100.00, 2.00));
+
+ final FavouriteProductEntity favouriteProduct = favouriteProductService.get(3L);
+ final UserEntity oldUser = favouriteProduct.getUser();
+
+ final FavouriteProductEntity newFavouriteProduct = favouriteProductService.update(3L, new FavouriteProductEntity(null, user, product));
+
+ Assertions.assertEquals(3, favouriteProductService.getAll(0L).size());
+ Assertions.assertEquals(newFavouriteProduct, favouriteProductService.get(3L));
+ Assertions.assertEquals(user, newFavouriteProduct.getUser());
+ Assertions.assertNotEquals(oldUser, newFavouriteProduct.getUser());
+ }
+
+ @Test
+ @Order(3)
+ void deleteTest() {
+ favouriteProductService.delete(3L);
+
+ Assertions.assertEquals(2, favouriteProductService.getAll(0L).size());
+ Assertions.assertThrows(NotFoundException.class, () -> favouriteProductService.get(3L));
+
+ final UserEntity user = userService.get(2L);
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "test"));
+ final ProductEntity product = productService
+ .create(new ProductEntity(null, "test", category, "descr", 100.00, 1.22));
+ final FavouriteProductEntity newFavouriteProduct = favouriteProductService.create(new FavouriteProductEntity(null, user, product));
+
+ Assertions.assertEquals(3, favouriteProductService.getAll(0L).size());
+ Assertions.assertEquals(4L, newFavouriteProduct.getId());
+
+ productRepository.deleteAll();
+ userRepository.deleteAll();
+ categoryRepository.deleteAll();
+ }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/OrderServiceTests.java b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/OrderServiceTests.java
new file mode 100644
index 0000000..be5871f
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/OrderServiceTests.java
@@ -0,0 +1,136 @@
+package com.example.qpickshop;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.orders.model.OrderEntity;
+import com.example.qpickshop.orders.model.OrderItemEntity;
+import com.example.qpickshop.orders.service.OrderService;
+import com.example.qpickshop.products.model.ProductEntity;
+import com.example.qpickshop.products.repository.ProductRepository;
+import com.example.qpickshop.products.service.ProductService;
+import com.example.qpickshop.categories.model.CategoryEntity;
+import com.example.qpickshop.categories.repository.CategoryRepository;
+import com.example.qpickshop.categories.service.CategoryService;
+import com.example.qpickshop.users.model.UserEntity;
+import com.example.qpickshop.users.repository.UserRepository;
+import com.example.qpickshop.users.service.UserService;
+
+@SpringBootTest
+@TestMethodOrder(OrderAnnotation.class)
+public class OrderServiceTests {
+ @Autowired
+ private OrderService orderService;
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private CategoryService categoryService;
+
+ @Autowired
+ private ProductRepository productRepository;
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private CategoryRepository categoryRepository;
+
+ @Autowired
+ private ProductService productService;
+
+ @Test
+ void getTest() {
+ Assertions.assertThrows(NotFoundException.class, () -> orderService.get(0L));
+ }
+
+ @Test
+ @Order(1)
+ void createTest() {
+ final UserEntity user = userService.create(new UserEntity(null, "test@mail.ru", "test"));
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "test"));
+ final ProductEntity product = productService
+ .create(new ProductEntity(null, "test", category, "description", 100.00, 5.00));
+
+ final ProductEntity secondProduct = productService
+ .create(new ProductEntity(null, "test2", category, "description2", 100.00, 5.00));
+
+ List orderItems = new ArrayList();
+ orderItems.add(new OrderItemEntity(null, null, product, 15));
+
+ List secondOrderItems = new ArrayList();
+ secondOrderItems.add(new OrderItemEntity(null, null, product, 10));
+ secondOrderItems.add(new OrderItemEntity(null, null, secondProduct, 10));
+
+ orderService.create(new OrderEntity(null, user, orderItems));
+ OrderEntity order = orderService.create(new OrderEntity(null, user, secondOrderItems));
+
+ Assertions.assertEquals(2, orderService.getAll(0L).size());
+ Assertions.assertEquals(order, orderService.get(2L));
+ Assertions.assertEquals(secondOrderItems, order.getItems());
+ Assertions.assertEquals(order.getItems().size(), 2);
+ Assertions.assertEquals(orderService.get(1L).getItems().size(), 1);
+ Assertions.assertEquals(order.getItems().get(1).getProduct().getName(), "test2");
+
+ productRepository.deleteAll();
+ userRepository.deleteAll();
+ categoryRepository.deleteAll();
+ }
+
+ // @Test
+ // @Order(2)
+ // void updateTest() {
+ // final UserEntity user = userService.create(new UserEntity(null,
+ // "test1@mail.ru", "test"));
+ // final CategoryEntity category = categoryService.create(new
+ // CategoryEntity(null, "test"));
+ // final ProductEntity product = productService
+ // .create(new ProductEntity(null, "test1", category, "description", 100.00,
+ // 2.00));
+
+ // final OrderEntity order = orderService.get(3L);
+ // final Integer oldQuantity = order.getQuantity();
+
+ // final OrderEntity newOrder = orderService.update(3L, new OrderEntity(null,
+ // user, product, 10));
+
+ // Assertions.assertEquals(3, orderService.getAll(0L).size());
+ // Assertions.assertEquals(newOrder, orderService.get(3L));
+ // Assertions.assertEquals(10, newOrder.getQuantity());
+ // Assertions.assertNotEquals(oldQuantity, newOrder.getQuantity());
+ // }
+
+ // @Test
+ // @Order(3)
+ // void deleteTest() {
+ // orderService.delete(3L);
+
+ // Assertions.assertEquals(2, orderService.getAll(0L).size());
+ // Assertions.assertThrows(NotFoundException.class, () -> orderService.get(3L));
+
+ // final UserEntity user = userService.get(2L);
+ // final CategoryEntity category = categoryService.create(new
+ // CategoryEntity(null, "test"));
+ // final ProductEntity product = productService
+ // .create(new ProductEntity(null, "test", category, "descr", 100.00, 1.22));
+ // final OrderEntity newOrder = orderService.create(new OrderEntity(null, user,
+ // product, 15));
+
+ // Assertions.assertEquals(3, orderService.getAll(0L).size());
+ // Assertions.assertEquals(4L, newOrder.getId());
+
+ // productRepository.deleteAll();
+ // userRepository.deleteAll();
+ // categoryRepository.deleteAll();
+ // }
+}
diff --git a/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/ProductServiceTests.java b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/ProductServiceTests.java
new file mode 100644
index 0000000..451b6aa
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/ProductServiceTests.java
@@ -0,0 +1,89 @@
+package com.example.qpickshop;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.products.model.ProductEntity;
+import com.example.qpickshop.products.repository.ProductRepository;
+import com.example.qpickshop.products.service.ProductService;
+import com.example.qpickshop.categories.model.CategoryEntity;
+import com.example.qpickshop.categories.repository.CategoryRepository;
+import com.example.qpickshop.categories.service.CategoryService;
+
+@SpringBootTest
+@TestMethodOrder(OrderAnnotation.class)
+class ProductServiceTests {
+ @Autowired
+ private ProductService productService;
+
+ @Autowired
+ private CategoryService categoryService;
+
+ @Autowired
+ private ProductRepository productRepository;
+
+ @Autowired
+ private CategoryRepository categoryRepository;
+
+ @Test
+ void getTest() {
+ Assertions.assertThrows(NotFoundException.class, () -> productService.get(0L));
+ }
+
+ @Test
+ @Order(1)
+ void createTest() {
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "Ноутбуки"));
+
+ productService.create(new ProductEntity(null, "Acer", category, "Description 1", 101.99, 0.00));
+ productService.create(new ProductEntity(null, "Honor", category, "Description 2", 102.00, 3.20));
+
+ final ProductEntity lastProduct = productService
+ .create(new ProductEntity(null, "Macbook", category, "Description 3", 103.00, 5.20));
+
+ Assertions.assertEquals(3, productService.getAll(0L).size());
+ Assertions.assertEquals(lastProduct, productService.get(3L));
+ }
+
+ @Test
+ @Order(2)
+ void updateTest() {
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "Телефоны"));
+
+ final ProductEntity entity = productService.get(3L);
+ final Double oldPrice = entity.getPrice();
+
+ final ProductEntity newEntity = productService.update(3L,
+ new ProductEntity(null, "Huawei", category, "Description 4", 40.00, 2.22));
+
+ Assertions.assertEquals(3, productService.getAll(0L).size());
+ Assertions.assertEquals(newEntity, productService.get(3L));
+ Assertions.assertEquals(40.00, newEntity.getPrice());
+ Assertions.assertNotEquals(oldPrice, newEntity.getPrice());
+ }
+
+ @Test
+ @Order(3)
+ void deleteTest() {
+ productService.delete(3L);
+
+ Assertions.assertEquals(2, productService.getAll(0L).size());
+ Assertions.assertThrows(NotFoundException.class, () -> productService.get(3L));
+
+ final CategoryEntity category = categoryService.create(new CategoryEntity(null, "Клавиатуры"));
+ final ProductEntity newEntity = productService.create(
+ new ProductEntity(null, "Logitec", category, "Description 5", 999.00, 2.44));
+
+ Assertions.assertEquals(3, productService.getAll(0L).size());
+ Assertions.assertEquals(4L, newEntity.getId());
+
+ productRepository.deleteAll();
+ categoryRepository.deleteAll();
+ }
+}
\ No newline at end of file
diff --git a/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/UserServiceTests.java b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/UserServiceTests.java
new file mode 100644
index 0000000..915c45e
--- /dev/null
+++ b/semestr_2/Lab. 2/qpick-shop/src/test/java/com/example/qpickshop/UserServiceTests.java
@@ -0,0 +1,71 @@
+package com.example.qpickshop;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import com.example.qpickshop.core.error.NotFoundException;
+import com.example.qpickshop.users.model.UserEntity;
+import com.example.qpickshop.users.repository.UserRepository;
+import com.example.qpickshop.users.service.UserService;
+
+@SpringBootTest
+@TestMethodOrder(OrderAnnotation.class)
+class UserServiceTests {
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Test
+ void getTest() {
+ Assertions.assertThrows(NotFoundException.class, () -> userService.get(0L));
+ }
+
+ @Test
+ @Order(1)
+ void createTest() {
+ userService.create(new UserEntity(null, "email@mail.ru", "password"));
+ userService.create(new UserEntity(null, "email2@mail.ru", "password2"));
+ final UserEntity last = userService.create(new UserEntity(null, "email3@mail.ru", "password3"));
+ Assertions.assertEquals(3, userService.getAll().size());
+ Assertions.assertEquals(last, userService.get(3L));
+ }
+
+ @Test
+ @Order(2)
+ void updateTest() {
+ final String newEmail = "effee2@bfbrb.com";
+
+ final UserEntity entity = userService.get(3L);
+ final String oldEmail = entity.getEmail();
+
+ final UserEntity newEntity = userService.update(3L, new UserEntity(null, newEmail, "rbgirgrbunrgu9nrbu9"));
+
+ Assertions.assertEquals(3, userService.getAll().size());
+ Assertions.assertEquals(newEntity, userService.get(3L));
+ Assertions.assertEquals(newEmail, newEntity.getEmail());
+ Assertions.assertNotEquals(oldEmail, newEntity.getEmail());
+ }
+
+ @Test
+ @Order(3)
+ void deleteTest() {
+ userService.delete(3L);
+ Assertions.assertEquals(2, userService.getAll().size());
+ final UserEntity last = userService.get(2L);
+ Assertions.assertEquals(2L, last.getId());
+
+ final UserEntity newEntity = userService
+ .create(new UserEntity(null, "ortrigr@rbirirrgi", "rgkrgimrgirg"));
+ Assertions.assertEquals(3, userService.getAll().size());
+ Assertions.assertEquals(4L, newEntity.getId());
+
+ userRepository.deleteAll();
+ }
+}