Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a36c6e9130 | ||
| 4f93068cce | |||
| a9112f5e06 | |||
| 2b40c29f36 | |||
|
|
5364651da2 | ||
| 816d2d1284 | |||
| ac0427a16e | |||
| 09dd2f7ae2 | |||
|
|
2babc111b9 | ||
| 07bd46c0ac | |||
| 7a1916bff3 | |||
|
|
6c9581c820 | ||
| b91f23a39e | |||
| 11173e07c4 | |||
|
|
89fcb3cbca | ||
|
|
9876a17856 | ||
|
|
128fd2ff2b | ||
|
|
1e958a8b94 | ||
|
|
ca7afdf94e | ||
| ba48211be0 |
39
demo/.gitignore
vendored
Normal file
39
demo/.gitignore
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
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/
|
||||
|
||||
*.db
|
||||
32
demo/build.gradle
Normal file
32
demo/build.gradle
Normal file
@@ -0,0 +1,32 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.0.2'
|
||||
id 'io.spring.dependency-management' version '1.1.0'
|
||||
}
|
||||
|
||||
group = 'com.example'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
sourceCompatibility = '17'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
jar{
|
||||
enabled = false
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'com.h2database:h2:2.1.210'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
implementation 'org.springdoc:springdoc-openapi-ui:1.6.5'
|
||||
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
BIN
demo/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
demo/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
demo/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
demo/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
240
demo/gradlew
vendored
Normal file
240
demo/gradlew
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
#!/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/master/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
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# 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"'
|
||||
|
||||
# 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
|
||||
which java >/dev/null 2>&1 || 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
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
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
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
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" "$@"
|
||||
91
demo/gradlew.bat
vendored
Normal file
91
demo/gradlew.bat
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
@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=.
|
||||
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
|
||||
1
demo/settings.gradle
Normal file
1
demo/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'demo'
|
||||
12
demo/src/main/java/com/example/demo/DemoApplication.java
Normal file
12
demo/src/main/java/com/example/demo/DemoApplication.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
|
||||
public class DemoApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DemoApplication.class, args);
|
||||
}
|
||||
}
|
||||
22
demo/src/main/java/com/example/demo/WebConfiguration.java
Normal file
22
demo/src/main/java/com/example/demo/WebConfiguration.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
public class WebConfiguration {
|
||||
@Bean
|
||||
public WebMvcConfigurer corsConfigurer() {
|
||||
return new WebMvcConfigurer() {
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH", "OPTIONS");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
105
demo/src/main/java/com/example/demo/supply/Order/Order.java
Normal file
105
demo/src/main/java/com/example/demo/supply/Order/Order.java
Normal file
@@ -0,0 +1,105 @@
|
||||
package com.example.demo.supply.Order;
|
||||
|
||||
import com.example.demo.supply.Product.Product;
|
||||
import com.example.demo.supply.Supplier.Supplier;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
@Table(name = "tab_order")
|
||||
public class Order {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date dateOfOrder;
|
||||
|
||||
@JsonIgnore
|
||||
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE})
|
||||
@JoinColumn(name = "supplier_fk")
|
||||
private Supplier supplier;
|
||||
@ManyToMany(fetch = FetchType.EAGER, cascade = {
|
||||
CascadeType.PERSIST,
|
||||
CascadeType.MERGE
|
||||
})
|
||||
@JoinTable(name = "ordersAndProducts",joinColumns = @JoinColumn(name = "order_fk"),
|
||||
inverseJoinColumns = @JoinColumn(name = "product_fk"))
|
||||
private List<Product> products;
|
||||
|
||||
public Long getId(){
|
||||
return id;
|
||||
}
|
||||
public Order(Date dateOfOrder) {
|
||||
this.dateOfOrder = dateOfOrder;
|
||||
products = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Date getDateOfOrder() {
|
||||
return dateOfOrder;
|
||||
}
|
||||
public void setDateOfOrder(Date dateOfOrder) {
|
||||
this.dateOfOrder = dateOfOrder;
|
||||
}
|
||||
public Supplier getSupplier() {
|
||||
return supplier;
|
||||
}
|
||||
public void setSupplier(Supplier supplier) {
|
||||
this.supplier = supplier;
|
||||
supplier.getOrders().add(this);
|
||||
}
|
||||
public List<Product> getProducts() {
|
||||
return products;
|
||||
}
|
||||
public void setProducts(List<Product> products) {
|
||||
this.products = products;
|
||||
}
|
||||
public void addProduct(Product product){
|
||||
if(!products.contains(product)){
|
||||
products.add(product);
|
||||
product.getOrders().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteProduct(Product product){
|
||||
if(products.contains(product)){
|
||||
products.remove(product);
|
||||
product.getOrders().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Order order = (Order) o;
|
||||
if(!Objects.equals(id, order.id)) return false;
|
||||
|
||||
if(!Objects.equals(dateOfOrder.toString(), order.dateOfOrder.toString())) return false;
|
||||
if(!Objects.equals(supplier, order.supplier)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Product{" +
|
||||
"id=" + id +
|
||||
", date='" + dateOfOrder + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.example.demo.supply.Order;
|
||||
|
||||
import com.example.demo.supply.Product.Product;
|
||||
import com.example.demo.supply.Product.ProductDto;
|
||||
import com.example.demo.supply.Supplier.Supplier;
|
||||
import com.example.demo.supply.Supplier.SupplierDto;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequestMapping("/order")
|
||||
public class OrderController {
|
||||
private OrderService orderService;
|
||||
|
||||
public OrderController(OrderService orderService){
|
||||
this.orderService = orderService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public OrderDto getOrder(@PathVariable Long id) {
|
||||
return new OrderDto(orderService.findOrder(id));
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public List<OrderDto> getOrders() {
|
||||
return orderService.findAllOrders().stream().map(OrderDto::new).toList();
|
||||
}
|
||||
|
||||
@GetMapping("/getProducts/{id}")
|
||||
public List<ProductDto> getOrderProducts(@PathVariable Long id) {
|
||||
return orderService.findAllOrderProducts(id).stream().map(ProductDto::new).toList();
|
||||
}
|
||||
|
||||
@GetMapping("/someSuppliers/{id}")
|
||||
public List<SupplierDto> getSomeSuppliers(@PathVariable Long id) {
|
||||
return orderService.suppliers(id).stream().map(SupplierDto::new).toList();
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public Long createOrder(@RequestParam() Long supplierId) {
|
||||
return new OrderDto(orderService.addOrder(supplierId)).getId();
|
||||
}
|
||||
|
||||
@PatchMapping("/addProduct/{id}")
|
||||
public OrderDto addProduct(@PathVariable Long id,
|
||||
@RequestParam() Long productId){
|
||||
return new OrderDto(orderService.addProduct(id, productId));
|
||||
}
|
||||
|
||||
@PatchMapping("/removeProduct/{id}")
|
||||
public OrderDto removeProduct(@PathVariable Long id,
|
||||
@RequestParam() Long productId){
|
||||
return new OrderDto(orderService.removeProduct(id, productId));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public OrderDto deleteOrder(@PathVariable Long id) {
|
||||
return new OrderDto(orderService.deleteOrder(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.example.demo.supply.Order;
|
||||
|
||||
import com.example.demo.supply.Product.Product;
|
||||
import com.example.demo.supply.Supplier.Supplier;
|
||||
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class OrderDto {
|
||||
|
||||
private Long id;
|
||||
private Date dateOfOrder;
|
||||
private Supplier supplier;
|
||||
private List<Product> products;
|
||||
|
||||
public OrderDto(Order order){
|
||||
this.id = order.getId();
|
||||
this.dateOfOrder = order.getDateOfOrder();
|
||||
this.supplier = order.getSupplier();
|
||||
this.products = order.getProducts();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Date getDateOfOrder() {
|
||||
return dateOfOrder;
|
||||
}
|
||||
|
||||
public Supplier getSupplier() {
|
||||
return supplier;
|
||||
}
|
||||
|
||||
public List<Product> getProducts() {
|
||||
return products;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.example.demo.supply.Order;
|
||||
|
||||
public class OrderNotFoundException extends RuntimeException{
|
||||
public OrderNotFoundException(Long id){
|
||||
super(String.format("Order with id [%s] is not found", id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.example.demo.supply.Order;
|
||||
|
||||
import com.example.demo.supply.Product.Product;
|
||||
import com.example.demo.supply.Supplier.Supplier;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface OrderRepository extends JpaRepository<Order, Long> {
|
||||
@Query("SELECT distinct o.supplier FROM Order o join Product p where p = ?1")
|
||||
// @Query("SELECT distinct o.supplier FROM Order o where ?1 member of o.products")
|
||||
List<Supplier> getSomeSuppliers(Product product);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.example.demo.supply.Order;
|
||||
|
||||
import com.example.demo.supply.Product.Product;
|
||||
import com.example.demo.supply.Product.ProductService;
|
||||
import com.example.demo.supply.Supplier.Supplier;
|
||||
import com.example.demo.supply.Supplier.SupplierService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class OrderService {
|
||||
|
||||
private final OrderRepository orderRepository;
|
||||
private final ProductService productService;
|
||||
private final SupplierService supplierService;
|
||||
|
||||
public OrderService(OrderRepository orderRepository,
|
||||
ProductService productService,
|
||||
SupplierService supplierService)
|
||||
{
|
||||
this.orderRepository = orderRepository;
|
||||
this.productService = productService;
|
||||
this.supplierService = supplierService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Order addOrder(Long supplierId){
|
||||
final Order order = new Order(new Date());
|
||||
order.setSupplier(supplierService.findSupplier(supplierId));
|
||||
return orderRepository.save(order);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Supplier> suppliers(Long productId){
|
||||
final Product product = productService.findProduct(productId);
|
||||
return orderRepository.getSomeSuppliers(product);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Order addProduct(Long id, Long productId) {
|
||||
final Order currentOrder = findOrder(id);
|
||||
currentOrder.addProduct(productService.findProduct(productId));
|
||||
return orderRepository.save(currentOrder);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Order removeProduct(Long id, Long productId) {
|
||||
final Order currentOrder = findOrder(id);
|
||||
currentOrder.addProduct(productService.findProduct(productId));
|
||||
return orderRepository.save(currentOrder);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Order findOrder(Long id) {
|
||||
final Optional<Order> order = orderRepository.findById(id);
|
||||
return order.orElseThrow(() -> new OrderNotFoundException(id));
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Order> findAllOrders() {
|
||||
return orderRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Product> findAllOrderProducts(Long orderId) {
|
||||
final Optional<Order> order = orderRepository.findById(orderId);
|
||||
return order.orElseThrow(() -> new OrderNotFoundException(orderId)).getProducts();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Order deleteOrder(Long id) {
|
||||
final Order currentOrder = findOrder(id);
|
||||
orderRepository.delete(currentOrder);
|
||||
return currentOrder;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteAll(){
|
||||
orderRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.example.demo.supply.Product;
|
||||
|
||||
import com.example.demo.supply.Order.Order;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
public class Product {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
// @NotBlank(message = "name cant be null or empty")
|
||||
private String name;
|
||||
// @NotBlank(message = "cost cant be < 0")
|
||||
@Column(nullable = false)
|
||||
private double cost;
|
||||
@JsonIgnore
|
||||
@ManyToMany(fetch = FetchType.EAGER, mappedBy = "products")
|
||||
private List<Order> orders;
|
||||
|
||||
public Product(){}
|
||||
|
||||
public Product(String name, double cost){
|
||||
this.name = name;
|
||||
this.cost = cost;
|
||||
orders = new ArrayList<>();
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public double getCost() {
|
||||
return cost;
|
||||
}
|
||||
public void setCost(double cost) {
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
public List<Order> getOrders() {
|
||||
return orders;
|
||||
}
|
||||
|
||||
public void setOrders(List<Order> orders) {
|
||||
this.orders = orders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Product product = (Product) o;
|
||||
return Objects.equals(id, product.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Product{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", cost='" + cost + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.example.demo.supply.Product;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequestMapping("/product")
|
||||
public class ProductController {
|
||||
|
||||
private final ProductService productService;
|
||||
|
||||
public ProductController(ProductService productService) {
|
||||
this.productService = productService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ProductDto getProduct(@PathVariable Long id) {
|
||||
return new ProductDto(productService.findProduct(id));
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public List<ProductDto> getProducts() {
|
||||
return productService.findAllProducts().stream().map(ProductDto::new).toList();
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public ProductDto createProduct(@RequestParam() String name,
|
||||
@RequestParam() double cost) {
|
||||
return new ProductDto(productService.addProduct(name, cost));
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}")
|
||||
public ProductDto updateProduct(@PathVariable Long id,
|
||||
@RequestParam String name,
|
||||
@RequestParam double cost) {
|
||||
return new ProductDto(productService.updateProduct(id, name, cost));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ProductDto deleteProduct(@PathVariable Long id) {
|
||||
return new ProductDto(productService.deleteProduct(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.example.demo.supply.Product;
|
||||
|
||||
import com.example.demo.supply.Order.Order;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ProductDto {
|
||||
private long id;
|
||||
private String name;
|
||||
private double cost;
|
||||
private List<Order> orders;
|
||||
|
||||
public ProductDto(Product product) {
|
||||
this.id = product.getId();
|
||||
this.name = product.getName();
|
||||
this.cost = product.getCost();
|
||||
this.orders = product.getOrders();
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public double getCost() {
|
||||
return cost;
|
||||
}
|
||||
public List<Order> getOrders() {
|
||||
return orders;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.example.demo.supply.Product;
|
||||
|
||||
public class ProductNotFoundException extends RuntimeException{
|
||||
public ProductNotFoundException(Long id){
|
||||
super(String.format("Product with id [%s] is not found", id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.example.demo.supply.Product;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ProductRepository extends JpaRepository<Product, Long> {
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.example.demo.supply.Product;
|
||||
|
||||
import com.example.demo.util.ValidatorUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class ProductService {
|
||||
private final ProductRepository productRepository;
|
||||
public ProductService(ProductRepository productRepository){
|
||||
this.productRepository = productRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Product addProduct(String name, double cost){
|
||||
final Product product = new Product(name, cost);
|
||||
return productRepository.save(product);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Product findProduct(Long id) {
|
||||
final Optional<Product> product = productRepository.findById(id);
|
||||
return product.orElseThrow(() -> new ProductNotFoundException(id));
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Product> findAllProducts() {
|
||||
return productRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Product updateProduct(Long id, String name, double cost) {
|
||||
final Product currentProduct = findProduct(id);
|
||||
currentProduct.setName(name);
|
||||
currentProduct.setCost(cost);
|
||||
return productRepository.save(currentProduct);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Product deleteProduct(Long id) {
|
||||
final Product product = findProduct(id);
|
||||
productRepository.delete(product);
|
||||
return product;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteAll(){
|
||||
productRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.example.demo.supply.Supplier;
|
||||
|
||||
import com.example.demo.supply.Order.Order;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
public class Supplier {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
@Column(nullable = false)
|
||||
private int license;
|
||||
|
||||
@JsonIgnore
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "supplier", cascade = CascadeType.REMOVE)
|
||||
private List<Order> orders;
|
||||
|
||||
public Supplier(){}
|
||||
|
||||
public Supplier( String name, int license) {
|
||||
this.name = name;
|
||||
this.license = license;
|
||||
orders = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Long getId() { return id; }
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getLicense() {
|
||||
return license;
|
||||
}
|
||||
|
||||
public void setLicense(int license) {
|
||||
this.license = license;
|
||||
}
|
||||
|
||||
public List<Order> getOrders() {
|
||||
return orders;
|
||||
}
|
||||
|
||||
public void setOrders(List<Order> orders) {
|
||||
this.orders = orders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Supplier supplier = (Supplier) o;
|
||||
return Objects.equals(id, supplier.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Product{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", license='" + license + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.example.demo.supply.Supplier;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequestMapping("/supplier")
|
||||
public class SupplierController {
|
||||
private final SupplierService supplierService;
|
||||
|
||||
public SupplierController(SupplierService supplierService) {
|
||||
this.supplierService = supplierService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public SupplierDto getSupplier(@PathVariable Long id) {
|
||||
return new SupplierDto(supplierService.findSupplier(id));
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public List<SupplierDto> getSuppliers() {
|
||||
return supplierService.findAllSuppliers().stream().map(SupplierDto::new).toList();
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public SupplierDto createSupplier(@RequestParam() String name,
|
||||
@RequestParam() int license) {
|
||||
return new SupplierDto(supplierService.addSupplier(name, license));
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}")
|
||||
public SupplierDto updateSupplier(@PathVariable Long id,
|
||||
@RequestParam() String name,
|
||||
@RequestParam() int license) {
|
||||
return new SupplierDto(supplierService.updateSupplier(id, name, license));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public SupplierDto deleteSupplier(@PathVariable Long id) {
|
||||
return new SupplierDto(supplierService.deleteSupplier(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.example.demo.supply.Supplier;
|
||||
|
||||
import com.example.demo.supply.Order.Order;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SupplierDto {
|
||||
private Long id;
|
||||
private String name;
|
||||
private int license;
|
||||
private List<Order> orders;
|
||||
|
||||
public SupplierDto(Supplier supplier){
|
||||
this.id = supplier.getId();
|
||||
this.name = supplier.getName();
|
||||
this.license = supplier.getLicense();
|
||||
this.orders = supplier.getOrders();
|
||||
}
|
||||
|
||||
public Long getId() { return id; }
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public int getLicense() {
|
||||
return license;
|
||||
}
|
||||
public List<Order> getOrders() {
|
||||
return orders;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.demo.supply.Supplier;
|
||||
|
||||
public class SupplierNotFoundException extends RuntimeException{
|
||||
public SupplierNotFoundException(Long id){
|
||||
super(String.format("Supplier with id [%s] is not found", id));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.example.demo.supply.Supplier;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface SupplierRepository extends JpaRepository<Supplier, Long> {
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.example.demo.supply.Supplier;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class SupplierService {
|
||||
private final SupplierRepository supplierRepository;
|
||||
|
||||
public SupplierService(SupplierRepository supplierRepository){
|
||||
this.supplierRepository = supplierRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Supplier addSupplier(String name, int license){
|
||||
final Supplier supplier = new Supplier(name, license);
|
||||
return supplierRepository.save(supplier);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Supplier findSupplier(Long id) {
|
||||
final Optional<Supplier> supplier = supplierRepository.findById(id);
|
||||
return supplier.orElseThrow(() -> new SupplierNotFoundException(id));
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Supplier> findAllSuppliers() {
|
||||
return supplierRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Supplier updateSupplier(Long id, String name, int license) {
|
||||
final Supplier currentSupplier = findSupplier(id);
|
||||
currentSupplier.setName(name);
|
||||
currentSupplier.setLicense(license);
|
||||
return supplierRepository.save(currentSupplier);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Supplier deleteSupplier(Long id) {
|
||||
final Supplier currentSupplier = findSupplier(id);
|
||||
supplierRepository.delete(currentSupplier);
|
||||
return currentSupplier;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteAll(){
|
||||
supplierRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.example.demo.util;
|
||||
|
||||
import com.example.demo.supply.Product.ProductNotFoundException;
|
||||
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ControllerAdvice
|
||||
public class AdviceController {
|
||||
@ExceptionHandler({
|
||||
ProductNotFoundException.class,
|
||||
ValidationException.class
|
||||
})
|
||||
public ResponseEntity<Object> handleException(Throwable e) {
|
||||
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<Object> handleBindException(MethodArgumentNotValidException e) {
|
||||
final ValidationException validationException = new ValidationException(
|
||||
e.getBindingResult().getAllErrors().stream()
|
||||
.map(DefaultMessageSourceResolvable::getDefaultMessage)
|
||||
.collect(Collectors.toSet()));
|
||||
return handleException(validationException);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<Object> handleUnknownException(Throwable e) {
|
||||
e.printStackTrace();
|
||||
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.example.demo.util;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class ValidationException extends RuntimeException {
|
||||
public ValidationException(Set<String> errors) {
|
||||
super(String.join("\n", errors));
|
||||
}
|
||||
}
|
||||
29
demo/src/main/java/com/example/demo/util/ValidatorUtil.java
Normal file
29
demo/src/main/java/com/example/demo/util/ValidatorUtil.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.example.demo.util;
|
||||
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.ValidatorFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class ValidatorUtil {
|
||||
private final Validator validator;
|
||||
|
||||
public ValidatorUtil() {
|
||||
try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
|
||||
this.validator = factory.getValidator();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void validate(T object) {
|
||||
final Set<ConstraintViolation<T>> errors = validator.validate(object);
|
||||
if (!errors.isEmpty()) {
|
||||
throw new ValidationException(errors.stream()
|
||||
.map(ConstraintViolation::getMessage)
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
demo/src/main/resources/application.properties
Normal file
11
demo/src/main/resources/application.properties
Normal file
@@ -0,0 +1,11 @@
|
||||
spring.main.banner-mode=off
|
||||
server.port=8080
|
||||
spring.datasource.url=jdbc:h2:file:./data
|
||||
spring.datasource.driverClassName=org.h2.Driver
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=password
|
||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.h2.console.enabled=true
|
||||
spring.h2.console.settings.trace=false
|
||||
spring.h2.console.settings.web-allow-others=false
|
||||
7
demo/src/test/java/com/example/demo/Tests.java
Normal file
7
demo/src/test/java/com/example/demo/Tests.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
public class Tests {
|
||||
}
|
||||
53
demo/src/test/java/com/example/demo/TestsProduct.java
Normal file
53
demo/src/test/java/com/example/demo/TestsProduct.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package com.example.demo;
|
||||
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest
|
||||
public class TestsProduct {
|
||||
// @Autowired
|
||||
// private ProductService productService;
|
||||
//
|
||||
//
|
||||
// @Test
|
||||
// void testProduct(){
|
||||
// productService.deleteAll();
|
||||
// final Product product = productService.addProduct("Huawei Band 3", 2000.13);
|
||||
// Assertions.assertNotNull(product.getId());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void testProductRead(){
|
||||
// productService.deleteAll();
|
||||
// final Product product = productService.addProduct("Huawei Band 3", 2000.13);
|
||||
// final Product findProduct = productService.findProduct(product.getId());
|
||||
// Assertions.assertEquals(product, findProduct);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void testProductReadNotFound(){
|
||||
// productService.deleteAll();
|
||||
// Assertions.assertThrows(EntityNotFoundException.class, () -> productService.findProduct(-1L));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void testProductReadAll(){
|
||||
// productService.deleteAll();
|
||||
// productService.addProduct("Samsung A3", 22000.4);
|
||||
// productService.addProduct("Huawei Band 3", 2000.13);
|
||||
// final List<Product> products = productService.findAllProducts();
|
||||
// Assertions.assertEquals(products.size(), 2);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void testProductReadAllEmpty(){
|
||||
// productService.deleteAll();
|
||||
// final List<Product> products = productService.findAllProducts();
|
||||
// Assertions.assertEquals(products.size(), 0);
|
||||
// }
|
||||
}
|
||||
59
demo/src/test/java/com/example/demo/TestsSupplier.java
Normal file
59
demo/src/test/java/com/example/demo/TestsSupplier.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package com.example.demo;
|
||||
|
||||
import com.example.demo.supply.Supplier.Supplier;
|
||||
import com.example.demo.supply.Order.OrderService;
|
||||
import com.example.demo.supply.Supplier.SupplierService;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest
|
||||
public class TestsSupplier {
|
||||
// @Autowired
|
||||
// private SupplierService supplierService;
|
||||
// @Autowired
|
||||
// private OrderService orderService;
|
||||
// @Autowired
|
||||
// private ProductService productService;
|
||||
//
|
||||
// @Test
|
||||
// void testSupplier(){
|
||||
// supplierService.deleteAll();
|
||||
// final Supplier supplier = supplierService.addSupplier("SuperSup", 359342);
|
||||
// Assertions.assertNotNull(supplier.getId());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void testSupplierRead(){
|
||||
// supplierService.deleteAll();
|
||||
// final Supplier supplier = supplierService.addSupplier("Huawei", 4357695);
|
||||
// final Supplier findSupplier = supplierService.findSupplier(supplier.getId());
|
||||
// Assertions.assertEquals(supplier, findSupplier);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void testSupplierReadNotFound(){
|
||||
// supplierService.deleteAll();
|
||||
// Assertions.assertThrows(EntityNotFoundException.class, () -> supplierService.findSupplier(-1L));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void testSupplierReadAll(){
|
||||
// supplierService.deleteAll();
|
||||
// supplierService.addSupplier("Samsung", 3485456);
|
||||
// supplierService.addSupplier("Huawei", 45736964);
|
||||
// final List<Supplier> suppliers = supplierService.findAllSuppliers();
|
||||
// Assertions.assertEquals(suppliers.size(), 2);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void testSupplierReadAllEmpty(){
|
||||
// supplierService.deleteAll();
|
||||
// final List<Supplier> suppliers = supplierService.findAllSuppliers();
|
||||
// Assertions.assertEquals(suppliers.size(), 0);
|
||||
// }
|
||||
}
|
||||
23
front/.gitignore
vendored
Normal file
23
front/.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
70
front/README.md
Normal file
70
front/README.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
||||
|
||||
The page will reload when you make changes.\
|
||||
You may also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
|
||||
|
||||
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
|
||||
|
||||
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
|
||||
### Code Splitting
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
||||
|
||||
### Analyzing the Bundle Size
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
||||
|
||||
### Making a Progressive Web App
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
||||
|
||||
### Deployment
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
||||
|
||||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
||||
17363
front/package-lock.json
generated
Normal file
17363
front/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
front/package.json
Normal file
40
front/package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "front",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"axios": "^1.3.6",
|
||||
"bootstrap": "^5.2.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.10.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
13
front/public/index.html
Normal file
13
front/public/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
|
||||
|
||||
<title>Поставки</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
27
front/src/App.js
Normal file
27
front/src/App.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { BrowserRouter, Route, Routes} from "react-router-dom";
|
||||
import CatalogProducts from "./Pages/CatalogProducts";
|
||||
import CatalogSuppliers from "./Pages/CatalogSuppliers";
|
||||
import OrderPage from "./Pages/OrdersPage";
|
||||
import CreateOrderPage from "./Pages/CreateOrderPage";
|
||||
import GetSomeSuppliers from "./Pages/GetSomeSuppliers";
|
||||
import Header from "./general/Header";
|
||||
|
||||
function App() {
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Header/>
|
||||
<Routes>
|
||||
<Route path="/" Component={CatalogProducts}/>
|
||||
<Route path="/products" Component={CatalogProducts} />
|
||||
<Route path="/suppliers" Component={CatalogSuppliers} />
|
||||
<Route path="/orders" Component={OrderPage} />
|
||||
<Route path="/createOrder" Component={CreateOrderPage} />
|
||||
<Route path="/dop" Component={GetSomeSuppliers} />
|
||||
</Routes>
|
||||
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
72
front/src/DataService.js
Normal file
72
front/src/DataService.js
Normal file
@@ -0,0 +1,72 @@
|
||||
import axios from 'axios';
|
||||
|
||||
function getFullUrl(url, data) {
|
||||
let currentUrl = new URL(url)
|
||||
//извлекаем поля
|
||||
const fields = Object.getOwnPropertyNames(data);
|
||||
//проходимся по каждому полю
|
||||
for (const field of fields) {
|
||||
if (field === undefined) continue
|
||||
if (field === 'id') continue
|
||||
if (field === 'date') continue
|
||||
if (field === 'countProducts') continue
|
||||
if (field === 'products') continue
|
||||
if (field === 'supplierName') continue
|
||||
currentUrl.searchParams.append(field, data[field])
|
||||
}
|
||||
|
||||
return currentUrl;
|
||||
}
|
||||
|
||||
export default class DataService {
|
||||
static mainUrl = 'http://localhost:8080/';
|
||||
|
||||
static async readAll(url, transformer) {
|
||||
const response = await axios.get(this.mainUrl + url);
|
||||
return response.data.map(item => transformer(item));
|
||||
}
|
||||
|
||||
static async getOrders(url){
|
||||
const response = await fetch(this.mainUrl + url)
|
||||
const res = response.json()
|
||||
return res
|
||||
}
|
||||
|
||||
static async read(url, transformer) {
|
||||
const response = await axios.get(this.mainUrl + url);
|
||||
return transformer(response.data);
|
||||
}
|
||||
|
||||
static async create(url, data) {
|
||||
const response = await axios.post(getFullUrl(this.mainUrl + url, data))
|
||||
const res = response.data
|
||||
return res
|
||||
}
|
||||
|
||||
static async addProduct(url) {
|
||||
await fetch(url, {
|
||||
method: 'PATCH',
|
||||
}).catch(e => console.log(e))
|
||||
return true;
|
||||
}
|
||||
|
||||
static async getSomeSuppliers(url){
|
||||
const response = await fetch(this.mainUrl + url, {
|
||||
method: 'GET',
|
||||
}).catch(e => console.log(e))
|
||||
const res = response.json()
|
||||
return res
|
||||
}
|
||||
|
||||
static async update(url, data) {
|
||||
await fetch(getFullUrl(this.mainUrl + url, data), {
|
||||
method: 'PATCH',
|
||||
}).catch(e => console.log(e))
|
||||
return true;
|
||||
}
|
||||
|
||||
static async delete(url) {
|
||||
const response = await axios.delete(this.mainUrl + url);
|
||||
return response.data.id;
|
||||
}
|
||||
}
|
||||
111
front/src/Pages/CatalogOrders.jsx
Normal file
111
front/src/Pages/CatalogOrders.jsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import { React, useState, useEffect } from 'react';
|
||||
import Catalog from '../general/Catalog'
|
||||
import Order from '../models/Order';
|
||||
import Supplier from '../models/Supplier';
|
||||
import Product from '../models/Product';
|
||||
import DataService from '../DataService';
|
||||
|
||||
export default function CatalogOrders(props) {
|
||||
const url = 'order/'
|
||||
const supplierUrl = 'supplier/'
|
||||
const productUrl = 'product/'
|
||||
|
||||
const transformer = (data) => {
|
||||
new Order(data)
|
||||
}
|
||||
|
||||
const catalogOrderHeaders = [
|
||||
{ name: 'date', label: 'Дата заказа' },
|
||||
{ name: 'supplier', label: 'Поставщик' },
|
||||
{ name: 'products', label: 'Продукт(ы)' }
|
||||
];
|
||||
|
||||
const [data, setData] = useState(new Order());
|
||||
const [suppliers, setSuppliers] = useState([]);
|
||||
const [products, setProducts] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
DataService.readAll(supplierUrl, (data) => new Supplier(data)).then(data => setSuppliers(data));
|
||||
DataService.readAll(productUrl, (data) => new Product(data)).then(data => setProducts(data));
|
||||
}, [])
|
||||
|
||||
const add = () =>{
|
||||
setData(new Order())
|
||||
console.log(data)
|
||||
}
|
||||
const edit = (data) => {
|
||||
console.log(data)
|
||||
setData(new Order(data))
|
||||
}
|
||||
|
||||
const addProduct = (data) => {
|
||||
setData(new Order(data))
|
||||
}
|
||||
|
||||
function handleFormChange(event) {
|
||||
console.log(data)
|
||||
setData({ ...data, [event.target.id]: event.target.value })
|
||||
console.log(data)
|
||||
}
|
||||
|
||||
const saveProducts = (event) => {
|
||||
console.log(products)
|
||||
setData({...products, [event.target.id]: event.target.value})
|
||||
console.log(products)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Catalog headers={catalogOrderHeaders}
|
||||
url={url}
|
||||
transformer={transformer}
|
||||
data={data}
|
||||
add={add}
|
||||
edit={edit}
|
||||
isOrder={true}
|
||||
addProduct={edit}
|
||||
modalAddProduct={
|
||||
<div className="mb-3">
|
||||
<label htmlFor="product" className="form-label">Поставщик</label>
|
||||
<select id="product" className="form-select" required
|
||||
value={data.product} onChange={saveProducts}>
|
||||
<option disabled value="">Укажите продукт</option>
|
||||
{
|
||||
products.map(product =>
|
||||
<option key={product.id} value={product.id}>{product.name}</option>
|
||||
)
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
}>
|
||||
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="supplierId" className="form-label">Поставщик</label>
|
||||
<select id="supplierId" className="form-select" required
|
||||
value={data.supplierId} onChange={handleFormChange}>
|
||||
<option disabled value="">Укажите поставщика</option>
|
||||
{
|
||||
suppliers.map(supplier =>
|
||||
<option key={supplier.id} value={supplier.id}>{supplier.name}</option>
|
||||
)
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="product" className="form-label">Поставщик</label>
|
||||
<select id="product" className="form-select" required
|
||||
value={data.product} onChange={handleFormChange}>
|
||||
<option disabled value="">Укажите продукт</option>
|
||||
{
|
||||
products.map(product =>
|
||||
<option key={product.id} value={product.id}>{product.name}</option>
|
||||
)
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</Catalog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
47
front/src/Pages/CatalogProducts.jsx
Normal file
47
front/src/Pages/CatalogProducts.jsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { useState } from 'react';
|
||||
import Catalog from '../general/Catalog'
|
||||
import Product from '../models/Product';
|
||||
|
||||
export default function CatalogProducts(props) {
|
||||
const url = 'product/'
|
||||
|
||||
const transformer = (data) => new Product(data)
|
||||
|
||||
const catalogProductHeaders = [
|
||||
{ name: 'name', label: 'Продукт' },
|
||||
{ name: 'cost', label: 'Цена' }
|
||||
];
|
||||
|
||||
const [data, setData] = useState(new Product());
|
||||
|
||||
const add = () => setData(new Product());
|
||||
const edit = (data) => setData(new Product(data))
|
||||
|
||||
|
||||
function handleFormChange(event) {
|
||||
setData({ ...data, [event.target.id]: event.target.value })
|
||||
}
|
||||
|
||||
return (
|
||||
<Catalog headers={catalogProductHeaders}
|
||||
getAllUrl={url}
|
||||
url={url}
|
||||
transformer={transformer}
|
||||
data={data}
|
||||
add={add}
|
||||
edit={edit}
|
||||
isOrder={false}>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="name" className="form-label">Наименование</label>
|
||||
<input type="text" id="name" className="form-control" required
|
||||
value={data.name} onChange={handleFormChange}/>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="cost" className="form-label">Цена</label>
|
||||
<input type="number" id="cost" className="form-control" required
|
||||
value={data.cost} onChange={handleFormChange}/>
|
||||
</div>
|
||||
</Catalog>
|
||||
);
|
||||
}
|
||||
46
front/src/Pages/CatalogSuppliers.jsx
Normal file
46
front/src/Pages/CatalogSuppliers.jsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { useState } from 'react';
|
||||
import Catalog from '../general/Catalog'
|
||||
import Supplier from '../models/Supplier';
|
||||
|
||||
export default function CatalogSuppliers(props) {
|
||||
const url = 'supplier/'
|
||||
|
||||
const transformer = (data) => new Supplier(data)
|
||||
|
||||
const catalogProductHeaders = [
|
||||
{ name: 'name', label: 'Поставщик' },
|
||||
{ name: 'license', label: 'Лицензия' }
|
||||
];
|
||||
|
||||
const [data, setData] = useState(new Supplier());
|
||||
|
||||
const add = () => setData(new Supplier());
|
||||
const edit = (data) => setData(new Supplier(data))
|
||||
|
||||
const handleFormChange = (event) => {
|
||||
setData({ ...data, [event.target.id]: event.target.value })
|
||||
}
|
||||
|
||||
return (
|
||||
<Catalog headers={catalogProductHeaders}
|
||||
getAllUrl={url}
|
||||
url={url}
|
||||
transformer={transformer}
|
||||
data={data}
|
||||
add={add}
|
||||
edit={edit}
|
||||
isOrder={false}>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="name" className="form-label">Поставщик</label>
|
||||
<input type="text" id="name" className="form-control" required
|
||||
value={data.name} onChange={handleFormChange}/>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="license" className="form-label">Лицензия</label>
|
||||
<input type="number" id="license" className="form-control" required
|
||||
value={data.license} onChange={handleFormChange}/>
|
||||
</div>
|
||||
</Catalog>
|
||||
);
|
||||
}
|
||||
175
front/src/Pages/CreateOrderPage.jsx
Normal file
175
front/src/Pages/CreateOrderPage.jsx
Normal file
@@ -0,0 +1,175 @@
|
||||
import { React, useState, useEffect } from "react";
|
||||
import { Link } from 'react-router-dom';
|
||||
import Supplier from "../models/Supplier";
|
||||
import DataService from "../DataService";
|
||||
import Order from "../models/Order";
|
||||
import Product from "../models/Product";
|
||||
import Table from "../general/Table";
|
||||
import Modal from "../general/Modal";
|
||||
|
||||
export default function CreateOrderPage(props){
|
||||
const url = 'order/'
|
||||
const supplierUrl = 'supplier/'
|
||||
const productUrl = 'product/'
|
||||
|
||||
let selectedItems = [];
|
||||
|
||||
const headers = [
|
||||
{ name: 'name', label: 'Продукт' },
|
||||
{ name: 'cost', label: 'Цена' }
|
||||
];
|
||||
|
||||
const transformer = (data) => new Order(data)
|
||||
const transformerSupplier = (data) => new Supplier(data)
|
||||
const transformerProduct = (data) => new Product(data)
|
||||
|
||||
const [suppliers, setSuppliers] = useState([])
|
||||
const [products, setProducts] = useState([])
|
||||
|
||||
const [order, setOrder] = useState(new Order())
|
||||
const [addsProduct, setAddsProduct] = useState(new Product())
|
||||
|
||||
const [modalHeader, setModalHeader] = useState('')
|
||||
const [modalConfirm, setModalConfirm] = useState('')
|
||||
const [modalVisible, setModalVisible] = useState(false)
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
loadItems()
|
||||
//eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const loadItems = () => {
|
||||
DataService.readAll(supplierUrl, transformerSupplier).then(data => setSuppliers(data))
|
||||
DataService.readAll(productUrl, transformerProduct).then(data => setProducts(data))
|
||||
}
|
||||
|
||||
const createOrder = () => {
|
||||
if(order.supplierId === ''){
|
||||
window.alert ('Заказ был заполнен неверно, попробуйте еще раз')
|
||||
return
|
||||
}
|
||||
DataService.create(url, order)
|
||||
.then(data => {
|
||||
order.products.map(product =>{
|
||||
DataService.addProduct(`http://localhost:8080/${url}addProduct/${data}?productId=${product.id}`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const addProductInOrder = () => {
|
||||
DataService.read(`${productUrl}${addsProduct.id}`, transformerProduct)
|
||||
.then(data => {
|
||||
let contains = false
|
||||
order.products.map(product => {
|
||||
if(product.id === data.id) contains = true
|
||||
})
|
||||
if(!contains){
|
||||
order.products.push(data)
|
||||
setOrder({ ...order, products: order.products })
|
||||
}
|
||||
else
|
||||
window.alert ('Такой продукт уже был добавлен')
|
||||
})
|
||||
}
|
||||
|
||||
const removeProduct = () => {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.confirm('Удалить выбранные элементы?')) {
|
||||
const promises = [];
|
||||
selectedItems.forEach(item => {
|
||||
promises.push(DataService.delete(props.url + item));
|
||||
});
|
||||
Promise.all(promises).then((results) => {
|
||||
selectedItems.length = 0;
|
||||
loadItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const handleFormChange = (event) => {
|
||||
setOrder({ ...order, [event.target.id]: event.target.value })
|
||||
}
|
||||
|
||||
const handleAddProduct = (event) => {
|
||||
setAddsProduct({ ...addsProduct, [event.target.id]: event.target.value })
|
||||
}
|
||||
|
||||
const addProduct = () => {
|
||||
setAddsProduct(new Product())
|
||||
setModalHeader('Добавление продукта');
|
||||
setModalConfirm('Добавить');
|
||||
setModalVisible(true);
|
||||
}
|
||||
|
||||
const hideModal = () => setModalVisible(false)
|
||||
const ds = () => console.log("")
|
||||
|
||||
const handleTableClick = (tableSelectedItems) => selectedItems = tableSelectedItems;
|
||||
|
||||
return(
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<h1 className="display-6">Создание заказа</h1>
|
||||
</div>
|
||||
|
||||
<div className="row gx-5">
|
||||
<div className="btn-group" role="group" aria-label="Basic mixed styles example">
|
||||
<Link to="/orders">
|
||||
<button type="button" className="btn btn-success" onClick={createOrder}>Создать</button>
|
||||
<button type="button" className="btn btn-danger">Отмена</button>
|
||||
</Link>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<br></br>
|
||||
<div className="mb-3">
|
||||
<p className="h4" htmlFor="supplierId">Поставщик</p>
|
||||
<select id="supplierId" className="form-select " required
|
||||
value={order.supplierId} onChange={handleFormChange}>
|
||||
<option disabled value="">Укажите поставщика</option>
|
||||
{
|
||||
suppliers.map(supplier =>
|
||||
<option key={supplier.id} value={supplier.id}>{supplier.name}</option>
|
||||
)
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<p className="h4">Продукты</p>
|
||||
<div className="btn-group" role="group" aria-label="Basic mixed styles example">
|
||||
<button type="button" className="btn btn-success" onClick={addProduct}>Добавить продукт</button>
|
||||
<button type="button" className="btn btn-danger" onClick={removeProduct} >Удалить продукт</button>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
headers={headers}
|
||||
items={order.products}
|
||||
selectable={true}
|
||||
onClick={handleTableClick}
|
||||
onDblClick={ds}/>
|
||||
|
||||
<Modal
|
||||
header={modalHeader}
|
||||
confirm={modalConfirm}
|
||||
visible={modalVisible}
|
||||
onHide={hideModal}
|
||||
onDone={addProductInOrder}>
|
||||
<div className="mb-3">
|
||||
<p className="h4" htmlFor="id">Продукт</p>
|
||||
<select id="id" className="form-select " required
|
||||
value={addsProduct.id} onChange={handleAddProduct}>
|
||||
<option disabled value="">Укажите продукт</option>
|
||||
{
|
||||
products.map(product =>
|
||||
<option key={product.id} value={product.id}>{product.name}</option>
|
||||
)
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
97
front/src/Pages/GetSomeSuppliers.jsx
Normal file
97
front/src/Pages/GetSomeSuppliers.jsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Modal from "../general/Modal";
|
||||
import Table from "../general/Table";
|
||||
import DataService from "../DataService";
|
||||
import Product from "../models/Product";
|
||||
import Supplier from "../models/Supplier";
|
||||
|
||||
export default function GetSomeSuppliers(props) {
|
||||
const url = 'order/someSuppliers/'
|
||||
const productUrl = 'product/'
|
||||
|
||||
const headers = [
|
||||
{ name: 'name', label: 'Поставщик' },
|
||||
{ name: 'license', label: 'Лицензия' }
|
||||
];
|
||||
|
||||
const transformer = (data) => new Supplier(data)
|
||||
const transformerProduct = (data) => new Product(data)
|
||||
|
||||
const [suppliers, setSuppliers] = useState([])
|
||||
const [products, setProducts] = useState([])
|
||||
const [product, setProduct] = useState(new Product())
|
||||
|
||||
const [modalHeader, setModalHeader] = useState('')
|
||||
const [modalConfirm, setModalConfirm] = useState('')
|
||||
const [modalVisible, setModalVisible] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
loadItems()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const loadItems = () => {
|
||||
DataService.readAll(productUrl, transformerProduct).then(data =>{
|
||||
console.log(data)
|
||||
setProducts(data)
|
||||
})
|
||||
}
|
||||
|
||||
const chooseProduct = () => {
|
||||
setModalHeader('Добавление')
|
||||
setModalConfirm('Добавить')
|
||||
setModalVisible(true)
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
console.log(product)
|
||||
DataService.getSomeSuppliers(`${url}${product.id}`)
|
||||
.then(data => setSuppliers(data))
|
||||
}
|
||||
|
||||
const handleChooseProduct = (event) => {
|
||||
// console.log(event.target.id)
|
||||
// console.log(event.target.value)
|
||||
setProduct({ ...product, [event.target.id]: event.target.value })
|
||||
}
|
||||
|
||||
const handleTableClick = (tableSelectedItems) => console.log("")
|
||||
const handleTableDblClick = (tableSelectedItem) => console.log("")
|
||||
|
||||
const hideModal = () => {
|
||||
setModalVisible(false)
|
||||
}
|
||||
const modalDone = () => save()
|
||||
|
||||
return (
|
||||
<>
|
||||
<button type="button" className="btn btn-success" onClick={chooseProduct}>Выбрать продукт</button>
|
||||
|
||||
<Table
|
||||
headers={headers}
|
||||
items={suppliers}
|
||||
selectable={false}
|
||||
onClick={handleTableClick}
|
||||
onDblClick={handleTableDblClick}/>
|
||||
<Modal
|
||||
header={modalHeader}
|
||||
confirm={modalConfirm}
|
||||
visible={modalVisible}
|
||||
onHide={hideModal}
|
||||
onDone={modalDone}>
|
||||
<div className="mb-3">
|
||||
<p className="h4" htmlFor="id">Продукт</p>
|
||||
<select id="id" className="form-select" required
|
||||
value={product.id} onChange={handleChooseProduct}>
|
||||
<option disabled value="">Укажите продукт</option>
|
||||
{
|
||||
products.map(product =>
|
||||
<option key={product.id} value={product.id}>{product.name}</option>
|
||||
)
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
79
front/src/Pages/OrdersPage.jsx
Normal file
79
front/src/Pages/OrdersPage.jsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { React, useState, useEffect } from "react";
|
||||
import Table from "../general/Table";
|
||||
import ToolBar from "../general/ToolBar";
|
||||
import DataService from "../DataService";
|
||||
import Order from "../models/Order";
|
||||
|
||||
export default function OrderPage(){
|
||||
const url = 'order/'
|
||||
|
||||
const [orders, setOrders] = useState([])
|
||||
|
||||
const headers = [
|
||||
{ name: 'date', label: 'Дата заказа' },
|
||||
{ name: 'supplierName', label: 'Поставщик' },
|
||||
{ name: 'products', label: 'Продукт(ы)' }
|
||||
];
|
||||
|
||||
let selectedItems = [];
|
||||
|
||||
useEffect(() => {
|
||||
loadItems()
|
||||
//eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const loadItems = () => {
|
||||
DataService.getOrders(url).then(data => {
|
||||
setOrders([])
|
||||
data.map(order => {
|
||||
const date = new Date(order.dateOfOrder)
|
||||
order.dateOfOrder = `${date.getDate()}-${date.getMonth()}-${date.getFullYear()}`
|
||||
setOrders(prevState => [...prevState, new Order(order)])
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const add = () => {
|
||||
console.log("add")
|
||||
loadItems()
|
||||
}
|
||||
const edit = () =>{}
|
||||
|
||||
const remove = () =>{
|
||||
if (selectedItems.length === 0)
|
||||
return
|
||||
|
||||
if (window.confirm('Удалить выбранные элементы?')) {
|
||||
const promises = [];
|
||||
selectedItems.forEach(item => {
|
||||
promises.push(DataService.delete(url + item));
|
||||
});
|
||||
Promise.all(promises).then(results => {
|
||||
selectedItems.length = 0;
|
||||
loadItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const handleTableClick = (tableSelectedItems) => {selectedItems = tableSelectedItems;}
|
||||
const handleTableDblClick = (tableSelectedItem) =>{
|
||||
DataService.getSomeSuppliers()
|
||||
}
|
||||
|
||||
return(
|
||||
<>
|
||||
<ToolBar
|
||||
add={add}
|
||||
edit={edit}
|
||||
remove={remove}
|
||||
addsVisible={true}/>
|
||||
|
||||
<Table
|
||||
headers={headers}
|
||||
items={orders}
|
||||
selectable={true}
|
||||
onClick={handleTableClick}
|
||||
onDblClick={handleTableDblClick}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
149
front/src/general/Catalog.jsx
Normal file
149
front/src/general/Catalog.jsx
Normal file
@@ -0,0 +1,149 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import ToolBar from "./ToolBar";
|
||||
import Modal from "./Modal";
|
||||
import Table from "./Table";
|
||||
import DataService from "../DataService";
|
||||
|
||||
function Catalog(props) {
|
||||
|
||||
const [items, setItems] = useState([]);
|
||||
const [modalHeader, setModalHeader] = useState('')
|
||||
const [modalConfirm, setModalConfirm] = useState('')
|
||||
const [modalVisible, setModalVisible] = useState(false)
|
||||
const [addProdVisible, setAddProdVisible] = useState(false)
|
||||
const [isEdit, setEdit] = useState(false)
|
||||
|
||||
|
||||
let selectedItems = [];
|
||||
|
||||
useEffect(() => {
|
||||
loadItems()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const loadItems = () => {
|
||||
DataService.readAll(props.url, props.transformer)
|
||||
.then(data =>{
|
||||
console.log(data)
|
||||
setItems(data)
|
||||
} )
|
||||
}
|
||||
|
||||
const saveItem = () => {
|
||||
if (!isEdit) {
|
||||
DataService.create(props.url, props.data).then(() => loadItems())
|
||||
} else
|
||||
DataService.update(props.url + props.data.id, props.data).then(() => loadItems())
|
||||
}
|
||||
|
||||
const add = () => {
|
||||
setEdit(false);
|
||||
setModalHeader('Добавление');
|
||||
setModalConfirm('Добавить');
|
||||
setModalVisible(true);
|
||||
props.add();
|
||||
}
|
||||
|
||||
const edit = () => {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
//editItem(selectedItems[0])
|
||||
|
||||
DataService.read(props.url + selectedItems[0], props.transformer)
|
||||
.then(data => {
|
||||
setEdit(true);
|
||||
setModalHeader('Редактирование элемента');
|
||||
setModalConfirm('Сохранить');
|
||||
setModalVisible(true);
|
||||
props.edit(data);
|
||||
});
|
||||
}
|
||||
|
||||
const editItem = (editedId) => {
|
||||
DataService.read(props.url + editedId, props.transformer)
|
||||
.then(data => {
|
||||
setEdit(true);
|
||||
setModalHeader('Редактирование элемента');
|
||||
setModalConfirm('Сохранить');
|
||||
setModalVisible(true);
|
||||
props.edit(data);
|
||||
});
|
||||
}
|
||||
|
||||
const remove = () => {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.confirm('Удалить выбранные элементы?')) {
|
||||
const promises = [];
|
||||
selectedItems.forEach(item => {
|
||||
promises.push(DataService.delete(props.url + item));
|
||||
});
|
||||
Promise.all(promises).then((results) => {
|
||||
selectedItems.length = 0;
|
||||
loadItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const addProduct = () => {
|
||||
if (selectedItems.length === 0)
|
||||
return
|
||||
|
||||
DataService.read(props.url + selectedItems[0], props.transformer)
|
||||
.then(data => {
|
||||
setEdit(false)
|
||||
setAddProdVisible(true)
|
||||
setModalHeader('Добавление продукта к заказу')
|
||||
setModalConfirm('Сохранить')
|
||||
setAddProdVisible(true)
|
||||
props.edit(data)
|
||||
});
|
||||
}
|
||||
|
||||
const handleTableClick = (tableSelectedItems) => selectedItems = tableSelectedItems;
|
||||
const handleTableDblClick = (tableSelectedItem) => editItem(tableSelectedItem);
|
||||
const hideModal = () => {
|
||||
setModalVisible(false)
|
||||
setAddProdVisible(false)
|
||||
}
|
||||
const modalDone = () => saveItem()
|
||||
|
||||
return (
|
||||
<>
|
||||
<ToolBar
|
||||
add={add}
|
||||
edit={edit}
|
||||
remove={remove}
|
||||
addProduct={addProduct}
|
||||
// removeProduct
|
||||
addsVisible={props.isOrder}/>
|
||||
<Table
|
||||
headers={props.headers}
|
||||
items={items}
|
||||
selectable={true}
|
||||
onClick={handleTableClick}
|
||||
onDblClick={handleTableDblClick}/>
|
||||
<Modal
|
||||
header={modalHeader}
|
||||
confirm={modalConfirm}
|
||||
visible={modalVisible}
|
||||
onHide={hideModal}
|
||||
onDone={modalDone}>
|
||||
{props.children}
|
||||
</Modal>
|
||||
<Modal
|
||||
header={modalHeader}
|
||||
confirm={modalConfirm}
|
||||
visible={addProdVisible}
|
||||
onHide={hideModal}
|
||||
onDone={modalDone}>
|
||||
{props.modalAddProduct}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Catalog;
|
||||
40
front/src/general/Header.jsx
Normal file
40
front/src/general/Header.jsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export default function Header() {
|
||||
return (
|
||||
<nav className="navbar navbar-expand-lg bg-light">
|
||||
<div className="container-fluid">
|
||||
<h1 className="navbar-brand">Поставки</h1>
|
||||
<button className="navbar-toggler" type="button"
|
||||
data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span className="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div className="collapse navbar-collapse" id="navbarNav">
|
||||
<ul className="navbar-nav">
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/products">
|
||||
Продукты
|
||||
</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/suppliers">
|
||||
Поставщики
|
||||
</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/orders">
|
||||
Заказы
|
||||
</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/dop">
|
||||
Доп задание
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav >
|
||||
);
|
||||
}
|
||||
47
front/src/general/Modal.jsx
Normal file
47
front/src/general/Modal.jsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import React from "react";
|
||||
|
||||
function Modal(props) {
|
||||
const formRef = React.createRef();
|
||||
|
||||
const hide = () => {
|
||||
props.onHide();
|
||||
}
|
||||
|
||||
const done = (e) => {
|
||||
e.preventDefault();
|
||||
if (formRef.current.checkValidity()) {
|
||||
props.onDone();
|
||||
hide();
|
||||
} else {
|
||||
formRef.current.reportValidity();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="modal fade show" tabIndex="-1" aria-hidden="true"
|
||||
style={{ display: props.visible ? 'block' : 'none' }}>
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h1 className="modal-title fs-5" id="exampleModalLabel">{props.header}</h1>
|
||||
<button className="btn-close" type="button" aria-label="Close"
|
||||
onClick={hide}></button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<form ref={formRef} onSubmit={done}>
|
||||
{props.children}
|
||||
</form>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button className="btn btn-secondary" type="button" onClick={hide}>Закрыть</button>
|
||||
<button className="btn btn-primary" type="button" onClick={done}>
|
||||
{props.confirm}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Modal;
|
||||
83
front/src/general/Table.jsx
Normal file
83
front/src/general/Table.jsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { useState } from 'react';
|
||||
import styles from './Table.module.css';
|
||||
|
||||
export default function Table(props) {
|
||||
const [tableUpdate, setTableUpdate] = useState(false);
|
||||
const [selectedItems, setSelectedItems] = useState([]);
|
||||
|
||||
const isSelected = (id) => {
|
||||
if (!props.selectable) {
|
||||
return false;
|
||||
}
|
||||
return selectedItems.includes(id);
|
||||
}
|
||||
|
||||
const click = (id) => {
|
||||
if (!props.selectable) {
|
||||
return;
|
||||
}
|
||||
if (isSelected(id)) {
|
||||
var index = selectedItems.indexOf(id);
|
||||
if (index !== -1) {
|
||||
selectedItems.splice(index, 1);
|
||||
setSelectedItems(selectedItems);
|
||||
setTableUpdate(!tableUpdate);
|
||||
}
|
||||
} else {
|
||||
selectedItems.push(id);
|
||||
setSelectedItems(selectedItems);
|
||||
setTableUpdate(!tableUpdate);
|
||||
}
|
||||
props.onClick(selectedItems);
|
||||
}
|
||||
|
||||
const dblClick = (id) => {
|
||||
if (!props.selectable) {
|
||||
return;
|
||||
}
|
||||
props.onDblClick(id);
|
||||
}
|
||||
|
||||
const view = (data, headName) =>{
|
||||
if(headName !== 'products')
|
||||
return data
|
||||
else{
|
||||
let prod = ''
|
||||
data.map(product => prod += ` ${product.name},`)
|
||||
return prod
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<table className={`table table-hover ${styles.table} ${props.selectable ? styles.selectable : ''}`}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
{
|
||||
props.headers.map(header =>
|
||||
<th key={header.name} scope="col">
|
||||
{header.label}
|
||||
</th>
|
||||
)
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
props.items && props.items.map((item, index) =>
|
||||
<tr key={item.id}
|
||||
className={isSelected(item.id) ? styles.selected : ''}
|
||||
onClick={(e) => click(item.id, e)} onDoubleClick={(e) => dblClick(item.id, e)}>
|
||||
<th scope="row">{index + 1}</th>
|
||||
{
|
||||
props.headers.map(header =>
|
||||
<td key={item.id + header.name}>{view(item[header.name], header.name)}</td>
|
||||
)
|
||||
}
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
</tbody >
|
||||
</table >
|
||||
);
|
||||
}
|
||||
12
front/src/general/Table.module.css
Normal file
12
front/src/general/Table.module.css
Normal file
@@ -0,0 +1,12 @@
|
||||
.table tbody tr {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.selectable tbody tr:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: #0d6efd;
|
||||
opacity: 80%;
|
||||
}
|
||||
36
front/src/general/ToolBar.jsx
Normal file
36
front/src/general/ToolBar.jsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import React from "react";
|
||||
import styles from './Toolbar.module.css';
|
||||
|
||||
//кнопочки
|
||||
function ToolBar(props) {
|
||||
|
||||
const add = () => props.add()
|
||||
const edit = () => props.edit()
|
||||
const remove = () => props.remove()
|
||||
|
||||
return (
|
||||
<div className="btn-group mt-2" role="group">
|
||||
<button type="button" className={`btn btn-success ${styles.btn}`} onClick={add}
|
||||
style={{ display: props.addsVisible ? 'none' : 'block' }}>
|
||||
Добавить
|
||||
</button>
|
||||
<Link to="/createOrder">
|
||||
<button type="button" className={`btn btn-success ${styles.btn}`} onClick={add}
|
||||
style={{ display: props.addsVisible ? 'block' : 'none' }}>
|
||||
Добавить
|
||||
</button>
|
||||
</Link>
|
||||
<button type="button" className={`btn btn-warning ${styles.btn}`} onClick={edit}
|
||||
style={{ display: props.addsVisible ? 'none' : 'block' }}>
|
||||
Изменить
|
||||
</button >
|
||||
<button type="button" className={`btn btn-danger ${styles.btn}`} onClick={remove}>
|
||||
Удалить
|
||||
</button >
|
||||
</div >
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default ToolBar;
|
||||
4
front/src/general/Toolbar.module.css
Normal file
4
front/src/general/Toolbar.module.css
Normal file
@@ -0,0 +1,4 @@
|
||||
.btn {
|
||||
min-width: 140px;
|
||||
margin: 5px;
|
||||
}
|
||||
10
front/src/index.js
Normal file
10
front/src/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
11
front/src/models/Order.js
Normal file
11
front/src/models/Order.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import Product from "./Product";
|
||||
|
||||
export default class Order {
|
||||
constructor(data) {
|
||||
this.id = data?.id;
|
||||
this.date = data?.dateOfOrder || '';
|
||||
this.supplierId = data?.supplier.id || '';
|
||||
this.supplierName = data?.supplier.name || '';
|
||||
this.products = data?.products || [];
|
||||
}
|
||||
}
|
||||
7
front/src/models/Product.js
Normal file
7
front/src/models/Product.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export default class Product {
|
||||
constructor(data) {
|
||||
this.id = data?.id;
|
||||
this.name = data?.name || '';
|
||||
this.cost = data?.cost || '';
|
||||
}
|
||||
}
|
||||
7
front/src/models/Supplier.js
Normal file
7
front/src/models/Supplier.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export default class Supplier {
|
||||
constructor(data) {
|
||||
this.id = data?.id;
|
||||
this.name = data?.name || '';
|
||||
this.license = data?.license || '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user