v1.1.1
# v1.1.1 ### Corrections * Désactivation de l'autocomplétion dans les étapes des recettes (permet d'éviter un bug qui affiche les suggestion par dessus toutes les étapes sur Edge) * Correction d'un bug qui permettait d'envoyer les formulaires demandant des mots de passe sans donner un mot de passe valide. * Amélioration des contrôlleurs et du service des mélanges. * Correction d'un bug avec la création des mélanges. ### Ajouts * L'onglet se ferme automatiquement lorsqu'un utilisateur tente d'accéder à un fichier SIMDUT inexistant. * Meilleure sélection des produits dans l'éditeur de mélange. * Retravail de l'affichage de la plupart des tables, les rendant moins chargées. * Retravail de l'affichage des étapes et des images dans l'explorateur et l'éditeur de recette. * Ajout de la page de l'historique des mises à jour. * Ajout de la journalisation. ### Dépendances * Ajout de Lombok
This commit is contained in:
parent
dc1c0b8585
commit
b66777aa23
BIN
TestProd.pdf
BIN
TestProd.pdf
Binary file not shown.
|
@ -0,0 +1,46 @@
|
|||
param (
|
||||
[string]$WorkDir = "./workdir",
|
||||
[string]$BackupPath = "./backup",
|
||||
[boolean]$OverWrite = $False
|
||||
)
|
||||
|
||||
Write-Host "Démarrage de la sauvegarde..."
|
||||
if (!(Test-Path -Path $WorkDir))
|
||||
{
|
||||
Write-Host "Le dossier de travail ($WorkDir) n'existe pas."
|
||||
exit
|
||||
}
|
||||
|
||||
if (!(Test-Path -Path $BackupPath))
|
||||
{
|
||||
Write-Host "Création du dossier des sauvegardes. ($BackupPath)"
|
||||
New-Item -ItemType directory -Path $BackupPath | Out-Null
|
||||
}
|
||||
|
||||
Write-Host "Début de la compression..."
|
||||
$BackupFile = "$BackupPath/backup_$( Get-Date -f yyyyMMdd-HHmm ).zip"
|
||||
$CompressArgs = @{
|
||||
'Path' = $WorkDir
|
||||
'DestinationPath' = $BackupFile
|
||||
'Update' = $OverWrite
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Compress-Archive @CompressArgs
|
||||
|
||||
Write-Host "Sauvegarde réussie! ($BackupFile)"
|
||||
}
|
||||
catch [System.IO.IOException]
|
||||
{
|
||||
Write-Output "Une erreur est survenue lors de la sauvegarde:"
|
||||
|
||||
if ($_.FullyQualifiedErrorId -like "ArchiveFileExists*")
|
||||
{
|
||||
Write-Host "L'archive de sauvegarde '$BackupFile' existe déjà. Ajoutez l'argument '-OverWrite `$true' pour écraser l'archive."
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host $_
|
||||
}
|
||||
}
|
63
pom.xml
63
pom.xml
|
@ -8,11 +8,10 @@
|
|||
<version>2.1.4.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>fyloz.trial</groupId>
|
||||
<groupId>dev.fyloz.trial.colorrecipesexplorer</groupId>
|
||||
<artifactId>ColorRecipesExplorer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>ColorRecipesExplorer</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
<version>1.1.1</version>
|
||||
<name>Color Recipes Explorer</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
@ -42,21 +41,26 @@
|
|||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- H2 -->
|
||||
<dependency>
|
||||
<groupId>org.xhtmlrenderer</groupId>
|
||||
<artifactId>flying-saucer-pdf</artifactId>
|
||||
<version>9.1.18</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.11</version>
|
||||
</dependency>
|
||||
|
||||
<!-- PDF -->
|
||||
<dependency>
|
||||
<groupId>com.itextpdf</groupId>
|
||||
<artifactId>itextpdf</artifactId>
|
||||
|
@ -67,6 +71,30 @@
|
|||
<artifactId>pdfbox</artifactId>
|
||||
<version>2.0.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atlassian.commonmark</groupId>
|
||||
<artifactId>commonmark</artifactId>
|
||||
<version>0.13.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -75,6 +103,23 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<copy file="start.bat" tofile="${basedir}/target/start.bat"/>
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
BIN
recipes.mv.db
BIN
recipes.mv.db
Binary file not shown.
|
@ -1,11 +1,13 @@
|
|||
package fyloz.trial.ColorRecipesExplorer;
|
||||
package dev.fyloz.trial.colorrecipesexplorer;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler;
|
||||
import fyloz.trial.ColorRecipesExplorer.web.StringBank;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.PasswordService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.MessageSource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -15,26 +17,38 @@ import java.util.List;
|
|||
@SpringBootApplication
|
||||
public class ColorRecipesExplorerApplication {
|
||||
|
||||
public static final Logger logger = LoggerFactory.getLogger(ColorRecipesExplorerApplication.class);
|
||||
// Chemin du fichier contenant les utilisateurs
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(ColorRecipesExplorerApplication.class);
|
||||
public static String UPLOAD_LOCATION;
|
||||
public static final String USERS_FILE_NAME = "passwords";
|
||||
public static boolean USE_PORT;
|
||||
|
||||
public static ColorRecipesExplorerApplication CREApp;
|
||||
|
||||
private MessageSource messageSource;
|
||||
|
||||
public static void main(String[] args) {
|
||||
logger.info("Le fichier des utilisateurs se situe à: " + new File(StringBank.UPLOAD_LOCATION + "/" + USERS_FILE_NAME).getAbsolutePath());
|
||||
loadPasswords();
|
||||
UPLOAD_LOCATION = args[0] != null ? args[0] : "./";
|
||||
|
||||
SpringApplication.run(ColorRecipesExplorerApplication.class, args);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public ColorRecipesExplorerApplication(MessageSource messageSource) {
|
||||
this.messageSource = messageSource;
|
||||
|
||||
CREApp = this;
|
||||
LOGGER.info("Le fichier des utilisateurs se situe à: " + new File(UPLOAD_LOCATION + "/" + USERS_FILE_NAME).getAbsolutePath());
|
||||
|
||||
loadPasswords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les mots de passes contenus dans le fichier.
|
||||
* <p>
|
||||
* Un mot de passe correspond à une ligne dans le fichier passwords.txt.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void loadPasswords() {
|
||||
FileHandler fileHandler = new FileHandler(USERS_FILE_NAME, FileHandler.FileContext.OTHERS, FileHandler.FileExtension.TXT);
|
||||
private void loadPasswords() {
|
||||
FileHandler fileHandler = new FileHandler(USERS_FILE_NAME, FileHandler.FileContext.OTHERS, FileHandler.FileExtension.TEXT);
|
||||
if (!fileHandler.isValid()) {
|
||||
fileHandler.createFile();
|
||||
}
|
||||
|
@ -43,15 +57,19 @@ public class ColorRecipesExplorerApplication {
|
|||
List<String> fileContent = Files.readAllLines(fileHandler.getPath());
|
||||
|
||||
if (fileContent.size() < 1) {
|
||||
logger.warn("Aucun mot de passe trouvé. Il sera impossible d'utiliser certaines fonctionnalitées de l'application.");
|
||||
LOGGER.warn("Aucun mot de passe trouvé. Il sera impossible d'utiliser certaines fonctionnalitées de l'application.");
|
||||
}
|
||||
|
||||
for (String line : fileContent) {
|
||||
PasswordValidator.addPassword(line);
|
||||
PasswordService.addPassword(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Une erreur est survenue lors du chargement du fichier des utilisateurs", e);
|
||||
logger.warn("Il sera impossible d'utiliser certaines fonctionnalitées de l'application.");
|
||||
LOGGER.error("Une erreur est survenue lors du chargement du fichier des utilisateurs", e);
|
||||
LOGGER.warn("Il sera impossible d'utiliser certaines fonctionnalitées de l'application.");
|
||||
}
|
||||
}
|
||||
|
||||
public MessageSource getMessageSource() {
|
||||
return messageSource;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.configuration;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class InitialDataLoader implements ApplicationListener<ApplicationReadyEvent> {
|
||||
|
||||
private MaterialTypeService materialTypeService;
|
||||
|
||||
@Autowired
|
||||
public InitialDataLoader(MaterialTypeService materialTypeService) {
|
||||
this.materialTypeService = materialTypeService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
|
||||
if (!materialTypeService.getByName(MaterialType.DEFAULT_MATERIAL_TYPE_NAME).isPresent()) {
|
||||
createDefaultMaterialType();
|
||||
}
|
||||
}
|
||||
|
||||
private void createDefaultMaterialType() {
|
||||
MaterialType defaultMaterialType = new MaterialType(MaterialType.DEFAULT_MATERIAL_TYPE_NAME, "", false);
|
||||
|
||||
Optional<MaterialType> optionalSavedMaterialType = materialTypeService.save(defaultMaterialType);
|
||||
if (!optionalSavedMaterialType.isPresent()) {
|
||||
ColorRecipesExplorerApplication.LOGGER.warn("Échec de la création du type de produit par défaut.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.core.configuration;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.configuration;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -18,19 +18,11 @@ public class LocaleConfiguration implements WebMvcConfigurer {
|
|||
@Bean
|
||||
public MessageSource messageSource() {
|
||||
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
|
||||
// messageSource.setBasenames("classpath:lang/messages", "classpath:lang/responses");
|
||||
messageSource.setBasename("classpath:lang/responses");
|
||||
messageSource.setBasenames("classpath:lang/messages", "classpath:lang/responses");
|
||||
messageSource.setDefaultEncoding("UTF-8");
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
// @Bean
|
||||
// public MessageSource responsesMessageSource() {
|
||||
// ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
|
||||
// messageSource.setBasename("classpath:lang/responses");
|
||||
// return messageSource;
|
||||
// }
|
||||
|
||||
@Bean
|
||||
public LocaleResolver localeResolver() {
|
||||
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.core.configuration;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.configuration;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
|
@ -0,0 +1,19 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.configuration;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class SpringConfiguration {
|
||||
|
||||
@Value("${response.useport}")
|
||||
public boolean usePort;
|
||||
|
||||
@Bean
|
||||
public void setUsePort() {
|
||||
ColorRecipesExplorerApplication.USE_PORT = usePort;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.core.io;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.io.file;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -9,12 +9,10 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.StringBank.UPLOAD_LOCATION;
|
||||
|
||||
public class FileHandler {
|
||||
|
||||
protected String name;
|
||||
protected Logger logger = ColorRecipesExplorerApplication.logger;
|
||||
protected Logger logger = ColorRecipesExplorerApplication.LOGGER;
|
||||
|
||||
private FileContext context;
|
||||
private FileExtension extension;
|
||||
|
@ -91,7 +89,7 @@ public class FileHandler {
|
|||
}
|
||||
|
||||
public Path getPath() {
|
||||
return Paths.get(String.format("%s/%s/%s%s", UPLOAD_LOCATION, context.getPath(), name, extension.getExtension()));
|
||||
return Paths.get(String.format("%s/%s/%s%s", ColorRecipesExplorerApplication.UPLOAD_LOCATION, context.getPath(), name, extension.getExtension()));
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
|
@ -118,8 +116,9 @@ public class FileHandler {
|
|||
public enum FileExtension {
|
||||
JPEG("jpeg"),
|
||||
PDF("pdf"),
|
||||
TXT("txt"),
|
||||
DB("db");
|
||||
TEXT("txt"),
|
||||
DATABASE("db"),
|
||||
MARKDOWN("md");
|
||||
|
||||
private String extension;
|
||||
|
|
@ -1,13 +1,16 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.core.io;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.io.file;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Recipe;
|
||||
import fyloz.trial.ColorRecipesExplorer.services.RecipeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ImageHandler extends FileHandler {
|
||||
|
||||
public static final String IMAGES_LOCATION = ColorRecipesExplorerApplication.UPLOAD_LOCATION + "/images";
|
||||
|
||||
private Recipe recipe;
|
||||
private int index = 0;
|
||||
private RecipeService recipeService;
|
||||
|
@ -22,6 +25,8 @@ public class ImageHandler extends FileHandler {
|
|||
public ImageHandler(String name, RecipeService recipeService) {
|
||||
super(name.replace(".jpeg", ""), FileContext.IMAGE, FileExtension.JPEG);
|
||||
|
||||
this.recipeService = recipeService;
|
||||
|
||||
String[] nameParts = name.split("-");
|
||||
index = Integer.parseInt(nameParts[1].replace(".jpeg", ""));
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class JSONResponseBuilder extends ResponseBuilder<JSONResponseBuilder, Map<String, Object>> {
|
||||
|
||||
@Override
|
||||
protected void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters) {
|
||||
Map<String, Object> attributeContent = new HashMap<>();
|
||||
|
||||
// Récupère le message depuis le fichier des messages de la bonne language et rajoute ces paramètres.
|
||||
String message = ColorRecipesExplorerApplication.CREApp.getMessageSource().getMessage(responseMessagePath, parameters, LocaleContextHolder.getLocale());
|
||||
attributeContent.put("message", message);
|
||||
|
||||
addAttribute(responseCodeType, attributeContent);
|
||||
}
|
||||
|
||||
public Map<String, Object> build() {
|
||||
return attributes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
|
||||
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
public class ModelResponseBuilder extends ResponseBuilder<ModelResponseBuilder, ModelAndView> {
|
||||
|
||||
private static final String PATH_PARAMETER_PATTERN = "(\\{\\w+\\})";
|
||||
|
||||
private ModelAndView model;
|
||||
|
||||
public ModelResponseBuilder() {
|
||||
this.model = new ModelAndView();
|
||||
}
|
||||
|
||||
public ModelResponseBuilder(String view) {
|
||||
this(new ModelAndView(view));
|
||||
}
|
||||
|
||||
public ModelResponseBuilder(ModelAndView model) {
|
||||
this.model = model == null ? new ModelAndView() : model;
|
||||
}
|
||||
|
||||
public ModelResponseBuilder withView(String path) {
|
||||
model.setViewName(path);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModelResponseBuilder withRedirect(String path, Object... parameters) {
|
||||
for (Object parameter : parameters) path = path.replaceFirst(PATH_PARAMETER_PATTERN, parameter.toString());
|
||||
model.setViewName("redirect:/" + path);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters) {
|
||||
addAttribute(responseCodeType, responseMessagePath);
|
||||
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
addAttribute(String.format("responseArg%s", i + 1), parameters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public ModelAndView build() {
|
||||
model.addAllObjects(attributes);
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class ResponseBuilder<T extends ResponseBuilder, R> {
|
||||
|
||||
protected static final String RESPONSE_PREFIX = "response.";
|
||||
protected static final String ERROR_ATTRIBUTE_NAME = "error";
|
||||
protected static final String SUCCESS_ATTRIBUTE_NAME = "success";
|
||||
|
||||
protected Map<String, Object> attributes;
|
||||
|
||||
private boolean containsErrors = false;
|
||||
|
||||
public ResponseBuilder() {
|
||||
attributes = new HashMap<>();
|
||||
|
||||
// Ajoute l'URL de base à toutes les réponses
|
||||
attributes.put("baseUrl", ControllerUtils.getCurrentBaseUrl());
|
||||
}
|
||||
|
||||
protected abstract void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters);
|
||||
|
||||
protected abstract R build();
|
||||
|
||||
public T addResponseCode(ResponseCode responseCode, Object... parameters) {
|
||||
String[] parametersAsStr = new String[parameters.length];
|
||||
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
parametersAsStr[i] = parameters[i].toString();
|
||||
}
|
||||
|
||||
return addResponseCode(responseCode, parametersAsStr);
|
||||
}
|
||||
|
||||
public T addResponseCode(ResponseCode responseCode, String... parameters) {
|
||||
int requiredParametersNumber = responseCode.getParametersNumber();
|
||||
int givenParametersNumber = parameters.length;
|
||||
|
||||
if (requiredParametersNumber != givenParametersNumber) {
|
||||
throw new IllegalArgumentException(String.format("Mauvais nombre de paramètre dans une réponse de modèle: %s requis, %s fournis", requiredParametersNumber, givenParametersNumber));
|
||||
}
|
||||
|
||||
// Ajoute les paramètres, si nécessaire
|
||||
if (requiredParametersNumber > 0) {
|
||||
// Avertit s'il y a plus de paramètres que le nombre de paramètres supporté par le template thymeleaf (aussi MAX_PARAMETERS_NUMBER)
|
||||
int maxParametersNumber = ResponseCode.MAX_PARAMETERS_NUMBER;
|
||||
if (givenParametersNumber > maxParametersNumber) {
|
||||
ColorRecipesExplorerApplication.LOGGER.warn(String.format("Trop de paramètres fournis pour le code de réponse %s: %s maximum, %s fournis", responseCode.name(), maxParametersNumber, givenParametersNumber));
|
||||
}
|
||||
}
|
||||
|
||||
String responseCodeType;
|
||||
if (responseCode.getType() == ResponseCode.ResponseCodeType.ERROR) {
|
||||
containsErrors = true;
|
||||
responseCodeType = ERROR_ATTRIBUTE_NAME;
|
||||
} else {
|
||||
responseCodeType = SUCCESS_ATTRIBUTE_NAME;
|
||||
}
|
||||
|
||||
String responseMessagePath = RESPONSE_PREFIX + responseCode.getCode();
|
||||
addResponseCodeToAttribute(responseCodeType, responseMessagePath, parameters);
|
||||
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T addResponseData(ResponseDataType responseDataType, @NotNull Object data) {
|
||||
Class requiredDataTypeClass = responseDataType.getDataType();
|
||||
Class requiredListDataTypeClass = responseDataType.getListDataType();
|
||||
Class givenDataTypeClass = data.getClass();
|
||||
|
||||
// Vérifie le type de l'objet
|
||||
if (!requiredDataTypeClass.equals(givenDataTypeClass)) {
|
||||
throw new IllegalArgumentException(String.format("L'objet passé en paramètre n'est pas du bon type. Requis: %s, fournis: %s", requiredDataTypeClass.getName(), givenDataTypeClass.getName()));
|
||||
}
|
||||
|
||||
// Si l'objet est une liste, vérifie qu'elle n'est pas vide et qu'elle est du bon type
|
||||
if (requiredDataTypeClass.equals(List.class) && requiredListDataTypeClass != null) {
|
||||
List listData = (List) data;
|
||||
|
||||
if (listData.size() < 1) {
|
||||
throw new IllegalArgumentException("La liste passée en paramètre ne contient aucun élément");
|
||||
}
|
||||
|
||||
Class givenListDataTypeClass = listData.get(0).getClass();
|
||||
if (givenDataTypeClass.equals(requiredListDataTypeClass)) {
|
||||
throw new IllegalArgumentException(String.format("La liste passée en paramètre contient des éléments du mauvais type. Requis: %s, fournis: %s", requiredListDataTypeClass.getName(), givenListDataTypeClass.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
// Ajoute l'attribut dans le Map
|
||||
addAttribute(responseDataType.getDataTypeName(), data);
|
||||
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T addAttribute(String attributeName, Object content) {
|
||||
attributes.put(attributeName, content);
|
||||
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public boolean containsErrors() {
|
||||
return containsErrors;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.core;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
|
||||
|
||||
public enum ResponseCode {
|
||||
SUCCESS_USING_MATERIALS(1, ResponseCodeType.SUCCESS, 0),
|
||||
|
@ -18,7 +18,21 @@ public enum ResponseCode {
|
|||
COMPANY_LINKED(15, ResponseCodeType.ERROR, 1),
|
||||
MIX_NOT_ASSOCIATED_WITH_RECIPE(16, ResponseCodeType.ERROR, 2),
|
||||
NOT_ENOUGH_MATERIAL(17, ResponseCodeType.ERROR, 1),
|
||||
MIX_TYPE_ALREADY_USED(18, ResponseCodeType.ERROR, 1);
|
||||
MIX_TYPE_ALREADY_USED(18, ResponseCodeType.ERROR, 1),
|
||||
MATERIAL_TYPE_NOT_FOUND(19, ResponseCodeType.ERROR, 1),
|
||||
MATERIAL_TYPE_ALREADY_EXIST_PREFIX(20, ResponseCodeType.ERROR, 1),
|
||||
MATERIAL_TYPE_LINKED(21, ResponseCodeType.ERROR, 1),
|
||||
NO_COMPANY(22, ResponseCodeType.ERROR, 0),
|
||||
NO_MATERIAL(23, ResponseCodeType.ERROR, 0),
|
||||
FILE_NOT_IMAGE(24, ResponseCodeType.ERROR, 0),
|
||||
RECIPE_NOT_FOUND_NO_PARAMS(25, ResponseCodeType.ERROR, 0),
|
||||
MATERIAL_NOT_FOUND_BY_NAME(26, ResponseCodeType.ERROR, 1),
|
||||
|
||||
// HTTP Errors
|
||||
_500(100, ResponseCodeType.ERROR, 0),
|
||||
_404(101, ResponseCodeType.ERROR, 0),
|
||||
_401(102, ResponseCodeType.ERROR, 0),
|
||||
;
|
||||
|
||||
public static final int MAX_PARAMETERS_NUMBER = 2;
|
||||
|
||||
|
@ -48,4 +62,5 @@ public enum ResponseCode {
|
|||
ERROR,
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.core;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.*;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public enum ModelDataType {
|
||||
public enum ResponseDataType {
|
||||
MATERIAL("material", Material.class),
|
||||
MATERIALS("materials", ArrayList.class, MATERIAL),
|
||||
MATERIAL_ID("materialID", Integer.class),
|
||||
|
@ -14,6 +14,7 @@ public enum ModelDataType {
|
|||
|
||||
MATERIAL_TYPE("materialType", MaterialType.class),
|
||||
MATERIAL_TYPES("materialTypes", ArrayList.class, MATERIAL_TYPE),
|
||||
MATERIAL_TYPE_NAME("materialTypeName", String.class),
|
||||
|
||||
RECIPE("recipe", Recipe.class),
|
||||
RECIPES("recipes", ArrayList.class, RECIPE),
|
||||
|
@ -40,17 +41,19 @@ public enum ModelDataType {
|
|||
COMPANY_NAME("companyName", String.class),
|
||||
|
||||
IMAGE("image", String.class),
|
||||
IMAGES("images", ArrayList.class, IMAGE);
|
||||
IMAGES("images", ArrayList.class, IMAGE),
|
||||
|
||||
BLOCK_BUTTON("blockButton", Boolean.class);
|
||||
|
||||
private String dataTypeName;
|
||||
private Class dataType;
|
||||
private Class listDataType;
|
||||
|
||||
ModelDataType(String dataTypeName, Class dataType) {
|
||||
ResponseDataType(String dataTypeName, Class dataType) {
|
||||
this(dataTypeName, dataType, null);
|
||||
}
|
||||
|
||||
ModelDataType(String dataTypeName, Class dataType, ModelDataType listDataType) {
|
||||
ResponseDataType(String dataTypeName, Class dataType, ResponseDataType listDataType) {
|
||||
this.dataTypeName = dataTypeName;
|
||||
this.dataType = dataType;
|
||||
|
||||
|
@ -76,7 +79,7 @@ public enum ModelDataType {
|
|||
return getDataTypeName();
|
||||
}
|
||||
|
||||
public static ModelDataType getModelDataTypeFromDataType(Class dataType) {
|
||||
public static ResponseDataType getModelDataTypeFromDataType(Class dataType) {
|
||||
return Stream.of(values()).filter(r -> r.getDataType().equals(dataType)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.model;
|
||||
|
||||
public abstract class BeanModel {
|
||||
public abstract Integer getID();
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.model;
|
||||
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.model;
|
||||
|
||||
import org.hibernate.annotations.ColumnDefault;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.model;
|
||||
|
||||
import org.hibernate.annotations.ColumnDefault;
|
||||
|
||||
|
@ -11,6 +11,8 @@ import java.util.Objects;
|
|||
@Entity
|
||||
public class MaterialType extends BeanModel implements Serializable {
|
||||
|
||||
public static final String DEFAULT_MATERIAL_TYPE_NAME = "Aucun";
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||
private Integer materialTypeID;
|
||||
|
@ -19,6 +21,7 @@ public class MaterialType extends BeanModel implements Serializable {
|
|||
@NotNull
|
||||
private String materialTypeName;
|
||||
|
||||
@Column(unique = true)
|
||||
@NotNull
|
||||
private String prefix;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.model;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
@ -23,7 +23,7 @@ public class Mix extends BeanModel implements Serializable {
|
|||
@ManyToOne
|
||||
private MixType mixType;
|
||||
|
||||
@OneToMany(mappedBy = "mix")
|
||||
@OneToMany(mappedBy = "mix", cascade = CascadeType.ALL)
|
||||
private List<MixQuantity> mixQuantities;
|
||||
|
||||
// Casier
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.model;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
@ -6,7 +6,7 @@ import java.io.Serializable;
|
|||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
@Table(name = "mixTypes")
|
||||
@Table(name = "mixTypes") // TODO retirer @Table
|
||||
public class MixType extends BeanModel implements Serializable {
|
||||
|
||||
@Id
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
@ -6,6 +6,7 @@ import org.hibernate.validator.constraints.Length;
|
|||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
|
@ -38,10 +39,10 @@ public class Recipe extends BeanModel implements Serializable {
|
|||
private String note;
|
||||
|
||||
@JsonIgnore
|
||||
@OneToMany(mappedBy = "recipe")
|
||||
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
|
||||
private List<Mix> recipeMixes;
|
||||
|
||||
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
|
||||
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<RecipeStep> recipeSteps;
|
||||
|
||||
public Recipe() {
|
||||
|
@ -131,7 +132,7 @@ public class Recipe extends BeanModel implements Serializable {
|
|||
}
|
||||
|
||||
public List<RecipeStep> getRecipeSteps() {
|
||||
return recipeSteps;
|
||||
return recipeSteps == null ? new ArrayList<>() : recipeSteps;
|
||||
}
|
||||
|
||||
public void setRecipeSteps(List<RecipeStep> recipeSteps) {
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
|
@ -15,7 +15,7 @@ public class RecipeStep extends BeanModel implements Serializable {
|
|||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||
private int stepID;
|
||||
|
||||
@ManyToOne
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JsonIgnore
|
||||
private Recipe recipe;
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.model.dto;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class MixCreationFormDto {
|
||||
|
||||
private Recipe recipe;
|
||||
|
||||
private String mixTypeName;
|
||||
|
||||
private List<String> materials;
|
||||
|
||||
private List<Float> quantities;
|
||||
|
||||
public MixCreationFormDto() {
|
||||
}
|
||||
}
|
|
@ -1,27 +1,29 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.services;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.services;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.BeanModel;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.BeanModel;
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class GenericService<T extends BeanModel> implements IGenericService<T> {
|
||||
public abstract class GenericService<T extends BeanModel, R extends JpaRepository<T, Integer>> implements IGenericService<T> {
|
||||
|
||||
protected Logger logger = ColorRecipesExplorerApplication.logger;
|
||||
protected Logger logger = ColorRecipesExplorerApplication.LOGGER;
|
||||
|
||||
protected JpaRepository<T, Integer> dao;
|
||||
protected R dao;
|
||||
|
||||
public GenericService(JpaRepository<T, Integer> dao) {
|
||||
public GenericService(R dao) {
|
||||
this.dao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getByID(int id) {
|
||||
return dao.findById(id).get();
|
||||
public Optional<T> getByID(int id) {
|
||||
return dao.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,36 +32,42 @@ public abstract class GenericService<T extends BeanModel> implements IGenericSer
|
|||
}
|
||||
|
||||
@Override
|
||||
public T save(T entity) {
|
||||
public Optional<T> save(T entity) {
|
||||
if (isValidForCreation(entity)) {
|
||||
return dao.save(entity);
|
||||
return Optional.of(dao.save(entity));
|
||||
}
|
||||
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveAll(List<T> entities) {
|
||||
public boolean saveAll(Iterable<T> entities) {
|
||||
if (entities == null) return false;
|
||||
|
||||
for (T e : entities) {
|
||||
if (save(e) == null) {
|
||||
if (!save(e).isPresent()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
dao.saveAll(entities);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T update(T entity) {
|
||||
if (exists(entity)) {
|
||||
return dao.save(entity);
|
||||
public Optional<T> update(@NonNull T entity) {
|
||||
if (isValidForUpdate(entity)) {
|
||||
return Optional.of(dao.save(entity));
|
||||
}
|
||||
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(T entity) {
|
||||
if (entity == null) return false;
|
||||
|
||||
if (exists(entity)) {
|
||||
dao.delete(entity);
|
||||
return true;
|
||||
|
@ -70,12 +78,13 @@ public abstract class GenericService<T extends BeanModel> implements IGenericSer
|
|||
|
||||
@Override
|
||||
public boolean deleteAll(List<T> entities) {
|
||||
for (T e : entities) {
|
||||
if (!delete(e)) {
|
||||
return false;
|
||||
}
|
||||
if (entities == null) return false;
|
||||
|
||||
for (T entity : entities) {
|
||||
if (!exists(entity)) return false;
|
||||
}
|
||||
|
||||
dao.deleteAll(entities);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -89,6 +98,16 @@ public abstract class GenericService<T extends BeanModel> implements IGenericSer
|
|||
return entity != null && !exists(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si une entité est valide pour la création dans la base de données.
|
||||
*
|
||||
* @param entity L'entité à vérifier.
|
||||
* @return Si l'entité est valide pour l'édition.
|
||||
*/
|
||||
public boolean isValidForUpdate(@NonNull T entity) {
|
||||
return exists(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si une entité existe dans la base de données.
|
||||
*
|
||||
|
@ -97,7 +116,12 @@ public abstract class GenericService<T extends BeanModel> implements IGenericSer
|
|||
*/
|
||||
@Override
|
||||
public boolean exists(T entity) {
|
||||
return dao.findById(entity.getID()).isPresent();
|
||||
return entity != null && existsById(entity.getID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existsById(int id) {
|
||||
return dao.existsById(id);
|
||||
}
|
||||
|
||||
/**
|
|
@ -1,16 +1,17 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.services;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.services;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.BeanModel;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.BeanModel;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface IGenericService<T extends BeanModel> {
|
||||
|
||||
/**
|
||||
* Récupère toutes les entités du même type dans la base de données.
|
||||
*
|
||||
* @return Une liste de toutes les entités du même type.
|
||||
* @return Une collection contenant toutes les entités du même type.
|
||||
*/
|
||||
List<T> getAll();
|
||||
|
||||
|
@ -20,7 +21,7 @@ public interface IGenericService<T extends BeanModel> {
|
|||
* @param id L'identifiant de l'entité
|
||||
* @return L'entité correspondant à l'identifiant.
|
||||
*/
|
||||
T getByID(int id);
|
||||
Optional<T> getByID(int id);
|
||||
|
||||
/**
|
||||
* Sauvegarde une entité dans la base de données.
|
||||
|
@ -30,7 +31,7 @@ public interface IGenericService<T extends BeanModel> {
|
|||
* @param entity L'entité à sauvegarder
|
||||
* @return Si la sauvegarde a fonctionné.
|
||||
*/
|
||||
T save(T entity);
|
||||
Optional<T> save(T entity);
|
||||
|
||||
/**
|
||||
* Sauvegarde des entités dans la base de données.
|
||||
|
@ -41,7 +42,7 @@ public interface IGenericService<T extends BeanModel> {
|
|||
* @return Si la sauvegarde a fonctionné.
|
||||
*/
|
||||
@Transactional
|
||||
boolean saveAll(List<T> entities);
|
||||
boolean saveAll(Iterable<T> entities);
|
||||
|
||||
/**
|
||||
* Met à jour une entité dans la base de données.
|
||||
|
@ -51,7 +52,7 @@ public interface IGenericService<T extends BeanModel> {
|
|||
* @param entity L'entité à mettre à jour
|
||||
* @return Si la mise à jour a fonctionné.
|
||||
*/
|
||||
T update(T entity);
|
||||
Optional<T> update(T entity);
|
||||
|
||||
/**
|
||||
* Supprime une entité dans la base de données.
|
||||
|
@ -75,4 +76,6 @@ public interface IGenericService<T extends BeanModel> {
|
|||
boolean deleteAll(List<T> entities);
|
||||
|
||||
boolean exists(T entity);
|
||||
|
||||
boolean existsById(int id);
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.services;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.services;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Material;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Mix;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.MixQuantity;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -32,12 +34,13 @@ public class InventoryService {
|
|||
}
|
||||
|
||||
public boolean useMix(Mix mix, Map<Material, Float> quantities) {
|
||||
for (Material material : mix.getMixQuantities().stream().map(MixQuantity::getMaterial).collect(Collectors.toList())) {
|
||||
List<Material> materials = mix.getMixQuantities().stream().map(MixQuantity::getMaterial).collect(Collectors.toList());
|
||||
for (Material material : materials) {
|
||||
if (!material.isMixType()) {
|
||||
float quantity = quantities.get(material);
|
||||
|
||||
material.setInventoryQuantity(material.getInventoryQuantity() - quantity);
|
||||
if (materialService.update(material) == null) return false;
|
||||
if (!materialService.update(material).isPresent()) return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package fyloz.trial.ColorRecipesExplorer;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.services;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PasswordValidator {
|
||||
public class PasswordService {
|
||||
|
||||
private static List<String> passwords = new ArrayList<>();
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.dao.CompanyDao;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.dao.RecipeDao;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class CompanyService extends GenericService<Company, CompanyDao> {
|
||||
|
||||
private RecipeDao recipeDao; // Utilise le Dao pour éviter une erreur au démarrage, citant une récursion (CompanyService -> RecipeService -> CompanyService -> ...)
|
||||
|
||||
@Autowired
|
||||
public CompanyService(CompanyDao companyDao, RecipeDao recipeDao) {
|
||||
super(companyDao);
|
||||
this.recipeDao = recipeDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidForCreation(Company entity) {
|
||||
return super.isValidForCreation(entity) && !existsByName(entity.getCompanyName());
|
||||
}
|
||||
|
||||
public boolean existsByName(String name) {
|
||||
return dao.existsByCompanyName(name);
|
||||
}
|
||||
|
||||
public boolean isLinkedToRecipes(Company company) {
|
||||
return !recipeDao.findAllByCompany(company).isEmpty();
|
||||
}
|
||||
|
||||
public boolean deleteIfNotLinked(Company company) {
|
||||
if (company == null) return false;
|
||||
if (isLinkedToRecipes(company)) return false;
|
||||
|
||||
return delete(company);
|
||||
}
|
||||
}
|
|
@ -1,17 +1,23 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.services;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler;
|
||||
import fyloz.trial.ColorRecipesExplorer.dao.MaterialDao;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.dao.MaterialDao;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class MaterialService extends GenericService<Material> {
|
||||
public class MaterialService extends GenericService<Material, MaterialDao> {
|
||||
|
||||
private MixQuantityService mixQuantityService;
|
||||
|
||||
|
@ -21,14 +27,14 @@ public class MaterialService extends GenericService<Material> {
|
|||
this.mixQuantityService = mixQuantityService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère la produit ayant le code spécifié dans la base de données.
|
||||
*
|
||||
* @param materialCode Le code du produit
|
||||
* @return Le produit correspondant au code.
|
||||
*/
|
||||
public Material getByMaterialCode(String materialCode) {
|
||||
return ((MaterialDao) dao).findByMaterialCode(materialCode);
|
||||
public Optional<Material> getByMaterialCode(String materialCode) {
|
||||
return dao.findByMaterialCode(materialCode);
|
||||
}
|
||||
|
||||
public List<Material> getAllByMaterialType(MaterialType materialType) {
|
||||
if (materialType == null) return new ArrayList<>();
|
||||
|
||||
return dao.findAllByMaterialType(materialType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,21 +44,43 @@ public class MaterialService extends GenericService<Material> {
|
|||
* @return Si le produit est lié à d'autres mélanges.
|
||||
*/
|
||||
public boolean isLinkedToMixes(Material material) {
|
||||
return !mixQuantityService.getByMaterial(material).isEmpty();
|
||||
return mixQuantityService.existsByMaterial(material);
|
||||
}
|
||||
|
||||
public boolean deleteIfNotLinked(Material material) {
|
||||
if (!isLinkedToMixes(material)) {
|
||||
return super.delete(material);
|
||||
return delete(material);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(Material entity) {
|
||||
Material material = getByMaterialCode(entity.getMaterialCode());
|
||||
return super.exists(entity) || material != null;
|
||||
public boolean exists(Material material) {
|
||||
return material != null && (super.exists(material) || dao.existsByMaterialCode(material.getMaterialCode()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidForUpdate(Material material) {
|
||||
if (material == null) return false;
|
||||
|
||||
Optional<Material> materialByCode = dao.findByMaterialCode(material.getMaterialCode());
|
||||
return super.isValidForUpdate(material) && (!materialByCode.isPresent() || material.getMaterialID().equals(materialByCode.get().getMaterialID()));
|
||||
}
|
||||
|
||||
public List<Material> getAllBySearchString(String searchString) {
|
||||
return dao.findAllByMaterialCodeContainingIgnoreCase(searchString).stream().filter(m -> !m.isMixType()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un FileHandler pour le produit passé en paramètre.
|
||||
*
|
||||
* @param material Le produit dont on veut créer un FileHandler
|
||||
* @return Le FileHandler correspondant au produit.
|
||||
*/
|
||||
private FileHandler getFileHandlerForMaterial(Material material) {
|
||||
String filename = String.format("%s_%s", material.getMaterialID(), material.getMaterialCode());
|
||||
return new FileHandler(filename, FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,9 +94,9 @@ public class MaterialService extends GenericService<Material> {
|
|||
* @return Si le fichier SIMDUT à bien été créé ou non.
|
||||
*/
|
||||
public boolean addSimdut(MultipartFile simdut, Material material) {
|
||||
if (simdut.getSize() <= 0) return true;
|
||||
if (simdut.getSize() <= 0) return false;
|
||||
|
||||
FileHandler fileHandler = getFilesServiceForMaterial(material);
|
||||
FileHandler fileHandler = getFileHandlerForMaterial(material);
|
||||
|
||||
if (!fileHandler.createFile()) {
|
||||
return false;
|
||||
|
@ -92,7 +120,7 @@ public class MaterialService extends GenericService<Material> {
|
|||
* @return Si la suppression du fichier SIMDUT s'est effectuée.
|
||||
*/
|
||||
public boolean removeSimdut(Material material) {
|
||||
FileHandler fileHandler = getFilesServiceForMaterial(material);
|
||||
FileHandler fileHandler = getFileHandlerForMaterial(material);
|
||||
|
||||
if (fileHandler.getFile().exists()) {
|
||||
return fileHandler.deleteFile();
|
||||
|
@ -100,15 +128,4 @@ public class MaterialService extends GenericService<Material> {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un FileHandler pour le produit passé en paramètre.
|
||||
*
|
||||
* @param material Le produit dont on veut créer un FileHandler
|
||||
* @return Le FileHandler correspondant au produit.
|
||||
*/
|
||||
private FileHandler getFilesServiceForMaterial(Material material) {
|
||||
String filename = String.format("%s_%s", material.getMaterialID(), material.getMaterialCode());
|
||||
return new FileHandler(filename, FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.dao.MaterialTypeDao;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class MaterialTypeService extends GenericService<MaterialType, MaterialTypeDao> {
|
||||
|
||||
private MaterialService materialService;
|
||||
|
||||
@Autowired
|
||||
public MaterialTypeService(MaterialTypeDao materialTypeDao, MaterialService materialService) {
|
||||
super(materialTypeDao);
|
||||
this.materialService = materialService;
|
||||
}
|
||||
|
||||
public boolean isLinkedToMaterials(MaterialType materialType) {
|
||||
return !materialService.getAllByMaterialType(materialType).isEmpty();
|
||||
}
|
||||
|
||||
public boolean deleteIfNotLinked(MaterialType materialType) {
|
||||
if (!isLinkedToMaterials(materialType)) {
|
||||
return delete(materialType);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidForCreation(MaterialType entity) {
|
||||
return entity != null && !existsByName(entity.getMaterialTypeName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidForUpdate(MaterialType materialType) {
|
||||
return super.isValidForUpdate(materialType)
|
||||
&& isValidForUpdateName(materialType)
|
||||
&& isValidForUpdatePrefix(materialType);
|
||||
}
|
||||
|
||||
public boolean isValidForUpdateName(MaterialType materialType) {
|
||||
Optional<MaterialType> materialTypeByName = dao.findByMaterialTypeName(materialType.getMaterialTypeName());
|
||||
|
||||
return !materialTypeByName.isPresent() || materialType.getMaterialTypeID().equals(materialTypeByName.get().getMaterialTypeID());
|
||||
}
|
||||
|
||||
public boolean isValidForUpdatePrefix(MaterialType materialType) {
|
||||
Optional<MaterialType> materialTypeByPrefix = dao.findByPrefix(materialType.getPrefix());
|
||||
|
||||
return !materialTypeByPrefix.isPresent() || materialType.getMaterialTypeID().equals(materialTypeByPrefix.get().getMaterialTypeID());
|
||||
}
|
||||
|
||||
public Optional<MaterialType> getByName(String name) {
|
||||
return dao.findByMaterialTypeName(name);
|
||||
}
|
||||
|
||||
public Optional<MaterialType> getDefaultMaterialType() {
|
||||
return getByName(MaterialType.DEFAULT_MATERIAL_TYPE_NAME);
|
||||
}
|
||||
|
||||
public boolean existsByName(String name) {
|
||||
return getByName(name).isPresent();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.dao.MixQuantityDao;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MixQuantityService extends GenericService<MixQuantity, MixQuantityDao> {
|
||||
|
||||
@Autowired
|
||||
public MixQuantityService(MixQuantityDao mixQuantityDao) {
|
||||
super(mixQuantityDao);
|
||||
}
|
||||
|
||||
public boolean existsByMaterial(Material material) {
|
||||
return dao.existsByMaterial(material);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.*;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.dto.MixCreationFormDto;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.dao.MixDao;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class MixService extends GenericService<Mix, MixDao> {
|
||||
|
||||
private MaterialService materialService;
|
||||
private MixQuantityService mixQuantityService;
|
||||
private MixTypeService mixTypeService;
|
||||
private RecipeService recipeService;
|
||||
|
||||
@Autowired
|
||||
public MixService(MixDao mixDao, MaterialService materialService, MixQuantityService mixQuantityService, MixTypeService mixTypeService, RecipeService recipeService) {
|
||||
super(mixDao);
|
||||
this.materialService = materialService;
|
||||
this.mixQuantityService = mixQuantityService;
|
||||
this.mixTypeService = mixTypeService;
|
||||
this.recipeService = recipeService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ModelResponseBuilder create(MixCreationFormDto formDto, @NotNull Recipe recipe) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
|
||||
|
||||
List<Material> materials = new ArrayList<>();
|
||||
for (String materialCode : formDto.getMaterials()) {
|
||||
Optional<Material> found = materialService.getByMaterialCode(materialCode);
|
||||
if (!found.isPresent()) {
|
||||
return modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND_BY_NAME, materialCode);
|
||||
}
|
||||
|
||||
materials.add(found.get());
|
||||
}
|
||||
|
||||
Optional<MixType> optionalMixType = mixTypeService.createByName(formDto.getMixTypeName());
|
||||
if (!optionalMixType.isPresent()) return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
|
||||
MixType mixType = optionalMixType.get();
|
||||
if (recipeService.hasMixType(recipe, mixType))
|
||||
return modelResponseBuilder.addResponseCode(ResponseCode.MIX_TYPE_ALREADY_USED, mixType.getTypeName());
|
||||
|
||||
// Crée le mélange en premier pour avoir accès à son ID pour les autres éléments
|
||||
Mix mix = new Mix(recipe, mixType, null);
|
||||
|
||||
Optional<Mix> savedMix = save(mix);
|
||||
if (savedMix.isPresent()) {
|
||||
mix = savedMix.get();
|
||||
|
||||
List<MixQuantity> mixQuantities = createMixQuantities(savedMix.get(), materials, formDto.getQuantities());
|
||||
mix.setMixQuantities(mixQuantities);
|
||||
|
||||
// Retourne aucune erreur s'il la mise à jour à lieu
|
||||
if (update(mix).isPresent()) return null;
|
||||
|
||||
deleteMix(mix);
|
||||
}
|
||||
|
||||
return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ModelResponseBuilder edit(Mix mix, MixCreationFormDto formDto) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
|
||||
|
||||
List<Material> materials = new ArrayList<>();
|
||||
for (String materialCode : formDto.getMaterials()) {
|
||||
Optional<Material> found = materialService.getByMaterialCode(materialCode);
|
||||
if (!found.isPresent()) {
|
||||
return modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND_BY_NAME, materialCode);
|
||||
}
|
||||
|
||||
materials.add(found.get());
|
||||
}
|
||||
|
||||
List<MixQuantity> mixQuantities = createMixQuantities(mix, materials, formDto.getQuantities());
|
||||
|
||||
// Supprime les anciens MixQuantity pour éviter les doublons et les entrées inutiles dans la base de données
|
||||
if (!mixQuantityService.deleteAll(mix.getMixQuantities())) {
|
||||
return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
}
|
||||
|
||||
mix.setMixQuantities(mixQuantities);
|
||||
if (update(mix).isPresent()) return null;
|
||||
else return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
}
|
||||
|
||||
public boolean deleteMix(Mix mix) {
|
||||
if (mixQuantityService.deleteAll(mix.getMixQuantities())) {
|
||||
return super.delete(mix);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une liste de MixQuantity, pour la création d'un mélange
|
||||
*
|
||||
* @param mix Le mélange associé aux MixQuantity
|
||||
* @param materials Les matériaux
|
||||
* @param quantities Les quantités
|
||||
* @return La liste des MixQuantity créés.
|
||||
*/
|
||||
public List<MixQuantity> createMixQuantities(Mix mix, List<Material> materials, List<Float> quantities) {
|
||||
List<MixQuantity> mixQuantities = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < materials.size(); i++) {
|
||||
Material material = materials.get(i);
|
||||
float quantity = quantities.get(i);
|
||||
|
||||
MixQuantity mixQuantity = new MixQuantity(mix, material, quantity);
|
||||
mixQuantities.add(mixQuantity);
|
||||
}
|
||||
|
||||
return mixQuantities;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.dao.MixTypeDao;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class MixTypeService extends GenericService<MixType, MixTypeDao> {
|
||||
|
||||
private MaterialTypeService materialTypeService;
|
||||
|
||||
@Autowired
|
||||
public MixTypeService(MixTypeDao mixTypeDao, MaterialTypeService materialTypeService) {
|
||||
super(mixTypeDao);
|
||||
this.materialTypeService = materialTypeService;
|
||||
}
|
||||
|
||||
public Optional<MixType> getByName(String name) {
|
||||
return dao.findByTypeName(name);
|
||||
}
|
||||
|
||||
public Optional<MixType> getByMaterial(Material material) {
|
||||
return dao.findByMaterial(material);
|
||||
}
|
||||
|
||||
public Optional<MixType> createByName(String name) {
|
||||
Optional<MaterialType> defaultType = materialTypeService.getDefaultMaterialType();
|
||||
if (!defaultType.isPresent()) return Optional.empty();
|
||||
|
||||
Optional<MixType> mixTypeByName = getByName(name);
|
||||
if (mixTypeByName.isPresent()) {
|
||||
return mixTypeByName;
|
||||
}
|
||||
|
||||
Material mixTypeMaterial = new Material(name, 0, true, defaultType.get());
|
||||
MixType mixType = new MixType(name, mixTypeMaterial);
|
||||
|
||||
return save(mixType);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.file.ImageHandler;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.*;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.dao.RecipeDao;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class RecipeService extends GenericService<Recipe, RecipeDao> {
|
||||
|
||||
private CompanyService companyService;
|
||||
private StepService stepService;
|
||||
|
||||
@Autowired
|
||||
public RecipeService(RecipeDao recipeDao, CompanyService companyService, StepService stepService) {
|
||||
super(recipeDao);
|
||||
this.companyService = companyService;
|
||||
this.stepService = stepService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère la liste des recettes associées à une compagnie.
|
||||
*
|
||||
* @param company La compagnie.
|
||||
* @return La liste des recettes associées à cette compagnie.
|
||||
*/
|
||||
public List<Recipe> getByCompany(Company company) {
|
||||
return dao.findAllByCompany(company);
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère une liste triée des mélanges pour une recette.
|
||||
*
|
||||
* @param recipe La recette dont on veut récupérer les mélanges
|
||||
* @return Une liste triée des mélanges.
|
||||
*/
|
||||
public List<Mix> getSortedMixes(Recipe recipe) {
|
||||
List<Mix> mixes = recipe.getRecipeMixes();
|
||||
mixes.sort(Comparator.comparing(Mix::getMixID));
|
||||
return mixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère toutes les recettes dans la base de données et les classes par compagnie.
|
||||
*
|
||||
* @return Un Map contenant les recettes classées par compagnie.
|
||||
*/
|
||||
public Map<Company, List<Recipe>> getRecipesByCompany() {
|
||||
return mappedByCompany(getAll());
|
||||
}
|
||||
|
||||
public Optional<Recipe> updateRecipe(Recipe newRecipe, Recipe storedRecipe, MultiValueMap<String, Object> form) {
|
||||
storedRecipe.setRecipeCode(newRecipe.getRecipeCode());
|
||||
storedRecipe.setCompany(newRecipe.getCompany());
|
||||
storedRecipe.setRecipeDescription(newRecipe.getRecipeDescription());
|
||||
storedRecipe.setSample(newRecipe.getSample());
|
||||
storedRecipe.setApprobationDate(newRecipe.getApprobationDate());
|
||||
storedRecipe.setRemark(newRecipe.getRemark());
|
||||
storedRecipe.setNote(newRecipe.getNote());
|
||||
|
||||
Optional<Recipe> optionalRecipe = convertAndCreateSteps(storedRecipe, form);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return update(optionalRecipe.get());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean deleteRecipe(Recipe recipe) {
|
||||
if (!delete(recipe)) return false;
|
||||
return removeAllFiles(recipe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère le nom des images liées à une recette.
|
||||
*
|
||||
* @param recipe La recette dont on veut récupérer les images
|
||||
* @return Une liste contenant le nom des images liées à la recette.
|
||||
*/
|
||||
public List<String> getImageFiles(Recipe recipe) {
|
||||
int recipeID = recipe.getRecipeID();
|
||||
String recipeCode = recipe.getRecipeCode();
|
||||
String fileName = String.format("%s_%s", recipeID, recipeCode);
|
||||
|
||||
File imageLocation = new File(ImageHandler.IMAGES_LOCATION);
|
||||
File[] result = imageLocation.listFiles((d, n) -> n.startsWith(fileName) && n.endsWith("jpeg"));
|
||||
|
||||
if (result == null) return new ArrayList<>();
|
||||
|
||||
return Arrays.stream(result).map(File::getName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les types de mélanges associés à la recette.
|
||||
*
|
||||
* @param recipe La recette dont on veut récupérer les types de mélange
|
||||
* @return Une liste contenant les types de mélanges.
|
||||
*/
|
||||
public List<MixType> getAssociatedMixesTypes(Recipe recipe) {
|
||||
return recipe
|
||||
.getRecipeMixes()
|
||||
.stream()
|
||||
.map(Mix::getMixType)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si une recette contient un mélange ayant le type de mélange spécifié.
|
||||
*
|
||||
* @param recipe La recette
|
||||
* @param mixType Le type de mélange
|
||||
* @return Si la recette contient le type de mélange
|
||||
*/
|
||||
public boolean hasMixType(Recipe recipe, MixType mixType) {
|
||||
return getAssociatedMixesTypes(recipe)
|
||||
.contains(mixType);
|
||||
}
|
||||
|
||||
public Map<Company, List<Recipe>> getRecipesForSearchString(String searchString) {
|
||||
List<Recipe> recipes = dao.findAllByRecipeDescriptionContainsOrRecipeCodeContains(searchString.toUpperCase());
|
||||
|
||||
return mappedByCompany(recipes);
|
||||
}
|
||||
|
||||
private Map<Company, List<Recipe>> mappedByCompany(List<Recipe> recipes) {
|
||||
List<Company> companies = companyService.getAll();
|
||||
Map<Company, List<Recipe>> mappedRecipes = new HashMap<>();
|
||||
|
||||
for (Company c : companies) {
|
||||
List<Recipe> recipesForCompany = recipes.stream().filter(r -> r.getCompany().equals(c)).collect(Collectors.toList());
|
||||
|
||||
if (recipesForCompany.size() > 0) {
|
||||
mappedRecipes.put(c, recipesForCompany);
|
||||
}
|
||||
}
|
||||
|
||||
return mappedRecipes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée et assigne des étapes à une recette, en se basant sur l'entrée de utilisateur.
|
||||
*
|
||||
* @param recipe La recette à assigner les étapes
|
||||
* @param input L'entrée de l'utilisateur, contenant les étapes (key = "step_*")
|
||||
* @return La recette avec les étapes.
|
||||
*/
|
||||
@Transactional
|
||||
public Optional<Recipe> convertAndCreateSteps(Recipe recipe, MultiValueMap<String, Object> input) {
|
||||
if (recipe == null || input == null) return Optional.empty();
|
||||
|
||||
// Convertit les étapes en RecipeSteps
|
||||
List<RecipeStep> steps = new ArrayList<>();
|
||||
if (input.containsKey("step")) {
|
||||
Object field = input.get("step");
|
||||
|
||||
if (field instanceof LinkedList && ((LinkedList) field).getFirst() instanceof String) {
|
||||
for (String step : (LinkedList<String>) field) {
|
||||
steps.add(new RecipeStep(recipe, step));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return setSteps(recipe, steps);
|
||||
}
|
||||
|
||||
private Optional<Recipe> setSteps(Recipe recipe, List<RecipeStep> steps) {
|
||||
if (!stepService.deleteAll(recipe.getRecipeSteps())) return Optional.empty();
|
||||
|
||||
recipe.setRecipeSteps(null);
|
||||
update(recipe);
|
||||
|
||||
recipe.setRecipeSteps(steps);
|
||||
return Optional.of(recipe);
|
||||
}
|
||||
|
||||
private boolean removeAllFiles(Recipe recipe) {
|
||||
FileHandler fileHandler;
|
||||
for (String image : getImageFiles(recipe)) {
|
||||
fileHandler = new FileHandler(image.replace(".jpeg", ""), FileHandler.FileContext.IMAGE, FileHandler.FileExtension.JPEG);
|
||||
|
||||
if (!fileHandler.deleteFile()) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.dao.StepDao;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class StepService extends GenericService<RecipeStep, StepDao> {
|
||||
|
||||
@Autowired
|
||||
public StepService(StepDao stepDao) {
|
||||
super(stepDao);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.utils;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public class ControllerUtils {
|
||||
|
||||
public static String redirect(String viewName) {
|
||||
return String.format("redirect:/%s", viewName);
|
||||
}
|
||||
|
||||
public static String getCurrentBaseUrl() {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
|
||||
String port = ":" + (ColorRecipesExplorerApplication.USE_PORT ? request.getServerPort() : "");
|
||||
return String.format("%s://%s%s%s", request.getScheme(), request.getServerName(), port, request.getContextPath());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.utils;
|
||||
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
public static String readClasspathFile(ResourceLoader loader, String path) {
|
||||
try (InputStream stream = loader.getResource(path).getInputStream()) {
|
||||
byte[] data = FileCopyUtils.copyToByteArray(stream);
|
||||
return new String(data, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,13 +1,11 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.dao;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.dao;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Company;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface CompanyDao extends JpaRepository<Company, Integer> {
|
||||
|
||||
void deleteByCompanyID(int companyID);
|
||||
|
||||
Company findByCompanyName(String companyName);
|
||||
boolean existsByCompanyName(String companyName);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.dao;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface MaterialDao extends JpaRepository<Material, Integer> {
|
||||
Optional<Material> findByMaterialCode(String materialCode);
|
||||
|
||||
List<Material> findAllByMaterialType(MaterialType materialType);
|
||||
|
||||
List<Material> findAllByMaterialCodeContainingIgnoreCase(String stringSearch);
|
||||
|
||||
boolean existsByMaterialCode(String materialCode);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.dao;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface MaterialTypeDao extends JpaRepository<MaterialType, Integer> {
|
||||
|
||||
Optional<MaterialType> findByMaterialTypeName(String name);
|
||||
|
||||
Optional<MaterialType> findByPrefix(String prefix);
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.dao;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.dao;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Mix;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.dao;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.dao;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Material;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.MixQuantity;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||
|
||||
@Repository
|
||||
public interface MixQuantityDao extends JpaRepository<MixQuantity, Integer> {
|
||||
MixQuantity findByMixQuantityID(int mixQuantityID);
|
||||
|
||||
List<MixQuantity> findAllByMaterial(Material material);
|
||||
|
||||
boolean existsByMaterial(Material material);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.dao;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface MixTypeDao extends JpaRepository<MixType, Integer> {
|
||||
Optional<MixType> findByTypeName(String typeName);
|
||||
|
||||
Optional<MixType> findByMaterial(Material material);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.dao;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface RecipeDao extends JpaRepository<Recipe, Integer> {
|
||||
|
||||
List<Recipe> findAllByCompany(Company company);
|
||||
|
||||
Recipe findByRecipeCode(String recipeCode);
|
||||
|
||||
Recipe findByRecipeID(int recipeID);
|
||||
|
||||
@Query("select r from Recipe r where upper(r.recipeCode) like %?1% or upper(r.recipeDescription) like %?1%")
|
||||
List<Recipe> findAllByRecipeDescriptionContainsOrRecipeCodeContains(String searchWordUpperCase);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.dao;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.dao;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Recipe;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.RecipeStep;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
|
@ -1,17 +1,25 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.web;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.web;
|
||||
|
||||
public class PagesPaths {
|
||||
// Autres
|
||||
public static final String INDEX = "index";
|
||||
public static final String SEARCH = "search";
|
||||
public static final String SEARCH_INVENTORY = "inventory/search";
|
||||
public static final String SIMDUT_FILES = "simdut/{materialID}";
|
||||
public static final String PASSWORD_VALIDATION = "password/valid";
|
||||
public static final String TOUCHUP = "touchup";
|
||||
public static final String RECIPE_XLS = "recipe/xls/{recipeID}";
|
||||
public static final String ALL_RECIPES_XLS = "recipe/xls";
|
||||
public static final String ERROR = "error";
|
||||
public static final String CLOSE_TAB = "closeTab";
|
||||
public static final String UPDATES = "updates";
|
||||
public static final String UPDATES_GET = "updates/get";
|
||||
|
||||
// Images
|
||||
public static final String IMAGES_FILES = "images/{image}";
|
||||
public static final String ADD_IMAGE = "images/add";
|
||||
public static final String ADD_IMAGE_SPECIFIC = "images/add/{recipeID}";
|
||||
public static final String DELETE_IMAGE = "images/deleteIfNotLinked";
|
||||
public static final String DELETE_IMAGE = "images/delete";
|
||||
|
||||
// Inventaire
|
||||
public static final String INVENTORY = "inventory";
|
||||
|
@ -47,6 +55,11 @@ public class PagesPaths {
|
|||
|
||||
// Types de matériaux
|
||||
public static final String CREATOR_MATERIAL_TYPE = "materialType/creator";
|
||||
public static final String REMOVER_MATERIAL_TYPE = "materialType/remover";
|
||||
public static final String REMOVER_MATERIAL_TYPE_SPECIFIC = "materialType/remover/{materialTypeID}";
|
||||
public static final String EDITOR_MATERIAL_TYPE = "materialType/editor";
|
||||
public static final String EDITOR_MATERIAL_TYPE_SPECIFIC = "materialType/editor/{materialTypeID}";
|
||||
public static final String EDITOR_MATERIAL_TYPE_EDITOR = "materialType/edit";
|
||||
|
||||
// Mélanges
|
||||
public static final String CREATOR_MIX = "mix/creator";
|
||||
|
@ -54,4 +67,6 @@ public class PagesPaths {
|
|||
public static final String EDITOR_MIX = "mix/editor";
|
||||
public static final String EDITOR_MIX_SPECIFIC = "mix/editor/{mixID}";
|
||||
public static final String REMOVER_MIX_SPECIFIC = "mix/remover/{mixID}";
|
||||
public static final String MATERIAL_SELECTOR_MIX = "mix/selector/{recipeID}/{mixID}";
|
||||
public static final String MATERIAL_SELECTOR_FRAGMENT = "mix/selector.html :: materialSelector";
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.web;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.web;
|
||||
|
||||
public class StringBank {
|
||||
|
||||
|
@ -48,8 +48,4 @@ public class StringBank {
|
|||
public static final String COMPANY = "company";
|
||||
public static final String COMPANY_ID = "companyID";
|
||||
|
||||
public static final String UPLOAD_LOCATION = System.getProperty("upload.location");
|
||||
public static final String IMAGES_LOCATION = UPLOAD_LOCATION + "/images";
|
||||
public static final String SIMDUTS_LOCATION = UPLOAD_LOCATION + "/simdut/";
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.ERROR;
|
||||
|
||||
@Controller
|
||||
public class CREErrorController implements ErrorController {
|
||||
|
||||
@RequestMapping("/error")
|
||||
public ModelAndView handleError(HttpServletRequest request) {
|
||||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder("error");
|
||||
responseBuilder.addAttribute("referer", request.getHeader("referer"));
|
||||
|
||||
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
|
||||
|
||||
ResponseCode responseCode = ResponseCode._500;
|
||||
if (status != null) {
|
||||
int statusCode = Integer.parseInt(status.toString());
|
||||
|
||||
switch (statusCode) {
|
||||
case 401:
|
||||
responseCode = ResponseCode._401;
|
||||
break;
|
||||
case 404:
|
||||
responseCode = ResponseCode._404;
|
||||
break;
|
||||
default:
|
||||
responseCode = ResponseCode._500;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
responseBuilder.addResponseCode(responseCode);
|
||||
return responseBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorPath() {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,14 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.web.controller;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.web.controller;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ResponseCode;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.io.ImageHandler;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Recipe;
|
||||
import fyloz.trial.ColorRecipesExplorer.services.RecipeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.file.ImageHandler;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
@ -17,15 +19,13 @@ import org.springframework.web.bind.annotation.*;
|
|||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static fyloz.trial.ColorRecipesExplorer.core.utils.ControllerUtils.redirect;
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*;
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.StringBank.ERROR_SAVING_IMAGE;
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.StringBank.RESPONSE_ERROR;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
|
||||
@Controller
|
||||
public class ImageFilesController {
|
||||
|
@ -68,9 +68,9 @@ public class ImageFilesController {
|
|||
*/
|
||||
@GetMapping(ADD_IMAGE_SPECIFIC)
|
||||
public ModelAndView showPage(ModelAndView model, @PathVariable int recipeID) {
|
||||
return new ModelBuilder(model)
|
||||
.setView(ADD_IMAGE)
|
||||
.addData(ModelDataType.RECIPE_ID, recipeID)
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(ADD_IMAGE)
|
||||
.addResponseData(ResponseDataType.RECIPE_ID, recipeID)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -95,37 +95,45 @@ public class ImageFilesController {
|
|||
* @return La page à afficher.
|
||||
*/
|
||||
@PostMapping(ADD_IMAGE)
|
||||
public ModelAndView addImage(int recipeID, MultipartFile image) {
|
||||
ModelBuilder modelBuilder = new ModelBuilder(redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(recipeID))));
|
||||
Recipe recipe = recipeService.getByID(recipeID);
|
||||
public ModelAndView addImage(int recipeID, MultipartFile image) throws IOException {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(recipeID))));
|
||||
|
||||
if (recipe == null) {
|
||||
modelBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, String.valueOf(recipeID));
|
||||
|
||||
return showPage(modelBuilder.build(), recipeID);
|
||||
// Vérifie que le fichier est bien une image
|
||||
if (ImageIO.read(image.getInputStream()) == null) {
|
||||
return showPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.FILE_NOT_IMAGE)
|
||||
.build(), recipeID);
|
||||
}
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
return showPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
.build(), recipeID);
|
||||
}
|
||||
|
||||
Recipe recipe = optionalRecipe.get();
|
||||
ImageHandler imageHandler = new ImageHandler(recipe, recipeService);
|
||||
if (!imageHandler.createFile()) {
|
||||
modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE);
|
||||
|
||||
return showPage(modelBuilder.build(), recipeID);
|
||||
return showPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE)
|
||||
.build(), recipeID);
|
||||
}
|
||||
|
||||
modelBuilder
|
||||
.addData(ModelDataType.RECIPE_CODE, recipe.getRecipeCode())
|
||||
.addData(ModelDataType.RECIPE_ID, recipe.getRecipeID());
|
||||
modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.RECIPE_CODE, recipe.getRecipeCode())
|
||||
.addResponseData(ResponseDataType.RECIPE_ID, recipe.getRecipeID());
|
||||
|
||||
try {
|
||||
// Si je n'utilise pas le path, il cherche un fichier dans les tmp ?
|
||||
image.transferTo(new File(imageHandler.getFile().getAbsolutePath()));
|
||||
|
||||
return modelBuilder.build();
|
||||
return modelResponseBuilder.build();
|
||||
} catch (IOException e) {
|
||||
ColorRecipesExplorerApplication.logger.error("Erreur inconnue lors de la création d'une image", e);
|
||||
modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE);
|
||||
ColorRecipesExplorerApplication.LOGGER.error("Erreur inconnue lors de la création d'une image", e);
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE);
|
||||
|
||||
return showPage(modelBuilder.build(), recipeID);
|
||||
return showPage(modelResponseBuilder.build(), recipeID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,18 +150,18 @@ public class ImageFilesController {
|
|||
* REQUIERT UNE AUTORISATION
|
||||
*
|
||||
* @param form Le formulaire contenant les informations sur l'opération
|
||||
* @return La réponse sous forme de Map (-> Json)
|
||||
* @return La réponse sous forme de Map (pour y accéder en Json)
|
||||
*/
|
||||
@PostMapping(value = DELETE_IMAGE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public Map<String, String> deleteImage(@RequestBody Map<String, String> form) {
|
||||
Map<String, String> response = new HashMap<>();
|
||||
public Map<String, Object> deleteImage(@RequestBody Map<String, String> form) {
|
||||
JSONResponseBuilder responseBuilder = new JSONResponseBuilder();
|
||||
|
||||
ImageHandler imageHandler = new ImageHandler(form.get("image"), recipeService);
|
||||
if (!imageHandler.deleteFile()) {
|
||||
response.put(RESPONSE_ERROR, ERROR_SAVING_IMAGE);
|
||||
responseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE);
|
||||
}
|
||||
|
||||
return response;
|
||||
return responseBuilder.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.PasswordService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
|
||||
@Controller
|
||||
public class IndexController {
|
||||
|
||||
private CompanyService companyService;
|
||||
private RecipeService recipeService;
|
||||
|
||||
@Autowired
|
||||
public IndexController(CompanyService companyService, RecipeService recipeService) {
|
||||
this.companyService = companyService;
|
||||
this.recipeService = recipeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la page d'acceuil.
|
||||
*
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping({INDEX, "/"})
|
||||
public ModelAndView showPage() {
|
||||
List<Company> companies = companyService.getAll();
|
||||
Map<Company, List<Recipe>> recipes = new HashMap<>();
|
||||
|
||||
for (Company company : companies) {
|
||||
recipes.put(company, recipeService.getByCompany(company));
|
||||
}
|
||||
|
||||
return new ModelResponseBuilder(INDEX)
|
||||
.addResponseData(ResponseDataType.RECIPE_MAP, recipes)
|
||||
.build();
|
||||
}
|
||||
|
||||
@GetMapping(value = SEARCH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public Map<String, Object> searchWord(@RequestParam String searchString) {
|
||||
Map<Company, List<Recipe>> searchResult = recipeService.getRecipesForSearchString(searchString);
|
||||
Map<Integer, List<Integer>> outputResult = new HashMap<>();
|
||||
|
||||
for (Company c : searchResult.keySet()) {
|
||||
outputResult.put(c.getCompanyID(), searchResult.get(c).stream().map(Recipe::getRecipeID).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return new JSONResponseBuilder()
|
||||
.addAttribute("result", outputResult)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide un mot de passe reçu dans une requête HTTP POST, dans le champ "password".
|
||||
*
|
||||
* @param data Corps de la requête HTTP
|
||||
* @return Si le mot de passe est valide.
|
||||
*/
|
||||
@PostMapping(value = PASSWORD_VALIDATION, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public boolean validatePassword(@RequestBody Map<String, Object> data) {
|
||||
return PasswordService.isValid((String) data.get("password"));
|
||||
}
|
||||
}
|
|
@ -1,33 +1,28 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.web.controller;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.web.controller;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Material;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Mix;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.MixQuantity;
|
||||
import fyloz.trial.ColorRecipesExplorer.services.InventoryService;
|
||||
import fyloz.trial.ColorRecipesExplorer.services.MaterialService;
|
||||
import fyloz.trial.ColorRecipesExplorer.services.MaterialTypeService;
|
||||
import fyloz.trial.ColorRecipesExplorer.services.MixService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.InventoryService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.INVENTORY;
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.USE_INVENTORY;
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.StringBank.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.RESPONSE_REASON;
|
||||
|
||||
@Controller
|
||||
public class InventoryController {
|
||||
|
@ -45,19 +40,12 @@ public class InventoryController {
|
|||
this.materialTypeService = materialTypeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la page de l'inventaire.
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - materials: Contient la liste de tous les matériaux
|
||||
*
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(INVENTORY)
|
||||
public ModelAndView getInventory(ModelAndView model) {
|
||||
return new ModelBuilder(INVENTORY)
|
||||
.addData(ModelDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
|
||||
.addData(ModelDataType.MATERIAL_TYPES, materialTypeService.getAll())
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(INVENTORY)
|
||||
.addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -83,14 +71,14 @@ public class InventoryController {
|
|||
* - success: Contient le message à affiche lors du succès de la méthode
|
||||
*
|
||||
* @param form Le JSON contenant les quantités à utiliser.
|
||||
* @return Une réponse sous forme de Map (-> Json).
|
||||
* @return Une réponse sous forme de Map (vers Json).
|
||||
*/
|
||||
@PostMapping(value = USE_INVENTORY, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
@Transactional
|
||||
// TODO traduits les méthodes JSON
|
||||
public Map<String, String> consumeMaterials(@RequestBody Map<String, Object> form) {
|
||||
Map<String, String> response = new HashMap<>();
|
||||
// TODO traduit les méthodes JSON
|
||||
public Map<String, Object> consumeMaterials(@RequestBody Map<String, Object> form) {
|
||||
JSONResponseBuilder responseBuilder = new JSONResponseBuilder();
|
||||
|
||||
List<Mix> mixes = new ArrayList<>();
|
||||
Map<Mix, Map<Material, Float>> quantities = new HashMap<>();
|
||||
|
@ -98,12 +86,14 @@ public class InventoryController {
|
|||
for (String mixIDStr : form.keySet()) {
|
||||
int mixID = Integer.parseInt(mixIDStr);
|
||||
|
||||
Mix mix = mixService.getByID(mixID);
|
||||
if (mix == null) {
|
||||
response.put(RESPONSE_ERROR, String.format(MIX_NOT_FOUND, mixID));
|
||||
return response;
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
if (!optionalMix.isPresent()) {
|
||||
return responseBuilder
|
||||
.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID)
|
||||
.build();
|
||||
}
|
||||
|
||||
Mix mix = optionalMix.get();
|
||||
mixes.add(mix);
|
||||
|
||||
Map<String, String> formMaterials = (Map<String, String>) form.get(mixIDStr);
|
||||
|
@ -123,20 +113,36 @@ public class InventoryController {
|
|||
for (Mix mix : mixes) {
|
||||
String errorCode = inventoryService.checkQuantities(mix, quantities.get(mix));
|
||||
if (errorCode != null) {
|
||||
response.put(RESPONSE_ERROR, String.format(NOT_ENOUGH_MATERIAL, materialService.getByID(Integer.parseInt(errorCode.split("-")[1])).getMaterialCode()));
|
||||
response.put(RESPONSE_REASON, errorCode);
|
||||
return response;
|
||||
String materialCode = materialService.getByID(Integer.parseInt(errorCode.split("-")[1])).orElse(new Material()).getMaterialCode();
|
||||
|
||||
return responseBuilder
|
||||
.addResponseCode(ResponseCode.NOT_ENOUGH_MATERIAL, materialCode)
|
||||
.addAttribute(RESPONSE_REASON, errorCode)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
for (Mix mix : mixes) {
|
||||
if (!inventoryService.useMix(mix, quantities.get(mix))) {
|
||||
response.put(RESPONSE_ERROR, ERROR_SAVING);
|
||||
return response;
|
||||
return responseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
response.put(RESPONSE_SUCCESS, SUCCESS_USING_MATERIALS);
|
||||
return response;
|
||||
return responseBuilder
|
||||
.addResponseCode(ResponseCode.SUCCESS_USING_MATERIALS)
|
||||
.build();
|
||||
}
|
||||
|
||||
@GetMapping(value = SEARCH_INVENTORY, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public Map<String, Object> searchWordInventory(@RequestParam String searchString) {
|
||||
List<Material> searchResult = materialService.getAllBySearchString(searchString);
|
||||
List<Integer> outputResult = searchResult.stream().map(Material::getMaterialID).collect(Collectors.toList());
|
||||
|
||||
return new JSONResponseBuilder()
|
||||
.addAttribute("result", outputResult)
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.utils.FileUtils;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.XlsxExporter;
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.parser.Parser;
|
||||
import org.commonmark.renderer.html.HtmlRenderer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.MATERIALS;
|
||||
|
||||
@Controller
|
||||
public class OthersController {
|
||||
|
||||
private RecipeService recipeService;
|
||||
private MaterialService materialService;
|
||||
private MixTypeService mixTypeService;
|
||||
private MixService mixService;
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
@Autowired
|
||||
public OthersController(RecipeService recipeService, MaterialService materialService, MixTypeService mixTypeService, MixService mixService, ResourceLoader resourceLoader) {
|
||||
this.recipeService = recipeService;
|
||||
this.materialService = materialService;
|
||||
this.mixTypeService = mixTypeService;
|
||||
this.mixService = mixService;
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@GetMapping(CLOSE_TAB)
|
||||
public ModelAndView closeTab() {
|
||||
return new ModelResponseBuilder(CLOSE_TAB).build();
|
||||
}
|
||||
|
||||
@GetMapping(MATERIAL_SELECTOR_MIX)
|
||||
public ModelAndView getMaterialSelectorFragment(@PathVariable int recipeID, @PathVariable int mixID) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(MATERIAL_SELECTOR_FRAGMENT);
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
return modelResponseBuilder
|
||||
.withView("")
|
||||
.build();
|
||||
}
|
||||
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
boolean mixExist = optionalMix.isPresent();
|
||||
|
||||
List<MixType> associatedMixTypes = recipeService.getAssociatedMixesTypes(optionalRecipe.get());
|
||||
// Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette
|
||||
List<Material> materials = materialService
|
||||
.getAll()
|
||||
.stream()
|
||||
.filter(m -> !m.isMixType() || (!mixExist || !m.equals(optionalMix.get().getMixType().getMaterial())) && associatedMixTypes.contains(mixTypeService.getByMaterial(m).get()))
|
||||
.sorted(Comparator.comparing(Material::getMaterialCode))
|
||||
.sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return modelResponseBuilder
|
||||
.addAttribute(MATERIALS, materials)
|
||||
.build();
|
||||
}
|
||||
|
||||
@GetMapping(TOUCHUP)
|
||||
public ModelAndView getTouchUpPdf() {
|
||||
return new ModelResponseBuilder().withRedirect("pdf/touchup.pdf").build();
|
||||
}
|
||||
|
||||
@GetMapping(RECIPE_XLS)
|
||||
public ResponseEntity<byte[]> getXlsForRecipe(HttpServletRequest request, @PathVariable int recipeID) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
headers.add(HttpHeaders.LOCATION, request.getHeader("referer"));
|
||||
return new ResponseEntity<>(headers, HttpStatus.FOUND);
|
||||
}
|
||||
|
||||
byte[] recipeXLS = new XlsxExporter().generate(optionalRecipe.get());
|
||||
if (recipeXLS.length <= 0) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.headers(headers)
|
||||
.contentLength(recipeXLS.length)
|
||||
.contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
|
||||
.body(recipeXLS);
|
||||
}
|
||||
|
||||
@GetMapping(value = ALL_RECIPES_XLS, produces = "application/zip")
|
||||
public ResponseEntity<byte[]> getAllXls() throws IOException {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
ColorRecipesExplorerApplication.LOGGER.info("Exportation de toutes les couleurs en XLS");
|
||||
|
||||
ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
|
||||
ZipOutputStream out = new ZipOutputStream(byteOS);
|
||||
|
||||
Collection<Recipe> recipes = recipeService.getAll();
|
||||
for (Recipe recipe : recipes) {
|
||||
byte[] recipeXLS = new XlsxExporter().generate(recipe);
|
||||
if (recipeXLS.length <= 0) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
|
||||
out.putNextEntry(new ZipEntry(String.format("%s_%s.xlsx", recipe.getCompany().getCompanyName(), recipe.getRecipeCode())));
|
||||
out.write(recipeXLS, 0, recipeXLS.length);
|
||||
out.closeEntry();
|
||||
}
|
||||
|
||||
out.close();
|
||||
|
||||
byte[] zipContent = byteOS.toByteArray();
|
||||
byteOS.close();
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.headers(headers)
|
||||
.contentLength(zipContent.length)
|
||||
.contentType(MediaType.parseMediaType("application/zip"))
|
||||
.body(zipContent);
|
||||
}
|
||||
|
||||
@GetMapping(value = UPDATES)
|
||||
public ModelAndView showUpdates() {
|
||||
return new ModelResponseBuilder(UPDATES).build();
|
||||
}
|
||||
|
||||
@GetMapping(value = UPDATES_GET, produces = MediaType.TEXT_HTML_VALUE)
|
||||
@ResponseBody
|
||||
public ResponseEntity<String> getUpdates() throws IOException {
|
||||
String fileContent = FileUtils.readClasspathFile(resourceLoader, "classpath:updates.md");
|
||||
if (fileContent == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
|
||||
|
||||
Parser parser = Parser.builder().build();
|
||||
Node document = parser.parse(fileContent);
|
||||
HtmlRenderer renderer = HtmlRenderer.builder().build();
|
||||
|
||||
return new ResponseEntity<>(renderer.render(document), HttpStatus.OK);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
|
||||
@Controller
|
||||
public class RecipeExplorerController {
|
||||
|
||||
private RecipeService recipeService;
|
||||
private MixService mixService;
|
||||
|
||||
@Autowired
|
||||
public RecipeExplorerController(RecipeService recipeService, MixService mixService) {
|
||||
this.recipeService = recipeService;
|
||||
this.mixService = mixService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la recette.
|
||||
* Cette méthode requiert l'identifiant de la recette à affiche dans l'URL.
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - error: Contient le message d'erreur, s'il y a lieu
|
||||
* - recipe: Contient la recette
|
||||
* - mixes: Contient les mélanges associées à la recette
|
||||
* - images: Contient la liste des noms des images associées à la recette
|
||||
*
|
||||
* @param recipeID L'identifiant de la recette
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(EXPLORER_RECIPE_SPECIFIC)
|
||||
public ModelAndView showRecipe(@PathVariable int recipeID) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(EXPLORER_RECIPE);
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
return modelResponseBuilder
|
||||
.withView(INDEX)
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
.build();
|
||||
}
|
||||
|
||||
Recipe recipe = optionalRecipe.get();
|
||||
List<Mix> mixes = new ArrayList<>(recipe.getRecipeMixes()); // Convertit le PersistentBag en ArrayList
|
||||
mixes.sort(Comparator.comparing(Mix::getMixID));
|
||||
|
||||
return modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.RECIPE, recipe)
|
||||
.addResponseData(ResponseDataType.MIXES, mixes)
|
||||
.addResponseData(ResponseDataType.IMAGES, recipeService.getImageFiles(recipe))
|
||||
.build();
|
||||
}
|
||||
|
||||
@PostMapping(value = EXPLORER_RECIPE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public Map<String, Object> saveRecipeInformations(@RequestBody Map<String, Object> form) {
|
||||
JSONResponseBuilder responseBuilder = new JSONResponseBuilder();
|
||||
|
||||
int recipeID = Integer.parseInt(form.get("recipeID").toString());
|
||||
Map<String, String> location = (Map<String, String>) form.get("locations");
|
||||
String note = form.get("note").toString();
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID);
|
||||
} else {
|
||||
Recipe recipe = optionalRecipe.get();
|
||||
|
||||
recipe.setNote(note);
|
||||
recipeService.save(recipe);
|
||||
}
|
||||
|
||||
for (String mixIDStr : location.keySet()) {
|
||||
int mixID = Integer.parseInt(mixIDStr);
|
||||
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
if (!optionalMix.isPresent()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID);
|
||||
} else {
|
||||
Mix mix = optionalMix.get();
|
||||
|
||||
if (mix.getRecipe().getRecipeID() != recipeID) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MIX_NOT_ASSOCIATED_WITH_RECIPE, mixID, recipeID);
|
||||
} else {
|
||||
mix.setLocation(location.get(mixIDStr));
|
||||
mixService.update(mix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!responseBuilder.containsErrors()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.SUCCESS_SAVING_RECIPE_INFORMATIONS);
|
||||
}
|
||||
|
||||
return responseBuilder.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CLOSE_TAB;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.SIMDUT_FILES;
|
||||
|
||||
@Controller
|
||||
public class SIMDUTFilesController {
|
||||
|
||||
private MaterialService materialService;
|
||||
|
||||
@Autowired
|
||||
public SIMDUTFilesController(MaterialService materialService) {
|
||||
this.materialService = materialService;
|
||||
}
|
||||
|
||||
@GetMapping(SIMDUT_FILES)
|
||||
public ResponseEntity<byte[]> getFile(HttpServletRequest request, @PathVariable int materialID) {
|
||||
Optional<Material> optionalMaterial = materialService.getByID(materialID);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
if (!optionalMaterial.isPresent()) {
|
||||
headers.add("Location", request.getHeader("referer"));
|
||||
return new ResponseEntity<>(headers, HttpStatus.FOUND);
|
||||
}
|
||||
|
||||
FileHandler fileHandler = new FileHandler(String.format("%s_%s", materialID, optionalMaterial.get().getMaterialCode()), FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF);
|
||||
if (!fileHandler.isValid()) {
|
||||
headers.add("Location", "/" + CLOSE_TAB);
|
||||
return new ResponseEntity<>(headers, HttpStatus.FOUND);
|
||||
}
|
||||
|
||||
byte[] fileContent = fileHandler.readFile();
|
||||
headers.setContentType(MediaType.APPLICATION_PDF);
|
||||
return new ResponseEntity<>(fileContent, headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping(SIMDUT_FILES)
|
||||
public ResponseEntity<Void> getFile(@PathVariable int materialID) {
|
||||
Optional<Material> optionalMaterial = materialService.getByID(materialID);
|
||||
if (!optionalMaterial.isPresent()) return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
|
||||
|
||||
FileHandler fileHandler = new FileHandler(String.format("%s_%s", materialID, optionalMaterial.get().getMaterialCode()), FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF);
|
||||
if (!fileHandler.isValid()) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
|
||||
return ResponseEntity.status(HttpStatus.FOUND).build();
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.web.controller.creators;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ResponseCode;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Company;
|
||||
import fyloz.trial.ColorRecipesExplorer.services.CompanyService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
@ -14,9 +14,10 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Optional;
|
||||
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_COMPANY;
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_COMPANY_SUCCESS;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_COMPANY;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_COMPANY_SUCCESS;
|
||||
|
||||
@Controller
|
||||
public class CompanyCreatorController {
|
||||
|
@ -28,16 +29,11 @@ public class CompanyCreatorController {
|
|||
this.companyService = companyService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la page de création d'une bannière.
|
||||
*
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(CREATOR_COMPANY)
|
||||
public ModelAndView showCreationPage(ModelAndView model, Company company) {
|
||||
return new ModelBuilder(model)
|
||||
.setView(CREATOR_COMPANY)
|
||||
.addData(ModelDataType.COMPANY, company)
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(CREATOR_COMPANY)
|
||||
.addResponseData(ResponseDataType.COMPANY, company)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -60,20 +56,22 @@ public class CompanyCreatorController {
|
|||
*/
|
||||
@PostMapping(value = CREATOR_COMPANY, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public ModelAndView createCompany(@ModelAttribute @Valid Company company) {
|
||||
ModelBuilder modelBuilder = new ModelBuilder(CREATOR_COMPANY_SUCCESS);
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(CREATOR_COMPANY_SUCCESS);
|
||||
|
||||
if (companyService.isValidForCreation(company)) {
|
||||
if ((company = companyService.save(company)) != null) {
|
||||
return modelBuilder
|
||||
.addData(ModelDataType.COMPANY_NAME, company.getCompanyName())
|
||||
Optional<Company> savedCompany = companyService.save(company);
|
||||
|
||||
if (savedCompany.isPresent()) {
|
||||
return modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.COMPANY_NAME, savedCompany.get().getCompanyName())
|
||||
.build();
|
||||
} else {
|
||||
modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
}
|
||||
} else {
|
||||
modelBuilder.addResponseCode(ResponseCode.MIX_NOT_ASSOCIATED_WITH_RECIPE, company.getCompanyName(), null);
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_ALREADY_EXIST, company.getCompanyName());
|
||||
}
|
||||
|
||||
return showCreationPage(modelBuilder.build(), company);
|
||||
return showCreationPage(modelResponseBuilder.build(), company);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_MATERIAL;
|
||||
|
||||
@Controller
|
||||
public class MaterialCreatorController {
|
||||
|
||||
private MaterialService materialService;
|
||||
private MaterialTypeService materialTypeService;
|
||||
|
||||
@Autowired
|
||||
public MaterialCreatorController(MaterialService materialService, MaterialTypeService materialTypeService) {
|
||||
this.materialService = materialService;
|
||||
this.materialTypeService = materialTypeService;
|
||||
}
|
||||
|
||||
@GetMapping(CREATOR_MATERIAL)
|
||||
public ModelAndView showCreationPage(ModelAndView model, Material material) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(CREATOR_MATERIAL)
|
||||
.addResponseData(ResponseDataType.MATERIAL, material != null ? material : new Material())
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet à l'utilisateur de créer un produit.
|
||||
* <p>
|
||||
* La création échouera si:
|
||||
* - L'utilisateur n'est pas autorisé à effectuer cette action
|
||||
* - Le produit existe déjà
|
||||
* - Une erreur est survenue lors de la sauvegarde dans la base de données
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - error: Contient le message d'erreur, s'il y a lieu
|
||||
* - materialCode: Contient le code de produit du produit créé
|
||||
* <p>
|
||||
* REQUIERT UNE AUTORISATION
|
||||
*
|
||||
* @param material Le produit à créer
|
||||
* @param simdut Le fichier SIMDUT du produit (optionnel)
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@PostMapping(value = CREATOR_MATERIAL, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public ModelAndView create(@Valid Material material, MultipartFile simdut) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
|
||||
|
||||
if (!materialService.exists(material)) {
|
||||
Optional<Material> savedMaterial = materialService.save(material);
|
||||
|
||||
if (savedMaterial.isPresent()) {
|
||||
material = savedMaterial.get();
|
||||
|
||||
modelResponseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode());
|
||||
|
||||
if (simdut.getSize() > 0 && !materialService.addSimdut(simdut, material)) {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
|
||||
}
|
||||
|
||||
return showCreationPage(modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode())
|
||||
.build(), null);
|
||||
} else {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
}
|
||||
} else {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode());
|
||||
}
|
||||
|
||||
return showCreationPage(modelResponseBuilder.build(), material);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_MATERIAL_TYPE;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.INDEX;
|
||||
|
||||
@Controller
|
||||
public class MaterialTypeCreatorController {
|
||||
|
||||
private MaterialTypeService materialTypeService;
|
||||
|
||||
@Autowired
|
||||
public MaterialTypeCreatorController(MaterialTypeService materialTypeService) {
|
||||
this.materialTypeService = materialTypeService;
|
||||
}
|
||||
|
||||
@GetMapping(CREATOR_MATERIAL_TYPE)
|
||||
public ModelAndView showPage(ModelAndView model, MaterialType materialType) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(CREATOR_MATERIAL_TYPE)
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPE, materialType == null ? new MaterialType() : materialType)
|
||||
.build();
|
||||
}
|
||||
|
||||
@PostMapping(CREATOR_MATERIAL_TYPE)
|
||||
public ModelAndView create(@Valid MaterialType materialType) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect(INDEX));
|
||||
|
||||
if (materialTypeService.isValidForCreation(materialType)) {
|
||||
if (materialTypeService.save(materialType) != null) {
|
||||
return modelResponseBuilder.build();
|
||||
} else {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
}
|
||||
} else {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST, materialType.getMaterialTypeName());
|
||||
}
|
||||
|
||||
return showPage(modelResponseBuilder.build(), materialType);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.dto.MixCreationFormDto;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
|
||||
@Controller
|
||||
public class MixCreatorController {
|
||||
|
||||
private MixService mixService;
|
||||
private RecipeService recipeService;
|
||||
private MaterialService materialService;
|
||||
private MixTypeService mixTypeService;
|
||||
|
||||
@Autowired
|
||||
public MixCreatorController(MixService mixService, RecipeService recipeService, MaterialService materialService, MixTypeService mixTypeService) {
|
||||
this.mixService = mixService;
|
||||
this.recipeService = recipeService;
|
||||
this.materialService = materialService;
|
||||
this.mixTypeService = mixTypeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la page de création d'un mélange.
|
||||
* Cette méthode requiert l'identifiant d'une recette dans l'URL.
|
||||
*
|
||||
* @param model Le Model injecté par Thymeleaf
|
||||
* @param recipeID L'identifiant de la recette
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(CREATOR_MIX_SPECIFIC)
|
||||
public ModelAndView showCreationPage(ModelAndView model, @PathVariable int recipeID) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(model)
|
||||
.withView(CREATOR_MIX);
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
return modelResponseBuilder
|
||||
.withView(ControllerUtils.redirect(EDITOR_RECIPE))
|
||||
.build();
|
||||
}
|
||||
|
||||
Recipe recipe = optionalRecipe.get();
|
||||
|
||||
List<MixType> associatedMixTypes = recipeService.getAssociatedMixesTypes(recipe);
|
||||
// Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette
|
||||
List<Material> materials = materialService
|
||||
.getAll()
|
||||
.stream()
|
||||
.filter(m -> !m.isMixType() || associatedMixTypes.contains(mixTypeService.getByMaterial(m).get()))
|
||||
.sorted(Comparator.comparing(Material::getMaterialCode))
|
||||
.sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ModelResponseBuilder responseBuilder = modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.RECIPE, recipe)
|
||||
.addAttribute("materialsJson", materialService.asJson(materials));
|
||||
|
||||
if (materialService.getAll().isEmpty()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.NO_MATERIAL)
|
||||
.addResponseData(ResponseDataType.BLOCK_BUTTON, true);
|
||||
}
|
||||
|
||||
return responseBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet à l'utilisateur de créer un mélange.
|
||||
* <p>
|
||||
* La création échouera si:
|
||||
* - L'utilisateur n'est pas autorisé à exécuter cette action
|
||||
* - La recette n'existe pas
|
||||
* - Un des produits n'existe pas
|
||||
* - Une erreur est survenue lors de la sauvegarde du type de mélange
|
||||
* - Une erreur est survenue lors de la sauvegarde du mélange
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - error: Contient le message d'erreur, s'il y a lieu
|
||||
* <p>
|
||||
* REQUIERT UNE AUTORISATION
|
||||
*
|
||||
* @param form La formulaire du mélange entré par l'utilisateur
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@PostMapping(value = CREATOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public ModelAndView createMix(@ModelAttribute @Valid MixCreationFormDto formDto) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
|
||||
|
||||
Recipe recipe = formDto.getRecipe();
|
||||
if (recipe == null) return modelResponseBuilder
|
||||
.withRedirect(EDITOR_RECIPE)
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND_NO_PARAMS)
|
||||
.build();
|
||||
|
||||
ModelResponseBuilder mixCreationResponse = mixService.create(formDto, recipe);
|
||||
if (mixCreationResponse != null)
|
||||
return showCreationPage(mixCreationResponse.build(), formDto.getRecipe().getRecipeID());
|
||||
|
||||
return modelResponseBuilder
|
||||
.withRedirect(EDITOR_RECIPE_SPECIFIC, recipe.getRecipeID())
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_RECIPE;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_RECIPE_SUCCESS;
|
||||
|
||||
@Controller
|
||||
public class RecipeCreatorController {
|
||||
|
||||
private RecipeService recipeService;
|
||||
private CompanyService companyService;
|
||||
|
||||
@Autowired
|
||||
public RecipeCreatorController(RecipeService recipeService, CompanyService companyService) {
|
||||
this.recipeService = recipeService;
|
||||
this.companyService = companyService;
|
||||
}
|
||||
|
||||
@GetMapping(CREATOR_RECIPE)
|
||||
public ModelAndView showCreationPage(ModelAndView model, Recipe recipe) {
|
||||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder(model)
|
||||
.withView(CREATOR_RECIPE)
|
||||
.addResponseData(ResponseDataType.COMPANIES, companyService.getAll())
|
||||
.addResponseData(ResponseDataType.RECIPE, recipe == null ? new Recipe() : recipe);
|
||||
|
||||
if (companyService.getAll().isEmpty()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.NO_COMPANY)
|
||||
.addResponseData(ResponseDataType.BLOCK_BUTTON, true);
|
||||
}
|
||||
|
||||
return responseBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet à l'utilisateur de créer une nouvelle recette.
|
||||
* <p>
|
||||
* La création échouera si:
|
||||
* - L'utilisateur n'est pas autorisé à exécuter cette action
|
||||
* - Une erreur est survenue lors de la sauvegarde dans la base de données
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - error: Contient le message d'erreur, s'il y a lieu
|
||||
* <p>
|
||||
* REQUIERT UNE AUTORISATION
|
||||
*
|
||||
* @param recipe La recette à créer
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@PostMapping(value = CREATOR_RECIPE)
|
||||
public ModelAndView createRecipe(@Valid Recipe recipe) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(CREATOR_RECIPE_SUCCESS);
|
||||
|
||||
Optional<Recipe> savedRecipe = recipeService.save(recipe);
|
||||
if (savedRecipe.isPresent()) {
|
||||
return modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.RECIPE, savedRecipe.get())
|
||||
.build();
|
||||
}
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
|
||||
return showCreationPage(modelResponseBuilder.build(), recipe);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
|
||||
@Controller
|
||||
public class MaterialEditorController {
|
||||
|
||||
private MaterialService materialService;
|
||||
private MaterialTypeService materialTypeService;
|
||||
|
||||
@Autowired
|
||||
public MaterialEditorController(MaterialService materialService, MaterialTypeService materialTypeService) {
|
||||
this.materialService = materialService;
|
||||
this.materialTypeService = materialTypeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la page de tous les produits.
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - materials: La liste de tous les produits
|
||||
*
|
||||
* @param model Le Model injecté par Thymeleaf
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(EDITOR_MATERIAL)
|
||||
public ModelAndView listMaterials(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(EDITOR_MATERIAL)
|
||||
.addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@GetMapping(EDITOR_MATERIAL_SPECIFIC)
|
||||
public ModelAndView showEditPage(ModelAndView model, @PathVariable int materialID, Material material) {
|
||||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder(model)
|
||||
.withView(EDITOR_MATERIAL_EDITOR);
|
||||
|
||||
if (material.getMaterialCode() == null) {
|
||||
Optional<Material> optionalMaterial = materialService.getByID(materialID);
|
||||
|
||||
if (!optionalMaterial.isPresent()) {
|
||||
return listMaterials(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
material = optionalMaterial.get();
|
||||
}
|
||||
|
||||
return responseBuilder
|
||||
.addResponseData(ResponseDataType.MATERIAL, material)
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet à l'utilisateur de modifier un produit.
|
||||
* <p>
|
||||
* La modification échouera si:
|
||||
* - L'utilisateur n'est pas autorisé à exécuter cette action
|
||||
* - Il n'y a aucun produit avec l'identifiant passé en paramètre
|
||||
* - Une erreur est survenue lors de la mise à jour dans la base de données
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - error: Contient le message d'erreur, s'il y a lieu
|
||||
* - materialCode: Contient le code du produit mit à jour
|
||||
* <p>
|
||||
* REQUIERT UNE AUTORISATION
|
||||
*
|
||||
* @param material Le produit à mettre à jour
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@PostMapping(value = EDITOR_MATERIAL, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public ModelAndView saveEditedMaterial(Material material) {
|
||||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
|
||||
int materialID = material.getMaterialID();
|
||||
|
||||
if (!materialService.existsById(materialID)) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID);
|
||||
} else if (!materialService.isValidForUpdate(material)) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode());
|
||||
|
||||
return showEditPage(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode())
|
||||
.build(),
|
||||
materialID, material);
|
||||
} else {
|
||||
Optional<Material> updatedMaterial = materialService.update(material);
|
||||
if (updatedMaterial.isPresent()) {
|
||||
responseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, updatedMaterial.get().getMaterialCode());
|
||||
} else {
|
||||
return showEditPage(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.build(),
|
||||
materialID, null);
|
||||
}
|
||||
}
|
||||
|
||||
return listMaterials(responseBuilder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la page d'upload d'un fichier SIMDUT pour un produit
|
||||
* Cette méthode requiert l'identifiant du produit dans l'URL
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - materialID: Contient l'identifiant du produit
|
||||
*
|
||||
* @param model Le Model injecté par Thymeleaf
|
||||
* @param materialID L'identifiant du produit à modifier le SIMDUT
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(value = EDIT_MATERIAL_SIMDUT_SPECIFIC)
|
||||
public ModelAndView chooseSIMDUTFile(ModelAndView model, @PathVariable int materialID) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(EDIT_MATERIAL_SIMDUT)
|
||||
.addResponseData(ResponseDataType.MATERIAL_ID, materialID)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde le fichier SIMDUT d'un produit.
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - error: Contient le message d'erreur, s'il y a lieu
|
||||
* <p>
|
||||
* REQUIERT UNE AUTORISATION
|
||||
*
|
||||
* @param materialID L'identifiant du produit
|
||||
* @param simdut Le fichier SIMDUT uploadé
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@PostMapping(value = EDIT_MATERIAL_SIMDUT, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public ModelAndView saveSIMDUT(int materialID, MultipartFile simdut) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect("material/editor/" + materialID));
|
||||
|
||||
Optional<Material> optionalMaterial = materialService.getByID(materialID);
|
||||
if (!optionalMaterial.isPresent()) {
|
||||
return chooseSIMDUTFile(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID)
|
||||
.build(),
|
||||
materialID);
|
||||
}
|
||||
|
||||
Material material = optionalMaterial.get();
|
||||
if (!materialService.removeSimdut(material) || !materialService.addSimdut(simdut, material)) {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
|
||||
|
||||
return chooseSIMDUTFile(modelResponseBuilder.build(), materialID);
|
||||
}
|
||||
|
||||
return modelResponseBuilder.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
|
||||
@Controller
|
||||
public class MaterialTypeEditorController {
|
||||
|
||||
private MaterialTypeService materialTypeService;
|
||||
|
||||
@Autowired
|
||||
public MaterialTypeEditorController(MaterialTypeService materialTypeService) {
|
||||
this.materialTypeService = materialTypeService;
|
||||
}
|
||||
|
||||
@GetMapping(EDITOR_MATERIAL_TYPE)
|
||||
public ModelAndView listMaterialTypes(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(EDITOR_MATERIAL_TYPE)
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
|
||||
.build();
|
||||
}
|
||||
|
||||
@GetMapping(EDITOR_MATERIAL_TYPE_SPECIFIC)
|
||||
public ModelAndView showEditPage(ModelAndView model, @PathVariable int materialTypeID, MaterialType materialType) {
|
||||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder(model)
|
||||
.withView(EDITOR_MATERIAL_TYPE_EDITOR);
|
||||
|
||||
if (materialType.getMaterialTypeName() == null) {
|
||||
Optional<MaterialType> optionalMaterialType = materialTypeService.getByID(materialTypeID);
|
||||
|
||||
if (!optionalMaterialType.isPresent()) {
|
||||
return listMaterialTypes(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
materialType = optionalMaterialType.get();
|
||||
}
|
||||
|
||||
return responseBuilder
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPE, materialType)
|
||||
.build();
|
||||
}
|
||||
|
||||
@PostMapping(value = EDITOR_MATERIAL_TYPE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public ModelAndView saveEditedMaterialType(MaterialType materialType) {
|
||||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
|
||||
int materialTypeID = materialType.getMaterialTypeID();
|
||||
|
||||
if (!materialTypeService.getByID(materialTypeID).isPresent()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID);
|
||||
} else if (!materialTypeService.isValidForUpdateName(materialType)) {
|
||||
return showEditPage(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST, materialType.getMaterialTypeName())
|
||||
.build(),
|
||||
materialTypeID, materialType);
|
||||
} else if (!materialTypeService.isValidForUpdatePrefix(materialType)) {
|
||||
return showEditPage(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST_PREFIX, materialType.getPrefix())
|
||||
.build(),
|
||||
materialTypeID, materialType);
|
||||
} else {
|
||||
Optional<MaterialType> updatedMaterialType = materialTypeService.update(materialType);
|
||||
if (updatedMaterialType.isPresent()) {
|
||||
responseBuilder.addResponseData(ResponseDataType.MATERIAL_TYPE_NAME, updatedMaterialType.get().getMaterialTypeName());
|
||||
} else {
|
||||
return showEditPage(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.build(),
|
||||
materialTypeID, null);
|
||||
}
|
||||
}
|
||||
|
||||
return listMaterialTypes(responseBuilder.build());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.dto.MixCreationFormDto;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.MIX_ID;
|
||||
|
||||
@Controller
|
||||
public class MixEditorController {
|
||||
|
||||
private MixService mixService;
|
||||
private MaterialService materialService;
|
||||
private RecipeService recipeService;
|
||||
private MixTypeService mixTypeService;
|
||||
|
||||
@Autowired
|
||||
public MixEditorController(MixService mixService, MaterialService materialService, RecipeService recipeService, MixTypeService mixTypeService) {
|
||||
this.mixService = mixService;
|
||||
this.materialService = materialService;
|
||||
this.recipeService = recipeService;
|
||||
this.mixTypeService = mixTypeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la page d'édition d'un mélange.
|
||||
* Cette méthode requiert l'identifiant du mélange à modifier dans l'URL.
|
||||
*
|
||||
* @param model Le Model injecté par Thymeleaf
|
||||
* @param mixID L'identifiant du mélange à modifier
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(EDITOR_MIX_SPECIFIC)
|
||||
public ModelAndView showPage(ModelAndView model, @PathVariable int mixID) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(model)
|
||||
.withView(EDITOR_MIX_SPECIFIC.replaceAll("/\\{" + MIX_ID + "}", ""));
|
||||
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
if (!optionalMix.isPresent()) {
|
||||
return modelResponseBuilder
|
||||
.withView(ControllerUtils.redirect(EDITOR_RECIPE))
|
||||
.build();
|
||||
}
|
||||
|
||||
Mix mix = optionalMix.get();
|
||||
List<MixType> associatedMixTypes = recipeService.getAssociatedMixesTypes(mix.getRecipe());
|
||||
// Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette
|
||||
List<Material> materials = materialService
|
||||
.getAll()
|
||||
.stream()
|
||||
.filter(m -> !m.isMixType() || (!m.equals(mix.getMixType().getMaterial()) && associatedMixTypes.contains(mixTypeService.getByMaterial(m).get())))
|
||||
.sorted(Comparator.comparing(Material::getMaterialCode))
|
||||
.sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.MIX, mix)
|
||||
.addResponseData(ResponseDataType.RECIPE_CODE, mix.getRecipe().getRecipeCode())
|
||||
.addAttribute("mixJson", materialService.asJson(mix))
|
||||
.addAttribute("materialsJson", materialService.asJson(materials))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet à l'utilisateur de modifier un mélange.
|
||||
* <p>
|
||||
* La mise à jour échouera si:
|
||||
* - L'utilisateur n'est pas autorisé à exécuter cette action
|
||||
* - Le mélange n'existe pas
|
||||
* - Un des produits n'existe pas
|
||||
* - Une erreur est survenue lors de la mise à jour dans la base de données
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - error: Contient le message d'erreur, s'il y a lieu
|
||||
* <p>
|
||||
* REQUIERT UNE AUTORISATION
|
||||
*
|
||||
* @param form Le formulaire du mélange entré par l'utilisateur
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@PostMapping(value = EDITOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public ModelAndView saveMix(@ModelAttribute @Valid MixCreationFormDto formDto, int mixID) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
|
||||
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
if (!optionalMix.isPresent()) {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID);
|
||||
|
||||
return showPage(modelResponseBuilder.build(), mixID);
|
||||
}
|
||||
|
||||
Mix mix = optionalMix.get();
|
||||
modelResponseBuilder.withRedirect(EDITOR_RECIPE_SPECIFIC, mix.getRecipe().getRecipeID());
|
||||
|
||||
ModelResponseBuilder editResult = mixService.edit(mix, formDto);
|
||||
if (editResult != null) {
|
||||
return showPage(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.build(),
|
||||
mixID);
|
||||
}
|
||||
|
||||
return modelResponseBuilder.build();
|
||||
}
|
||||
|
||||
@GetMapping(REMOVER_MIX_SPECIFIC)
|
||||
public ModelAndView deleteMix(@PathVariable int mixID) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
|
||||
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
if (!optionalMix.isPresent()) {
|
||||
return showPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID)
|
||||
.build(),
|
||||
mixID);
|
||||
}
|
||||
|
||||
Mix mix = optionalMix.get();
|
||||
modelResponseBuilder.withView(ControllerUtils.redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(mix.getRecipe().getRecipeID()))));
|
||||
|
||||
if (!mixService.deleteMix(mix)) {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
|
||||
return showPage(modelResponseBuilder.build(), mixID);
|
||||
}
|
||||
|
||||
return modelResponseBuilder.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
|
||||
@Controller
|
||||
public class RecipeEditorController {
|
||||
|
||||
private RecipeService recipeService;
|
||||
private CompanyService companyService;
|
||||
|
||||
@Autowired
|
||||
public RecipeEditorController(RecipeService recipeService, CompanyService companyService) {
|
||||
this.recipeService = recipeService;
|
||||
this.companyService = companyService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la page listant toutes les recettes.
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - recipes: Contient un Map de toutes les recettes triées par compagnie
|
||||
*
|
||||
* @param model Le Model injecté par Thymeleaf
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(EDITOR_RECIPE)
|
||||
public ModelAndView listRecipes(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(EDITOR_RECIPE)
|
||||
.addResponseData(ResponseDataType.RECIPE_MAP, recipeService.getRecipesByCompany())
|
||||
.build();
|
||||
}
|
||||
|
||||
@GetMapping(EDITOR_RECIPE_SPECIFIC)
|
||||
public ModelAndView showEditPage(ModelAndView model, @PathVariable int recipeID, Recipe recipe) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(model)
|
||||
.withView(EDITOR_RECIPE_EDITOR);
|
||||
|
||||
if (recipe.getRecipeCode() == null || recipe.getCompany() == null) {
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
return listRecipes(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
recipe = optionalRecipe.get();
|
||||
}
|
||||
|
||||
return modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.RECIPE, recipe)
|
||||
.addResponseData(ResponseDataType.COMPANIES, companyService.getAll())
|
||||
.addResponseData(ResponseDataType.MIXES, new ArrayList<>(recipeService.getSortedMixes(recipe))) // Convertit le PersistentBag en ArrayList
|
||||
.addResponseData(ResponseDataType.IMAGES, recipeService.getImageFiles(recipe))
|
||||
.addAttribute("recipeJSON", recipeService.asJson(recipe))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet à l'utilisateur de modifier une recette.
|
||||
* <p>
|
||||
* La mise à jour échouera si:
|
||||
* - L'utilisateur n'est pas autorisé à exécuter cette action
|
||||
* - La recette n'existe pas
|
||||
* - Une erreur est survenue lors de la mise à jour dans la base de données
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - error: Contient le message d'erreur, s'il y a lieu
|
||||
* - recipeCode: Contient la couleur d'une recette
|
||||
* <p>
|
||||
* REQUIERT UNE AUTORISATION
|
||||
*
|
||||
* @param recipe La recette à modifier
|
||||
* @param form Le formulaire entré par l'utilisateur
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@PostMapping(value = EDITOR_RECIPE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
@Transactional
|
||||
public ModelAndView saveRecipe(Recipe recipe, @RequestBody MultiValueMap<String, Object> form) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
|
||||
int recipeID = recipe.getRecipeID();
|
||||
|
||||
Optional<Recipe> optionalStoredRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalStoredRecipe.isPresent()) {
|
||||
return listRecipes(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
.build());
|
||||
}
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.updateRecipe(recipe, optionalStoredRecipe.get(), form);
|
||||
if (optionalRecipe.isPresent()) {
|
||||
modelResponseBuilder.addResponseData(ResponseDataType.RECIPE_CODE, optionalRecipe.get().getRecipeCode());
|
||||
return listRecipes(modelResponseBuilder.build());
|
||||
}
|
||||
|
||||
return listRecipes(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.build());
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.web.controller.removers;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ResponseCode;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Company;
|
||||
import fyloz.trial.ColorRecipesExplorer.services.CompanyService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
@ -12,8 +12,10 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_COMPANY;
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_COMPANY_SPECIFIC;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_COMPANY;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_COMPANY_SPECIFIC;
|
||||
|
||||
@Controller
|
||||
public class CompanyRemoverController {
|
||||
|
@ -36,9 +38,9 @@ public class CompanyRemoverController {
|
|||
*/
|
||||
@GetMapping(REMOVER_COMPANY)
|
||||
public ModelAndView showPage(ModelAndView model) {
|
||||
return new ModelBuilder(model)
|
||||
.setView(REMOVER_COMPANY)
|
||||
.addData(ModelDataType.COMPANIES, companyService.getAll())
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(REMOVER_COMPANY)
|
||||
.addResponseData(ResponseDataType.COMPANIES, companyService.getAll())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -63,19 +65,21 @@ public class CompanyRemoverController {
|
|||
|
||||
@PostMapping(REMOVER_COMPANY_SPECIFIC)
|
||||
public ModelAndView removeCompany(@PathVariable int companyID) {
|
||||
ModelBuilder modelBuilder = new ModelBuilder("");
|
||||
Company company = companyService.getByID(companyID);
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
|
||||
|
||||
Optional<Company> optionalCompany = companyService.getByID(companyID);
|
||||
if (optionalCompany.isPresent()) {
|
||||
Company company = optionalCompany.get();
|
||||
|
||||
if (companyService.exists(company)) {
|
||||
if (companyService.deleteIfNotLinked(company)) {
|
||||
modelBuilder.addData(ModelDataType.COMPANY_NAME, company.getCompanyName());
|
||||
modelResponseBuilder.addResponseData(ResponseDataType.COMPANY_NAME, company.getCompanyName());
|
||||
} else {
|
||||
modelBuilder.addResponseCode(ResponseCode.COMPANY_LINKED, company.getCompanyName());
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_LINKED, company.getCompanyName());
|
||||
}
|
||||
} else {
|
||||
modelBuilder.addResponseCode(ResponseCode.COMPANY_NOT_FOUND, String.valueOf(companyID));
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_NOT_FOUND, companyID);
|
||||
}
|
||||
|
||||
return showPage(modelBuilder.build());
|
||||
return showPage(modelResponseBuilder.build());
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.web.controller.removers;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.ResponseCode;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Material;
|
||||
import fyloz.trial.ColorRecipesExplorer.services.MaterialService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
@ -12,10 +12,11 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_MATERIAL;
|
||||
import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_MATERIAL_SPECIFIC;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_SPECIFIC;
|
||||
|
||||
@Controller
|
||||
public class MaterialRemoverController {
|
||||
|
@ -35,9 +36,9 @@ public class MaterialRemoverController {
|
|||
*/
|
||||
@GetMapping(REMOVER_MATERIAL)
|
||||
public ModelAndView showPage(ModelAndView model) {
|
||||
return new ModelBuilder(model)
|
||||
.setView(REMOVER_MATERIAL)
|
||||
.addData(ModelDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(REMOVER_MATERIAL)
|
||||
.addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -61,23 +62,25 @@ public class MaterialRemoverController {
|
|||
*/
|
||||
@PostMapping(REMOVER_MATERIAL_SPECIFIC)
|
||||
public ModelAndView removeMaterial(@PathVariable int materialID) {
|
||||
ModelBuilder modelBuilder = new ModelBuilder("");
|
||||
Material material = materialService.getByID(materialID);
|
||||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
|
||||
|
||||
if (material == null) {
|
||||
modelBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, String.valueOf(materialID));
|
||||
Optional<Material> optionalMaterial = materialService.getByID(materialID);
|
||||
if (!optionalMaterial.isPresent()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID);
|
||||
} else {
|
||||
Material material = optionalMaterial.get();
|
||||
|
||||
if (materialService.deleteIfNotLinked(material)) {
|
||||
modelBuilder.addData(ModelDataType.MATERIAL_CODE, material.getMaterialCode());
|
||||
responseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode());
|
||||
|
||||
if (!materialService.removeSimdut(material)) {
|
||||
modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
|
||||
responseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
|
||||
}
|
||||
} else {
|
||||
modelBuilder.addResponseCode(ResponseCode.MATERIAL_LINKED, material.getMaterialCode());
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_LINKED, material.getMaterialCode());
|
||||
}
|
||||
}
|
||||
|
||||
return showPage(modelBuilder.build());
|
||||
return showPage(responseBuilder.build());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_TYPE;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_TYPE_SPECIFIC;
|
||||
|
||||
@Controller
|
||||
public class MaterialTypeRemoverController {
|
||||
|
||||
private MaterialTypeService materialTypeService;
|
||||
|
||||
@Autowired
|
||||
|
||||
public MaterialTypeRemoverController(MaterialTypeService materialTypeService) {
|
||||
this.materialTypeService = materialTypeService;
|
||||
}
|
||||
|
||||
@GetMapping(REMOVER_MATERIAL_TYPE)
|
||||
public ModelAndView showPage(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(REMOVER_MATERIAL_TYPE)
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
|
||||
.build();
|
||||
}
|
||||
|
||||
@PostMapping(REMOVER_MATERIAL_TYPE_SPECIFIC)
|
||||
public ModelAndView removeMaterialType(@PathVariable int materialTypeID) {
|
||||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
|
||||
|
||||
Optional<MaterialType> optionalMaterialType = materialTypeService.getByID(materialTypeID);
|
||||
if (!optionalMaterialType.isPresent()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID);
|
||||
} else {
|
||||
MaterialType materialType = optionalMaterialType.get();
|
||||
|
||||
if (materialTypeService.deleteIfNotLinked(materialType)) {
|
||||
responseBuilder.addResponseData(ResponseDataType.MATERIAL_TYPE_NAME, materialType.getMaterialTypeName());
|
||||
} else {
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_LINKED, materialType.getMaterialTypeName());
|
||||
}
|
||||
}
|
||||
|
||||
return showPage(responseBuilder.build());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_RECIPE;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_RECIPE_SPECIFIC;
|
||||
|
||||
@Controller
|
||||
public class RecipeRemoverController {
|
||||
|
||||
private RecipeService recipeService;
|
||||
|
||||
public RecipeRemoverController(RecipeService recipeService) {
|
||||
this.recipeService = recipeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la liste de toutes les recettes.
|
||||
*
|
||||
* @param model Le Model injecté par Thymeleaf
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(REMOVER_RECIPE)
|
||||
public ModelAndView listRecipes(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(REMOVER_RECIPE)
|
||||
.addResponseData(ResponseDataType.RECIPE_MAP, recipeService.getRecipesByCompany())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet à l'utilisateur de supprimer une recette.
|
||||
* Cette méthode requiert l'identifiant de la recette dans l'URL.
|
||||
* <p>
|
||||
* La suppression échouera si:
|
||||
* - L'utilisateur n'est pas autorisé à exécuter cette action
|
||||
* - La recette n'existe pas
|
||||
* - Une erreur est survenue lors de la suppression dans la base de données
|
||||
* <p>
|
||||
* Modèle de la page:
|
||||
* - error: Contient le message d'erreur, s'il y a lieu
|
||||
* - recipeCode: Contient la couleur de la recette
|
||||
* <p>
|
||||
* REQUIERT UNE AUTORISATION
|
||||
*
|
||||
* @param recipeID L'identifiant de la recette
|
||||
* @return La page à afficher.
|
||||
*/
|
||||
@PostMapping(REMOVER_RECIPE_SPECIFIC)
|
||||
public ModelAndView removeRecipe(@PathVariable int recipeID) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
return listRecipes(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
.build());
|
||||
}
|
||||
|
||||
Recipe recipe = optionalRecipe.get();
|
||||
if (!recipeService.deleteRecipe(recipe)) {
|
||||
return listRecipes(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.build());
|
||||
}
|
||||
|
||||
modelResponseBuilder.addResponseData(ResponseDataType.RECIPE_CODE, recipe.getRecipeCode());
|
||||
return listRecipes(modelResponseBuilder.build());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Catalog;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Sheet;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Table;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.DescriptionCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.NoteCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.SectionTitleCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.TitleCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.util.Position;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
public class XlsxExporter {
|
||||
|
||||
public byte[] generate(Recipe recipe) {
|
||||
ColorRecipesExplorerApplication.LOGGER.info(String.format("Génération du XLS de la couleur %s (%s)", recipe.getRecipeCode(), recipe.getRecipeID()));
|
||||
|
||||
Document document = new Document(recipe.getRecipeCode());
|
||||
Sheet sheet = document.getSheet();
|
||||
registerCells(recipe, sheet);
|
||||
|
||||
document.buildSheet();
|
||||
|
||||
byte[] output;
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
document.write(outputStream);
|
||||
output = outputStream.toByteArray();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private void registerCells(Recipe recipe, Sheet sheet) {
|
||||
// Header
|
||||
sheet.registerCell(new TitleCell(recipe.getRecipeCode()));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Bannière"));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getCompany().getCompanyName()));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Description"));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getRecipeDescription()));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Échantillon"));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_NUM, recipe.getSample()));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Date d'approbation"));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getApprobationDate()));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Remarque"));
|
||||
sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getRemark()));
|
||||
|
||||
// Mélanges
|
||||
Collection<Mix> recipeMixes = recipe.getRecipeMixes();
|
||||
if (recipeMixes.size() > 0) {
|
||||
sheet.registerCell(new SectionTitleCell("Recette"));
|
||||
|
||||
for (Mix mix : recipeMixes) {
|
||||
Table mixTable = new Table(4, mix.getMixQuantities().size() + 1, mix.getMixType().getTypeName());
|
||||
mixTable.setColumnName(0, "Quantité");
|
||||
mixTable.setColumnName(2, "Unités");
|
||||
|
||||
int row = 0;
|
||||
for (MixQuantity mixQuantity : mix.getMixQuantities()) {
|
||||
mixTable.setRowName(row, mixQuantity.getMaterial().getMaterialCode());
|
||||
mixTable.setContent(new Position(1, row + 1), mixQuantity.getQuantity());
|
||||
mixTable.setContent(new Position(3, row + 1), mixQuantity.getMaterial().getMaterialType().getUsePercentages() ? "%" : "mL");
|
||||
|
||||
row++;
|
||||
}
|
||||
|
||||
sheet.registerAllCells(mixTable.getCells());
|
||||
}
|
||||
}
|
||||
|
||||
// Étapes
|
||||
Collection<RecipeStep> steps = recipe.getRecipeSteps();
|
||||
if (steps.size() > 0) {
|
||||
sheet.registerCell(new SectionTitleCell("Étapes"));
|
||||
Catalog stepsCatalog = new Catalog();
|
||||
|
||||
for (RecipeStep step : recipe.getRecipeSteps()) stepsCatalog.addContent(step.getStepMessage());
|
||||
|
||||
sheet.registerAllCells(stepsCatalog.getCells());
|
||||
}
|
||||
|
||||
// Note
|
||||
String note = recipe.getNote();
|
||||
if (note != null) {
|
||||
sheet.registerCell(new SectionTitleCell("Note"));
|
||||
sheet.registerCell(new NoteCell(recipe.getNote()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.builder;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException;
|
||||
import org.apache.poi.ss.usermodel.FillPatternType;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCell;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
|
||||
import org.apache.poi.xssf.usermodel.XSSFFont;
|
||||
|
||||
public class CellBuilder {
|
||||
|
||||
private Document document;
|
||||
private Cell cell;
|
||||
private XSSFCell xcell;
|
||||
|
||||
public CellBuilder(Document document, Cell cell, int x, int y) {
|
||||
this.document = document;
|
||||
this.cell = cell;
|
||||
|
||||
xcell = document.getSheet().getCell(cell, x, y, true);
|
||||
}
|
||||
|
||||
private void applyColor(IColoredCell cell, XSSFCellStyle style) {
|
||||
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
style.setFillForegroundColor(cell.getBackgroundColor().getIndex());
|
||||
}
|
||||
|
||||
private void applyFont(IFontCell cell, XSSFCellStyle style) {
|
||||
XSSFFont font = document.createFont();
|
||||
font.setBold(cell.isBold());
|
||||
font.setColor(cell.getFontColor().getIndex());
|
||||
font.setFontHeightInPoints(cell.getFontHeight());
|
||||
|
||||
style.setFont(font);
|
||||
if (cell.isCentered()) style.setAlignment(HorizontalAlignment.CENTER);
|
||||
}
|
||||
|
||||
private void applyStyle() {
|
||||
XSSFCellStyle style = document.createCellStyle();
|
||||
style.setWrapText(true);
|
||||
|
||||
if (cell instanceof IColoredCell) applyColor((IColoredCell) cell, style);
|
||||
if (cell instanceof IFontCell) applyFont((IFontCell) cell, style);
|
||||
|
||||
xcell.setCellStyle(style);
|
||||
}
|
||||
|
||||
private void applyContent() throws InvalidCellTypeException {
|
||||
switch (cell.getType()) {
|
||||
case STRING:
|
||||
xcell.setCellValue(cell.getContentText());
|
||||
break;
|
||||
case NUMERIC:
|
||||
xcell.setCellValue(cell.getContentNum());
|
||||
break;
|
||||
default:
|
||||
throw new InvalidCellTypeException(cell.getType());
|
||||
}
|
||||
}
|
||||
|
||||
public void build() throws InvalidCellTypeException {
|
||||
applyStyle();
|
||||
applyContent();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.builder;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Sheet;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.util.CellUtils;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
public class SheetBuilder {
|
||||
|
||||
private Sheet sheet;
|
||||
private Iterable<Cell> cells;
|
||||
|
||||
public SheetBuilder(Sheet sheet) {
|
||||
this.sheet = sheet;
|
||||
|
||||
cells = sheet.getRegisteredCells();
|
||||
}
|
||||
|
||||
private void applyCellMerge(IBiggerCell cell, int x, int y) {
|
||||
int width = cell.getWidth() - 1;
|
||||
int height = cell.getHeight() - 1;
|
||||
|
||||
sheet.getXSheet().addMergedRegion(new CellRangeAddress(y, y + height, x, x + width));
|
||||
}
|
||||
|
||||
public void build() throws InvalidCellTypeException {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
for (Cell cell : cells) {
|
||||
while (!CellUtils.isCellEmpty(sheet, x, y) || CellUtils.isCellInMergedCell(sheet, x, y)) {
|
||||
x++;
|
||||
|
||||
if (x >= Document.WIDTH) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
new CellBuilder(sheet.getDocument(), cell, x, y).build();
|
||||
if (cell instanceof IBiggerCell) {
|
||||
IBiggerCell biggerCell = (IBiggerCell) cell;
|
||||
|
||||
applyCellMerge(biggerCell, x, y);
|
||||
|
||||
x += biggerCell.getWidth() - 1;
|
||||
} else {
|
||||
x++;
|
||||
}
|
||||
|
||||
if (x >= Document.WIDTH) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class Catalog {
|
||||
|
||||
private List<String> content;
|
||||
|
||||
public Catalog() {
|
||||
content = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addContent(String value) {
|
||||
content.add(value);
|
||||
}
|
||||
|
||||
public Collection<Cell> getCells() {
|
||||
Collection<Cell> cells = new ArrayList<>();
|
||||
|
||||
int index = 1;
|
||||
for (String value : content) {
|
||||
cells.add(new CatalogValueCell(String.format("%s. %s", index, value)));
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
private class CatalogValueCell extends Cell implements IBiggerCell, IFontCell {
|
||||
|
||||
private String value;
|
||||
|
||||
public CatalogValueCell(String value) {
|
||||
super(CellType.STRING);
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return Document.WIDTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentText() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCentered() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBold() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.builder.SheetBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbookType;
|
||||
|
||||
public class Document extends XSSFWorkbook {
|
||||
|
||||
public static final int WIDTH = 8;
|
||||
private static final XSSFWorkbookType WORKBOOK_TYPE = XSSFWorkbookType.XLSX;
|
||||
|
||||
private Sheet sheet;
|
||||
|
||||
public Document(String name) {
|
||||
super(WORKBOOK_TYPE);
|
||||
|
||||
sheet = new Sheet(this, createSheet(name));
|
||||
}
|
||||
|
||||
public void buildSheet() {
|
||||
try {
|
||||
new SheetBuilder(sheet).build();
|
||||
} catch (InvalidCellTypeException e) {
|
||||
ColorRecipesExplorerApplication.LOGGER.error("Une erreur est survenue lors de la génération du document: " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public Sheet getSheet() {
|
||||
return sheet;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCell;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Sheet {
|
||||
|
||||
private Document document;
|
||||
private XSSFSheet xsheet;
|
||||
|
||||
private Map<Integer, XSSFRow> rows;
|
||||
private List<Cell> registeredCells;
|
||||
|
||||
Sheet(Document document, XSSFSheet xsheet) {
|
||||
this.document = document;
|
||||
this.xsheet = xsheet;
|
||||
xsheet.setDefaultColumnWidth(xsheet.getDefaultColumnWidth() * 2);
|
||||
|
||||
rows = new HashMap<>();
|
||||
registeredCells = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void registerCell(Cell cell) {
|
||||
registeredCells.add(cell);
|
||||
}
|
||||
|
||||
public void registerAllCells(Collection<Cell> cells) {
|
||||
registeredCells.addAll(cells);
|
||||
}
|
||||
|
||||
public List<Cell> getRegisteredCells() {
|
||||
return registeredCells;
|
||||
}
|
||||
|
||||
public XSSFRow getRow(int rownum, boolean create) {
|
||||
int rowSize = rows.keySet().size();
|
||||
|
||||
if (rowSize <= rownum) {
|
||||
if (!create) return null;
|
||||
|
||||
for (int i = rowSize; i <= rownum; i++) {
|
||||
rows.put(i, xsheet.createRow(i));
|
||||
}
|
||||
}
|
||||
|
||||
return rows.get(rownum);
|
||||
}
|
||||
|
||||
public XSSFCell getCell(int rownum, int columnnum, CellType type, boolean create) {
|
||||
XSSFRow row = getRow(rownum, create);
|
||||
// List<XSSFCell> columns = rows.get(row);
|
||||
int columnsSize = row.getLastCellNum();
|
||||
|
||||
if (columnsSize == -1) columnsSize = 0;
|
||||
|
||||
if (columnsSize <= columnnum) {
|
||||
if (!create) return null;
|
||||
|
||||
for (int i = columnsSize; i <= columnnum; i++) {
|
||||
row.createCell(i, type);
|
||||
}
|
||||
}
|
||||
|
||||
return row.getCell(columnnum);
|
||||
}
|
||||
|
||||
public XSSFCell getCell(Cell cell, int x, int y, boolean create) {
|
||||
return getCell(y, x, cell.getType(), create);
|
||||
}
|
||||
|
||||
public XSSFSheet getXSheet() {
|
||||
return xsheet;
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.IndexOutOfTableBoundsException;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.util.Position;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.*;
|
||||
|
||||
public class Table {
|
||||
|
||||
private static DecimalFormat format = new DecimalFormat("#.###");
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
private int cellWidth;
|
||||
|
||||
private Map<Position, Cell> content;
|
||||
|
||||
private List<TableSubNameCell> columns;
|
||||
private List<TableSubNameCell> rows;
|
||||
|
||||
public Table(int width, int height, String name) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
cellWidth = Document.WIDTH / width;
|
||||
|
||||
content = new HashMap<>();
|
||||
columns = new ArrayList<>();
|
||||
rows = new ArrayList<>();
|
||||
|
||||
for (int row = 0; row < this.height; row++) {
|
||||
for (int col = 0; col < this.width; col++) {
|
||||
Position pos = new Position(col, row);
|
||||
Cell cell;
|
||||
|
||||
if (col == 0 && row == 0) { // Titre
|
||||
cell = new TableNameCell(name, cellWidth);
|
||||
} else if (col == 0 || row == 0) { // Colonnes/Rangée
|
||||
cell = new TableSubNameCell("", cellWidth);
|
||||
|
||||
if (col > 0) columns.add((TableSubNameCell) cell);
|
||||
else rows.add((TableSubNameCell) cell);
|
||||
} else {
|
||||
cell = new TableStringValueCell("", cellWidth);
|
||||
}
|
||||
|
||||
content.put(pos, cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setColumnName(int index, String name) {
|
||||
int columnnum = columns.size() - 1;
|
||||
if (columnnum < index) throw new IndexOutOfTableBoundsException(index, columnnum);
|
||||
|
||||
columns.get(index).setName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index Index de la rangée (à partir de 0)
|
||||
* @param name Nouveau nom de la rangée
|
||||
* @throws IndexOutOfTableBoundsException La rangée à l'index défini est en dehors de la portée du tableau.
|
||||
* @author
|
||||
*/
|
||||
public void setRowName(int index, String name) {
|
||||
int rownum = rows.size() - 1;
|
||||
if (rownum < index) throw new IndexOutOfTableBoundsException(index, rownum);
|
||||
|
||||
rows.get(index).setName(name);
|
||||
}
|
||||
|
||||
public void setContent(Position position, String value) {
|
||||
if (isInTableRange(position, this)) {
|
||||
content.put(position, new TableStringValueCell(value, cellWidth));
|
||||
}
|
||||
}
|
||||
|
||||
public void setContent(Position position, double value) {
|
||||
if (isInTableRange(position, this)) {
|
||||
value = Double.parseDouble(format.format(value).replace(',', '.'));
|
||||
content.put(position, new TableNumValueCell(value, cellWidth));
|
||||
}
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public Collection<Cell> getCells() {
|
||||
int col = 0;
|
||||
int row = 0;
|
||||
|
||||
Collection<Cell> cells = new ArrayList<>();
|
||||
while (row < height) {
|
||||
|
||||
while (col < width) {
|
||||
Position pos = new Position(col, row);
|
||||
|
||||
cells.add(content.get(pos));
|
||||
|
||||
col++;
|
||||
}
|
||||
|
||||
col = 0;
|
||||
row++;
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
public static boolean isInTableRange(Position position, Table table) {
|
||||
int col = position.getColumn();
|
||||
int columnnum = table.getWidth() - 1;
|
||||
if (col > columnnum) throw new IndexOutOfTableBoundsException(col, columnnum);
|
||||
|
||||
int row = position.getRow();
|
||||
int rownum = table.getHeight() - 1;
|
||||
if (row > rownum) throw new IndexOutOfTableBoundsException(row, rownum);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private class TableNameCell extends Cell implements IColoredCell, IFontCell, IBiggerCell {
|
||||
|
||||
private final IndexedColors COLOR = IndexedColors.GREY_40_PERCENT;
|
||||
|
||||
private String name;
|
||||
private int width;
|
||||
private int height = 2;
|
||||
|
||||
public TableNameCell(String name, int width) {
|
||||
super(CellType.STRING);
|
||||
|
||||
this.name = name;
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentText() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexedColors getBackgroundColor() {
|
||||
return COLOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
||||
private class TableSubNameCell extends Cell implements IFontCell, IBiggerCell, IColoredCell {
|
||||
|
||||
private String name;
|
||||
private int width;
|
||||
private int height = 2;
|
||||
|
||||
public TableSubNameCell(String name, int width) {
|
||||
super(CellType.STRING);
|
||||
|
||||
this.name = name;
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentText() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexedColors getBackgroundColor() {
|
||||
return IndexedColors.GREY_25_PERCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
||||
private class TableStringValueCell extends Cell implements IFontCell, IBiggerCell {
|
||||
|
||||
private String value;
|
||||
private int width;
|
||||
private int height = 2;
|
||||
|
||||
public TableStringValueCell(String value, int width) {
|
||||
super(CellType.STRING);
|
||||
|
||||
this.value = value;
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentText() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBold() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
||||
private class TableNumValueCell extends Cell implements IFontCell, IBiggerCell {
|
||||
|
||||
private double value;
|
||||
private int width;
|
||||
private int height = 2;
|
||||
|
||||
public TableNumValueCell(double value, int width) {
|
||||
super(CellType.NUMERIC);
|
||||
|
||||
this.value = value;
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getContentNum() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBold() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
|
||||
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
|
||||
public class Cell {
|
||||
|
||||
protected CellType type;
|
||||
|
||||
public Cell(CellType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public CellType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getContentText() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public double getContentNum() {
|
||||
return 0.0d;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
|
||||
public class DescriptionCell extends Cell implements IColoredCell, IBiggerCell, IFontCell {
|
||||
|
||||
private static final int WIDTH_NAME = 2;
|
||||
private static final int WIDTH_VALUE = 6;
|
||||
private static final int HEIGHT = 2;
|
||||
private static final IndexedColors BG_COLOR_NAME = IndexedColors.GREY_40_PERCENT;
|
||||
private static final short FONT_HEIGHT = 18;
|
||||
|
||||
private DescriptionCellType type;
|
||||
private String valueStr;
|
||||
private double valueNbr;
|
||||
|
||||
public DescriptionCell(DescriptionCellType type, String value) {
|
||||
super(CellType.STRING);
|
||||
|
||||
this.type = type;
|
||||
this.valueStr = value;
|
||||
}
|
||||
|
||||
public DescriptionCell(DescriptionCellType type, double value) {
|
||||
super(CellType.NUMERIC);
|
||||
|
||||
this.type = type;
|
||||
this.valueNbr = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return type == DescriptionCellType.NAME ? WIDTH_NAME : WIDTH_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexedColors getBackgroundColor() {
|
||||
return type == DescriptionCellType.NAME ? BG_COLOR_NAME : IndexedColors.WHITE1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getFontHeight() {
|
||||
return FONT_HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentText() {
|
||||
return type != DescriptionCellType.VALUE_NUM ? valueStr : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getContentNum() {
|
||||
return type == DescriptionCellType.VALUE_NUM ? valueNbr : 0.0d;
|
||||
}
|
||||
|
||||
public enum DescriptionCellType {
|
||||
NAME, VALUE_STR, VALUE_NUM
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
|
||||
public class NoteCell extends Cell implements IBiggerCell, IFontCell {
|
||||
|
||||
private String value;
|
||||
|
||||
public NoteCell(String value) {
|
||||
super(CellType.STRING);
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return Document.WIDTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return Math.max(Math.abs(value.length() / 100), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBold() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentText() {
|
||||
return value.replaceAll("(.{100})", "$1\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
|
||||
|
||||
public class SectionTitleCell extends Cell implements IColoredCell, IBiggerCell, IFontCell {
|
||||
|
||||
private static final int WIDTH = Document.WIDTH;
|
||||
private static final int HEIGHT = 2;
|
||||
private static final IndexedColors BG_COLOR = IndexedColors.BLACK;
|
||||
private static final IndexedColors FONT_COLOR = IndexedColors.WHITE;
|
||||
private static final int FONT_HEIGHT = 24;
|
||||
|
||||
private String title;
|
||||
|
||||
public SectionTitleCell(String title) {
|
||||
super(CellType.STRING);
|
||||
|
||||
this.title = title.toUpperCase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return WIDTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexedColors getBackgroundColor() {
|
||||
return BG_COLOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexedColors getFontColor() {
|
||||
return FONT_COLOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getFontHeight() {
|
||||
return FONT_HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentText() {
|
||||
return title;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
|
||||
public class TitleCell extends Cell implements IColoredCell, IBiggerCell, IFontCell {
|
||||
|
||||
private static final int WIDTH = Document.WIDTH;
|
||||
private static final int HEIGHT = 3;
|
||||
private static final CellType TYPE = CellType.STRING;
|
||||
private static final IndexedColors FONT_COLOR = IndexedColors.WHITE;
|
||||
private static IndexedColors BACKGROUND_COLOR = IndexedColors.BLACK;
|
||||
|
||||
private String title;
|
||||
|
||||
public TitleCell(String title) {
|
||||
super(TYPE);
|
||||
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexedColors getBackgroundColor() {
|
||||
return BACKGROUND_COLOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexedColors getFontColor() {
|
||||
return FONT_COLOR;
|
||||
}
|
||||
|
||||
public Cell setColor(IndexedColors color) {
|
||||
BACKGROUND_COLOR = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getFontHeight() {
|
||||
return 36;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return WIDTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentText() {
|
||||
return title;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles;
|
||||
|
||||
public interface IBiggerCell {
|
||||
int getWidth();
|
||||
|
||||
int getHeight();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles;
|
||||
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
|
||||
public interface IColoredCell {
|
||||
IndexedColors getBackgroundColor();
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles;
|
||||
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
|
||||
public interface IFontCell {
|
||||
|
||||
default IndexedColors getFontColor() {
|
||||
return IndexedColors.BLACK;
|
||||
}
|
||||
|
||||
default short getFontHeight() {
|
||||
return 14;
|
||||
}
|
||||
|
||||
default boolean isBold() {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean isCentered() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.exception;
|
||||
|
||||
public class IndexOutOfTableBoundsException extends RuntimeException {
|
||||
|
||||
public IndexOutOfTableBoundsException(int current, int max) {
|
||||
super(String.format("L'index '%s' se trouve hors de portée du tableau (maximum: %s)", current, max));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.exception;
|
||||
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
|
||||
public class InvalidCellTypeException extends Exception {
|
||||
|
||||
public InvalidCellTypeException(CellType type) {
|
||||
super(String.format("Les recettes ne peuvent contenir que des cellules de type STRING et NUMERIC. Actuel: %s", type.name()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.util;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Sheet;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.usermodel.*;
|
||||
|
||||
public class CellUtils {
|
||||
public static XSSFColor getXSSFColor(int[] rgb) {
|
||||
return new XSSFColor(new byte[]{(byte) rgb[0], (byte) rgb[1], (byte) rgb[2]}, new DefaultIndexedColorMap());
|
||||
}
|
||||
|
||||
public static boolean isCellEmpty(Sheet sheet, int x, int y) {
|
||||
XSSFRow row = sheet.getRow(y, false);
|
||||
|
||||
if (row == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
XSSFCell cell = row.getCell(x);
|
||||
|
||||
if (cell == null) { // use row.getCell(x, Row.CREATE_NULL_AS_BLANK) to avoid null cells
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell.getCellType() == CellType.BLANK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell.getCellType() == CellType.STRING && cell.getStringCellValue().trim().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isCellInMergedCell(Sheet sheet, int x, int y) {
|
||||
XSSFSheet xsheet = sheet.getXSheet();
|
||||
|
||||
int numberOfMergedRegions = xsheet.getNumMergedRegions();
|
||||
|
||||
for (int i = 0; i < numberOfMergedRegions; i++) {
|
||||
CellRangeAddress mergedCell = xsheet.getMergedRegion(i);
|
||||
|
||||
if (mergedCell.isInRange(y, x)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.xlsx.util;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Position {
|
||||
|
||||
private int column;
|
||||
private int row;
|
||||
|
||||
public Position(int column, int row) {
|
||||
this.column = column;
|
||||
this.row = row;
|
||||
}
|
||||
|
||||
public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
public void setColumn(int column) {
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public int getRow() {
|
||||
return row;
|
||||
}
|
||||
|
||||
public void setRow(int row) {
|
||||
this.row = row;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Position position = (Position) o;
|
||||
return column == position.column &&
|
||||
row == position.row;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(column, row);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s, %s", column, row);
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.core;
|
||||
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ModelBuilder {
|
||||
|
||||
private static String RESPONSE_PREFIX = "response.";
|
||||
private static String ERROR_ATTRIBUTE_NAME = "error";
|
||||
private static String SUCCESS_ATTRIBUTE_NAME = "success";
|
||||
|
||||
private ModelAndView model;
|
||||
private Map<String, Object> modelAttributes;
|
||||
|
||||
public ModelBuilder(String view) {
|
||||
this(new ModelAndView(view));
|
||||
}
|
||||
|
||||
public ModelBuilder(ModelAndView model) {
|
||||
this.model = model == null ? new ModelAndView() : model;
|
||||
|
||||
modelAttributes = new HashMap<>();
|
||||
}
|
||||
|
||||
public ModelBuilder setView(String view) {
|
||||
model.setViewName(view);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModelBuilder addAttribute(String attributeName, Object content) {
|
||||
modelAttributes.put(attributeName, content);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModelBuilder addResponseCode(ResponseCode responseCode, String... parameters) {
|
||||
int requiredParametersNumber = responseCode.getParametersNumber();
|
||||
int givenParametersNumber = parameters.length;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (requiredParametersNumber != givenParametersNumber) {
|
||||
throw new IllegalArgumentException(String.format("Mauvais nombre de paramètre dans un réponse de modèle: %s requis, %s fournis", requiredParametersNumber, givenParametersNumber));
|
||||
}
|
||||
|
||||
// Construit le code de réponse
|
||||
builder.append(RESPONSE_PREFIX);
|
||||
builder.append(responseCode.getCode());
|
||||
|
||||
// Ajoute les paramètres, si nécessaire
|
||||
if (requiredParametersNumber > 0) {
|
||||
builder.append("('");
|
||||
|
||||
for (int i = 0; i < givenParametersNumber; i++) {
|
||||
builder.append(parameters[i]);
|
||||
|
||||
if (i < givenParametersNumber - 1) {
|
||||
builder.append("','");
|
||||
}
|
||||
}
|
||||
|
||||
builder.append("')");
|
||||
}
|
||||
|
||||
// Ajoute l'attribut dans le Map
|
||||
addAttribute(responseCode.getType() == ResponseCode.ResponseCodeType.ERROR ? ERROR_ATTRIBUTE_NAME : SUCCESS_ATTRIBUTE_NAME, builder.toString());
|
||||
addAttribute("arg1", "Bathia");
|
||||
addAttribute("arg2", "test");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModelBuilder addData(ModelDataType modelDataType, @NotNull Object data) {
|
||||
Class modelDataTypeClass = modelDataType.getDataType();
|
||||
Class modelListDataTypeClass = modelDataType.getListDataType();
|
||||
Class givenDataTypeClass = data.getClass();
|
||||
|
||||
// Vérifie le type de l'objet
|
||||
if (!modelDataTypeClass.equals(givenDataTypeClass)) {
|
||||
throw new IllegalArgumentException(String.format("L'objet passé en paramètre n'est pas du bon type. Requis: %s, fournis: %s", modelDataTypeClass.getName(), givenDataTypeClass.getName()));
|
||||
}
|
||||
|
||||
// Si l'objet est une liste, vérifie qu'elle n'est pas vide et qu'elle est du bon type
|
||||
if (modelDataTypeClass.equals(List.class) && modelListDataTypeClass != null) {
|
||||
List listData = (List) data;
|
||||
|
||||
if (listData.size() < 1) {
|
||||
throw new IllegalArgumentException("La liste passée en paramètre ne contient aucun élément");
|
||||
}
|
||||
|
||||
Class givenListDataTypeClass = listData.get(0).getClass();
|
||||
if (givenDataTypeClass.equals(modelListDataTypeClass)) {
|
||||
throw new IllegalArgumentException(String.format("La liste passée en paramètre contient des éléments du mauvais type. Requis: %s, fournis: %s", modelListDataTypeClass.getName(), givenListDataTypeClass.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
// Ajoute l'attribut dans le Map
|
||||
addAttribute(modelDataType.getDataTypeName(), data);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModelAndView build() {
|
||||
model.addAllObjects(modelAttributes);
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.core.utils;
|
||||
|
||||
public class ControllerUtils {
|
||||
|
||||
public static String redirect(String viewName) {
|
||||
return String.format("redirect:/%s", viewName);
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.dao;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Material;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface MaterialDao extends JpaRepository<Material, Integer> {
|
||||
Material findByMaterialID(int materialID);
|
||||
|
||||
Material findByMaterialCode(String materialCode);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.dao;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.MaterialType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface MaterialTypeDao extends JpaRepository<MaterialType, Integer> {
|
||||
|
||||
MaterialType findByMaterialTypeName(String name);
|
||||
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.dao;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Material;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.MixType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface MixTypeDao extends JpaRepository<MixType, Integer> {
|
||||
MixType findByTypeID(int id);
|
||||
|
||||
MixType findByTypeName(String typeName);
|
||||
|
||||
MixType findByMaterial(Material material);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.dao;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Company;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Recipe;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface RecipeDao extends JpaRepository<Recipe, Integer> {
|
||||
|
||||
List<Recipe> findAllByCompany(Company company);
|
||||
|
||||
Recipe findByRecipeCode(String recipeCode);
|
||||
|
||||
Recipe findByRecipeID(int recipeID);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.factory.files;
|
||||
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.DocumentException;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class PdfFactory {
|
||||
|
||||
protected Document document;
|
||||
|
||||
private String fileName;
|
||||
private FileHandler fileHandler;
|
||||
|
||||
public PdfFactory(String fileName) {
|
||||
this(fileName, FileHandler.FileContext.OTHERS);
|
||||
}
|
||||
|
||||
public PdfFactory(String fileName, FileHandler.FileContext context) {
|
||||
this.fileName = fileName;
|
||||
|
||||
fileHandler = new FileHandler(fileName, context, FileHandler.FileExtension.PDF);
|
||||
}
|
||||
|
||||
public PdfFactory open() throws FileNotFoundException, DocumentException {
|
||||
document = new Document();
|
||||
PdfWriter.getInstance(document, new FileOutputStream(fileHandler.getPath().toString()));
|
||||
|
||||
document.open();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void write() {
|
||||
document.close();
|
||||
}
|
||||
|
||||
public FileHandler getFileHandler() {
|
||||
return fileHandler;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.factory.files;
|
||||
|
||||
import com.itextpdf.text.*;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TouchUpKitPdfFactory {
|
||||
|
||||
private String kitName;
|
||||
private ByteArrayOutputStream pdfContent;
|
||||
private Document document;
|
||||
|
||||
public TouchUpKitPdfFactory(String kitName) {
|
||||
this.kitName = kitName.toUpperCase();
|
||||
|
||||
pdfContent = new ByteArrayOutputStream();
|
||||
document = new Document();
|
||||
}
|
||||
|
||||
public TouchUpKitPdfFactory build() throws DocumentException {
|
||||
ColorRecipesExplorerApplication.logger.info(String.format("Génération d'un PDF pour le kit de retouche '%s'", kitName));
|
||||
|
||||
PdfWriter.getInstance(document, pdfContent);
|
||||
|
||||
Font descFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 48, BaseColor.BLACK);
|
||||
Font kitNameFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, kitName.length() > 22 ? 32 : 38, BaseColor.BLACK);
|
||||
|
||||
Paragraph descFr = new Paragraph("KIT DE RETOUCHE", descFont);
|
||||
Paragraph descEn = new Paragraph("TOUCH UP KIT", descFont);
|
||||
Paragraph touchUpKitName = new Paragraph(kitName, kitNameFont);
|
||||
|
||||
descFr.setAlignment(Element.ALIGN_CENTER);
|
||||
descEn.setAlignment(Element.ALIGN_CENTER);
|
||||
touchUpKitName.setAlignment(Element.ALIGN_CENTER);
|
||||
|
||||
document.open();
|
||||
document.add(descFr);
|
||||
document.add(descEn);
|
||||
document.add(touchUpKitName);
|
||||
document.close();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] toByteArray() {
|
||||
byte[] content = pdfContent.toByteArray();
|
||||
|
||||
try {
|
||||
pdfContent.close();
|
||||
} catch (IOException e) {
|
||||
ColorRecipesExplorerApplication.logger.error("Une erreur est survenue lors de la fermeture d'un ByteArrayOutputStream", e);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.model.form;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
public class MaterialForm {
|
||||
|
||||
private String materialCode;
|
||||
|
||||
private int inventoryQuantity;
|
||||
|
||||
private MultipartFile file;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.services;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.dao.CompanyDao;
|
||||
import fyloz.trial.ColorRecipesExplorer.dao.RecipeDao;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.Company;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class CompanyService extends GenericService<Company> {
|
||||
|
||||
private RecipeDao recipeDao; // Utilise le Dao pour éviter une erreur au démarrage, citant une récursion (CompanyService -> RecipeService -> CompanyService -> ...)
|
||||
|
||||
@Autowired
|
||||
public CompanyService(CompanyDao companyDao, RecipeDao recipeDao) {
|
||||
super(companyDao);
|
||||
this.recipeDao = recipeDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidForCreation(Company entity) {
|
||||
return super.isValidForCreation(entity) && getByName(entity.getCompanyName()) == null;
|
||||
}
|
||||
|
||||
public Company getByName(String name) {
|
||||
return ((CompanyDao) dao).findByCompanyName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si une bannière est liée à une ou plusieurs recettes en faisant une requête dans la base de données,
|
||||
* pour retourner s'il y a des résultats ou non.
|
||||
*
|
||||
* @return Si la bannière est liée à une ou plusieurs recettes.
|
||||
*/
|
||||
public boolean isLinkedToRecipes(Company company) {
|
||||
return !recipeDao.findAllByCompany(company).isEmpty();
|
||||
}
|
||||
|
||||
public boolean deleteIfNotLinked(Company company) {
|
||||
if (!isLinkedToRecipes(company)) {
|
||||
return super.delete(company);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package fyloz.trial.ColorRecipesExplorer.services;
|
||||
|
||||
import fyloz.trial.ColorRecipesExplorer.dao.MaterialTypeDao;
|
||||
import fyloz.trial.ColorRecipesExplorer.model.MaterialType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MaterialTypeService extends GenericService<MaterialType> {
|
||||
|
||||
private MaterialTypeDao materialTypeDao;
|
||||
|
||||
@Autowired
|
||||
public MaterialTypeService(MaterialTypeDao materialTypeDao) {
|
||||
super(materialTypeDao);
|
||||
this.materialTypeDao = materialTypeDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidForCreation(MaterialType entity) {
|
||||
return entity != null && !existsByName(entity);
|
||||
}
|
||||
|
||||
public MaterialType getByName(String name) {
|
||||
return materialTypeDao.findByMaterialTypeName(name);
|
||||
}
|
||||
|
||||
public MaterialType getDefaultMaterialType() {
|
||||
MaterialType defaultType = getByName("Aucun");
|
||||
|
||||
if (defaultType == null) {
|
||||
defaultType = new MaterialType("Aucun", "", false);
|
||||
save(defaultType);
|
||||
}
|
||||
|
||||
return defaultType;
|
||||
}
|
||||
|
||||
public boolean existsByName(MaterialType entity) {
|
||||
return getByName(entity.getMaterialTypeName()) != null;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue