Compare commits

..

No commits in common. "LabWork05" and "main" have entirely different histories.

70 changed files with 0 additions and 20521 deletions

39
demo/.gitignore vendored
View File

@ -1,39 +0,0 @@
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

View File

@ -1,41 +0,0 @@
plugins {
id 'java'
id 'org.springframework.boot' version '2.6.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
}
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-thymeleaf'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
implementation 'org.webjars:bootstrap:5.1.3'
implementation 'org.webjars:jquery:3.6.0'
implementation 'org.webjars:font-awesome:6.1.0'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.h2database:h2:2.1.210'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.5'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}

Binary file not shown.

View File

@ -1,5 +0,0 @@
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
View File

@ -1,240 +0,0 @@
#!/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
View File

@ -1,91 +0,0 @@
@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

View File

@ -1 +0,0 @@
rootProject.name = 'demo'

View File

@ -1,12 +0,0 @@
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);
}
}

View File

@ -1,23 +0,0 @@
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.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
WebMvcConfigurer.super.addViewControllers(registry);
registry.addViewController("rest-test");
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*");
}
}

View File

@ -1,110 +0,0 @@
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 javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Objects;
import javax.persistence.*;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;
@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 + '\'' +
'}';
}
}

View File

@ -1,63 +0,0 @@
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("/api/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));
}
}

View File

@ -1,52 +0,0 @@
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(){
}
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;
}
public void setDateOfOrder(Date dateOfOrder) {
this.dateOfOrder = dateOfOrder;
}
public void setSupplier(Supplier supplier) {
this.supplier = supplier;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}

View File

@ -1,52 +0,0 @@
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 OrderDtoForCreate {
private Long id;
private Date dateOfOrder;
private long supplierId;
private List<Long> productsId;
public OrderDtoForCreate(){
}
public OrderDtoForCreate(Order order){
this.id = order.getId();
this.dateOfOrder = order.getDateOfOrder();
this.supplierId = order.getSupplier().getId();
this.productsId = order.getProducts().stream().map(Product::getId).toList();
}
public long getId() {
return id;
}
public Date getDateOfOrder() {
return dateOfOrder;
}
public void setDateOfOrder(Date dateOfOrder) {
this.dateOfOrder = dateOfOrder;
}
public long getSupplierId() {
return supplierId;
}
public void setSupplierId(long supplierId) {
this.supplierId = supplierId;
}
public List<Long> getProductsId() {
return productsId;
}
public void setProductsId(List<Long> productsId) {
this.productsId = productsId;
}
}

View File

@ -1,87 +0,0 @@
package com.example.demo.supply.Order;
import com.example.demo.supply.Product.ProductDto;
import com.example.demo.supply.Product.ProductService;
import com.example.demo.supply.Supplier.SupplierDto;
import com.example.demo.supply.Supplier.SupplierService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.sql.Array;
import java.util.ArrayList;
@Controller
@RequestMapping("/order")
public class OrderMvcController {
private OrderService orderService;
private ProductService productService;
private SupplierService supplierService;
public OrderMvcController(OrderService orderService,
ProductService productService,
SupplierService supplierService){
this.orderService = orderService;
this.productService = productService;
this.supplierService = supplierService;
}
@GetMapping
public String getOrders(Model model) {
model.addAttribute("orders",
orderService.findAllOrders().stream()
.map(OrderDto::new)
.toList());
return "order";
}
@GetMapping("/dop")
public String getSuppliers(Model model,
@RequestParam(required = false) Long id) {
if(id == null || id <= 0) {
model.addAttribute("productDto", new ProductDto());
model.addAttribute("suppliers", null);
model.addAttribute("selectedProduct", null);
}
else{
ProductDto product = new ProductDto(productService.findProduct(id));
model.addAttribute("productDto", product);
model.addAttribute("selectedProduct", null);
model.addAttribute("suppliers", orderService.suppliers(id).stream().map(SupplierDto::new).toList());
}
model.addAttribute("products", productService.findAllProducts().stream().map(ProductDto::new).toList());
// model.addAttribute("orderDto", new OrderDto(orderService.findOrder(id)));
return "order-dop";
}
@GetMapping("/add")
public String addOrder(Model model) {
model.addAttribute("orderDto", new OrderDtoForCreate());
model.addAttribute("selectedSupplier", null);
model.addAttribute("suppliers", supplierService.findAllSuppliers().stream().map(SupplierDto::new).toList());
model.addAttribute("products", productService.findAllProducts().stream().map(ProductDto::new).toList());
return "order-add";
}
@PostMapping("/create")
public String saveOrder(Model model,
@ModelAttribute("orderDto") @Valid OrderDtoForCreate order,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "order-add";
}
Order newOrder = orderService.addOrder(supplierService.findSupplier(order.getSupplierId()).getId());
for(Long obj: order.getProductsId())
orderService.addProduct(newOrder.getId(), obj);
return "redirect:/order";
}
@PostMapping("/delete/{id}")
public String deleteOrder(@PathVariable Long id) {
orderService.deleteOrder(id);
return "redirect:/order";
}
}

View File

@ -1,7 +0,0 @@
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));
}
}

View File

@ -1,13 +0,0 @@
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 o.supplier FROM Order o where ?1 member of o.products")
List<Supplier> getSomeSuppliers(Product product);
}

View File

@ -1,85 +0,0 @@
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();
}
}

View File

@ -1,81 +0,0 @@
package com.example.demo.supply.Product;
import com.example.demo.supply.Order.Order;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.util.Objects;
import java.util.ArrayList;
import java.util.List;
@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 + '\'' +
'}';
}
}

View File

@ -1,45 +0,0 @@
package com.example.demo.supply.Product;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@CrossOrigin
@RequestMapping("/api/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));
}
}

View File

@ -1,46 +0,0 @@
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() {}
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;
}
public void setName(String name) {
this.name = name;
}
public void setCost(double cost) {
this.cost = cost;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
}

View File

@ -1,60 +0,0 @@
package com.example.demo.supply.Product;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@Controller
@RequestMapping("/product")
public class ProductMvcController {
private final ProductService productService;
public ProductMvcController(ProductService productService){ this.productService = productService;}
@GetMapping
public String getProducts(Model model) {
model.addAttribute("products",
productService.findAllProducts().stream()
.map(ProductDto::new)
.toList());
return "product";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editProduct(@PathVariable(required = false) Long id,
Model model) {
if (id == null || id <= 0) {
model.addAttribute("productDto", new ProductDto());
} else {
model.addAttribute("productId", id);
model.addAttribute("productDto", new ProductDto(productService.findProduct(id)));
}
return "product-edit";
}
@PostMapping(value = {"", "/{id}"})
public String saveProduct(@PathVariable(required = false) Long id,
@ModelAttribute @Valid ProductDto productDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "product-edit";
}
if (id == null || id <= 0) {
productService.addProduct(productDto.getName(), productDto.getCost());
} else {
productService.updateProduct(id, productDto.getName(), productDto.getCost());
}
return "redirect:/product";
}
@PostMapping("/delete/{id}")
public String deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
return "redirect:/product";
}
}

View File

@ -1,7 +0,0 @@
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));
}
}

View File

@ -1,6 +0,0 @@
package com.example.demo.supply.Product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}

View File

@ -1,52 +0,0 @@
package com.example.demo.supply.Product;
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();
}
}

View File

@ -1,81 +0,0 @@
package com.example.demo.supply.Supplier;
import com.example.demo.supply.Order.Order;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.util.Objects;
import java.util.ArrayList;
import java.util.List;
@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 + '\'' +
'}';
}
}

View File

@ -1,44 +0,0 @@
package com.example.demo.supply.Supplier;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@CrossOrigin
@RequestMapping("/api/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));
}
}

View File

@ -1,45 +0,0 @@
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(){
}
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;
}
public void setName(String name) {
this.name = name;
}
public void setLicense(int license) {
this.license = license;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
}

View File

@ -1,60 +0,0 @@
package com.example.demo.supply.Supplier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@Controller
@RequestMapping("/supplier")
public class SupplierMvcController {
private final SupplierService supplierService;
public SupplierMvcController(SupplierService supplierService){ this.supplierService = supplierService;}
@GetMapping
public String getSuppliers(Model model) {
model.addAttribute("suppliers",
supplierService.findAllSuppliers().stream()
.map(SupplierDto::new)
.toList());
return "supplier";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editSuppliers(@PathVariable(required = false) Long id,
Model model) {
if (id == null || id <= 0) {
model.addAttribute("supplierDto", new SupplierDto());
} else {
model.addAttribute("supplierId", id);
model.addAttribute("supplierDto", new SupplierDto(supplierService.findSupplier(id)));
}
return "supplier-edit";
}
@PostMapping(value = {"", "/{id}"})
public String saveSuppliers(@PathVariable(required = false) Long id,
@ModelAttribute @Valid SupplierDto supplierDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "supplier-edit";
}
if (id == null || id <= 0) {
supplierService.addSupplier(supplierDto.getName(), supplierDto.getLicense());
} else {
supplierService.updateSupplier(id, supplierDto.getName(), supplierDto.getLicense());
}
return "redirect:/supplier";
}
@PostMapping("/delete/{id}")
public String deleteSuppliers(@PathVariable Long id) {
supplierService.deleteSupplier(id);
return "redirect:/supplier";
}
}

View File

@ -1,8 +0,0 @@
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));
}
}

View File

@ -1,6 +0,0 @@
package com.example.demo.supply.Supplier;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SupplierRepository extends JpaRepository<Supplier, Long> {
}

View File

@ -1,53 +0,0 @@
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();
}
}

View File

@ -1,11 +0,0 @@
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

View File

@ -1,15 +0,0 @@
.container-padding {
padding: 10px;
}
.margin-bottom {
margin-bottom: 10px;
}
.button-fixed {
min-width: 120px;
}
.button-sm {
padding: 1px;
}

View File

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"><!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
<path d="M448 48V384c-63.09 22.54-82.34 32-119.5 32c-62.82 0-86.6-32-149.3-32C158.6 384 142.6 387.6 128 392.2v-64C142.6 323.6 158.6 320 179.2 320c62.73 0 86.51 32 149.3 32C348.9 352 364.1 349 384 342.7v-208C364.1 141 348.9 144 328.5 144c-62.82 0-86.6-32-149.3-32C128.4 112 104.3 132.6 64 140.7v307.3C64 465.7 49.67 480 32 480S0 465.7 0 448V63.1C0 46.33 14.33 32 31.1 32S64 46.33 64 63.1V76.66C104.3 68.63 128.4 48 179.2 48c62.73 0 86.51 32 149.3 32C365.7 80 384.9 70.54 448 48z"/>
</svg>

Before

Width:  |  Height:  |  Size: 727 B

View File

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
</html>

View File

@ -1,52 +0,0 @@
<!DOCTYPE html>
<html lang="ru"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8"/>
<title>Поставки</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" href="/favicon.svg">
<script type="text/javascript" src="/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="/webjars/bootstrap/5.1.3/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/webjars/font-awesome/6.1.0/css/all.min.css"/>
<link rel="stylesheet" href="/css/style.css"/>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<i class="fa-solid fa-font-awesome"></i>
Поставки
</a>
<button class="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav" th:with="activeLink=${#request.requestURI}">
<a class="nav-link" href="/"
th:classappend="${#strings.equals(activeLink, '/')} ? 'active' : ''">Главная</a>
<a class="nav-link" href="/product"
th:classappend="${#strings.equals(activeLink, '/product')} ? 'active' : ''">Продукты</a>
<a class="nav-link" href="/supplier"
th:classappend="${#strings.equals(activeLink, '/supplier')} ? 'active' : ''">Поставщики</a>
<a class="nav-link" href="/order"
th:classappend="${#strings.equals(activeLink, '/order')} ? 'active' : ''">Заказы</a>
<a class="nav-link" href="/order/dop"
th:classappend="${#strings.equals(activeLink, '/order')} ? 'active' : ''">Доп задание</a>
<a class="nav-link" href="/swagger-ui/index.html" target="_blank">Документация REST API</a>
<a class="nav-link" href="/h2-console/" target="_blank">Консоль H2</a>
</ul>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="container container-padding" layout:fragment="content">
</div>
</div>
</body>
<th:block layout:fragment="scripts">
</th:block>
</html>

View File

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div>It's works!</div>
</div>
</body>
</html>

View File

@ -1,35 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<form action="#" th:action="@{/order/create}" th:object="${orderDto}" method="post">
<div class="mb-3">
<button type="submit" class="btn btn-primary btn-success">Создать</button>
<a class="btn btn-primary btn-danger" th:href="@{/order}">
Назад
</a>
</div>
<div class="mb-3">
<label for="supplier" class="form-label">Поставщик</label>
<select id="supplier" class="form-select" th:field="*{supplierId}" th:name="${selectedSupplier}">
<option th:each="value: ${suppliers}" th:selected="${selectedSupplier != null and selectedSupplier == value.id}" th:value="${value.id}" th:text=" ${value.name}"></option>
</select>
</div>
<label>Продукты:</label>
<select id="author" class="form-select" multiple size="6" th:field="*{productsId}" >
<option th:each="product: ${products}"
th:value="${product.id}"
th:text="${product.name}" ></option>
</select>
</form>
</div>
</body>
</html>

View File

@ -1,44 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<form action="#" th:action="@{/order/dop}" th:object="${productDto}" method="get">
<div class="mb-3">
<label for="product" class="form-label">Продукт</label>
<select id="product" class="form-select" th:field="*{id}" th:name="${selectedProduct}">
<option th:each="value: ${products}" th:selected="${selectedProduct != null and selectedProduct == value.id}" th:value="${value.id}" th:text="${value.name}"></option>
</select>
</div>
<button type="submit" class="btn btn-success button-fixed">Сформировать</button>
</form>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">ID</th>
<th scope="col">Название</th>
<th scope="col">Лицензия</th>
</tr>
</thead>
<tbody>
<tr th:each="supplier, iterator: ${suppliers}">
<th scope="row" th:text="${iterator.index} + 1"/>
<td th:text="${supplier.id}"/>
<td th:text="${supplier.name}"/>
<td th:text="${supplier.license}"/>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -1,55 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div>
<a class="btn btn-success button-fixed"
th:href="@{/order/add}">
<i class="fa-solid fa-plus"></i> Создать заказ
</a>
</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">ID</th>
<th scope="col">Дата создания</th>
<th scope="col">Поставщик</th>
<th scope="col">Продукты</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="order, iterator: ${orders}">
<th scope="row" th:text="${iterator.index} + 1"/>
<td th:text="${order.id}"/>
<td th:text="${order.dateOfOrder}" />
<td th:text="${order.supplier.name}" />
<td>
<li th:each="product : ${order.products}" th:text="${product.name}"></li>
</td>
<td style="width: 10%">
<div class="btn-group" role="group" aria-label="Basic example">
<button type="button" class="btn btn-danger button-fixed button-sm"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${order.id}').click()|">
<i class="fa fa-trash" aria-hidden="true"></i> Удалить
</button>
</div>
<form th:action="@{/order/delete/{id}(id=${order.id})}" method="post">
<button th:id="'remove-' + ${order.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<form action="#" th:action="@{/product/{id}(id=${id})}" th:object="${productDto}" method="post">
<div class="mb-3">
<label for="name" class="form-label">Название</label>
<input type="text" class="form-control" id="name" th:field="${productDto.name}" required="true">
</div>
<div class="mb-3">
<label for="cost" class="form-label">Цена</label>
<input type="text" class="form-control" id="cost" th:field="${productDto.cost}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/product}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -1,55 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div>
<a class="btn btn-success button-fixed"
th:href="@{/product/edit/}">
<i class="fa-solid fa-plus"></i> Добавить
</a>
</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">ID</th>
<th scope="col">Название</th>
<th scope="col">Цена</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="product, iterator: ${products}">
<th scope="row" th:text="${iterator.index} + 1"/>
<td th:text="${product.id}"/>
<td th:text="${product.name}" />
<td th:text="${product.cost}" />
<td style="width: 10%">
<div class="btn-group" role="group" aria-label="Basic example">
<a class="btn btn-warning button-fixed button-sm"
th:href="@{/product/edit/{id}(id=${product.id})}">
<i class="fa fa-pencil" aria-hidden="true"></i> Изменить
</a>
<button type="button" class="btn btn-danger button-fixed button-sm"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${product.id}').click()|">
<i class="fa fa-trash" aria-hidden="true"></i> Удалить
</button>
</div>
<form th:action="@{/product/delete/{id}(id=${product.id})}" method="post">
<button th:id="'remove-' + ${product.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<form action="#" th:action="@{/supplier/{id}(id=${id})}" th:object="${supplierDto}" method="post">
<div class="mb-3">
<label for="name" class="form-label">Название</label>
<input type="text" class="form-control" id="name" th:field="${supplierDto.name}" required="true">
</div>
<div class="mb-3">
<label for="license" class="form-label">Лицензия</label>
<input type="text" class="form-control" id="license" th:field="${supplierDto.license}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/supplier}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -1,55 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div>
<a class="btn btn-success button-fixed"
th:href="@{/supplier/edit/}">
<i class="fa-solid fa-plus"></i> Добавить
</a>
</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">ID</th>
<th scope="col">Название</th>
<th scope="col">Лицензия</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="supplier, iterator: ${suppliers}">
<th scope="row" th:text="${iterator.index} + 1"/>
<td th:text="${supplier.id}"/>
<td th:text="${supplier.name}"/>
<td th:text="${supplier.license}"/>
<td style="width: 10%">
<div class="btn-group" role="group" aria-label="Basic example">
<a class="btn btn-warning button-fixed button-sm"
th:href="@{/supplier/edit/{id}(id=${supplier.id})}">
<i class="fa fa-pencil" aria-hidden="true"></i> Изменить
</a>
<button type="button" class="btn btn-danger button-fixed button-sm"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${supplier.id}').click()|">
<i class="fa fa-trash" aria-hidden="true"></i> Удалить
</button>
</div>
<form th:action="@{/supplier/delete/{id}(id=${supplier.id})}" method="post">
<button th:id="'remove-' + ${supplier.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -1,7 +0,0 @@
package com.example.demo;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class Tests {
}

View File

@ -1,53 +0,0 @@
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);
// }
}

View File

@ -1,59 +0,0 @@
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
View File

@ -1,23 +0,0 @@
# 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*

View File

@ -1,70 +0,0 @@
# 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

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +0,0 @@
{
"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"
]
}
}

View File

@ -1,13 +0,0 @@
<!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>

View File

@ -1,25 +0,0 @@
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 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} />
</Routes>
</BrowserRouter>
);
}
export default App;

View File

@ -1,87 +0,0 @@
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(){
const arr =[
{
"id":104,
"name":"prod3",
"cost":3333
},
{
"id":153,
"name":"prod3",
"cost":5555
}
]
//const resArr = JSON.stringify(arr)
//console.log(resArr)
const response = await axios.post(this.mainUrl + `order/someSuppliers/`, {
body: {arr}
});
console.log(response)
}
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;
}
}

View File

@ -1,112 +0,0 @@
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';
import Modal from '../general/Modal';
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>
</>
);
}

View File

@ -1,47 +0,0 @@
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>
);
}

View File

@ -1,46 +0,0 @@
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>
);
}

View File

@ -1,175 +0,0 @@
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>
)
}

View File

@ -1,79 +0,0 @@
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}/>
</>
)
}

View File

@ -1,147 +0,0 @@
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)
const [isAddProd, setIsAddProd] = useState(false)
let selectedItems = [];
useEffect(() => {
loadItems()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const loadItems = () => {
DataService.readAll(props.url, props.transformer)
.then(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;

View File

@ -1,35 +0,0 @@
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>
</ul>
</div>
</div>
</nav >
);
}

View File

@ -1,47 +0,0 @@
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;

View File

@ -1,83 +0,0 @@
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 >
);
}

View File

@ -1,12 +0,0 @@
.table tbody tr {
user-select: none;
}
.selectable tbody tr:hover {
cursor: pointer;
}
.selected {
background-color: #0d6efd;
opacity: 80%;
}

View File

@ -1,36 +0,0 @@
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;

View File

@ -1,4 +0,0 @@
.btn {
min-width: 140px;
margin: 5px;
}

View File

@ -1,10 +0,0 @@
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>
);

View File

@ -1,11 +0,0 @@
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 || [];
}
}

View File

@ -1,7 +0,0 @@
export default class Product {
constructor(data) {
this.id = data?.id;
this.name = data?.name || '';
this.cost = data?.cost || '';
}
}

View File

@ -1,7 +0,0 @@
export default class Supplier {
constructor(data) {
this.id = data?.id;
this.name = data?.name || '';
this.license = data?.license || '';
}
}