# v1.2.0 (Imprimante P-touch)
### Corrections * Correction d'un bug qui empêchait la suppression des mélanges. * Correction d'un bug qui empêche les boutons supprimer de fonctionner. * Correction d'un bug qui permettait d'envoyer les formulaires demandant des mots de passe sans donner un mot de passe valide. * Correction d'une désynchronisation entre le nom des mélanges et leur produit interne. * Amélioration du style. * Amélioration de la fluidité de la navigation. * Transition complète des modèles vers Lombok. ### Ajouts * Ajout du support pour l'imprimante P-touch de Brother. * L'extension b-Pac doit être installée sur le navigateur des clients. * [Firefox](https://cre.fyloz.dev/bpac.xpi) * [Chrome](https://chrome.google.com/webstore/detail/brother-b-pac-extension/ilpghlfadkjifilabejhhijpfphfcfhb) * Le logiciel b-Pac doit être installé sur l'ordinateur des clients. * [Windows](https://download.brother.com/welcome/dlfp100614/bcciw32031.msi) * Ajout de la possibilité d'imprimer les mélanges avec P-Touch * Ajout de la possibilité d'imprimer les étiquettes de kit de retouche avec P-Touch * Ajout des boîtes de confirmation. * Ajout d'un type de produit aux mélanges. * Ajout du changement d'ordre des produits d'un mélange. * Les produits dans l'inventaire sont maintenant ordonnés alphabétiquement. ### Dépendances * Ajout de jQuery, début de la transition. * Migration vers Java 11
This commit is contained in:
parent
4f7336e982
commit
88f7ec338e
25
pom.xml
25
pom.xml
|
@ -10,12 +10,12 @@
|
|||
</parent>
|
||||
<groupId>dev.fyloz.trial.colorrecipesexplorer</groupId>
|
||||
<artifactId>ColorRecipesExplorer</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<version>1.2.0</version>
|
||||
<name>Color Recipes Explorer</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<java.version>11</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -41,11 +41,6 @@
|
|||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<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>
|
||||
|
@ -56,16 +51,6 @@
|
|||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.itextpdf</groupId>
|
||||
<artifactId>itextpdf</artifactId>
|
||||
<version>5.5.10</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
|
@ -95,6 +80,12 @@
|
|||
<artifactId>commonmark</artifactId>
|
||||
<version>0.13.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -35,7 +35,7 @@ public class InitialDataLoader implements ApplicationListener<ApplicationReadyEv
|
|||
MaterialType defaultMaterialType = new MaterialType(name, "", false);
|
||||
|
||||
Optional<MaterialType> optionalSavedMaterialType = materialTypeService.save(defaultMaterialType);
|
||||
if (!optionalSavedMaterialType.isPresent()) {
|
||||
if (optionalSavedMaterialType.isEmpty()) {
|
||||
ColorRecipesExplorerApplication.LOGGER.warn(String.format("Échec de la création du type de produit par défaut '%s'.", name));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,13 @@ public enum ResponseCode {
|
|||
RECIPE_NOT_FOUND_NO_PARAMS(25, ResponseCodeType.ERROR, 0),
|
||||
MATERIAL_NOT_FOUND_BY_NAME(26, ResponseCodeType.ERROR, 1),
|
||||
SUCCESS_DELETING_COMPANY(27, ResponseCodeType.SUCCESS, 1),
|
||||
SUCCESS_SAVING_MATERIAL(28, ResponseCodeType.SUCCESS, 1),
|
||||
SUCCESS_SAVING_MATERIAL_TYPE(29, ResponseCodeType.SUCCESS, 1),
|
||||
SUCCESS_SAVING_RECIPE(30, ResponseCodeType.SUCCESS, 1),
|
||||
SUCCESS_DELETING_MATERIAL(31, ResponseCodeType.SUCCESS, 1),
|
||||
SUCCESS_SAVING_COMPANY(32, ResponseCodeType.SUCCESS, 1),
|
||||
SUCCESS_DELETING_RECIPE(33, ResponseCodeType.SUCCESS, 1),
|
||||
SUCCESS_DELETING_MATERIAL_TYPE(34, ResponseCodeType.SUCCESS, 1),
|
||||
|
||||
// HTTP Errors
|
||||
_500(100, ResponseCodeType.ERROR, 0),
|
||||
|
|
|
@ -11,9 +11,9 @@ import java.io.Serializable;
|
|||
@Entity
|
||||
@Table(name = "materials")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@RequiredArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Material extends BeanModel implements Serializable {
|
||||
|
||||
@Id
|
||||
|
|
|
@ -20,7 +20,7 @@ public class MaterialType extends BeanModel implements Serializable {
|
|||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||
private Integer materialTypeID;
|
||||
private Integer materialTypeID = 0;
|
||||
|
||||
@NonNull
|
||||
@NotNull
|
||||
|
|
|
@ -57,27 +57,13 @@ public class Recipe extends BeanModel implements Serializable {
|
|||
return recipeID;
|
||||
}
|
||||
|
||||
public Material getBase() {
|
||||
if (recipeMixes.isEmpty() || recipeMixes.stream().allMatch(m -> m.getMixQuantities().isEmpty())) return null;
|
||||
|
||||
Material base = recipeMixes
|
||||
.stream()
|
||||
.map(mix -> mix
|
||||
.getMixQuantities()
|
||||
.stream()
|
||||
.filter(mq -> mq.getMaterial().getMaterialType().getMaterialTypeName().equals(MaterialType.BASE_MATERIAL_TYPE_NAME))
|
||||
.findFirst().get()
|
||||
)
|
||||
.findFirst().orElse(recipeMixes
|
||||
.stream()
|
||||
.filter(m -> !m.getMixQuantities().isEmpty())
|
||||
.findFirst()
|
||||
.get()
|
||||
.getMixQuantities()
|
||||
.stream()
|
||||
.findFirst()
|
||||
.get()).getMaterial();
|
||||
|
||||
return base;
|
||||
}
|
||||
// public Material getBase() {
|
||||
// for (Mix mix : recipeMixes) {
|
||||
// for(MixQuantity mq : mix.getMixQuantities()) {
|
||||
// if(mq.getMaterial().getMaterialType().getMaterialTypeName().equals(MaterialType.BASE_MATERIAL_TYPE_NAME)) return mq.getMaterial();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -32,13 +32,13 @@ public class InventoryService {
|
|||
return null;
|
||||
}
|
||||
|
||||
public boolean useMix(Mix mix, Map<Material, Float> quantities) {
|
||||
public boolean useMix(Map<Material, Float> quantities) {
|
||||
for (Map.Entry<Material, Float> entry : quantities.entrySet()) {
|
||||
Material material = entry.getKey();
|
||||
|
||||
if (!material.isMixType()) {
|
||||
material.setInventoryQuantity(material.getInventoryQuantity() - entry.getValue());
|
||||
if (!materialService.update(material).isPresent()) return false;
|
||||
if (materialService.update(material).isEmpty()) return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,9 +72,10 @@ public class MaterialService extends GenericService<Material, MaterialDao> {
|
|||
if (material == null) return false;
|
||||
|
||||
Optional<Material> materialByCode = dao.findByMaterialCode(material.getMaterialCode());
|
||||
return super.isValidForUpdate(material) && (!materialByCode.isPresent() || material.getMaterialID().equals(materialByCode.get().getMaterialID()));
|
||||
return super.isValidForUpdate(material) && (materialByCode.isEmpty() || material.getMaterialID().equals(materialByCode.get().getMaterialID()));
|
||||
}
|
||||
|
||||
@Deprecated(since = "1.2.0")
|
||||
public List<Material> getAllBySearchString(String searchString) {
|
||||
return dao.findAllByMaterialCodeContainingIgnoreCase(searchString).stream().filter(m -> !m.isMixType()).collect(Collectors.toList());
|
||||
}
|
||||
|
|
|
@ -46,13 +46,13 @@ public class MaterialTypeService extends GenericService<MaterialType, MaterialTy
|
|||
public boolean isValidForUpdateName(MaterialType materialType) {
|
||||
Optional<MaterialType> materialTypeByName = dao.findByMaterialTypeName(materialType.getMaterialTypeName());
|
||||
|
||||
return !materialTypeByName.isPresent() || materialType.getMaterialTypeID().equals(materialTypeByName.get().getMaterialTypeID());
|
||||
return materialTypeByName.isEmpty() || 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());
|
||||
return materialTypeByPrefix.isEmpty() || materialType.getMaterialTypeID().equals(materialTypeByPrefix.get().getMaterialTypeID());
|
||||
}
|
||||
|
||||
public Optional<MaterialType> getByName(String name) {
|
||||
|
|
|
@ -11,9 +11,8 @@ 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;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class MixService extends GenericService<Mix, MixDao> {
|
||||
|
@ -32,6 +31,25 @@ public class MixService extends GenericService<Mix, MixDao> {
|
|||
this.recipeService = recipeService;
|
||||
}
|
||||
|
||||
public Collection<Material> getAvailableMaterialsForNewMix(Recipe recipe) {
|
||||
Collection<MixType> recipeMixTypes = recipeService.getAssociatedMixesTypes(recipe);
|
||||
|
||||
return materialService
|
||||
.getAll()
|
||||
.stream()
|
||||
.filter(m -> !m.isMixType() || recipeMixTypes.contains(mixTypeService.getByMaterial(m).get()))
|
||||
.sorted(Comparator.comparing(Material::getMaterialCode))
|
||||
.sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Collection<Material> getAvailableMaterialsForMix(Recipe recipe, Mix mix) {
|
||||
return getAvailableMaterialsForNewMix(recipe)
|
||||
.stream()
|
||||
.filter(m -> !m.equals(mix.getMixType().getMaterial()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ModelResponseBuilder create(MixCreationFormDto formDto, @NotNull Recipe recipe) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
|
||||
|
@ -39,7 +57,7 @@ public class MixService extends GenericService<Mix, MixDao> {
|
|||
List<Material> materials = new ArrayList<>();
|
||||
for (String materialCode : formDto.getMaterials()) {
|
||||
Optional<Material> found = materialService.getByMaterialCode(materialCode);
|
||||
if (!found.isPresent()) {
|
||||
if (found.isEmpty()) {
|
||||
return modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND_BY_NAME, materialCode);
|
||||
}
|
||||
|
||||
|
@ -47,7 +65,7 @@ public class MixService extends GenericService<Mix, MixDao> {
|
|||
}
|
||||
|
||||
Optional<MixType> optionalMixType = mixTypeService.createByName(formDto.getMixTypeName(), formDto.getMaterialType());
|
||||
if (!optionalMixType.isPresent()) return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
if (optionalMixType.isEmpty()) return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
|
||||
MixType mixType = optionalMixType.get();
|
||||
if (recipeService.hasMixType(recipe, mixType))
|
||||
|
@ -80,7 +98,7 @@ public class MixService extends GenericService<Mix, MixDao> {
|
|||
List<Material> materials = new ArrayList<>();
|
||||
for (String materialCode : formDto.getMaterials()) {
|
||||
Optional<Material> found = materialService.getByMaterialCode(materialCode);
|
||||
if (!found.isPresent()) {
|
||||
if (found.isEmpty()) {
|
||||
return modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND_BY_NAME, materialCode);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ public class RecipeService extends GenericService<Recipe, RecipeDao> {
|
|||
storedRecipe.setNote(newRecipe.getNote());
|
||||
|
||||
Optional<Recipe> optionalRecipe = convertAndCreateSteps(storedRecipe, form);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
@ -126,6 +126,7 @@ public class RecipeService extends GenericService<Recipe, RecipeDao> {
|
|||
.contains(mixType);
|
||||
}
|
||||
|
||||
@Deprecated(since = "1.2.0")
|
||||
public Map<Company, List<Recipe>> getRecipesForSearchString(String searchString) {
|
||||
List<Recipe> recipes = dao.findAllByRecipeDescriptionContainsOrRecipeCodeContains(searchString.toUpperCase());
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.utils.PdfBuilder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Service
|
||||
public class TouchUpKitService {
|
||||
|
||||
private static final String TOUCH_UP_FR = "KIT DE RETOUCHE";
|
||||
private static final String TOUCH_UP_EN = "TOUCH UP KIT";
|
||||
public static final int FONT_SIZE = 42;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
@Autowired
|
||||
public TouchUpKitService(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
public byte[] getPdfForJobNumber(String jobNumber) throws IOException {
|
||||
return new PdfBuilder(resourceLoader, true, FONT_SIZE)
|
||||
.addLine(TOUCH_UP_FR, true, 0)
|
||||
.addLine(TOUCH_UP_EN, true, 0)
|
||||
.addLine(jobNumber, false, 10)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.core.utils;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class PdfBuilder {
|
||||
|
||||
private PDFont font;
|
||||
private PDDocument document = new PDDocument();
|
||||
private PDPage page = new PDPage();
|
||||
private Collection<PdfLine> lines = new ArrayList<>();
|
||||
private boolean duplicated;
|
||||
private int fontSize;
|
||||
private int fontSizeBold;
|
||||
private int lineSpacing;
|
||||
|
||||
public PdfBuilder(ResourceLoader resourceLoader, boolean duplicated, int fontSize) throws IOException {
|
||||
this.duplicated = duplicated;
|
||||
this.fontSize = fontSize;
|
||||
this.fontSizeBold = this.fontSize + 12;
|
||||
this.lineSpacing = (int) (this.fontSize * 1.5f);
|
||||
|
||||
document.addPage(page);
|
||||
font = PDType0Font.load(document, resourceLoader.getResource(WebsitePaths.FONT_ARIAL_BOLD).getFile());
|
||||
}
|
||||
|
||||
public PdfBuilder addLine(String text, boolean bold, int marginTop) {
|
||||
lines.add(new PdfLine(text, bold, marginTop));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] build() throws IOException {
|
||||
writeContent();
|
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
document.save(outputStream);
|
||||
document.close();
|
||||
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
private void writeContent() throws IOException {
|
||||
PDPageContentStream contentStream = new PDPageContentStream(document, page);
|
||||
contentStream.beginText();
|
||||
|
||||
int marginTop = 30;
|
||||
for (PdfLine line : lines) {
|
||||
writeCenteredText(contentStream, line, marginTop);
|
||||
marginTop += lineSpacing;
|
||||
}
|
||||
|
||||
if (duplicated) {
|
||||
marginTop = (int) page.getMediaBox().getHeight() / 2;
|
||||
for (PdfLine line : lines) {
|
||||
writeCenteredText(contentStream, line, marginTop);
|
||||
marginTop += lineSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
contentStream.endText();
|
||||
contentStream.close();
|
||||
}
|
||||
|
||||
private void writeCenteredText(PDPageContentStream contentStream, PdfLine line, int marginTop) throws IOException {
|
||||
float textWidth = font.getStringWidth(line.getText()) / 1000 * (line.isBold() ? fontSizeBold : fontSize);
|
||||
float textHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * (line.isBold() ? fontSizeBold : fontSize);
|
||||
float textX = (page.getMediaBox().getWidth() - textWidth) / 2f;
|
||||
float textY = (page.getMediaBox().getHeight() - (marginTop + line.getMarginTop()) - textHeight);
|
||||
|
||||
if (line.isBold()) contentStream.setFont(font, fontSizeBold);
|
||||
else contentStream.setFont(font, fontSize);
|
||||
|
||||
contentStream.newLineAtOffset(textX, textY);
|
||||
contentStream.showText(line.getText());
|
||||
contentStream.newLineAtOffset(-textX, -textY); // Réinitialise la position pour la prochaine ligne
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public static class PdfLine {
|
||||
|
||||
private String text;
|
||||
private boolean bold;
|
||||
private int marginTop;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +1,19 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web;
|
||||
|
||||
public class PagesPaths {
|
||||
public class WebsitePaths {
|
||||
// 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";
|
||||
public static final String FONT_ARIAL_BOLD = "classpath:fonts/arialbd.ttf";
|
||||
|
||||
// Images
|
||||
public static final String IMAGES_FILES = "images/{image}";
|
||||
|
@ -21,6 +21,12 @@ public class PagesPaths {
|
|||
public static final String ADD_IMAGE_SPECIFIC = "images/add/{recipeID}";
|
||||
public static final String DELETE_IMAGE = "images/delete";
|
||||
|
||||
// Touch up kits
|
||||
public static final String TOUCHUP = "touchup";
|
||||
public static final String TOUCHUP_PDF = "touchup/pdf";
|
||||
public static final String TOUCHUP_PTOUCH = "touchup/ptouch";
|
||||
public static final String TOUCHUP_PTOUCH_PAGE = "touchupPtouch";
|
||||
|
||||
// Inventaire
|
||||
public static final String INVENTORY = "inventory";
|
||||
public static final String USE_INVENTORY = "inventory/use";
|
|
@ -10,7 +10,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.ERROR;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.ERROR;
|
||||
|
||||
@Controller
|
||||
public class CREErrorController implements ErrorController {
|
||||
|
|
|
@ -6,7 +6,6 @@ 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;
|
||||
|
@ -19,17 +18,16 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.INDEX;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.PASSWORD_VALIDATION;
|
||||
|
||||
@Controller
|
||||
public class IndexController {
|
||||
|
||||
private CompanyService companyService;
|
||||
private RecipeService recipeService;
|
||||
|
||||
@Autowired
|
||||
public IndexController(CompanyService companyService, RecipeService recipeService) {
|
||||
this.companyService = companyService;
|
||||
public IndexController(RecipeService recipeService) {
|
||||
this.recipeService = recipeService;
|
||||
}
|
||||
|
||||
|
@ -39,21 +37,14 @@ public class IndexController {
|
|||
* @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));
|
||||
}
|
||||
|
||||
public ModelAndView getPage() {
|
||||
return new ModelResponseBuilder(INDEX)
|
||||
.addResponseData(ResponseDataType.RECIPE_MAP, recipes)
|
||||
.addResponseData(ResponseDataType.RECIPE_MAP, recipeService.getRecipesByCompany())
|
||||
.build();
|
||||
}
|
||||
|
||||
@GetMapping(value = SEARCH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
// @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<>();
|
||||
|
|
|
@ -21,8 +21,9 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.RESPONSE_REASON;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.INVENTORY;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.USE_INVENTORY;
|
||||
|
||||
@Controller
|
||||
public class InventoryController {
|
||||
|
@ -41,7 +42,7 @@ public class InventoryController {
|
|||
}
|
||||
|
||||
@GetMapping(INVENTORY)
|
||||
public ModelAndView getInventory(ModelAndView model) {
|
||||
public ModelAndView getPage(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(INVENTORY)
|
||||
.addResponseData(ResponseDataType.MATERIALS, materialService.getAllOrdered().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
|
||||
|
@ -77,7 +78,8 @@ public class InventoryController {
|
|||
@ResponseBody
|
||||
@Transactional
|
||||
// TODO vers DTO
|
||||
public Map<String, Object> consumeMaterials(@RequestBody Map<String, Object> form) {
|
||||
// TODO + vers service
|
||||
public Map<String, Object> consumeMaterials(@RequestBody Map<String, Map<String, Float>> form) {
|
||||
JSONResponseBuilder responseBuilder = new JSONResponseBuilder();
|
||||
|
||||
List<Mix> mixes = new ArrayList<>();
|
||||
|
@ -87,7 +89,7 @@ public class InventoryController {
|
|||
int mixID = Integer.parseInt(mixIDStr);
|
||||
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
if (!optionalMix.isPresent()) {
|
||||
if (optionalMix.isEmpty()) {
|
||||
return responseBuilder
|
||||
.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID)
|
||||
.build();
|
||||
|
@ -96,14 +98,15 @@ public class InventoryController {
|
|||
Mix mix = optionalMix.get();
|
||||
mixes.add(mix);
|
||||
|
||||
Map<String, String> formMaterials = (Map<String, String>) form.get(mixIDStr);
|
||||
Map<String, Float> formMaterials = form.get(mixIDStr);
|
||||
Map<Material, Float> mixQuantities = new HashMap<>();
|
||||
|
||||
for (Material material : mix.getMixQuantities().stream().map(MixQuantity::getMaterial).collect(Collectors.toList())) {
|
||||
String materialIDAsString = String.valueOf(material.getMaterialID());
|
||||
|
||||
if (formMaterials.containsKey(materialIDAsString)) {
|
||||
mixQuantities.put(material, Float.parseFloat(formMaterials.get(materialIDAsString)));
|
||||
Float quantityAsString = formMaterials.get(materialIDAsString);
|
||||
mixQuantities.put(material, quantityAsString);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +126,7 @@ public class InventoryController {
|
|||
}
|
||||
|
||||
for (Mix mix : mixes) {
|
||||
if (!inventoryService.useMix(mix, quantities.get(mix))) {
|
||||
if (!inventoryService.useMix(quantities.get(mix))) {
|
||||
return responseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.build();
|
||||
|
@ -135,8 +138,8 @@ public class InventoryController {
|
|||
.build();
|
||||
}
|
||||
|
||||
@GetMapping(value = SEARCH_INVENTORY, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
// @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());
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
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;
|
||||
|
@ -27,19 +23,11 @@ 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;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*;
|
||||
|
||||
@Controller
|
||||
public class OthersController {
|
||||
|
@ -69,7 +57,7 @@ public class OthersController {
|
|||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(MATERIAL_SELECTOR_FRAGMENT);
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return modelResponseBuilder
|
||||
.withView("")
|
||||
.build();
|
||||
|
@ -78,77 +66,13 @@ public class OthersController {
|
|||
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());
|
||||
Collection<Material> materials = mixExist ? mixService.getAvailableMaterialsForMix(optionalRecipe.get(), optionalMix.get()) : mixService.getAvailableMaterialsForNewMix(optionalRecipe.get());
|
||||
|
||||
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();
|
||||
|
@ -156,7 +80,7 @@ public class OthersController {
|
|||
|
||||
@GetMapping(value = UPDATES_GET, produces = MediaType.TEXT_HTML_VALUE)
|
||||
@ResponseBody
|
||||
public ResponseEntity<String> getUpdates() throws IOException {
|
||||
public ResponseEntity<String> getUpdates() {
|
||||
String fileContent = FileUtils.readClasspathFile(resourceLoader, "classpath:updates.md");
|
||||
if (fileContent == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*;
|
||||
|
||||
@Controller
|
||||
public class RecipeExplorerController {
|
||||
|
@ -44,11 +44,11 @@ public class RecipeExplorerController {
|
|||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(EXPLORER_RECIPE_SPECIFIC)
|
||||
public ModelAndView showRecipe(@PathVariable int recipeID) {
|
||||
public ModelAndView getPage(@PathVariable int recipeID) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(EXPLORER_RECIPE);
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return modelResponseBuilder
|
||||
.withView(INDEX)
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
|
@ -78,7 +78,7 @@ public class RecipeExplorerController {
|
|||
String note = form.get("note").toString();
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID);
|
||||
} else {
|
||||
Recipe recipe = optionalRecipe.get();
|
||||
|
@ -91,7 +91,7 @@ public class RecipeExplorerController {
|
|||
int mixID = Integer.parseInt(mixIDStr);
|
||||
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
if (!optionalMix.isPresent()) {
|
||||
if (optionalMix.isEmpty()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID);
|
||||
} else {
|
||||
Mix mix = optionalMix.get();
|
||||
|
|
|
@ -16,8 +16,8 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
import javax.validation.Valid;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_COMPANY;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.INDEX;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.CREATOR_COMPANY;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.INDEX;
|
||||
|
||||
@Controller
|
||||
public class CompanyCreatorController {
|
||||
|
@ -33,7 +33,7 @@ public class CompanyCreatorController {
|
|||
public ModelAndView showCreationPage(ModelAndView model, Company company) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(CREATOR_COMPANY)
|
||||
.addResponseData(ResponseDataType.COMPANY, company)
|
||||
.addResponseData(ResponseDataType.COMPANY, company == null ? new Company() : company)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,9 @@ public class CompanyCreatorController {
|
|||
Optional<Company> savedCompany = companyService.save(company);
|
||||
|
||||
if (savedCompany.isPresent()) {
|
||||
return modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.COMPANY_NAME, savedCompany.get().getCompanyName())
|
||||
.build();
|
||||
return showCreationPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.SUCCESS_SAVING_COMPANY, savedCompany.get().getCompanyName())
|
||||
.build(), null);
|
||||
} else {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
import javax.validation.Valid;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_MATERIAL;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.CREATOR_MATERIAL;
|
||||
|
||||
@Controller
|
||||
public class MaterialCreatorController {
|
||||
|
@ -68,7 +68,7 @@ public class MaterialCreatorController {
|
|||
if (savedMaterial.isPresent()) {
|
||||
material = savedMaterial.get();
|
||||
|
||||
modelResponseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode());
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.SUCCESS_SAVING_MATERIAL, material.getMaterialCode());
|
||||
|
||||
if (simdut.getSize() > 0 && !materialService.addSimdut(simdut, material)) {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
|
||||
|
|
|
@ -13,9 +13,10 @@ 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_MATERIAL_TYPE;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.INDEX;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.CREATOR_MATERIAL_TYPE;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.INDEX;
|
||||
|
||||
@Controller
|
||||
public class MaterialTypeCreatorController {
|
||||
|
@ -28,7 +29,7 @@ public class MaterialTypeCreatorController {
|
|||
}
|
||||
|
||||
@GetMapping(CREATOR_MATERIAL_TYPE)
|
||||
public ModelAndView showPage(ModelAndView model, MaterialType materialType) {
|
||||
public ModelAndView getPage(ModelAndView model, MaterialType materialType) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(CREATOR_MATERIAL_TYPE)
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPE, materialType == null ? new MaterialType() : materialType)
|
||||
|
@ -40,8 +41,11 @@ public class MaterialTypeCreatorController {
|
|||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect(INDEX));
|
||||
|
||||
if (materialTypeService.isValidForCreation(materialType)) {
|
||||
if (materialTypeService.save(materialType) != null) {
|
||||
return modelResponseBuilder.build();
|
||||
Optional<MaterialType> optionalMaterialType = materialTypeService.save(materialType);
|
||||
if (optionalMaterialType.isPresent()) {
|
||||
return getPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.SUCCESS_SAVING_MATERIAL_TYPE, optionalMaterialType.get().getMaterialTypeName())
|
||||
.build(), null);
|
||||
} else {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
}
|
||||
|
@ -49,6 +53,6 @@ public class MaterialTypeCreatorController {
|
|||
modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST, materialType.getMaterialTypeName());
|
||||
}
|
||||
|
||||
return showPage(modelResponseBuilder.build(), materialType);
|
||||
return getPage(modelResponseBuilder.build(), materialType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ 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.*;
|
||||
|
@ -19,12 +17,9 @@ 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.WebsitePaths.*;
|
||||
|
||||
@Controller
|
||||
public class MixCreatorController {
|
||||
|
@ -58,7 +53,7 @@ public class MixCreatorController {
|
|||
.withView(CREATOR_MIX);
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return modelResponseBuilder
|
||||
.withView(ControllerUtils.redirect(EDITOR_RECIPE))
|
||||
.build();
|
||||
|
@ -66,20 +61,10 @@ public class MixCreatorController {
|
|||
|
||||
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)
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
|
||||
.addAttribute("materialsJson", materialService.asJson(materials));
|
||||
.addAttribute("materialsJson", materialService.asJson(mixService.getAvailableMaterialsForNewMix(recipe)));
|
||||
|
||||
if (materialService.getAll().isEmpty()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.NO_MATERIAL)
|
||||
|
|
|
@ -15,8 +15,8 @@ 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;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.CREATOR_RECIPE;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.EDITOR_RECIPE_SPECIFIC;
|
||||
|
||||
@Controller
|
||||
public class RecipeCreatorController {
|
||||
|
@ -62,12 +62,12 @@ public class RecipeCreatorController {
|
|||
*/
|
||||
@PostMapping(value = CREATOR_RECIPE)
|
||||
public ModelAndView createRecipe(@Valid Recipe recipe) {
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(CREATOR_RECIPE_SUCCESS);
|
||||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
|
||||
|
||||
Optional<Recipe> savedRecipe = recipeService.save(recipe);
|
||||
if (savedRecipe.isPresent()) {
|
||||
return modelResponseBuilder
|
||||
.addResponseData(ResponseDataType.RECIPE, savedRecipe.get())
|
||||
.withRedirect(EDITOR_RECIPE_SPECIFIC, savedRecipe.get().getRecipeID())
|
||||
.build();
|
||||
}
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
|
|
|
@ -19,7 +19,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*;
|
||||
|
||||
@Controller
|
||||
public class MaterialEditorController {
|
||||
|
@ -58,7 +58,7 @@ public class MaterialEditorController {
|
|||
if (material.getMaterialCode() == null) {
|
||||
Optional<Material> optionalMaterial = materialService.getByID(materialID);
|
||||
|
||||
if (!optionalMaterial.isPresent()) {
|
||||
if (optionalMaterial.isEmpty()) {
|
||||
return listMaterials(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID)
|
||||
|
@ -110,7 +110,8 @@ public class MaterialEditorController {
|
|||
} else {
|
||||
Optional<Material> updatedMaterial = materialService.update(material);
|
||||
if (updatedMaterial.isPresent()) {
|
||||
responseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, updatedMaterial.get().getMaterialCode());
|
||||
responseBuilder.addResponseCode(ResponseCode.SUCCESS_SAVING_MATERIAL, updatedMaterial.get().getMaterialCode());
|
||||
// responseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, updatedMaterial.get().getMaterialCode());
|
||||
} else {
|
||||
return showEditPage(
|
||||
responseBuilder
|
||||
|
@ -159,7 +160,7 @@ public class MaterialEditorController {
|
|||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect("material/editor/" + materialID));
|
||||
|
||||
Optional<Material> optionalMaterial = materialService.getByID(materialID);
|
||||
if (!optionalMaterial.isPresent()) {
|
||||
if (optionalMaterial.isEmpty()) {
|
||||
return chooseSIMDUTFile(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID)
|
||||
.build(),
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*;
|
||||
|
||||
@Controller
|
||||
public class MaterialTypeEditorController {
|
||||
|
@ -43,7 +43,7 @@ public class MaterialTypeEditorController {
|
|||
if (materialType.getMaterialTypeName() == null) {
|
||||
Optional<MaterialType> optionalMaterialType = materialTypeService.getByID(materialTypeID);
|
||||
|
||||
if (!optionalMaterialType.isPresent()) {
|
||||
if (optionalMaterialType.isEmpty()) {
|
||||
return listMaterialTypes(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID)
|
||||
|
@ -62,32 +62,38 @@ public class MaterialTypeEditorController {
|
|||
@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);
|
||||
// L'ID est 0 lors de la désérialisation, il faut utiliser le nom unique
|
||||
String materialTypeName = materialType.getMaterialTypeName();
|
||||
Optional<MaterialType> optionalMaterialType = materialTypeService.getByName(materialTypeName);
|
||||
|
||||
if (optionalMaterialType.isEmpty()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeName);
|
||||
} else {
|
||||
Optional<MaterialType> updatedMaterialType = materialTypeService.update(materialType);
|
||||
if (updatedMaterialType.isPresent()) {
|
||||
responseBuilder.addResponseData(ResponseDataType.MATERIAL_TYPE_NAME, updatedMaterialType.get().getMaterialTypeName());
|
||||
} else {
|
||||
materialType = optionalMaterialType.get();
|
||||
if (!materialTypeService.isValidForUpdateName(materialType)) {
|
||||
return showEditPage(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST, materialType.getMaterialTypeName())
|
||||
.build(),
|
||||
materialTypeID, null);
|
||||
materialType.getMaterialTypeID(), materialType);
|
||||
} else if (!materialTypeService.isValidForUpdatePrefix(materialType)) {
|
||||
return showEditPage(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST_PREFIX, materialType.getPrefix())
|
||||
.build(),
|
||||
materialType.getMaterialTypeID(), materialType);
|
||||
} else {
|
||||
Optional<MaterialType> updatedMaterialType = materialTypeService.update(materialType);
|
||||
if (updatedMaterialType.isPresent()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.SUCCESS_SAVING_MATERIAL_TYPE, updatedMaterialType.get().getMaterialTypeName());
|
||||
} else {
|
||||
return showEditPage(
|
||||
responseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.build(),
|
||||
materialType.getMaterialTypeID(), materialType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@ 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.*;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
|
||||
|
@ -19,13 +17,10 @@ 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.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*;
|
||||
|
||||
@Controller
|
||||
public class MixEditorController {
|
||||
|
@ -54,27 +49,18 @@ public class MixEditorController {
|
|||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(EDITOR_MIX_SPECIFIC)
|
||||
public ModelAndView showPage(ModelAndView model, @PathVariable int mixID) {
|
||||
public ModelAndView getPage(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()) {
|
||||
if (optionalMix.isEmpty()) {
|
||||
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)
|
||||
|
@ -82,7 +68,7 @@ public class MixEditorController {
|
|||
.addAttribute(MATERIAL_TYPE, mix.getMixType().getMaterial().getMaterialType())
|
||||
.addAttribute(MATERIAL_TYPES, materialTypeService.getAll())
|
||||
.addAttribute("mixJson", materialService.asJson(mix))
|
||||
.addAttribute("materialsJson", materialService.asJson(materials))
|
||||
.addAttribute("materialsJson", mixService.asJson(mixService.getAvailableMaterialsForMix(mix.getRecipe(), mix)))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -108,10 +94,10 @@ public class MixEditorController {
|
|||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
|
||||
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
if (!optionalMix.isPresent()) {
|
||||
if (optionalMix.isEmpty()) {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID);
|
||||
|
||||
return showPage(modelResponseBuilder.build(), mixID);
|
||||
return getPage(modelResponseBuilder.build(), mixID);
|
||||
}
|
||||
|
||||
Mix mix = optionalMix.get();
|
||||
|
@ -119,7 +105,7 @@ public class MixEditorController {
|
|||
|
||||
ModelResponseBuilder editResult = mixService.edit(mix, formDto);
|
||||
if (editResult != null) {
|
||||
return showPage(
|
||||
return getPage(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING)
|
||||
.build(),
|
||||
|
@ -134,8 +120,8 @@ public class MixEditorController {
|
|||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
|
||||
|
||||
Optional<Mix> optionalMix = mixService.getByID(mixID);
|
||||
if (!optionalMix.isPresent()) {
|
||||
return showPage(modelResponseBuilder
|
||||
if (optionalMix.isEmpty()) {
|
||||
return getPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID)
|
||||
.build(),
|
||||
mixID);
|
||||
|
@ -147,7 +133,7 @@ public class MixEditorController {
|
|||
if (!mixService.deleteMix(mix)) {
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
|
||||
|
||||
return showPage(modelResponseBuilder.build(), mixID);
|
||||
return getPage(modelResponseBuilder.build(), mixID);
|
||||
}
|
||||
|
||||
return modelResponseBuilder.build();
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*;
|
||||
|
||||
@Controller
|
||||
public class RecipeEditorController {
|
||||
|
@ -59,7 +59,7 @@ public class RecipeEditorController {
|
|||
if (recipe.getRecipeCode() == null || recipe.getCompany() == null) {
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return listRecipes(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
|
@ -104,7 +104,7 @@ public class RecipeEditorController {
|
|||
int recipeID = recipe.getRecipeID();
|
||||
|
||||
Optional<Recipe> optionalStoredRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalStoredRecipe.isPresent()) {
|
||||
if (optionalStoredRecipe.isEmpty()) {
|
||||
return listRecipes(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
|
@ -113,7 +113,7 @@ public class RecipeEditorController {
|
|||
|
||||
Optional<Recipe> optionalRecipe = recipeService.updateRecipe(recipe, optionalStoredRecipe.get(), form);
|
||||
if (optionalRecipe.isPresent()) {
|
||||
modelResponseBuilder.addResponseData(ResponseDataType.RECIPE_CODE, optionalRecipe.get().getRecipeCode());
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.SUCCESS_SAVING_RECIPE, optionalRecipe.get().getRecipeCode());
|
||||
return listRecipes(modelResponseBuilder.build());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.files;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.file.ImageHandler;
|
||||
|
@ -25,7 +25,7 @@ import java.io.IOException;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*;
|
||||
|
||||
@Controller
|
||||
public class ImageFilesController {
|
||||
|
@ -67,7 +67,7 @@ public class ImageFilesController {
|
|||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(ADD_IMAGE_SPECIFIC)
|
||||
public ModelAndView showPage(ModelAndView model, @PathVariable int recipeID) {
|
||||
public ModelAndView getPage(ModelAndView model, @PathVariable int recipeID) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(ADD_IMAGE)
|
||||
.addResponseData(ResponseDataType.RECIPE_ID, recipeID)
|
||||
|
@ -100,14 +100,14 @@ public class ImageFilesController {
|
|||
|
||||
// Vérifie que le fichier est bien une image
|
||||
if (ImageIO.read(image.getInputStream()) == null) {
|
||||
return showPage(modelResponseBuilder
|
||||
return getPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.FILE_NOT_IMAGE)
|
||||
.build(), recipeID);
|
||||
}
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
return showPage(modelResponseBuilder
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return getPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
.build(), recipeID);
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ public class ImageFilesController {
|
|||
Recipe recipe = optionalRecipe.get();
|
||||
ImageHandler imageHandler = new ImageHandler(recipe, recipeService);
|
||||
if (!imageHandler.createFile()) {
|
||||
return showPage(modelResponseBuilder
|
||||
return getPage(modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE)
|
||||
.build(), recipeID);
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ public class ImageFilesController {
|
|||
ColorRecipesExplorerApplication.LOGGER.error("Erreur inconnue lors de la création d'une image", e);
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE);
|
||||
|
||||
return showPage(modelResponseBuilder.build(), recipeID);
|
||||
return getPage(modelResponseBuilder.build(), recipeID);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller;
|
||||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.files;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
|
||||
|
@ -16,8 +16,8 @@ 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;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.CLOSE_TAB;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.SIMDUT_FILES;
|
||||
|
||||
@Controller
|
||||
public class SIMDUTFilesController {
|
||||
|
@ -34,7 +34,7 @@ public class SIMDUTFilesController {
|
|||
Optional<Material> optionalMaterial = materialService.getByID(materialID);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
if (!optionalMaterial.isPresent()) {
|
||||
if (optionalMaterial.isEmpty()) {
|
||||
headers.add("Location", request.getHeader("referer"));
|
||||
return new ResponseEntity<>(headers, HttpStatus.FOUND);
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ public class SIMDUTFilesController {
|
|||
@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();
|
||||
if (optionalMaterial.isEmpty()) 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();
|
|
@ -0,0 +1,53 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.files;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.TouchUpKitService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*;
|
||||
|
||||
@Controller
|
||||
public class TouchUpKitController {
|
||||
|
||||
private TouchUpKitService touchUpKitService;
|
||||
private RecipeService recipeService;
|
||||
|
||||
@Autowired
|
||||
public TouchUpKitController(TouchUpKitService touchUpKitService, RecipeService recipeService) {
|
||||
this.touchUpKitService = touchUpKitService;
|
||||
this.recipeService = recipeService;
|
||||
}
|
||||
|
||||
@GetMapping(TOUCHUP)
|
||||
public ModelAndView getPage(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(TOUCHUP)
|
||||
.addResponseData(ResponseDataType.RECIPE_MAP, recipeService.getRecipesByCompany())
|
||||
.build();
|
||||
}
|
||||
|
||||
@PostMapping(value = TOUCHUP_PDF, produces = MediaType.APPLICATION_PDF_VALUE)
|
||||
public ResponseEntity<byte[]> getTouchUpKitPdf(@RequestBody String jobNumber) throws IOException {
|
||||
return new ResponseEntity<>(touchUpKitService.getPdfForJobNumber(jobNumber.replace("jobNumber=", "")), HttpStatus.FOUND);
|
||||
}
|
||||
|
||||
@PostMapping(value = TOUCHUP_PTOUCH)
|
||||
public ModelAndView getTouchUpKitPtouch(@RequestBody String jobNumber) {
|
||||
return new ModelResponseBuilder(TOUCHUP_PTOUCH_PAGE)
|
||||
.addAttribute("jobNumber", jobNumber.replace("jobNumber=", ""))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.web.controller.files;
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
|
||||
import dev.fyloz.trial.colorrecipesexplorer.xlsx.XlsxExporter;
|
||||
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 javax.servlet.http.HttpServletRequest;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.ALL_RECIPES_XLS;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.RECIPE_XLS;
|
||||
|
||||
// TODO Une grande partie du code de ce controlleur devrait se trouver dans un service
|
||||
@Controller
|
||||
public class XlsExporterController {
|
||||
|
||||
private RecipeService recipeService;
|
||||
|
||||
@Autowired
|
||||
public XlsExporterController(RecipeService recipeService) {
|
||||
this.recipeService = recipeService;
|
||||
}
|
||||
|
||||
@GetMapping(RECIPE_XLS)
|
||||
public ResponseEntity<byte[]> getXlsForRecipe(HttpServletRequest request, @PathVariable int recipeID) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -14,8 +14,8 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
|
||||
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;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.REMOVER_COMPANY;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.REMOVER_COMPANY_SPECIFIC;
|
||||
|
||||
@Controller
|
||||
public class CompanyRemoverController {
|
||||
|
@ -37,7 +37,7 @@ public class CompanyRemoverController {
|
|||
* @return La page à afficher
|
||||
*/
|
||||
@GetMapping(REMOVER_COMPANY)
|
||||
public ModelAndView showPage(ModelAndView model) {
|
||||
public ModelAndView getPage(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(REMOVER_COMPANY)
|
||||
.addResponseData(ResponseDataType.COMPANIES, companyService.getAll())
|
||||
|
@ -78,6 +78,6 @@ public class CompanyRemoverController {
|
|||
modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_NOT_FOUND, companyID);
|
||||
}
|
||||
|
||||
return showPage(modelResponseBuilder.build());
|
||||
return getPage(modelResponseBuilder.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_SPECIFIC;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.REMOVER_MATERIAL;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.REMOVER_MATERIAL_SPECIFIC;
|
||||
|
||||
@Controller
|
||||
public class MaterialRemoverController {
|
||||
|
@ -35,7 +35,7 @@ public class MaterialRemoverController {
|
|||
* @return La page à afficher.
|
||||
*/
|
||||
@GetMapping(REMOVER_MATERIAL)
|
||||
public ModelAndView showPage(ModelAndView model) {
|
||||
public ModelAndView getPage(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(REMOVER_MATERIAL)
|
||||
.addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
|
||||
|
@ -65,13 +65,13 @@ public class MaterialRemoverController {
|
|||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
|
||||
|
||||
Optional<Material> optionalMaterial = materialService.getByID(materialID);
|
||||
if (!optionalMaterial.isPresent()) {
|
||||
if (optionalMaterial.isEmpty()) {
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID);
|
||||
} else {
|
||||
Material material = optionalMaterial.get();
|
||||
|
||||
if (materialService.deleteIfNotLinked(material)) {
|
||||
responseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode());
|
||||
responseBuilder.addResponseCode(ResponseCode.SUCCESS_DELETING_MATERIAL, material.getMaterialCode());
|
||||
|
||||
if (!materialService.removeSimdut(material)) {
|
||||
responseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
|
||||
|
@ -81,6 +81,6 @@ public class MaterialRemoverController {
|
|||
}
|
||||
}
|
||||
|
||||
return showPage(responseBuilder.build());
|
||||
return getPage(responseBuilder.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ 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;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.REMOVER_MATERIAL_TYPE;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.REMOVER_MATERIAL_TYPE_SPECIFIC;
|
||||
|
||||
@Controller
|
||||
public class MaterialTypeRemoverController {
|
||||
|
@ -29,7 +29,7 @@ public class MaterialTypeRemoverController {
|
|||
}
|
||||
|
||||
@GetMapping(REMOVER_MATERIAL_TYPE)
|
||||
public ModelAndView showPage(ModelAndView model) {
|
||||
public ModelAndView getPage(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(REMOVER_MATERIAL_TYPE)
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
|
||||
|
@ -41,18 +41,18 @@ public class MaterialTypeRemoverController {
|
|||
ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
|
||||
|
||||
Optional<MaterialType> optionalMaterialType = materialTypeService.getByID(materialTypeID);
|
||||
if (!optionalMaterialType.isPresent()) {
|
||||
if (optionalMaterialType.isEmpty()) {
|
||||
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());
|
||||
responseBuilder.addResponseCode(ResponseCode.SUCCESS_DELETING_MATERIAL_TYPE, materialType.getMaterialTypeName());
|
||||
} else {
|
||||
responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_LINKED, materialType.getMaterialTypeName());
|
||||
}
|
||||
}
|
||||
|
||||
return showPage(responseBuilder.build());
|
||||
return getPage(responseBuilder.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ 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;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.REMOVER_RECIPE;
|
||||
import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.REMOVER_RECIPE_SPECIFIC;
|
||||
|
||||
@Controller
|
||||
public class RecipeRemoverController {
|
||||
|
@ -62,7 +62,7 @@ public class RecipeRemoverController {
|
|||
ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
|
||||
|
||||
Optional<Recipe> optionalRecipe = recipeService.getByID(recipeID);
|
||||
if (!optionalRecipe.isPresent()) {
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return listRecipes(
|
||||
modelResponseBuilder
|
||||
.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
|
||||
|
@ -77,7 +77,7 @@ public class RecipeRemoverController {
|
|||
.build());
|
||||
}
|
||||
|
||||
modelResponseBuilder.addResponseData(ResponseDataType.RECIPE_CODE, recipe.getRecipeCode());
|
||||
modelResponseBuilder.addResponseCode(ResponseCode.SUCCESS_DELETING_RECIPE, recipe.getRecipeCode());
|
||||
return listRecipes(modelResponseBuilder.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ spring:
|
|||
web-allow-others: true
|
||||
server:
|
||||
port: 9090
|
||||
http2:
|
||||
enabled: true
|
||||
error:
|
||||
whitelabel:
|
||||
enabled: false
|
||||
|
|
Binary file not shown.
|
@ -1,105 +1,118 @@
|
|||
company.form.companyName=Banner name
|
||||
menu.explore=Explore
|
||||
menu.add=Add
|
||||
menu.edit=Edit
|
||||
menu.delete=Delete
|
||||
menu.inventory=Inventory
|
||||
menu.others=Others
|
||||
recipe.color=Color
|
||||
recipe.description=Description
|
||||
recipe.sample=Sample
|
||||
recipe.approbationDate=Approbation date
|
||||
recipe.remark=Remark
|
||||
recipe.notice=Notice
|
||||
recipe.steps=Steps
|
||||
keyword.company=Banner
|
||||
keyword.material=Material
|
||||
keyword.recipe=Recipe
|
||||
keyword.touchUpKitPDF=Touch Up Kit PDF
|
||||
keyword.quantity=Quantity
|
||||
keyword.type=Type
|
||||
keyword.units=Units
|
||||
keyword.edit=Edit
|
||||
keyword.use=Use
|
||||
keyword.save=Save
|
||||
keyword.back=Back
|
||||
mix.location=Location
|
||||
material.code=Code
|
||||
material.inventoryQuantity=Inventory quantity
|
||||
material.type=Material type
|
||||
material.simdutFile=SIMDUT File
|
||||
units.milliliters=Milliliters
|
||||
units.liters=Liters
|
||||
units.gallons=Gallons
|
||||
inventory.lowQuantity=Low quantity
|
||||
inventory.hideOthers=Hide other materials
|
||||
inventory.showOnly=Show only
|
||||
material.error.anyFound=No materials were found.
|
||||
app.title=Color recipes explorer
|
||||
footer.lang=Voir en français
|
||||
company.add.title=Adding a banner
|
||||
company.success.created=The banner {0} has been saved.
|
||||
keyword.see=See
|
||||
company.error.anyFound=No banners were found.
|
||||
recipe.warning.notApproved=This recipe is not approved
|
||||
company.add.title=Add a banner
|
||||
company.delete.title=Delete banners
|
||||
company.error.anyFound=No banners were found.
|
||||
company.form.companyName=Banner name
|
||||
company.success.created=The banner {0} has been saved.
|
||||
company.success.deleted=The banner {0} has been deleted.
|
||||
keyword.delete=Delete
|
||||
material.add.title=Adding a material
|
||||
material.success.created=The material {0} has been saved.
|
||||
material.editing.title=Editing {0}
|
||||
material.delete.title=Delete materials
|
||||
material.success.deleted=The material {0} has been deleted.
|
||||
material.success.saved=The material {0} has been saved.
|
||||
material.edit.title=Edit materials
|
||||
material.simdut.choose=Choose material's SIMDUT file
|
||||
materialType.add.title=Add a material type
|
||||
materialType.name=Name
|
||||
materialType.prefix=Prefix
|
||||
keyword.characters=characters
|
||||
materialType.usePercents=Use percentages
|
||||
image.add.title=Add an image
|
||||
mix.add.title=Adding a banner
|
||||
mix.add.subtitle=Adding a mix for the recipe {0}
|
||||
mix.mixType=Mix type
|
||||
keyword.remove=Remove
|
||||
mix.edit.title=Editing a mix
|
||||
mix.edit.subtitle=Editing a mix for the recipe {0} ({1})
|
||||
password.ask=What is your password?
|
||||
password.notValid=Your password is not valid
|
||||
error.serverError=An error occurred while sending data to the server.
|
||||
recipe.add.title=Add a recipe
|
||||
recipe.sucess.saved=The recipe {0} has been saved. You can now add ingredients.
|
||||
keyword.continue=Continue
|
||||
recipe.editing.title=Editing {0}
|
||||
recipe.edit.addMix=Add a mix
|
||||
recipe.edit.addImage=Add an image
|
||||
recipe.success.edit=The recipe {0} has been saved.
|
||||
recipe.edit.title=Edit a recipe
|
||||
recipe.explore.title={0} color
|
||||
recipe.warning.notApproved.short=Not approved
|
||||
recipe.image.corrupted=Image deleted or corrupted
|
||||
recipe.delete.title=Delete recipes
|
||||
recipe.success.deleted=The recipe {0} has been deleted.
|
||||
keyword.search=Search
|
||||
materialType.editor.title=Edit material types
|
||||
materialType.editing.title=Editing {0}
|
||||
keyword.id=ID
|
||||
materialType.success.saved=The material type {0} has been saved.
|
||||
materialType.delete.title=Delete material types
|
||||
materialType.success.deleted=The material type {0} has been deleted.
|
||||
materialType.error.anyFound=Any material type has been found.
|
||||
keyword.calculation=Calculation
|
||||
recipe.error.anyFound=No recipes were found.
|
||||
recipe.exportAllXLS=Export all colors (XLSX)
|
||||
recipe.xlsVersion=XLSX version
|
||||
keyword.updates=Updates history
|
||||
material.simdutFile.notFound=No SIMDUT file found
|
||||
recipe.warning.changesNotSaved=Changes are not saved
|
||||
recipe.warning.exportAll=Do you really want to export all the colors? This can take some times and slow down the application.
|
||||
warning.noResult=Nothing corresponding the the research was found
|
||||
footer.lang=Voir en français
|
||||
image.add.title=Add an image
|
||||
inventory.askUseMix=Do you really want to deduct this mix from the inventory?
|
||||
inventory.askUseRecipe=Do you really want to deduct this recipe from the inventory?
|
||||
inventory.hideOthers=Hide other materials
|
||||
inventory.lowQuantity=Low quantity
|
||||
inventory.showOnly=Show only
|
||||
keyword.back=Back
|
||||
keyword.calculation=Calculation
|
||||
keyword.cancel=Cancel
|
||||
keyword.characters=characters
|
||||
keyword.company=Banner
|
||||
keyword.continue=Continue
|
||||
keyword.delete=Delete
|
||||
keyword.edit=Edit
|
||||
keyword.id=ID
|
||||
keyword.images=Images
|
||||
warning.askChangePage=Are you sure you want to continue? Unsaved changes will be lost.
|
||||
keyword.material=Material
|
||||
keyword.pdf=PDF
|
||||
keyword.print=Print
|
||||
keyword.ptouch=P-touch
|
||||
keyword.ptouchTemplate=P-touch templates
|
||||
keyword.quantity=Quantity
|
||||
keyword.recipe=Recipe
|
||||
keyword.remove=Remove
|
||||
keyword.save=Save
|
||||
keyword.search=Search
|
||||
keyword.see=See
|
||||
keyword.type=Type
|
||||
keyword.units=Units
|
||||
keyword.updates=Updates history
|
||||
keyword.use=Use
|
||||
material.add.title=Add a material
|
||||
material.code=Code
|
||||
material.delete.title=Delete materials
|
||||
material.edit.title=Edit materials
|
||||
material.editing.title=Editing {0}
|
||||
material.error.anyFound=No materials were found.
|
||||
material.inventoryQuantity=Inventory quantity
|
||||
material.simdut.choose=Choose material's SIMDUT file
|
||||
material.simdut.error.notFound=No SIMDUT file found
|
||||
material.simdut=SIMDUT File
|
||||
material.success.created=The material {0} has been saved.
|
||||
material.success.deleted=The material {0} has been deleted.
|
||||
material.success.saved=The material {0} has been saved.
|
||||
material.type=Material type
|
||||
materialType.add.title=Add a material type
|
||||
materialType.delete.title=Delete material types
|
||||
materialType.editing.title=Editing {0}
|
||||
materialType.editor.title=Edit material types
|
||||
materialType.error.anyFound=Any material type has been found.
|
||||
materialType.name=Name
|
||||
materialType.prefix=Prefix
|
||||
materialType.success.deleted=The material type {0} has been deleted.
|
||||
materialType.success.saved=The material type {0} has been saved.
|
||||
materialType.usePercents=Use percentages
|
||||
menu.add=Add
|
||||
menu.delete=Delete
|
||||
menu.edit=Edit
|
||||
menu.explore=Explore
|
||||
menu.inventory=Inventory
|
||||
menu.others=Others
|
||||
mix.add.subtitle=Add a mix for the recipe {0}
|
||||
mix.add.title=Add a banner
|
||||
mix.edit.subtitle=Editing a mix for the recipe {0} ({1})
|
||||
mix.edit.title=Editing a mix
|
||||
mix.location=Location
|
||||
mix.mixType=Mix type
|
||||
password.ask=What is your password?
|
||||
password.notValid=Your password is not valid
|
||||
recipe.add.title=Add a recipe
|
||||
recipe.approbationDate=Approbation date
|
||||
recipe.color=Color
|
||||
recipe.delete.title=Delete recipes
|
||||
recipe.description=Description
|
||||
recipe.edit.addImage=Add an image
|
||||
recipe.edit.addMix=Add a mix
|
||||
recipe.edit.title=Edit a recipe
|
||||
recipe.editing.title=Editing {0}
|
||||
recipe.error.anyFound=No recipes were found.
|
||||
recipe.explore.title={0} color
|
||||
recipe.exportAllXLS=Export all colors (XLSX)
|
||||
recipe.image.corrupted=Image deleted or corrupted
|
||||
recipe.notice=Notice
|
||||
recipe.print.confirm=Are you sure you want to print this mix?
|
||||
recipe.print.error.bpacNotInstalled=BPac is not installed
|
||||
recipe.print.error.noBase=There is no base in this mix
|
||||
recipe.print.error=An error occurred while printing
|
||||
recipe.print.printing=Printing in progress. This may take a few seconds.
|
||||
recipe.print.status.error=The b-Pac extension is not installed
|
||||
recipe.print.status.ok=The b-Pac extension is installed
|
||||
recipe.remark=Remark
|
||||
recipe.sample=Sample
|
||||
recipe.steps=Steps
|
||||
recipe.success.deleted=The recipe {0} has been deleted.
|
||||
recipe.success.edit=The recipe {0} has been saved.
|
||||
recipe.sucess.saved=The recipe {0} has been saved. You can now add ingredients.
|
||||
recipe.touchup.title=Touch-up kit labels
|
||||
recipe.touchup=Touch-up kit labels
|
||||
recipe.warning.changesNotSaved=Changes are not saved
|
||||
recipe.warning.exportAll=Do you really want to export all the colors? This can take some times and slow down the application.
|
||||
recipe.warning.notApproved.short=Not approved
|
||||
recipe.warning.notApproved=This recipe is not approved
|
||||
recipe.xlsVersion=XLSX version
|
||||
units.gallons=Gallons
|
||||
units.liters=Liters
|
||||
units.milliliters=Milliliters
|
||||
warning.askChangePage=Are you sure you want to continue? Unsaved changes will be lost.
|
||||
warning.noResult=Search returned no results
|
||||
keyword.jobNumber=Job number
|
||||
|
|
|
@ -1,106 +1,118 @@
|
|||
menu.explore=Explorer
|
||||
menu.add=Ajouter
|
||||
menu.edit=Modifier
|
||||
menu.delete=Supprimer
|
||||
menu.inventory=Inventaire
|
||||
menu.others=Autres
|
||||
recipe.color=Couleur
|
||||
recipe.description=Description
|
||||
recipe.sample=Échantillon
|
||||
recipe.approbationDate=Date d'approbation
|
||||
recipe.remark=Remarque
|
||||
recipe.notice=Note
|
||||
recipe.steps=Étapes
|
||||
keyword.company=Bannière
|
||||
keyword.material=Produit
|
||||
keyword.recipe=Recette
|
||||
keyword.touchUpKitPDF=PDF Kits de retouche
|
||||
keyword.quantity=Quantité
|
||||
keyword.type=Type
|
||||
keyword.units=Unités
|
||||
keyword.edit=Modifier
|
||||
keyword.use=Utiliser
|
||||
keyword.save=Enregistrer
|
||||
keyword.back=Retour
|
||||
keyword.delete=Supprimer
|
||||
mix.location=Position
|
||||
material.code=Code
|
||||
material.inventoryQuantity=Quantité en inventaire
|
||||
material.type=Type de produit
|
||||
material.simdutFile=Fichier SIMDUT
|
||||
units.milliliters=Millilitres
|
||||
units.liters=Litres
|
||||
units.gallons=Gallons
|
||||
inventory.lowQuantity=Quantité faible
|
||||
inventory.hideOthers=Cacher les autres produits
|
||||
inventory.showOnly=Voir seulement
|
||||
material.error.anyFound=Aucun produit n'a été trouvé.
|
||||
app.title=Explorateur de recettes de couleur
|
||||
footer.lang=See in english
|
||||
company.add.title=Ajout d'une bannière
|
||||
company.success.created=La bannière {0} à été enregistrée.
|
||||
company.form.companyName=Nom de la bannière
|
||||
keyword.see=Voir
|
||||
company.error.anyFound=Aucune bannière n'a été trouvée.
|
||||
recipe.warning.notApproved=Cette recette n'est pas approuvée
|
||||
company.delete.title=Supprimer des bannières
|
||||
company.error.anyFound=Aucune bannière n'a été trouvée.
|
||||
company.form.companyName=Nom de la bannière
|
||||
company.success.created=La bannière {0} à été enregistrée.
|
||||
company.success.deleted=La bannière {0} a bien été supprimée.
|
||||
material.add.title=Ajout d'un produit
|
||||
material.success.created=Le produit {0} a été enregistré.
|
||||
material.editing.title=Modification de {0}
|
||||
material.delete.title=Supprimer des produits
|
||||
material.success.deleted=Le produit {0} a bien été supprimée.
|
||||
material.success.saved=Le produit {0} a bien été sauvegardé.
|
||||
material.edit.title=Modifer des produits
|
||||
material.simdut.choose=Choisissez le fichier SIMDUT du produit
|
||||
materialType.add.title=Ajout d'un type de produit
|
||||
materialType.name=Nom
|
||||
materialType.prefix=Préfix
|
||||
keyword.characters=caractères
|
||||
materialType.usePercents=Utiliser les pourcentages
|
||||
image.add.title=Ajout une image
|
||||
mix.add.title=Ajout d'un mélange
|
||||
mix.add.subtitle=Ajout d''un mélange pour la recette {0}
|
||||
mix.mixType=Type de mélange
|
||||
keyword.remove=Retirer
|
||||
mix.edit.title=Modifier un mélange
|
||||
mix.edit.subtitle=Modifier un mélange pour la recette {0} ({1})
|
||||
password.ask=Quel est votre mot de passe?
|
||||
password.notValid=Votre mot de passe n'est pas valide
|
||||
error.serverError=Une erreur est survenue lors de l'envoie des informations vers le serveur.
|
||||
recipe.add.title=Ajout d'une recette
|
||||
recipe.sucess.saved=La recette {0} à été enregistrée. Vous pouvez maintenant ajouter les ingrédients.
|
||||
keyword.continue=Continuer
|
||||
recipe.editing.title=Modification de {0}
|
||||
recipe.edit.addMix=Ajouter un mélange
|
||||
recipe.edit.addImage=Ajouter une image
|
||||
recipe.success.edit=La recette {0} a bien été sauvegardée.
|
||||
recipe.edit.title=Modifier une recette
|
||||
recipe.explore.title=Couleur {0}
|
||||
recipe.warning.notApproved.short=Non approuvée
|
||||
recipe.image.corrupted=Image supprimée ou corrompue
|
||||
recipe.delete.title=Supprimer des recettes
|
||||
recipe.success.deleted=La recette {0} a bien été supprimée.
|
||||
keyword.search=Rechercher
|
||||
materialType.editor.title=Modifier un type de produit
|
||||
materialType.editing.title=Modification de {0}
|
||||
keyword.id=Identifiant
|
||||
materialType.success.saved=Le type de produit {0} a bien été sauvegardé.
|
||||
materialType.delete.title=Supprimer des types de produit
|
||||
materialType.success.deleted=Le type de produit {0} a bien été supprimé.
|
||||
materialType.error.anyFound=Aucun type de produit n'a été trouvé.
|
||||
keyword.calculation=Calcul
|
||||
recipe.error.anyFound=Aucune recette n'a été trouvée.
|
||||
recipe.exportAllXLS=Exporter toutes les couleurs (XLSX)
|
||||
recipe.xlsVersion=Version XLSX
|
||||
keyword.updates=Historique des mises à jour
|
||||
material.simdutFile.notFound=Aucun fichier SIMDUT trouvé
|
||||
recipe.warning.changesNotSaved=Des modifications ne sont pas sauvegardées
|
||||
recipe.warning.exportAll=Voulez-vous vraiment exporter toutes les couleurs? Cela peut prendre un certain temps et ralentir l'application.
|
||||
warning.noResult=Rien correspondant à la recherche n'a été trouvé
|
||||
footer.lang=See in english
|
||||
image.add.title=Ajout une image
|
||||
inventory.askUseMix=Êtes-vous certain de vouloir déduire ce mélange de l'inventaire?
|
||||
inventory.askUseRecipe=Êtes-vous certain de vouloir déduire cette recette de l'inventaire?
|
||||
inventory.hideOthers=Cacher les autres produits
|
||||
inventory.lowQuantity=Quantité faible
|
||||
inventory.showOnly=Voir seulement
|
||||
keyword.back=Retour
|
||||
keyword.calculation=Calcul
|
||||
keyword.cancel=Annuler
|
||||
keyword.characters=caractères
|
||||
keyword.company=Bannière
|
||||
keyword.continue=Continuer
|
||||
keyword.delete=Supprimer
|
||||
keyword.edit=Modifier
|
||||
keyword.id=Identifiant
|
||||
keyword.images=Images
|
||||
warning.askChangePage=Êtes-vous sûr de vouloir continuer? Les modifications non enregistrées seront perdues.
|
||||
keyword.material=Produit
|
||||
keyword.pdf=PDF
|
||||
keyword.print=Imprimer
|
||||
|
||||
keyword.ptouch=P-touch
|
||||
keyword.ptouchTemplate=Modèles P-touch
|
||||
keyword.quantity=Quantité
|
||||
keyword.recipe=Recette
|
||||
keyword.remove=Retirer
|
||||
keyword.save=Enregistrer
|
||||
keyword.search=Rechercher
|
||||
keyword.see=Voir
|
||||
keyword.type=Type
|
||||
keyword.units=Unités
|
||||
keyword.updates=Historique des mises à jour
|
||||
keyword.use=Utiliser
|
||||
material.add.title=Ajout d'un produit
|
||||
material.code=Code
|
||||
material.delete.title=Supprimer des produits
|
||||
material.edit.title=Modifer des produits
|
||||
material.editing.title=Modification de {0}
|
||||
material.error.anyFound=Aucun produit n'a été trouvé.
|
||||
material.inventoryQuantity=Quantité en inventaire
|
||||
material.simdut.choose=Choisissez le fichier SIMDUT du produit
|
||||
material.simdut.error.notFound=Aucun fichier SIMDUT trouvé
|
||||
material.simdut=Fichier SIMDUT
|
||||
material.success.created=Le produit {0} a été enregistré.
|
||||
material.success.deleted=Le produit {0} a bien été supprimée.
|
||||
material.success.saved=Le produit {0} a bien été sauvegardé.
|
||||
material.type=Type de produit
|
||||
materialType.add.title=Ajout d'un type de produit
|
||||
materialType.delete.title=Supprimer des types de produit
|
||||
materialType.editing.title=Modification de {0}
|
||||
materialType.editor.title=Modifier un type de produit
|
||||
materialType.error.anyFound=Aucun type de produit n'a été trouvé.
|
||||
materialType.name=Nom
|
||||
materialType.prefix=Préfix
|
||||
materialType.success.deleted=Le type de produit {0} a bien été supprimé.
|
||||
materialType.success.saved=Le type de produit {0} a bien été sauvegardé.
|
||||
materialType.usePercents=Utiliser les pourcentages
|
||||
menu.add=Ajouter
|
||||
menu.delete=Supprimer
|
||||
menu.edit=Modifier
|
||||
menu.explore=Explorer
|
||||
menu.inventory=Inventaire
|
||||
menu.others=Autres
|
||||
mix.add.subtitle=Ajout d''un mélange pour la recette {0}
|
||||
mix.add.title=Ajout d'un mélange
|
||||
mix.edit.subtitle=Modifier un mélange pour la recette {0} ({1})
|
||||
mix.edit.title=Modifier un mélange
|
||||
mix.location=Position
|
||||
mix.mixType=Type de mélange
|
||||
password.ask=Quel est votre mot de passe?
|
||||
password.notValid=Votre mot de passe n'est pas valide
|
||||
recipe.add.title=Ajout d'une recette
|
||||
recipe.approbationDate=Date d'approbation
|
||||
recipe.color=Couleur
|
||||
recipe.delete.title=Supprimer des recettes
|
||||
recipe.description=Description
|
||||
recipe.edit.addImage=Ajouter une image
|
||||
recipe.edit.addMix=Ajouter un mélange
|
||||
recipe.edit.title=Modifier une recette
|
||||
recipe.editing.title=Modification de {0}
|
||||
recipe.error.anyFound=Aucune recette n'a été trouvée.
|
||||
recipe.explore.title=Couleur {0}
|
||||
recipe.exportAllXLS=Exporter toutes les couleurs (XLSX)
|
||||
recipe.image.corrupted=Image supprimée ou corrompue
|
||||
recipe.notice=Note
|
||||
recipe.print.confirm=Voulez-vous vraiment imprimer ce mélange?
|
||||
recipe.print.error.bpacNotInstalled=BPac n'est pas installé
|
||||
recipe.print.error.noBase=Il n'y a pas de base dans ce mélange
|
||||
recipe.print.error=Une erreur est survenue pendant l'impression
|
||||
recipe.print.printing=Impression en cours. Cette opération peut prendre quelques secondes.
|
||||
recipe.print.status.error=L'extension b-Pac n'est pas installée
|
||||
recipe.print.status.ok=L'extension b-Pac est installée
|
||||
recipe.remark=Remarque
|
||||
recipe.sample=Échantillon
|
||||
recipe.steps=Étapes
|
||||
recipe.success.deleted=La recette {0} a bien été supprimée.
|
||||
recipe.success.edit=La recette {0} a bien été sauvegardée.
|
||||
recipe.sucess.saved=La recette {0} à été enregistrée. Vous pouvez maintenant ajouter les ingrédients.
|
||||
recipe.touchup.title=Étiquettes de kit de retouche
|
||||
recipe.touchup=Étiquettes de kit de retouche
|
||||
recipe.warning.changesNotSaved=Des modifications ne sont pas sauvegardées
|
||||
recipe.warning.exportAll=Voulez-vous vraiment exporter toutes les couleurs? Cela peut prendre un certain temps et ralentir l'application.
|
||||
recipe.warning.notApproved.short=Non approuvée
|
||||
recipe.warning.notApproved=Cette recette n'est pas approuvée
|
||||
recipe.xlsVersion=Version XLSX
|
||||
units.gallons=Gallons
|
||||
units.liters=Litres
|
||||
units.milliliters=Millilitres
|
||||
warning.askChangePage=Êtes-vous sûr de vouloir continuer? Les modifications non enregistrées seront perdues.
|
||||
warning.noResult=La recherche n'a donné aucun résultat
|
||||
keyword.jobNumber=Numéro de job
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
response.1=The quantities of each material used have been deducted from the inventory
|
||||
response.1=The quantities of used materials have been deducted from the inventory
|
||||
response.10=There is already a material with the code {0}
|
||||
response.11=There is already a material type named {0}
|
||||
response.12=Any banner with the ID {0} has been found
|
||||
response.12=No banner with the ID {0} has been found
|
||||
response.13=There is already a banner named {0}
|
||||
response.14=The material {0} is linked to one or more recipes, edit them first
|
||||
response.15=The banner {0} is linked to one or more recipes, delete them first
|
||||
response.16=The mix with the ID {0} is not linked to the recipe with the ID {1}
|
||||
response.17=There is not enough {0} in inventory for this recipe
|
||||
response.18=This recipe already contains a mix of the type {0}
|
||||
response.19=Any material type with the ID {0} has been found
|
||||
response.19=No material type with the name {0} has been found
|
||||
response.2=The recipe's informations have been saved
|
||||
response.3=An error has occurred while saving
|
||||
response.4=An error has occurred while saving the image
|
||||
response.5=An error has occurred while saving the SIMDUT file
|
||||
response.6=Your password is not valid
|
||||
response.7=Any recipe with the ID {0} has been found
|
||||
response.8=Any mix with the ID {0} has been found
|
||||
response.9=Any material with the ID {0} has been found
|
||||
response.7=No recipe with the ID {0} has been found
|
||||
response.8=No mix with the ID {0} has been found
|
||||
response.9=No material with the ID {0} has been found
|
||||
response.20=There is already a material type with the prefix {0}
|
||||
response.21=The material type {0} is linked to one or more materials, delete them first.
|
||||
response.101=The requested page could not be found
|
||||
|
@ -28,3 +28,10 @@ response.24=This file need to be an image
|
|||
response.25=The recipe was not found
|
||||
response.26=The material with the code {0} was not found
|
||||
response.27=The banner {0} has been delete
|
||||
response.28=The material {0} has been saved
|
||||
response.29=The material type {0} has been saved
|
||||
response.30=The recipe for the color {0} has been saved
|
||||
response.31=The material {0} has been deleted
|
||||
response.32=The banner {0} has been saved
|
||||
response.33=The recipe {0} has been deleted
|
||||
response.34=The material type {0} has been deleted
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
response.1=Les quantités de chaque produits utilisés ont été déduites de l'inventaire
|
||||
response.1=Les quantités des produits utilisés ont été déduites de l'inventaire
|
||||
response.10=Il y a déjà un produit ayant le code {0}
|
||||
response.11=Il y a déjà un type de produit s''appellant {0}
|
||||
response.12=Aucune bannière ayant l''identifiant {0} n''a été trouvée
|
||||
|
@ -8,7 +8,7 @@ response.15=La bannière {0} est liée à une ou plusieurs recettes, veuillez le
|
|||
response.16=Le mélange ayant l''identifiant {0} n''est pas associé à la recette ayant l''identifiant {1}
|
||||
response.17=Il n''y a pas assez de {0} en inventaire pour cette recette
|
||||
response.18=Cette recette contient déjà un mélange du type {0}
|
||||
response.19=Aucun type de produit ayant l''identifiant {0} n''a été trouvée
|
||||
response.19=Aucun type de produit ayant le nom {0} n''a été trouvée
|
||||
response.2=Les informations de la recette ont été sauvegardées
|
||||
response.3=Une erreur est survenue lors de l''enregistrement
|
||||
response.4=Une erreur est survenue lors de l'enregistrement de l'image
|
||||
|
@ -28,3 +28,10 @@ response.24=Ce fichier doit être une image
|
|||
response.25=La recette n'a pas été trouvée
|
||||
response.26=Le produit ayant le code {0} n''a pas été trouvé
|
||||
response.27=La bannière {0} a bien été supprimée
|
||||
response.28=Le produit {0} a bien été sauvegardé
|
||||
response.29=Le type de produit {0} a bien été sauvegardé
|
||||
response.30=La recette pour la couleur {0} a bien été sauvegardée
|
||||
response.31=Le produit {0} a bien été supprimée
|
||||
response.32=La bannière {0} a bien été sauvegardée
|
||||
response.33=La recette {0} a bien été supprimée
|
||||
response.34=Le type de produit {0} a bien été supprimé
|
||||
|
|
Binary file not shown.
|
@ -4,6 +4,10 @@ body {
|
|||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
* {
|
||||
transition: all .1s;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
@ -73,18 +77,6 @@ textarea {
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
/*.error {*/
|
||||
/* color: red;*/
|
||||
/*}*/
|
||||
|
||||
/*.success {*/
|
||||
/* color: green;*/
|
||||
/*}*/
|
||||
|
||||
/*.error, .success {*/
|
||||
/* font-weight: bold;*/
|
||||
/*}*/
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
@ -129,49 +121,82 @@ table:not(.noStyle) tr:nth-child(odd) {
|
|||
width: 150px;
|
||||
}
|
||||
|
||||
.errorBox {
|
||||
background-color: #ef9a9a;
|
||||
color: #e53935;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.successBox {
|
||||
background-color: #a5d6a7;
|
||||
color: #4caf50;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.warningBox {
|
||||
background-color: #fff59d;
|
||||
color: #fdd835;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.messageBox {
|
||||
display: inline-block;
|
||||
margin: 20px auto auto;
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: -20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.messageBox .messageBoxContainer {
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
padding: 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.messageBox .messageBoxInnerBox {
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
.messageBox .messageBoxMessageContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
vertical-align: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.messageBox img {
|
||||
float: left;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.messageBox p {
|
||||
display: inline-block;
|
||||
margin: 0 0 0 16px;
|
||||
line-height: 24px;
|
||||
font-weight: bold;
|
||||
margin: 0 0 0 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#errorBox {
|
||||
background-color: #ef9a9a;
|
||||
color: #e53935;
|
||||
}
|
||||
|
||||
#successBox {
|
||||
background-color: #a5d6a7;
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
#warningBox {
|
||||
background-color: #fff59d;
|
||||
color: #fdd835;
|
||||
}
|
||||
|
||||
#confirmBox, #promptBox {
|
||||
background-color: #90caf9;
|
||||
color: #1e88e5;
|
||||
height: 75px;
|
||||
z-index: 60;
|
||||
}
|
||||
|
||||
#promptBox {
|
||||
height: 110px;
|
||||
}
|
||||
|
||||
.confirmButtonsContainer button {
|
||||
margin: 0 60px;
|
||||
}
|
||||
|
||||
.confirmButtonsContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 5px 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.confirmInputContainer input {
|
||||
width: 90%;
|
||||
background-color: white;
|
||||
padding: 2px 0;
|
||||
margin: 10px 5% 2px;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
|
@ -205,3 +230,14 @@ table:not(.noStyle) tr:nth-child(odd) {
|
|||
.submitButton {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#filter {
|
||||
display: none;
|
||||
background-color: black;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
z-index: 50;
|
||||
}
|
||||
|
|
|
@ -4,24 +4,46 @@ header, footer {
|
|||
text-align: center;
|
||||
width: 100%;
|
||||
color: white;
|
||||
position: fixed;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
header {
|
||||
top: 0;
|
||||
display: flex;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
header .spacer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header a:hover, .dropdown:hover .dropbtn {
|
||||
background-color: #0d0d0d;
|
||||
}
|
||||
|
||||
header .header-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
header #printStatusIcon {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
height: 5%;
|
||||
bottom: 0;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
nav img {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: visible;
|
||||
background-color: inherit;
|
||||
section {
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
nav a {
|
||||
|
@ -50,10 +72,6 @@ nav a {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
nav a:hover, .dropdown:hover .dropbtn {
|
||||
background-color: #0d0d0d;
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
|
@ -81,7 +99,7 @@ nav a:hover, .dropdown:hover .dropbtn {
|
|||
}
|
||||
|
||||
@media only screen and (max-width: 702px) {
|
||||
nav img {
|
||||
header img {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24"
|
||||
viewBox="0 0 24 24">
|
||||
<path fill="#1e88e5"
|
||||
d="M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 395 B |
|
@ -2,5 +2,5 @@
|
|||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#e53935"
|
||||
d="M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/>
|
||||
d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 390 B After Width: | Height: | Size: 485 B |
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#4caf50"
|
||||
d="M18 7H6V3H18V7M6 21V17H2V11C2 9.34 3.34 8 5 8H19C20.66 8 22 9.34 22 11V13.81C21.12 13.3 20.1 13 19 13C17.77 13 16.64 13.37 15.69 14H8V19H13C13 19.7 13.13 20.37 13.35 21H6M18 11C18 11.55 18.45 12 19 12S20 11.55 20 11 19.55 10 19 10 18 10.45 18 11M23.5 17L22 15.5L18.5 19L16.5 17L15 18.5L18.5 22L23.5 17"/>
|
||||
</svg>
|
After Width: | Height: | Size: 586 B |
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#e53935"
|
||||
d="M14,4V8H6V4H14M15,13A1,1 0 0,0 16,12A1,1 0 0,0 15,11A1,1 0 0,0 14,12A1,1 0 0,0 15,13M13,19V15H7V19H13M15,9A3,3 0 0,1 18,12V17H15V21H5V17H2V12A3,3 0 0,1 5,9H15M22,7V12H20V7H22M22,14V16H20V14H22Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 478 B |
File diff suppressed because it is too large
Load Diff
|
@ -1,16 +1,19 @@
|
|||
const body = document.querySelector("body");
|
||||
const errorMsgBox = document.querySelector(".errorBox");
|
||||
const errorMsgBoxText = errorMsgBox.querySelector("p");
|
||||
const warningMsgBox = document.querySelector(".warningBox");
|
||||
const warningMsgBoxText = warningMsgBox.querySelector("p");
|
||||
const successMsgBox = document.querySelector(".successBox");
|
||||
const successMsgBoxText = successMsgBox.querySelector("p");
|
||||
const body = $("body");
|
||||
const errorMsg = $("#errorBox");
|
||||
const warningMsg = $("#warningBox");
|
||||
const successMsg = $("#successBox");
|
||||
const confirmMsg = $("#confirmBox");
|
||||
const promptMsg = $("#promptBox");
|
||||
|
||||
const messageBoxesAnimationTime = 200;
|
||||
const messageBoxesFunctionsDelay = 300;
|
||||
|
||||
$(() => {
|
||||
$('.materialCode').each(function () {
|
||||
const row = $(this);
|
||||
const materialID = row.data("materialid");
|
||||
|
||||
// SIMDUT
|
||||
axios.post(`/simdut/${materialID}`)
|
||||
.catch(function (err) {
|
||||
if (err.response.status === 404) {
|
||||
|
@ -19,127 +22,203 @@ $(() => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(".messageBox").each(function () {
|
||||
checkMessageBoxesDisplay($(this)[0])
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
|
||||
document.querySelectorAll(".returnButton").forEach((e) => {
|
||||
e.addEventListener("click", () => {
|
||||
document.location.href = referer;
|
||||
});
|
||||
$(".toSave").on({
|
||||
keyup: function () {
|
||||
showMessage(warningMsg, changesNotSavedText, false);
|
||||
}
|
||||
});
|
||||
$(".returnButton").on({click: () => window.location.href = referer});
|
||||
$(".materialCode").on({
|
||||
click: function () {
|
||||
window.open(`/simdut/${$(this).data("materialid")}`, "_blank");
|
||||
}
|
||||
});
|
||||
$("img").on({
|
||||
click: function () {
|
||||
if ($(this).attr("id") === "logo") return;
|
||||
window.open($(this).attr("src"), "_blank");
|
||||
}
|
||||
});
|
||||
$('input[type="text"], input[type="number"], input[type="date"], textarea').each(function () {
|
||||
$(this).addClass("rawInput");
|
||||
});
|
||||
$(".rawInput:not(.noPlaceholder)").each(function () {
|
||||
$(this).attr({placeholder: "N/A"});
|
||||
});
|
||||
|
||||
document.querySelectorAll(".materialCode").forEach((e) => {
|
||||
const materialID = e.getAttribute("data-materialID");
|
||||
e.addEventListener("click", () => {
|
||||
window.open("/simdut/" + materialID, "_blank");
|
||||
});
|
||||
// Formulaires protégés
|
||||
$(".requireAuth").on({
|
||||
submit: function () {
|
||||
return checkPassword(this);
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll("img").forEach((e) => {
|
||||
if (e.id !== "logo") {
|
||||
e.addEventListener("click", () => {
|
||||
window.open(e.src, "_blank");
|
||||
const removerForm = $(".requireAuth-remover");
|
||||
removerForm.find(".remover").on({
|
||||
click: function () {
|
||||
console.log($(this));
|
||||
removerForm.attr({
|
||||
action: removerForm.attr("action") + $(this).data("entityid")
|
||||
});
|
||||
|
||||
checkPassword(removerForm);
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll(".requireAuth").forEach((e) => {
|
||||
e.onsubmit = () => {
|
||||
return checkPassword(e);
|
||||
};
|
||||
// Favicon
|
||||
$("head").append($("<link/>").attr({
|
||||
rel: "icon",
|
||||
href: "/favicon.png"
|
||||
}));
|
||||
|
||||
// Imprimante
|
||||
let src = `${baseUrl}/icons/printerError.svg`;
|
||||
let title = printErrorTitle;
|
||||
if ($(".bpac-extension-installed").length) {
|
||||
src = `${baseUrl}/icons/printer.svg`;
|
||||
title = printOkTitle;
|
||||
}
|
||||
$("#printStatusIcon").attr({
|
||||
src: src,
|
||||
title: title
|
||||
});
|
||||
|
||||
document.querySelectorAll(".requireAuth-remover").forEach((e) => {
|
||||
e.querySelectorAll(".remover").forEach(elem => {
|
||||
elem.addEventListener("click", () => {
|
||||
e.action += elem.getAttribute("data-entityID");
|
||||
checkPassword(e);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll(".companyTabTitle").forEach(e => {
|
||||
e.addEventListener("click", () => {
|
||||
const companyName = e.getAttribute("data-companyName");
|
||||
const table = document.getElementById("recipes_" + companyName);
|
||||
|
||||
if (table.style.display === "none") {
|
||||
table.style.display = "table";
|
||||
} else {
|
||||
table.style.display = "none";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('input[type="text"], input[type="number"], input[type="date"], textarea').forEach(e => e.classList.add("rawInput"))
|
||||
|
||||
document.querySelectorAll(".rawInput").forEach(e => e.placeholder = "N/A");
|
||||
|
||||
window.addEventListener("keyup", e => {
|
||||
if (e.target) {
|
||||
if (e.target.classList.contains("toSave")) {
|
||||
warningMsgBoxText.innerText = changesNotSavedText;
|
||||
showElement(warningMsgBox);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Ajoute le favicon
|
||||
let faviconElement = document.createElement("link");
|
||||
faviconElement.rel = "icon";
|
||||
faviconElement.href = "/favicon.png";
|
||||
document.querySelector("head").appendChild(faviconElement);
|
||||
});
|
||||
|
||||
function askDatabaseExport() {
|
||||
return confirm(exportAllWarningText);
|
||||
function confirmDatabaseExport() {
|
||||
showConfirm(exportAllWarningText, false, () => {
|
||||
window.location.href = "./recipe/xls";
|
||||
});
|
||||
}
|
||||
|
||||
function checkPassword(form, callback) {
|
||||
hideElement(errorMsgBox);
|
||||
function checkPassword(form, callback = () => {
|
||||
}) {
|
||||
let shouldContinue = false;
|
||||
|
||||
const password = prompt(askPasswordText);
|
||||
if (!password) return false;
|
||||
promptMsg.find("input").attr({type: "password"});
|
||||
showConfirm(askPasswordText, true, async pwd => {
|
||||
let data = {};
|
||||
data.password = pwd;
|
||||
|
||||
let data = {};
|
||||
data.password = password;
|
||||
await axios.post("/password/valid", data)
|
||||
.then(r => {
|
||||
if (r.data === true) {
|
||||
if (form != null) form.submit();
|
||||
callback();
|
||||
shouldContinue = true;
|
||||
} else {
|
||||
showMessage(errorMsg, invalidPasswordText);
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
showMessage(errorMsg, generalErrorText);
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
axios.post("/password/valid", data)
|
||||
.then(r => {
|
||||
if (r.data === true) {
|
||||
if (form != null) form.submit();
|
||||
if (callback != null) callback();
|
||||
return true;
|
||||
} else {
|
||||
errorMsgBoxText.innerText = invalidPasswordText;
|
||||
showElement(errorMsgBox);
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
errorMsgBoxText.innerText = generalErrorText;
|
||||
showElement(errorMsgBox);
|
||||
console.log(e);
|
||||
});
|
||||
promptMsg.find("input").attr({type: "text"});
|
||||
}, () => promptMsg.find("input").attr({type: "text"}));
|
||||
|
||||
return false;
|
||||
return shouldContinue;
|
||||
}
|
||||
|
||||
const messageBoxesY = -20;
|
||||
const headerY = 70;
|
||||
|
||||
function checkMessageBoxesDisplay(element) {
|
||||
if (!element.querySelector("p").textContent) hideElement(element);
|
||||
else showElement(element);
|
||||
const node = $(element);
|
||||
|
||||
if (!node.find("p").text()) hideMessage(element);
|
||||
else showMessage(element);
|
||||
}
|
||||
|
||||
function hideElement(element) {
|
||||
element.style.display = "none";
|
||||
function isMessageVisible(type) {
|
||||
return $(type).is(":visible");
|
||||
}
|
||||
|
||||
function showElement(element) {
|
||||
element.style.display = "";
|
||||
function showMessage(type, value, autoHide = true, hideTimeout = 2000) {
|
||||
const node = $(type);
|
||||
const message = node.find("p");
|
||||
|
||||
// Cache les autres boîtes de message sauf si une boîte de confirmation est active
|
||||
if (!$("#filter").is(":visible")) {
|
||||
$(`.messageBox:not(#${$(type).attr("id")}`).each(function () {
|
||||
hideMessage(this);
|
||||
});
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isMessageVisible(type)) {
|
||||
message.text(value);
|
||||
node.show();
|
||||
node.animate({top: `${headerY}px`}, messageBoxesAnimationTime);
|
||||
|
||||
if (autoHide) {
|
||||
setTimeout(() => {
|
||||
hideMessage(node);
|
||||
}, hideTimeout);
|
||||
}
|
||||
} else {
|
||||
if (message.text() !== value) hideMessage(type, () => showMessage(type, value, autoHide, hideTimeout));
|
||||
}
|
||||
}
|
||||
|
||||
function hideMessage(type, callback = () => {
|
||||
}) {
|
||||
const node = $(type);
|
||||
|
||||
if (isMessageVisible(type)) {
|
||||
node.animate({top: `${messageBoxesY}px`}, messageBoxesAnimationTime, "swing", () => {
|
||||
node.hide();
|
||||
callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showConfirm(value, prompt = false, continueCallback = () => {
|
||||
}, cancelCallback = () => {
|
||||
}) {
|
||||
const filter = $("#filter");
|
||||
const node = prompt ? $(promptMsg) : $(confirmMsg);
|
||||
|
||||
if (prompt) node.find("#confirmInput").val("");
|
||||
|
||||
showMessage(node, value, false);
|
||||
filter.show();
|
||||
filter.animate({opacity: 0.5}, messageBoxesAnimationTime);
|
||||
|
||||
node.find(".confirmContinue").one({
|
||||
click: function () {
|
||||
hideConfirm(node);
|
||||
|
||||
setTimeout(function () {
|
||||
if (!prompt) continueCallback();
|
||||
else continueCallback(node.find("#confirmInput").val());
|
||||
}, messageBoxesFunctionsDelay);
|
||||
}
|
||||
});
|
||||
node.find(".confirmCancel").one({
|
||||
click: function () {
|
||||
hideConfirm(node);
|
||||
|
||||
setTimeout(function () {
|
||||
cancelCallback();
|
||||
}, messageBoxesFunctionsDelay);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function hideConfirm(node) {
|
||||
hideMessage(node);
|
||||
|
||||
const filter = $("#filter");
|
||||
filter.animate({opacity: 0}, messageBoxesAnimationTime + 100, "swing", () => {
|
||||
filter.hide();
|
||||
// Retire les callbacks des anciennes confirmations
|
||||
$(confirmMsg).find(".confirmContinue").unbind();
|
||||
$(confirmMsg).find(".confirmCancel").unbind();
|
||||
});
|
||||
}
|
||||
|
||||
const lTomL = 1000;
|
||||
|
@ -151,15 +230,14 @@ let currentUnit = "mL";
|
|||
function changeUnits(unitSelect, quantitiesSelector, unitsDisplay) {
|
||||
currentUnit = unitSelect.value;
|
||||
|
||||
document.querySelectorAll(unitsDisplay).forEach(e => {
|
||||
e.innerText = currentUnit;
|
||||
$(unitsDisplay).each(function () {
|
||||
$(this).text(currentUnit);
|
||||
|
||||
// Modifie la quantitée
|
||||
const quantityElem = e.parentElement.parentElement.querySelector(quantitiesSelector);
|
||||
const quantityElem = $(this).parents(".materialRow").find(quantitiesSelector);
|
||||
console.log(quantityElem);
|
||||
if (quantityElem) {
|
||||
const originalQuantity = parseInt(quantityElem.dataset.quantityml);
|
||||
|
||||
quantityElem.innerText = convertMlToUnit(originalQuantity);
|
||||
const originalQuantity = parseInt(quantityElem.data("quantityml"));
|
||||
quantityElem.text(convertMlToUnit(originalQuantity));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -187,3 +265,7 @@ function percentageOf(percentage, number) {
|
|||
function searchIn(searchString, str) {
|
||||
return str.toUpperCase().indexOf(searchString.toUpperCase()) > -1;
|
||||
}
|
||||
|
||||
function formatMessage(message) {
|
||||
return message.replace(/'/g, "'");
|
||||
}
|
||||
|
|
|
@ -8,19 +8,22 @@ let materialSelectorHtml;
|
|||
let recipeID;
|
||||
|
||||
$(() => {
|
||||
recipeID = document.querySelector("#recipeID").value;
|
||||
recipeID = $("#recipeID").val();
|
||||
|
||||
axios.get(`/mix/selector/${recipeID}/-1`)
|
||||
const mixIDInput = $("#mixID");
|
||||
const mixID = mixIDInput ? mixIDInput.val() : -1;
|
||||
|
||||
axios.get(`/mix/selector/${recipeID}/${mixID}`)
|
||||
.then(r => {
|
||||
materialSelectorHtml = r.data;
|
||||
init();
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e.status);
|
||||
errorMsgBoxText.innerText = generalErrorText;
|
||||
showElement(errorMsgBox);
|
||||
showMessage(errorMsg, generalErrorText);
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
onRowPositionChanged();
|
||||
});
|
||||
|
||||
$(document).on("click", function () {
|
||||
|
@ -32,165 +35,204 @@ $(document).on("click", ".materialSelector", function (event) {
|
|||
showMaterialList($(this)[0]);
|
||||
});
|
||||
|
||||
// $(document).on("click", ".materialList p", function () {
|
||||
// $(this).parents(".materialSelector").find("input").val($(this).data("materialcode"));
|
||||
// });
|
||||
|
||||
$(document).on("click", ".removeMaterial", function () {
|
||||
const id = $(this).data("removerow");
|
||||
if ($(".materialListRow").length > 1) $(`#${id}`).remove();
|
||||
});
|
||||
|
||||
$(document).on("click", ".upRow", function () {
|
||||
const row = $(this).parent().parent();
|
||||
const row = $(this).parents(".materialListRow");
|
||||
row.insertBefore(row.prev());
|
||||
|
||||
onRowPositionChanged();
|
||||
});
|
||||
|
||||
$(document).on("click", ".downRow", function () {
|
||||
const row = $(this).parent().parent();
|
||||
row.insertBefore(row.next());
|
||||
const row = $(this).parents(".materialListRow");
|
||||
row.insertAfter(row.next());
|
||||
|
||||
onRowPositionChanged()
|
||||
});
|
||||
|
||||
document.querySelector(".mixMaterialListTitle button").addEventListener("click", () => {
|
||||
addMaterial(null, null);
|
||||
$(".mixMaterialListTitle button").on({
|
||||
click: function () {
|
||||
addMaterial(null, null);
|
||||
}
|
||||
});
|
||||
|
||||
function onRowPositionChanged() {
|
||||
$(".materialListRow").each(function () {
|
||||
const node = $(this);
|
||||
const upRow = node.find(".upRow");
|
||||
const downRow = node.find(".downRow");
|
||||
|
||||
let upRowHidden = false;
|
||||
let downRowHidden = false;
|
||||
|
||||
if (node.is(":first-child")) {
|
||||
upRowHidden = true;
|
||||
} else if (node.is(":last-child")) {
|
||||
downRowHidden = true;
|
||||
}
|
||||
|
||||
if (upRowHidden) upRow.css({opacity: 0});
|
||||
else upRow.css({opacity: 1});
|
||||
|
||||
if (downRowHidden) downRow.css({opacity: 0});
|
||||
else downRow.css({opacity: 1});
|
||||
});
|
||||
}
|
||||
|
||||
function addMaterial(materialCode, quantity) {
|
||||
const row = addRow(materialNbr);
|
||||
const positionColumn = addColumn("positionButtons", row);
|
||||
const materialColumn = addColumn("material", row);
|
||||
const quantityColumn = addColumn("quantity", row);
|
||||
const unitsColumn = addColumn("units", row);
|
||||
const removeButtonColumn = addColumn("removeButton", row);
|
||||
const positionColumn = $(addColumn("positionButtons", row));
|
||||
const materialColumn = $(addColumn("material", row));
|
||||
const quantityColumn = $(addColumn("quantity", row));
|
||||
const unitsColumn = $(addColumn("units", row));
|
||||
const removeButtonColumn = $(addColumn("removeButton", row));
|
||||
|
||||
addPositionButtons(positionColumn);
|
||||
addQuantityInput(quantity, quantityColumn);
|
||||
addUnits(unitsColumn);
|
||||
addRemoveButton(materialNbr, removeButtonColumn);
|
||||
|
||||
materialColumn.innerHTML = materialSelectorHtml;
|
||||
const materialSelector = materialColumn.querySelector("input");
|
||||
materialColumn.html(materialSelectorHtml);
|
||||
const materialSelector = materialColumn.find("input");
|
||||
if (materialCode) {
|
||||
const material = materialColumn.querySelector(`.materialList p[data-materialcode="${materialCode}"]`);
|
||||
const material = materialColumn.find(`.materialList p[data-materialcode="${materialCode}"]`);
|
||||
|
||||
if (material) {
|
||||
materialSelector.value = material.dataset.materialcode;
|
||||
materialSelector.dataset.usepercentages = material.dataset.usepercentages;
|
||||
materialSelector.val(material.data("materialcode"));
|
||||
materialSelector.data({
|
||||
usepercentages: material.data("usepercentages")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
row.appendChild(materialColumn);
|
||||
row.appendChild(quantityColumn);
|
||||
row.appendChild(unitsColumn);
|
||||
row.appendChild(removeButtonColumn);
|
||||
|
||||
document.querySelector(".mixMaterialList").appendChild(row);
|
||||
$(".mixMaterialList").append(row);
|
||||
|
||||
checkUnits(materialSelector, row);
|
||||
onRowPositionChanged();
|
||||
materialNbr++;
|
||||
}
|
||||
|
||||
function addRow(index) {
|
||||
const row = document.createElement("div");
|
||||
row.classList.add("materialListRow");
|
||||
row.id = `material_${index}`;
|
||||
return row;
|
||||
return $("<div></div>")
|
||||
.attr({
|
||||
class: "materialListRow",
|
||||
id: `material_${index}`
|
||||
});
|
||||
}
|
||||
|
||||
function addColumn(type, parent) {
|
||||
const column = document.createElement("div");
|
||||
column.classList.add(type);
|
||||
const column = $("<div></div>")
|
||||
.attr({class: type});
|
||||
|
||||
parent.appendChild(column);
|
||||
$(parent).append(column);
|
||||
return column;
|
||||
}
|
||||
|
||||
function addUnits(parent) {
|
||||
const units = document.createElement("p");
|
||||
units.classList.add("quantityUnits");
|
||||
units.textContent = "mL";
|
||||
const units = $("<p></p>")
|
||||
.attr({class: "quantityUnits"})
|
||||
.text("mL");
|
||||
|
||||
parent.appendChild(units);
|
||||
$(parent).append(units);
|
||||
return units;
|
||||
}
|
||||
|
||||
function addRemoveButton(index, parent) {
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.textContent = removeText;
|
||||
button.dataset.removerow = `material_${index}`;
|
||||
button.classList.add("removeMaterial");
|
||||
const button = $("<button></button>")
|
||||
.attr({
|
||||
type: "button",
|
||||
class: "removeMaterial"
|
||||
})
|
||||
.data({removerow: `material_${index}`})
|
||||
.text(removeText);
|
||||
|
||||
parent.appendChild(button);
|
||||
$(parent).append(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
function addQuantityInput(quantity, parent) {
|
||||
let input = document.createElement("input");
|
||||
|
||||
if (quantity === undefined || quantity === null) quantity = 1;
|
||||
|
||||
input.type = "number";
|
||||
input.name = "quantities";
|
||||
input.value = quantity;
|
||||
input.step = 0.001;
|
||||
input.min = 0.001;
|
||||
input.required = true;
|
||||
const input = $("<input/>")
|
||||
.attr({
|
||||
type: "number",
|
||||
name: "quantities",
|
||||
value: quantity,
|
||||
step: 0.001,
|
||||
min: 0.001,
|
||||
required: true
|
||||
});
|
||||
|
||||
parent.appendChild(input);
|
||||
$(parent).append(input);
|
||||
return input;
|
||||
}
|
||||
|
||||
function addPositionButtons(parent) {
|
||||
const up = document.createElement("button");
|
||||
up.classList.add("upRow");
|
||||
up.type = "button";
|
||||
up.textContent = "↑";
|
||||
parent.appendChild(up);
|
||||
$(parent).append($("<button></button>")
|
||||
.attr({
|
||||
class: "upRow",
|
||||
type: "button"
|
||||
})
|
||||
.text("↑"));
|
||||
|
||||
const down = document.createElement("button");
|
||||
down.classList.add("downRow");
|
||||
down.type = "button";
|
||||
down.textContent = "↓";
|
||||
parent.appendChild(down);
|
||||
$(parent).append($("<button></button>")
|
||||
.attr({
|
||||
class: "downRow",
|
||||
type: "button"
|
||||
})
|
||||
.text("↓"));
|
||||
}
|
||||
|
||||
function showMaterialList(input) {
|
||||
hideMaterialList();
|
||||
input.parentElement.querySelector(".materialSelector .materialList").classList.add("show");
|
||||
$(input).parent().find(".materialSelector .materialList").addClass("show");
|
||||
}
|
||||
|
||||
function hideMaterialList() {
|
||||
const list = document.querySelector(".materialSelector .materialList.show");
|
||||
|
||||
if (list != null) list.classList.remove("show");
|
||||
const list = $(".materialSelector .materialList.show");
|
||||
if (list) list.removeClass("show");
|
||||
}
|
||||
|
||||
function selectMaterial(material) {
|
||||
const materialName = material.dataset.materialcode;
|
||||
const input = material.parentElement.parentElement.querySelector("input");
|
||||
const materialName = $(material).data("materialcode");
|
||||
const input = $(material).parents(".materialSelector").find("input");
|
||||
|
||||
input.value = materialName;
|
||||
input.val(materialName);
|
||||
|
||||
hideMaterialList();
|
||||
checkUnits(material, input.parentElement.parentElement.parentElement)
|
||||
checkUnits(material, input.parents(".materialListRow"));
|
||||
}
|
||||
|
||||
function searchMaterial(input) {
|
||||
let filter, filterUpper, materials;
|
||||
const filter = input.val();
|
||||
const materials = input.parent().find(".materialList p");
|
||||
|
||||
filter = input.value;
|
||||
materials = input.parentElement.querySelectorAll(".materialList p");
|
||||
|
||||
materials.forEach(e => {
|
||||
if (searchIn(filter, e.textContent) || searchIn(filter, e.dataset.materialtype)) e.style.display = "";
|
||||
else e.style.display = "none";
|
||||
materials.each(function () {
|
||||
const node = $(this);
|
||||
if (searchIn(filter, node.text()) || searchIn(filter, node.data("materialtype"))) node.hide();
|
||||
else node.show();
|
||||
});
|
||||
|
||||
const found = input.parentElement.querySelector(`.materialList p[data-materialcode="${filter}"]`);
|
||||
if (found) input.dataset.usepercentages = found.dataset.usepercentages;
|
||||
const found = input.parent().find(`.materialList p[data-materialcode="${filter}"]`);
|
||||
if (found) {
|
||||
input.data({
|
||||
usepercentages: found.data("usepercentages")
|
||||
});
|
||||
}
|
||||
|
||||
checkUnits(input, input.parentElement.parentElement.parentElement);
|
||||
checkUnits(input, input.parents(".materialListRow"));
|
||||
}
|
||||
|
||||
function checkUnits(materialSelector, row) {
|
||||
const quantityUnits = row.querySelector(".quantityUnits");
|
||||
if (materialSelector.dataset.usepercentages === "true") quantityUnits.innerText = "%";
|
||||
else quantityUnits.innerText = "mL";
|
||||
function checkUnits(materialSelector) {
|
||||
const quantityUnits = $(materialSelector).parents(".materialListRow").find(".quantityUnits");
|
||||
console.log($(quantityUnits));
|
||||
if ($(materialSelector).data("usepercentages")) quantityUnits.text("%");
|
||||
else quantityUnits.text("mL");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import * as bpac from "/js/bpac.js";
|
||||
|
||||
export class PtouchPrinter {
|
||||
constructor(object) {
|
||||
this.object = object;
|
||||
this.pdocument = bpac.IDocument;
|
||||
}
|
||||
|
||||
async print() {
|
||||
if (!bpac.IsExtensionInstalled()) {
|
||||
console.error("L'extension b-Pac n'est pas installée");
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.openDoc();
|
||||
await this.fillDoc();
|
||||
this.printDoc();
|
||||
this.pdocument.Close();
|
||||
|
||||
return 1;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return 99;
|
||||
}
|
||||
};
|
||||
|
||||
async openDoc() {
|
||||
const docUrl = `${baseUrl}/lbx/${this.object.template}.lbx`;
|
||||
console.log("Ouverture du modèle: " + docUrl);
|
||||
await this.pdocument.Open(docUrl);
|
||||
}
|
||||
|
||||
async fillDoc() {
|
||||
for (let i = 0; i < this.object.lines.length; i++) {
|
||||
const line = this.object.lines[i];
|
||||
const label = await this.pdocument.GetObject(line.name);
|
||||
label.Text = line.value;
|
||||
}
|
||||
}
|
||||
|
||||
printDoc() {
|
||||
this.pdocument.StartPrint("", 0);
|
||||
this.pdocument.PrintOut(1, 0);
|
||||
this.pdocument.EndPrint();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
$(() => {
|
||||
$(".companyTabTitle").on({
|
||||
click: function () {
|
||||
const companyID = $(this).parent().data("companyid");
|
||||
$(`#recipes_${companyID}`).toggle();
|
||||
}
|
||||
});
|
||||
});
|
|
@ -33,8 +33,6 @@ function performSearch(searchString) {
|
|||
companyRows.forEach(c => {
|
||||
const recipeRows = c.querySelectorAll(".recipeRow");
|
||||
|
||||
hideElement(warningMsgBox);
|
||||
|
||||
if (!searchString || !searchString.replace(/\s/g, '').length) {
|
||||
c.classList.add("researchResult");
|
||||
|
||||
|
@ -44,7 +42,7 @@ function performSearch(searchString) {
|
|||
|
||||
found = true;
|
||||
emptySearch = true;
|
||||
} else if (searchIn(searchString, c.querySelector("h2").dataset.companyname)) {
|
||||
} else if (searchIn(searchString, c.querySelector("h2").textContent)) {
|
||||
c.classList.add("researchResult");
|
||||
recipeRows.forEach(r => r.classList.add("researchResult"));
|
||||
found = true;
|
||||
|
@ -59,14 +57,12 @@ function performSearch(searchString) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
warningMsgBoxText.innerText = researchNotFound;
|
||||
showElement(warningMsgBox);
|
||||
}
|
||||
|
||||
if (emptySearch) closeTabs();
|
||||
else openTabs();
|
||||
}
|
||||
);
|
||||
|
||||
if (!found) showMessage(warningMsg, researchNotFound, false);
|
||||
else hideMessage(warningMsg);
|
||||
|
||||
if (emptySearch) closeTabs();
|
||||
else openTabs();
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -6,7 +6,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
</head>
|
||||
<body>
|
||||
|
||||
<div th:fragment="header">
|
||||
<div th:fragment="header(showPrinterIcon)">
|
||||
<nav>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn" onclick="document.location.href='/'" th:text="#{menu.explore}">
|
||||
<button class="dropbtn" onclick="window.location.href='/'" th:text="#{menu.explore}">
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
|
@ -44,59 +44,116 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn" onclick="document.location.href='/inventory'" th:text="#{menu.inventory}"></button>
|
||||
<button class="dropbtn" onclick="window.location.href='/inventory'" th:text="#{menu.inventory}"></button>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn" th:text="#{menu.others}"></button>
|
||||
<div class="dropdown-content">
|
||||
<a th:href="@{|${baseUrl}/touchup|}" th:text="#{keyword.touchUpKitPDF}"></a>
|
||||
<a th:href="@{|${baseUrl}/recipe/xls|}" th:text="#{recipe.exportAllXLS}"
|
||||
onclick="return askDatabaseExport()"></a>
|
||||
<a th:href="@{|${baseUrl}/touchup|}" th:text="#{recipe.touchup}"></a>
|
||||
<a href="#" th:text="#{recipe.exportAllXLS}"
|
||||
onclick="return confirmDatabaseExport()"></a>
|
||||
<a th:href="@{|${baseUrl}/lbx/Templates.zip|}" th:text="#{keyword.ptouchTemplate}"></a>
|
||||
<a th:href="@{|${baseUrl}/updates|}" th:text="#{keyword.updates}"></a>
|
||||
</div>
|
||||
</div>
|
||||
<img alt="logo" id="logo" th:src="@{|${baseUrl}/logo.png|}" onclick="location.href = '/'"/>
|
||||
</nav>
|
||||
<div class="spacer"></div>
|
||||
<div class="header-right">
|
||||
<img th:if="${showPrinterIcon}" alt="print status" id="printStatusIcon"
|
||||
th:src="@{|${baseUrl}/icons/printerError.svg|}"/>
|
||||
<img alt="logo" id="logo" th:src="@{|${baseUrl}/logo.png|}" onclick="location.href = '/'"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:fragment="messages">
|
||||
<div th:include="fragments.html :: error"></div>
|
||||
<div th:include="fragments.html :: success"></div>
|
||||
<div th:include="fragments.html :: warning"></div>
|
||||
<div th:include="fragments.html :: confirm"></div>
|
||||
<div th:include="fragments.html :: prompt"></div>
|
||||
<div th:include="fragments.html :: filter"></div>
|
||||
</div>
|
||||
|
||||
<div th:fragment="error">
|
||||
<div class="messageBox errorBox">
|
||||
<div class="messageBox" id="errorBox">
|
||||
<div class="messageBoxContainer">
|
||||
<img th:src="@{|${baseUrl}/icons/error.svg|}" alt="error icon"/>
|
||||
<p th:if="${error != null && !error.isEmpty()}" th:text="#{${error}(${responseArg1}, ${responseArg2})}"></p>
|
||||
<p th:if="${error == null || error.isEmpty()}"></p>
|
||||
<div class="messageBoxMessageContainer">
|
||||
<img th:src="@{|${baseUrl}/icons/error.svg|}" alt="error icon"/>
|
||||
<p th:if="${error != null && !error.isEmpty()}"
|
||||
th:text="#{${error}(${responseArg1}, ${responseArg2})}"></p>
|
||||
<p th:if="${error == null || error.isEmpty()}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:fragment="success">
|
||||
<div class="messageBox successBox">
|
||||
<div class="messageBox" id="successBox">
|
||||
<div class="messageBoxContainer">
|
||||
<img th:src="@{|${baseUrl}/icons/success.svg|}" alt="success icon"/>
|
||||
<p th:if="${success != null && !success.isEmpty()}"
|
||||
th:text="#{${success}(${responseArg1}, ${responseArg2})}"></p>
|
||||
<p th:if="${success == null || success.isEmpty()}"></p>
|
||||
<div class="messageBoxMessageContainer">
|
||||
<img th:src="@{|${baseUrl}/icons/success.svg|}" alt="success icon"/>
|
||||
<p th:if="${success != null && !success.isEmpty()}"
|
||||
th:text="#{${success}(${responseArg1}, ${responseArg2})}"></p>
|
||||
<p th:if="${success == null || success.isEmpty()}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:fragment="warning">
|
||||
<div class="messageBox warningBox">
|
||||
<div class="messageBox" id="warningBox">
|
||||
<div class="messageBoxContainer">
|
||||
<img th:src="@{|${baseUrl}/icons/warning.svg|}" alt="warning icon"/>
|
||||
<p th:if="${warning != null && !warning.isEmpty()}"
|
||||
th:text="#{${warning}(${responseArg1}, ${responseArg2})}"></p>
|
||||
<p th:if="${warning == null || warning.isEmpty()}"></p>
|
||||
<div class="messageBoxMessageContainer">
|
||||
<img th:src="@{|${baseUrl}/icons/warning.svg|}" alt="warning icon"/>
|
||||
<p th:if="${warning != null && !warning.isEmpty()}"
|
||||
th:text="#{${warning}(${responseArg1}, ${responseArg2})}"></p>
|
||||
<p th:if="${warning == null || warning.isEmpty()}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:fragment="confirm">
|
||||
<div class="messageBox" id="confirmBox">
|
||||
<div class="messageBoxContainer">
|
||||
<div class="messageBoxMessageContainer">
|
||||
<img th:src="@{|${baseUrl}/icons/confirm.svg|}" alt="confirm icon"/>
|
||||
<p th:if="${confirm != null && !confirm.isEmpty()}"
|
||||
th:text="#{${confirm}(${responseArg1}, ${responseArg2})}"></p>
|
||||
<p th:if="${confirm == null || confirm.isEmpty()}"></p>
|
||||
</div>
|
||||
<div class="confirmButtonsContainer">
|
||||
<button type="button" class="confirmCancel" th:text="#{keyword.cancel}"></button>
|
||||
<button type="button" class="confirmContinue" th:text="#{keyword.continue}"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:fragment="prompt">
|
||||
<div class="messageBox" id="promptBox">
|
||||
<div class="messageBoxContainer">
|
||||
<div class="messageBoxMessageContainer">
|
||||
<img th:src="@{|${baseUrl}/icons/confirm.svg|}" alt="confirm icon"/>
|
||||
<p th:if="${prompt != null && !prompt.isEmpty()}"
|
||||
th:text="#{${prompt}(${responseArg1}, ${responseArg2})}"></p>
|
||||
<p th:if="${prompt == null || prompt.isEmpty()}"></p>
|
||||
</div>
|
||||
<div class="confirmInputContainer">
|
||||
<input type="text" class="noPlaceholder" id="confirmInput"/>
|
||||
</div>
|
||||
<div class="confirmButtonsContainer">
|
||||
<button type="button" class="confirmCancel" th:text="#{keyword.cancel}"></button>
|
||||
<button type="button" class="confirmContinue" th:text="#{keyword.continue}"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:fragment="filter">
|
||||
<div id="filter"></div>
|
||||
</div>
|
||||
|
||||
<div th:fragment="separator">
|
||||
<td colspan="2">
|
||||
<hr/>
|
||||
|
@ -116,17 +173,20 @@
|
|||
<script th:src="@{|${baseUrl}/js/main.js|}"></script>
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
const simdutNotFoundText = "[[#{material.simdutFile.notFound}]]".replace("'", "'");
|
||||
const changesNotSavedText = "[[#{recipe.warning.changesNotSaved}]]".replace("'", "'");
|
||||
const exportAllWarningText = "[[#{recipe.warning.exportAll}]]".replace("'", "'");
|
||||
const askPasswordText = "[[#{password.ask}]]".replace("'", "'");
|
||||
const invalidPasswordText = "[[#{password.notValid}]]".replace("'", "'");
|
||||
const generalErrorText = "[[#{error.serverError}]]".replace("'", "'");
|
||||
const researchNotFound = "[[#{warning.noResult}]]".replace("'", "'");
|
||||
const recipeNotApproved = "[[#{recipe.warning.notApproved}]]".replace("'", "'");
|
||||
const askChangePage = "[[#{warning.askChangePage}]]".replace("'", "'");
|
||||
const simdutNotFoundText = formatMessage("[[#{material.simdutFile.notFound}]]");
|
||||
const changesNotSavedText = formatMessage("[[#{recipe.warning.changesNotSaved}]]");
|
||||
const exportAllWarningText = formatMessage("[[#{recipe.warning.exportAll}]]");
|
||||
const askPasswordText = formatMessage("[[#{password.ask}]]");
|
||||
const invalidPasswordText = formatMessage("[[#{password.notValid}]]");
|
||||
const generalErrorText = formatMessage("[[#{error.serverError}]]");
|
||||
const researchNotFound = formatMessage("[[#{warning.noResult}]]");
|
||||
const recipeNotApproved = formatMessage("[[#{recipe.warning.notApproved}]]");
|
||||
const askChangePage = formatMessage("[[#{warning.askChangePage}]]");
|
||||
const printOkTitle = formatMessage("[[#{recipe.print.status.ok}]]");
|
||||
const printErrorTitle = formatMessage("[[#{recipe.print.status.error}]]");
|
||||
|
||||
const referer = "[[${referer}]]";
|
||||
const baseUrl = "[[${baseUrl}]]";
|
||||
/*]]>*/
|
||||
</script>
|
||||
</div>
|
||||
|
@ -147,5 +207,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script th:fragment="printStrings">
|
||||
const noBaseError = formatMessage("[[#{recipe.print.error.noBase}]]");
|
||||
const bpacNotInstalledError = formatMessage("[[#{recipe.print.error.bpacNotInstalled}]]");
|
||||
const printError = formatMessage("[[#{recipe.print.error}]]");
|
||||
const confirmPrintMessage = formatMessage("[[#{recipe.print.confirm}]]");
|
||||
const printingMessage = formatMessage("[[#{recipe.print.printing}]]");
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div id="researchBoxContainer">
|
||||
|
@ -20,10 +20,9 @@
|
|||
<div class="content recipesContainer">
|
||||
<div class="companyTab" th:if="${!recipeMap.empty}" th:each="company : ${recipeMap.keySet()}"
|
||||
th:data-companyID="${company.companyID}">
|
||||
<h2 class="companyTabTitle" th:data-companyName="${company.companyName}"
|
||||
th:text="${company.companyName}"></h2>
|
||||
<h2 class="companyTabTitle" th:text="${company.companyName}"></h2>
|
||||
|
||||
<table style="display:none" th:id="'recipes_' + ${company.companyName}" class="recipesList"
|
||||
<table style="display:none" th:id="'recipes_' + ${company.companyID}" class="recipesList"
|
||||
th:if="${!recipeMap.get(company).empty}">
|
||||
<tr>
|
||||
<th th:text="#{recipe.color}"></th>
|
||||
|
@ -51,16 +50,15 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script th:src="@{|${baseUrl}/js/recipeResearch.js|}"></script>
|
||||
<script th:src="@{|${baseUrl}/js/recipeList.js|}"></script>
|
||||
<script>
|
||||
(() => {
|
||||
document.querySelectorAll(".gotoRecipe").forEach(e => {
|
||||
e.addEventListener("click", () => {
|
||||
const recipeID = e.getAttribute("data-recipeID");
|
||||
|
||||
document.location.href = "/recipe/explore/" + recipeID;
|
||||
});
|
||||
$(() => {
|
||||
$(".gotoRecipe").on({
|
||||
click: function () {
|
||||
window.location.href = `/recipe/explore/${$(this).data("recipeid")}`;
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<th:block th:each="materialType : ${materialTypes}"
|
||||
|
@ -156,7 +156,7 @@
|
|||
// Rajoute un événement sur les boutons pour modifier les produits pour rediriger l'utilisateur vers la page de modification
|
||||
document.querySelectorAll(".modifyMaterial").forEach(e => {
|
||||
e.addEventListener("click", () => {
|
||||
document.location.href = `/material/editor/${e.dataset.materialid}`;
|
||||
window.location.href = `/material/editor/${e.dataset.materialid}`;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -213,8 +213,6 @@
|
|||
const materialRows = document.querySelectorAll(".materialRow");
|
||||
|
||||
function performSearch(searchString) {
|
||||
hideElement(warningMsgBox);
|
||||
|
||||
let found = false;
|
||||
|
||||
const recipesContainer = document.querySelector(".materialsContainer:not(.researchEnabled)");
|
||||
|
@ -242,10 +240,8 @@
|
|||
}
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
warningMsgBoxText.innerText = researchNotFound;
|
||||
showElement(warningMsgBox);
|
||||
}
|
||||
if (!found) showMessage(warningMsg, researchNotFound, false);
|
||||
else hideMessage(warningMsg);
|
||||
}
|
||||
|
||||
/*]]>*/
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<p th:text="#{material.success.created(${materialCode})}"></p>
|
||||
|
|
|
@ -6,10 +6,9 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<p th:if="${materialCode != null}" th:text="#{material.success.created(${materialCode})}" class="success"></p>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
||||
<h1 th:text="#{material.add.title}"></h1>
|
||||
|
@ -29,7 +28,7 @@
|
|||
<label th:for="${#ids.next('materialType')}" th:text="#{material.type} + ':'"></label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="simdut" th:text="#{material.simdutFile} + ':'"></label>
|
||||
<label for="simdut" th:text="#{material.simdut} + ':'"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formColumn">
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
@ -34,6 +34,9 @@
|
|||
<div>
|
||||
<label th:for="${#ids.next('materialType')}">Type de produit: </label>
|
||||
</div>
|
||||
<div>
|
||||
<label th:text="#{material.simdut} + ':'"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formColumn">
|
||||
<div>
|
||||
|
@ -71,6 +74,10 @@
|
|||
th:value="${mType.materialTypeID}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<button id="showSIMDUT" type="button" th:text="#{keyword.see}"></button>
|
||||
<button id="editSIMDUT" type="button" th:text="#{keyword.edit}"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div th:include="fragments.html :: formEndButtons"></div>
|
||||
|
@ -90,7 +97,7 @@
|
|||
});
|
||||
|
||||
document.querySelector("#editSIMDUT").addEventListener("click", () => {
|
||||
document.location.href = `/material/simdut/${materialID}`;
|
||||
window.location.href = `/material/simdut/${materialID}`;
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
|
@ -17,13 +17,10 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
<p class="success" th:if="${materialCode != null}"
|
||||
th:text="#{material.success.saved(${materialCode})}"></b>
|
||||
</p>
|
||||
<h1 th:text="#{material.edit.title}"></h1>
|
||||
|
||||
<table th:if="${!materials.empty}">
|
||||
|
@ -55,7 +52,7 @@
|
|||
e.addEventListener("click", () => {
|
||||
const materialID = e.getAttribute("data-materialID");
|
||||
|
||||
document.location.href = "/material/editor/" + materialID;
|
||||
window.location.href = "/material/editor/" + materialID;
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -17,12 +17,10 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
<p class="success" th:if="${materialCode != null}"
|
||||
th:text="#{material.success.deleted(${materialCode})}"></p>
|
||||
<h1 th:text="#{material.delete.title}"></h1>
|
||||
|
||||
<form th:action="@{/material/remover/}" class="requireAuth-remover" method="POST">
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<div class="formWrap">
|
||||
<div class="formColumn">
|
||||
<div>
|
||||
<label th:for="${#ids.next('materialTypeID')}" th:text="#{material.type}"></label>
|
||||
<label th:for="${#ids.next('materialTypeID')}" th:text="#{keyword.id} + ':'"></label>
|
||||
</div>
|
||||
<div>
|
||||
<label th:for="${#ids.next('materialTypeName')}" th:text="#{materialType.name} + ':'"></label>
|
||||
|
|
|
@ -17,13 +17,10 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
<p class="success" th:if="${materialTypeName != null}"
|
||||
th:text="#{materialType.success.saved(${materialTypeName})}"></b>
|
||||
</p>
|
||||
<h1 th:text="#{materialType.editor.title}"></h1>
|
||||
|
||||
<table th:if="${!materialTypes.empty}">
|
||||
|
@ -53,7 +50,7 @@
|
|||
e.addEventListener("click", () => {
|
||||
const materialTypeID = e.getAttribute("data-materialTypeID");
|
||||
|
||||
document.location.href = "/materialType/editor/" + materialTypeID;
|
||||
window.location.href = "/materialType/editor/" + materialTypeID;
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
</head>
|
||||
<body th:with="nbrMaterials = 0">
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
@ -85,9 +85,9 @@
|
|||
removeText = "[[#{keyword.remove}]]";
|
||||
|
||||
document.querySelector("#removeMix").addEventListener("click", () => {
|
||||
showElement(errorMsgBox);
|
||||
showMessage(errorMsg);
|
||||
|
||||
checkPassword(null, () => document.location.href = `/mix/remover/[[${mix.mixID}]]`);
|
||||
checkPassword(null, () => window.location.href = `/mix/remover/[[${mix.mixID}]]`);
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
th:text="${material.materialType.materialTypeName == 'Aucun' ? '' : '[' + material.materialType.prefix + ']'} + ' ' + ${material.materialCode}"
|
||||
th:data-materialcode="${material.materialCode}"
|
||||
th:data-materialtype="${material.materialType.materialTypeName}"
|
||||
th:data-usepercentages="${material.materialType.usePercentages}"></p>
|
||||
th:data-usepercentages="${material.materialType.usePercentages}"
|
||||
onclick="selectMaterial(this)"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
<div class="form">
|
||||
<form th:action="@{/recipe/editor}" th:object="${recipe}" class="requireAuth" method="POST">
|
||||
<input type="hidden" th:field="*{recipeID}"/>
|
||||
|
||||
<table class="mainTable">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td><b th:text="#{keyword.id} + ':'"></b></td>
|
||||
<td th:text="${recipe.recipeID}"></td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
<tr>
|
||||
<td><b><label th:for="${#ids.next('recipeCode')}"
|
||||
th:text="#{recipe.color} + ':'"></label></b></td>
|
||||
<td><input type="text" th:field="*{recipeCode}"></td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
<tr>
|
||||
<td><b><label th:for="${#ids.next('company')}"
|
||||
th:text="#{keyword.company} + ':'"></label></b>
|
||||
</td>
|
||||
<td>
|
||||
<select th:field="*{company}">
|
||||
<option th:each="company : ${companies}"
|
||||
th:selected="${recipe.company.equals(company)}"
|
||||
th:text="${company.companyName}"
|
||||
th:value="${company.companyID}"></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
<tr>
|
||||
<td><b><label th:for="${#ids.next('recipeDescription')}"
|
||||
th:text="#{recipe.description} + ':'"></label></b></td>
|
||||
<td><input type="text" th:field="*{recipeDescription}"/></td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
<tr>
|
||||
<td><b><label th:for="${#ids.next('sample')}" th:text="#{recipe.sample} + ':'"></label></b>
|
||||
</td>
|
||||
<td><input type="number" th:field="*{sample}"/></td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
<tr>
|
||||
<td><b><label th:for="${#ids.next('approbationDate')}"
|
||||
th:text="#{recipe.approbationDate} + ':'"></label></b></td>
|
||||
<td><input type="date" th:field="*{approbationDate}"/></td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
<tr>
|
||||
<td><b><label th:for="${#ids.next('remark')}" th:text="#{recipe.remark} + ':'"></label></b>
|
||||
</td>
|
||||
<td><textarea cols="20" rows="2" th:field="*{remark}"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan="2" style="height: 40px; text-align: right">
|
||||
<button id="newMix" type="button" th:text="#{recipe.edit.addMix}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<th:block th:each="mix : ${mixes}">
|
||||
<tr>
|
||||
<td class="mixNameColumn">
|
||||
<b th:text="${mix.mixType.typeName} + ':'"></b>
|
||||
<br/>
|
||||
<th:block th:if="${mix != null}">
|
||||
<button class="mixEditor" th:data-mixID="${mix.mixID}" type="button"
|
||||
th:text="#{keyword.edit}"></button>
|
||||
</th:block>
|
||||
</td>
|
||||
<td>
|
||||
<div class="recipe">
|
||||
<table style="margin-left: 50px">
|
||||
<!-- Produits -->
|
||||
<tr>
|
||||
<th th:text="#{keyword.material}"></th>
|
||||
<th th:text="#{keyword.type}"></th>
|
||||
<th th:text="#{keyword.quantity}"></th>
|
||||
</tr>
|
||||
<tr th:each="mixQuantity : ${mix.mixQuantities}"
|
||||
th:with="material = ${mixQuantity.material}">
|
||||
<td th:classappend="${material.isMixType()} ? '' : materialCode"
|
||||
th:data-materialID="${material.materialID}"
|
||||
th:text="${material.materialCode}"></td>
|
||||
<td>
|
||||
<p th:text="${material.materialType.materialTypeName}"></p>
|
||||
</td>
|
||||
<td th:text="${mixQuantity.quantity} + ' ' + ${material.materialType.usePercentages ? '%' : 'mL'}"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
</th:block>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<!-- Images -->
|
||||
<table>
|
||||
<tr th:each="image : ${images}">
|
||||
<td class="centerTD">
|
||||
<img alt="Image supprimée ou corrompue" th:src="'/images/' + ${image}"
|
||||
height="250px"/>
|
||||
</td>
|
||||
<td style="text-align: left; padding-left: 50px">
|
||||
<button class="deleteImg" th:data-image="${image}" type="button"
|
||||
style="height: 250px">
|
||||
<span th:text="#{keyword.delete}"
|
||||
style="display: inline-block; transform: rotate(90deg); font-weight: bolder"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td>
|
||||
<!-- Étapes -->
|
||||
<table>
|
||||
<tr>
|
||||
<td style="text-align: center">
|
||||
<h3 th:text="#{recipe.steps}"></h3>
|
||||
</td>
|
||||
<td style="text-align: left; vertical-align: middle; padding-left: 20px">
|
||||
<button id="addStep" type="button">+</button>
|
||||
</td>
|
||||
<td style="width: 100%"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<table id="steps" style="width:100%">
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="addImg" th:data-recipeID="${recipe.recipeID}" type="button"
|
||||
th:text="#{recipe.edit.addImage}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
|
@ -6,14 +6,14 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
||||
<h1 th:text="#{recipe.add.title}"></h1>
|
||||
<p th:text="#{recipe.sucess.saved(${recipe.recipeCode})}"></p>
|
||||
<button th:onclick="'document.location.href=\'/recipe/editor/' + ${recipe.recipeID} + '\''"
|
||||
<button th:onclick="'window.location.href=\'/recipe/editor/' + ${recipe.recipeID} + '\''"
|
||||
th:text="#{keyword.continue}"></button>
|
||||
</section>
|
||||
<!-- Fragment du pied de page -->
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
|
|
@ -6,29 +6,6 @@
|
|||
<link href="/css/explore.css" rel="stylesheet"/>
|
||||
|
||||
<style>
|
||||
/*p {*/
|
||||
/* display: inline;*/
|
||||
/*}*/
|
||||
|
||||
/*.recipe table {*/
|
||||
/* background-color: #fafafa;*/
|
||||
/* border: 1px solid #7a7a7a;*/
|
||||
/* border-collapse: collapse !important;*/
|
||||
/*}*/
|
||||
|
||||
/*.recipe td, .recipe th {*/
|
||||
/* min-width: 100px;*/
|
||||
/* text-align: center;*/
|
||||
/*}*/
|
||||
|
||||
/*.recipe tr:nth-child(odd) {*/
|
||||
/* background-color: #f5f5f5;*/
|
||||
/*}*/
|
||||
|
||||
/*.mixNameColumn {*/
|
||||
/* display: inline-block;*/
|
||||
/*}*/
|
||||
|
||||
.content {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
@ -63,14 +40,14 @@
|
|||
}
|
||||
|
||||
#steps label {
|
||||
vertical-align: middle;
|
||||
/*vertical-align: middle;*/
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
@ -171,16 +148,13 @@
|
|||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mixActionsContainer">
|
||||
<button class="useMixSubmit" type="button" th:text="#{keyword.use}"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Étapes -->
|
||||
<div class="flexContent" id="steps" style="display: flex; flex-direction: column">
|
||||
<div style="display: flex; flex-direction: row; justify-content: center">
|
||||
<h3 th:text="#{recipe.steps}"></h3>
|
||||
<button id="addStep" type="button" style="width: 20px; height: 20px; margin:20px">+</button>
|
||||
<h3 th:text="#{recipe.steps}" style="margin: 0"></h3>
|
||||
<button id="addStep" type="button" style="width: 20px; height: 20px; margin: 0 20px">+</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -224,50 +198,44 @@
|
|||
e.addEventListener("click", () => {
|
||||
const mixID = e.getAttribute("data-mixID");
|
||||
|
||||
document.location.href = "/mix/editor/" + mixID;
|
||||
window.location.href = "/mix/editor/" + mixID;
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector("#newMix").addEventListener("click", () => {
|
||||
const recipeID = "[[${recipe.recipeID}]]";
|
||||
|
||||
document.location.href = "/mix/creator/" + recipeID;
|
||||
window.location.href = "/mix/creator/" + recipeID;
|
||||
});
|
||||
|
||||
document.querySelectorAll(".deleteImg").forEach(e => {
|
||||
e.addEventListener("click", async () => {
|
||||
if (confirm(askChangePage)) {
|
||||
showConfirm(askChangePage, false, () => {
|
||||
checkPassword(null, () => {
|
||||
let data = {};
|
||||
|
||||
data['image'] = e.getAttribute("data-image");
|
||||
hideElement(errorMsgBox);
|
||||
|
||||
axios.post("/images/delete", data)
|
||||
.then(r => {
|
||||
const data = r.data;
|
||||
|
||||
if (data['error'] !== undefined) {
|
||||
errorMsgBoxText.innerText = data['error'];
|
||||
showElement(errorMsgBox);
|
||||
showMessage(errorMsg, data['error']);
|
||||
} else {
|
||||
document.location.reload();
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
errorMsgBoxText.innerText = "[[#{error.serverError}]]";
|
||||
showElement(errorMsgBox);
|
||||
showMessage(errorMsg, generalErrorText);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector("#addImage").addEventListener("click", () => {
|
||||
if (confirm(askChangePage)) {
|
||||
document.location.href = "/images/add/[[${recipe.recipeID}]]";
|
||||
}
|
||||
showConfirm(askChangePage, false, () => window.location.href = "/images/add/[[${recipe.recipeID}]]");
|
||||
});
|
||||
|
||||
const recipeText = "[[${recipeJSON}]]";
|
||||
|
@ -288,7 +256,7 @@
|
|||
let input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.id = `step_${stepNbr}`;
|
||||
input.classList.add("step", "rawInput");
|
||||
input.classList.add("step", "rawInput", "toSave");
|
||||
input.name = "step";
|
||||
input.autocomplete = "off";
|
||||
if (value != null) input.value = value;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div id="researchBoxContainer">
|
||||
|
@ -21,10 +21,8 @@
|
|||
<div class="content recipesContainer">
|
||||
<div class="companyTab" th:if="${!recipeMap.empty}" th:each="company : ${recipeMap.keySet()}"
|
||||
th:data-companyID="${company.companyID}">
|
||||
<h2 class="companyTabTitle" th:data-companyName="${company.companyName}"
|
||||
th:text="${company.companyName}"></h2>
|
||||
|
||||
<table style="display:none" th:id="'recipes_' + ${company.companyName}" class="recipesList"
|
||||
<h2 class="companyTabTitle" th:text="${company.companyName}"></h2>
|
||||
<table style="display:none" th:id="'recipes_' + ${company.companyID}" class="recipesList"
|
||||
th:if="${!recipeMap.get(company).empty}">
|
||||
<tr>
|
||||
<th th:text="#{recipe.color}"></th>
|
||||
|
@ -52,16 +50,15 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script th:src="@{|${baseUrl}/js/recipeResearch.js|}"></script>
|
||||
<script th:src="@{|${baseUrl}/js/recipeList.js|}"></script>
|
||||
<script>
|
||||
(() => {
|
||||
document.querySelectorAll(".editRecipe").forEach((e) => {
|
||||
e.addEventListener("click", () => {
|
||||
const recipeID = e.getAttribute("data-recipeID");
|
||||
|
||||
document.location.href = "/recipe/editor/" + recipeID;
|
||||
});
|
||||
$(() => {
|
||||
$(".editRecipe").on({
|
||||
click: function () {
|
||||
window.location.href = `/recipe/editor/${$(this).data("recipeid")}`;
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(true)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
@ -117,6 +117,8 @@
|
|||
<!-- Produits -->
|
||||
<tr th:each="mixQuantity : ${mix.mixQuantities}"
|
||||
th:with="material = ${mixQuantity.material}"
|
||||
class="materialRow"
|
||||
th:data-materialtypename="${material.materialType.materialTypeName}"
|
||||
th:id="'material-' + ${material.materialID}">
|
||||
<td class="materialCodeColumn"
|
||||
th:classappend="${material.isMixType()} ? '' : materialCode"
|
||||
|
@ -136,6 +138,7 @@
|
|||
th:data-mixID="${mix.mixID}"
|
||||
th:data-quantityML="${mixQuantity.quantity}"
|
||||
th:data-usePercentages="${material.materialType.usePercentages}"
|
||||
th:data-defaultvalue="${mixQuantity.quantity}"
|
||||
th:value="${mixQuantity.quantity}"
|
||||
th:disabled="${material.materialType.usePercentages}"
|
||||
type="number"/></td>
|
||||
|
@ -170,7 +173,7 @@
|
|||
</div>
|
||||
<div class="mixActionsContainer">
|
||||
<button class="useMixSubmit" type="button" th:text="#{keyword.use}"></button>
|
||||
<button type="button" th:text="#{keyword.print}"></button>
|
||||
<button type="button" class="printButton" th:text="#{keyword.print}"></button>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
|
@ -207,210 +210,160 @@
|
|||
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
const quantityKeyword = "[[#{keyword.quantity}]]";
|
||||
|
||||
(() => {
|
||||
document.querySelector("#modifyRecipe").addEventListener("click", () => {
|
||||
const recipeID = document.querySelector("#recipeID").value;
|
||||
document.location.href = `/recipe/editor/${recipeID}`;
|
||||
});
|
||||
|
||||
document.querySelectorAll(".quantityCustomizer").forEach(e => {
|
||||
if (e.dataset.usepercentages === "true") {
|
||||
const parentQuantity = e.parentElement.parentElement.parentElement.querySelectorAll(".quantityCustomizer")[0].dataset.quantityml;
|
||||
|
||||
e.dataset.quantityml = percentageOf(e.value, parentQuantity);
|
||||
$(() => {
|
||||
$("#modifyRecipe").on({
|
||||
click: function () {
|
||||
window.location.href = `/recipe/editor/${$("#recipeID").val()}`;
|
||||
}
|
||||
|
||||
e.addEventListener("change", () => {
|
||||
// Les 3 parentElement récupèrent la table dans laquelle le produit se trouve
|
||||
const parentTable = e.parentElement.parentElement.parentElement;
|
||||
const firstInput = parentTable.querySelectorAll(".quantityCustomizer")[0];
|
||||
if (e.dataset.usepercentages === "false") {
|
||||
const value = e.valueAsNumber;
|
||||
const oldValue = e.defaultValue;
|
||||
const currentUnit = document.querySelector("#unitsSelect").value;
|
||||
|
||||
// Modifie les quantités de tous les produits
|
||||
parentTable.querySelectorAll(".quantityCustomizer").forEach((elem) => {
|
||||
if (elem.dataset.usepercentages === "false") {
|
||||
const defaultValue = elem.defaultValue;
|
||||
const newValue = (defaultValue * value) / oldValue;
|
||||
|
||||
elem.value = round(newValue);
|
||||
|
||||
// Recalcule la quantité en millilitres de chaque produit
|
||||
elem.dataset.quantityml = convertUnitToMl(newValue);
|
||||
} else {
|
||||
elem.dataset.quantityml = percentageOf(elem.value, firstInput.dataset.quantityml);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
e.dataset.quantityml = percentageOf(e.value, firstInput.dataset.quantityml);
|
||||
}
|
||||
|
||||
doCalculations(parentTable);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll(".totalQuantityCustomizer").forEach(e => {
|
||||
e.addEventListener("change", () => {
|
||||
console.log(e);
|
||||
const value = e.valueAsNumber;
|
||||
const oldValue = e.defaultValue;
|
||||
const mixID = e.dataset.mixid;
|
||||
const mixTable = document.querySelector(`#mix-${mixID}`);
|
||||
$(".quantityCustomizer").each(function () {
|
||||
if ($(this).data("usepercentages")) {
|
||||
const parentQuantity = $(this).parents(".mixContainer").find(".quantityCustomizer").eq(0).data("quantityml");
|
||||
$(this).data({quantityml: percentageOf($(this).val(), parentQuantity)});
|
||||
}
|
||||
});
|
||||
|
||||
mixTable.querySelectorAll(".quantityCustomizer").forEach(elem => {
|
||||
if (elem.dataset.usepercentages === "false") {
|
||||
const defaultValue = elem.defaultValue;
|
||||
const newValue = (defaultValue * value) / oldValue;
|
||||
$(".quantityCustomizer").on({
|
||||
keyup: function () {
|
||||
computeQuantities($(this));
|
||||
}
|
||||
});
|
||||
|
||||
console.log(value + "/" + oldValue + "/" + defaultValue + "/" + newValue);
|
||||
$(".totalQuantityCustomizer").on({
|
||||
keyup: function () {
|
||||
const mix = $(this).parents(".mixContainer");
|
||||
|
||||
elem.value = round(newValue);
|
||||
}
|
||||
const value = $(this).val();
|
||||
const defaultValue = $(this).data("defaultvalue");
|
||||
|
||||
const firstMaterial = mix.find(".quantityCustomizer").eq(0);
|
||||
const firstDefaultValue = firstMaterial.data("defaultvalue");
|
||||
const firstNewValue = (firstDefaultValue * value) / defaultValue;
|
||||
firstMaterial.val(round(firstNewValue));
|
||||
|
||||
computeQuantities(firstMaterial, false);
|
||||
}
|
||||
});
|
||||
|
||||
$("#formSubmit").on({
|
||||
click: function () {
|
||||
let formData = {};
|
||||
formData.recipeID = $("#recipeID").val();
|
||||
|
||||
formData.locations = {};
|
||||
$(".recipeLocation").each(function () {
|
||||
formData.locations[$(this).data("mixid")] = $(this).val();
|
||||
});
|
||||
|
||||
doCalculations(mixTable);
|
||||
})
|
||||
formData.note = $("#note").val();
|
||||
|
||||
sendPost(formData, "/recipe/explore", () => showMessage(errorMsg, generalErrorText));
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelector("#formSubmit").addEventListener("click", () => {
|
||||
let formData = {};
|
||||
|
||||
// Identifiant de la recette
|
||||
formData.recipeID = document.querySelector("#recipeID").value;
|
||||
|
||||
// Position
|
||||
formData.locations = {};
|
||||
document.querySelectorAll(".recipeLocation").forEach((e) => {
|
||||
formData.locations[e.dataset.mixid] = e.value;
|
||||
});
|
||||
|
||||
formData.note = document.querySelector("#note").value;
|
||||
|
||||
sendPost(formData, "/recipe/explore", () => showElement(warningMsgBox));
|
||||
hideElement(warningMsgBox);
|
||||
});
|
||||
|
||||
document.querySelector("#useSubmit").addEventListener("click", () => {
|
||||
const shouldContinue = confirm("[[#{inventory.askUseRecipe}]]".replace("'", "'"));
|
||||
if (!shouldContinue) return;
|
||||
|
||||
let formData = {};
|
||||
|
||||
document.querySelectorAll(".quantityCustomizer").forEach(e => {
|
||||
const materialID = e.dataset.materialid;
|
||||
const mixID = e.dataset.mixid;
|
||||
|
||||
if (formData[mixID] === undefined) {
|
||||
formData[mixID] = {};
|
||||
}
|
||||
|
||||
formData[mixID][materialID] = e.dataset.quantityml;
|
||||
});
|
||||
|
||||
clearNotEnoughClasses();
|
||||
|
||||
sendPost(formData, "/inventory/use", r => displayNotEnoughReason(r));
|
||||
});
|
||||
|
||||
document.querySelectorAll(".useMixSubmit").forEach(e => {
|
||||
e.addEventListener("click", () => {
|
||||
const shouldContinue = confirm("[[#{inventory.askUseMix}]]".replace("'", "'"));
|
||||
if (!shouldContinue) return;
|
||||
|
||||
$("#useSubmit").on({
|
||||
click: function () {
|
||||
let formData = {};
|
||||
|
||||
e.parentElement.parentElement.querySelectorAll(".quantityCustomizer").forEach(elem => {
|
||||
const materialID = elem.getAttribute("data-materialID");
|
||||
const mixID = elem.getAttribute("data-mixID");
|
||||
$(".quantityCustomizer").each(function () {
|
||||
const materialID = $(this).data("materialid");
|
||||
const mixID = $(this).data("mixid");
|
||||
|
||||
if (formData[mixID] === undefined) {
|
||||
formData[mixID] = {};
|
||||
}
|
||||
|
||||
formData[mixID][materialID] = elem.dataset.quantityml;
|
||||
formData[mixID][materialID] = $(this).data("quantityml");
|
||||
});
|
||||
|
||||
clearNotEnoughClasses();
|
||||
|
||||
sendPost(formData, "/inventory/use", r => displayNotEnoughReason(r));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
document.querySelectorAll(".mix").forEach(e => doCalculations(e));
|
||||
$(".useMixSubmit").on({
|
||||
click: function () {
|
||||
showConfirm(formatMessage("[[#{inventory.askUseMix}]]"), false, () => {
|
||||
let formData = {};
|
||||
|
||||
$(this).parents(".mixContainer").find(".quantityCustomizer").each(function () {
|
||||
const materialID = $(this).data("materialid");
|
||||
const mixID = $(this).data("mixid");
|
||||
|
||||
if (formData[mixID] === undefined) formData[mixID] = {};
|
||||
formData[mixID][materialID] = $(this).data("quantityml");
|
||||
});
|
||||
|
||||
clearNotEnoughClasses();
|
||||
sendPost(formData, "/inventory/use", r => displayNotEnoughReason(r));
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
$(".mix").each(function () {
|
||||
doCalculations(this)
|
||||
});
|
||||
});
|
||||
|
||||
function changeCustomizersUnits() {
|
||||
document.querySelectorAll(".quantityCustomizer").forEach(e => {
|
||||
if (e.dataset.usepercentages === "false") {
|
||||
const originalValue = e.dataset.quantityml;
|
||||
|
||||
e.value = convertMlToUnit(originalValue);
|
||||
}
|
||||
$(".quantityCustomizer").each(function () {
|
||||
const node = $(this);
|
||||
if (node.data("usepercentages") === "false") $(this).val(convertMlToUnit($(this).data("quantityml")));
|
||||
});
|
||||
}
|
||||
|
||||
function clearNotEnoughClasses() {
|
||||
document.querySelectorAll(".notEnough").forEach(elem => {
|
||||
elem.classList.remove("notEnough");
|
||||
});
|
||||
$(".notEnough").removeClass("notEnough");
|
||||
}
|
||||
|
||||
function displayNotEnoughReason(reason) {
|
||||
const splitReason = reason.split("-");
|
||||
const mixID = splitReason[0];
|
||||
const materialID = splitReason[1];
|
||||
|
||||
document.querySelector(`#mix-${mixID}`).querySelector(`#material-${materialID}`).classList.add("notEnough");
|
||||
$(`#mix-${splitReason[0]}`).find(`#material-${splitReason[1]}`).addClass("notEnough");
|
||||
}
|
||||
|
||||
function hideQuantities(button) {
|
||||
let hidden = button.dataset.hidden;
|
||||
button = $(button);
|
||||
|
||||
if (hidden === "true") hidden = "false";
|
||||
else hidden = "true";
|
||||
// Récupère la valeur, la convertit en bool, puis l'inverse
|
||||
let hiddenString = button.data("hidden");
|
||||
let hidden = hiddenString || hiddenString === "true";
|
||||
hidden = !hidden;
|
||||
|
||||
button.parents(".mix").find(".inventoryQuantity").each(function () {
|
||||
const node = $(this);
|
||||
let css;
|
||||
|
||||
button.parentElement.parentElement.parentElement.querySelectorAll(".inventoryQuantity").forEach(e => {
|
||||
if (hidden === "true") {
|
||||
e.style.display = "none";
|
||||
e.parentElement.setAttribute("style", "min-width: auto !important");
|
||||
button.parentElement.setAttribute("style", "min-width: auto !important");
|
||||
if (hidden) {
|
||||
css = {minWidth: "auto"};
|
||||
node.parent().css(css);
|
||||
button.parent().css(css);
|
||||
|
||||
button.innerText = "->";
|
||||
node.hide();
|
||||
button.text("->");
|
||||
} else {
|
||||
e.style.display = "inline";
|
||||
css = {minWidth: 75};
|
||||
node.parent().css(css);
|
||||
button.parent().css(css);
|
||||
|
||||
e.parentElement.setAttribute("style", "min-width: 75px !important");
|
||||
button.parentElement.setAttribute("style", "min-width: 75px !important");
|
||||
|
||||
button.innerText = quantityKeyword;
|
||||
node.show();
|
||||
button.text("[[#{keyword.quantity}]]");
|
||||
}
|
||||
});
|
||||
|
||||
button.dataset.hidden = hidden;
|
||||
button.data({hidden: hidden});
|
||||
}
|
||||
|
||||
function sendPost(data, url, errorCallback) {
|
||||
hideElement(successMsgBox);
|
||||
hideElement(errorMsgBox);
|
||||
|
||||
axios.post(url, data)
|
||||
.then(r => {
|
||||
const data = r.data;
|
||||
|
||||
if (data.success !== undefined) {
|
||||
successMsgBoxText.innerHTML = data.success.message;
|
||||
showElement(successMsgBox);
|
||||
showMessage(successMsg, data.success.message);
|
||||
return true;
|
||||
} else if (data.error !== undefined) {
|
||||
errorMsgBoxText.innerText = data.error.message;
|
||||
showElement(errorMsgBox);
|
||||
showMessage(errorMsg, data.error.message);
|
||||
|
||||
if (typeof errorCallback !== 'undefined') {
|
||||
errorCallback(data.reason);
|
||||
|
@ -421,96 +374,146 @@
|
|||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
errorMsgBoxText.innerText = "[[#{error.serverError}]]";
|
||||
showElement(errorMsgBox);
|
||||
showMessage(errorMsg, generalErrorText);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function doCalculations(parent) {
|
||||
function computeQuantities(customizer, computeTotal) {
|
||||
const mix = customizer.parents(".mixContainer");
|
||||
const mixCustomizers = mix.find(".quantityCustomizer");
|
||||
const firstInput = mixCustomizers.eq(0);
|
||||
|
||||
const value = customizer.val();
|
||||
const defaultValue = customizer.data("defaultvalue");
|
||||
customizer.data("blabla", "balbla");
|
||||
|
||||
mixCustomizers.each(function () {
|
||||
if (!$(this).data("usepercentages")) {
|
||||
const currentDefaultValue = $(this).data("defaultvalue");
|
||||
const newValue = (currentDefaultValue * value) / defaultValue;
|
||||
|
||||
$(this).val(round(newValue));
|
||||
$(this).data({
|
||||
quantityml: convertUnitToMl(newValue)
|
||||
});
|
||||
} else {
|
||||
$(this).data({
|
||||
quantityml: percentageOf($(this).val(), firstInput.data("quantityml"))
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
doCalculations(mix, computeTotal);
|
||||
}
|
||||
|
||||
function doCalculations(parent, computeTotal = true) {
|
||||
let lastQuantity = 0;
|
||||
parent = $(parent);
|
||||
|
||||
parent.querySelectorAll(".quantityCustomizer").forEach(e => {
|
||||
const materialID = e.dataset.materialid;
|
||||
const mixID = e.dataset.mixid;
|
||||
const quantity = e.dataset.usepercentages === "true" ? round(convertMlToUnit(e.dataset.quantityml)) : round(e.value);
|
||||
parent.find(".quantityCustomizer").each(function () {
|
||||
const node = $(this);
|
||||
const materialID = node.data("materialid");
|
||||
const mixID = node.data("mixid");
|
||||
const quantity = round(convertMlToUnit(node.data("quantityml")));
|
||||
const p = parent.find(`.calculation[data-materialid='${materialID}'][data-mixid='${mixID}']`);
|
||||
const totalQuantity = round(lastQuantity + parseFloat(quantity));
|
||||
p.data({
|
||||
quantity: quantity,
|
||||
totalQuantity: totalQuantity
|
||||
});
|
||||
|
||||
const p = parent.querySelector(`.calculation[data-materialid='${materialID}'][data-mixid='${mixID}']`);
|
||||
|
||||
let totalQuantity = round(lastQuantity + parseFloat(quantity));
|
||||
p.dataset.quantity = quantity;
|
||||
p.dataset.totalQuantity = totalQuantity;
|
||||
|
||||
p.innerHTML = `<span>+${quantity}</span> (${totalQuantity})`;
|
||||
p.html(`<span>+${quantity}</span> (${totalQuantity})`);
|
||||
|
||||
lastQuantity = totalQuantity;
|
||||
});
|
||||
|
||||
const totalQuantityCustomizer = parent.querySelector(".totalQuantityCustomizer");
|
||||
totalQuantityCustomizer.value = lastQuantity;
|
||||
totalQuantityCustomizer.defaultValue = lastQuantity;
|
||||
if (computeTotal) {
|
||||
const totalQuantityCustomizer = parent.find(".totalQuantityCustomizer");
|
||||
totalQuantityCustomizer.val(lastQuantity);
|
||||
totalQuantityCustomizer.data({
|
||||
defaultvalue: lastQuantity
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function changeCalculations() {
|
||||
document.querySelectorAll(".calculation").forEach(e => {
|
||||
e.dataset.quantity = convertMlToUnit(e.dataset.quantity);
|
||||
e.dataset.totalQuantity = convertMlToUnit(e.dataset.quantity);
|
||||
const node = $(".calculation");
|
||||
const initialQuantity = node.data("quantity");
|
||||
|
||||
node.each(function () {
|
||||
node.data({
|
||||
quantity: convertMlToUnit(initialQuantity),
|
||||
totalQuantity: convertMlToUnit(initialQuantity)
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll(".mix").forEach(e => doCalculations(e));
|
||||
$(".mix").each(e => doCalculations(e));
|
||||
}
|
||||
|
||||
startHovering = () => document.querySelector(".imagesContainer").classList.add("hovering");
|
||||
endHovering = () => document.querySelector(".imagesContainer").classList.remove("hovering");
|
||||
startHovering = () => $(".imagesContainer").addClass("hovering");
|
||||
endHovering = () => $(".imagesContainer").removeClass("hovering");
|
||||
|
||||
/*]]>*/
|
||||
</script>
|
||||
<script th:include="fragments.html :: printStrings"></script>
|
||||
<script type="module">
|
||||
import * as bpac from "/js/bpac.js";
|
||||
/*<![CDATA[*/
|
||||
|
||||
const dataFolder = "/lbx";
|
||||
const labelPath = dataFolder + "/Couleur.lbx";
|
||||
console.log(labelPath);
|
||||
import {PtouchPrinter} from "/js/ptouchPrint.js";
|
||||
|
||||
const recipeCode = "[[${recipe.recipeCode}]]";
|
||||
const banner = "[[${recipe.company.companyName}]]";
|
||||
const baseMaterial = "[[${recipe.getBase().materialCode}]]";
|
||||
const description = "[[${recipe.recipeDescription}]]";
|
||||
|
||||
async function print(mix) {
|
||||
if (!document.querySelector(".bpac-extension-installed")) {
|
||||
console.log("No extension");
|
||||
async function printMix(printButton) {
|
||||
const mixContainer = $(printButton).parents(".mixContainer");
|
||||
const allBases = $(mixContainer).find(".materialRow[data-materialtypename='[[${T(dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType).BASE_MATERIAL_TYPE_NAME}]]']");
|
||||
console.log(allBases.length + " bases trouvées");
|
||||
if (allBases.length <= 0) {
|
||||
showMessage(errorMsg, noBaseError);
|
||||
return;
|
||||
}
|
||||
const baseName = allBases.eq(0).find(".materialCodeColumn").text();
|
||||
|
||||
try {
|
||||
const objDoc = bpac.IDocument;
|
||||
await objDoc.Open("http://localhost:9090/lbx/Couleur.lbx");
|
||||
|
||||
const objColor = await objDoc.GetObject("color");
|
||||
objColor.Text = recipeCode;
|
||||
|
||||
const objBanner = await objDoc.GetObject("banner");
|
||||
objBanner.Text = banner;
|
||||
|
||||
const objBarcode = await objDoc.GetObject("color_barcode");
|
||||
objBarcode.Text = recipeCode;
|
||||
|
||||
objDoc.StartPrint("", 0);
|
||||
objDoc.PrintOut(1, 0);
|
||||
objDoc.EndPrint();
|
||||
|
||||
objDoc.Close();
|
||||
// } else {
|
||||
// console.log("Can't open document");
|
||||
// }
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
const printer = new PtouchPrinter({
|
||||
template: "Couleur",
|
||||
lines: [
|
||||
{name: "color", value: recipeCode},
|
||||
{name: "banner", value: banner},
|
||||
{name: "base", value: baseName},
|
||||
{name: "description", value: description}
|
||||
]
|
||||
});
|
||||
const errorCode = await printer.print();
|
||||
switch (errorCode) {
|
||||
case -1:
|
||||
showMessage(errorMsg, bpacNotInstalledError);
|
||||
break;
|
||||
case 99:
|
||||
showMessage(errorMsg, printError);
|
||||
break;
|
||||
case 1:
|
||||
showMessage(successMsg, printingMessage);
|
||||
break;
|
||||
default:
|
||||
showMessage(errorMsg, generalErrorText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
//print();
|
||||
$('.printButton').on({
|
||||
click: function () {
|
||||
const node = $(this);
|
||||
showConfirm(confirmPrintMessage, false, () => {
|
||||
setTimeout(() => {
|
||||
printMix(node);
|
||||
}, 300);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/*]]>*/
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<body>
|
||||
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div id="researchBoxContainer">
|
||||
|
@ -22,10 +22,8 @@
|
|||
<form th:action="@{/recipe/remover/}" class="requireAuth-remover" method="POST">
|
||||
<div class="companyTab" th:if="${!recipeMap.empty}" th:each="company : ${recipeMap.keySet()}"
|
||||
th:data-companyID="${company.companyID}">
|
||||
<h2 class="companyTabTitle" th:data-companyName="${company.companyName}"
|
||||
th:text="${company.companyName}"></h2>
|
||||
|
||||
<table style="display:none" th:id="'recipes_' + ${company.companyName}" class="recipesList"
|
||||
<h2 class="companyTabTitle" th:text="${company.companyName}"></h2>
|
||||
<table style="display:none" th:id="'recipes_' + ${company.companyID}" class="recipesList"
|
||||
th:if="${!recipeMap.get(company).empty}">
|
||||
<tr>
|
||||
<th th:text="#{recipe.color}"></th>
|
||||
|
@ -55,5 +53,6 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script th:src="@{|${baseUrl}/js/recipeResearch.js|}"></script>
|
||||
<script th:src="@{|${baseUrl}/js/recipeList.js|}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:include="fragments.html :: head(#{recipe.touchup.title}, 'form')"></th:block>
|
||||
|
||||
<style>
|
||||
.content button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body th:with='error = ${recipeMap.empty ? "__#{recipe.error.anyFound}__" : error}'>
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header(true)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
||||
<h1 th:text="#{recipe.touchup.title}"></h1>
|
||||
|
||||
<form action="#" method="post">
|
||||
<div class="content">
|
||||
<div class="formWrap">
|
||||
<div class="formColumn">
|
||||
<label for="jobNumber" th:text="#{keyword.jobNumber} + ':'"></label>
|
||||
<button type="button" class="printPtouch" th:text="#{keyword.ptouch}"></button>
|
||||
</div>
|
||||
<div class="formColumn">
|
||||
<input type="text" name="jobNumber" id="jobNumber" required/>
|
||||
<button type="button" class="printPdf" th:text="#{keyword.pdf}"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
$(() => {
|
||||
const form = $("form");
|
||||
|
||||
$(".printPtouch").on({
|
||||
click: function () {
|
||||
if (!$("#jobNumber").val()) return;
|
||||
|
||||
form.attr({
|
||||
action: "[[@{|${baseUrl}/touchup/ptouch|}]]"
|
||||
});
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
|
||||
$(".printPdf").on({
|
||||
click: function () {
|
||||
if (!$("#jobNumber").val()) return;
|
||||
|
||||
form.attr({
|
||||
action: "[[@{|${baseUrl}/touchup/pdf|}]]"
|
||||
});
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
/*]]>*/
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:include="fragments.html :: head(#{recipe.touchup.title}, null)"></th:block>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header(true)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
</section>
|
||||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
<script th:include="fragments.html :: printStrings"></script>
|
||||
<script type="module">
|
||||
/*<![CDATA[*/
|
||||
import {PtouchPrinter} from "/js/ptouchPrint.js";
|
||||
|
||||
const jobNumber = "[[${jobNumber}]]";
|
||||
|
||||
$(async () => {
|
||||
const printer = new PtouchPrinter({
|
||||
template: "Touchup",
|
||||
lines: [
|
||||
{name: "job", value: jobNumber}
|
||||
]
|
||||
});
|
||||
const errorCode = await printer.print();
|
||||
switch (errorCode) {
|
||||
case -1:
|
||||
showMessage(errorMsg, bpacNotInstalledError, false);
|
||||
break;
|
||||
case 99:
|
||||
showMessage(errorMsg, printError, false);
|
||||
break;
|
||||
case 1:
|
||||
showMessage(successMsg, printingMessage, false);
|
||||
break;
|
||||
default:
|
||||
showMessage(errorMsg, generalErrorText, false);
|
||||
break;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = referer;
|
||||
}, 3000);
|
||||
});
|
||||
/*]]>*/
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -14,7 +14,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<!-- Fragment de l'entête -->
|
||||
<header th:include="fragments.html :: header"></header>
|
||||
<header th:include="fragments.html :: header(false)"></header>
|
||||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
@ -34,8 +34,7 @@
|
|||
document.querySelector("#markdown").innerHTML = r.data;
|
||||
})
|
||||
.catch(e => {
|
||||
errorMsgBoxText.innerText = generalErrorText;
|
||||
showElement(errorMsgBox);
|
||||
showMessage(errorMsg, generalErrorText);
|
||||
console.log(e);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,16 +3,28 @@
|
|||
* Correction d'un bug qui empêchait la suppression des mélanges.
|
||||
* Correction d'un bug qui empêche les boutons supprimer de fonctionner.
|
||||
* Correction d'un bug qui permettait d'envoyer les formulaires demandant des mots de passe sans donner un mot de passe valide.
|
||||
* Correction d'une désynchronisation entre le nom des mélanges et leurs produits internes.
|
||||
* Amélioration du style du site.
|
||||
* Transition des modèles vers Lombok.
|
||||
* Correction d'une désynchronisation entre le nom des mélanges et leur produit interne.
|
||||
* Amélioration du style.
|
||||
* Amélioration de la fluidité de la navigation.
|
||||
* Transition complète des modèles vers Lombok.
|
||||
|
||||
### Ajouts
|
||||
* +++ Ajout du support pour l'imprimante P-touch.
|
||||
* Les produits dans l'inventaire sont maintenant ordonnés alphabétiquement.
|
||||
* Changement de l'ordre d'un mélange.
|
||||
* Ajout du support pour l'imprimante P-touch de Brother.
|
||||
* L'extension b-Pac doit être installée sur le navigateur des clients.
|
||||
* [Firefox](https://cre.fyloz.dev/bpac.xpi)
|
||||
* [Chrome](https://chrome.google.com/webstore/detail/brother-b-pac-extension/ilpghlfadkjifilabejhhijpfphfcfhb)
|
||||
* Le logiciel b-Pac doit être installé sur l'ordinateur des clients.
|
||||
* [Windows](https://download.brother.com/welcome/dlfp100614/bcciw32031.msi)
|
||||
* Ajout de la possibilité d'imprimer les mélanges avec P-Touch
|
||||
* Ajout de la possibilité d'imprimer les étiquettes de kit de retouche avec P-Touch
|
||||
* Ajout des boîtes de confirmation.
|
||||
* Ajout d'un type de produit aux mélanges.
|
||||
* Ajout du changement d'ordre des produits d'un mélange.
|
||||
* Les produits dans l'inventaire sont maintenant ordonnés alphabétiquement.
|
||||
|
||||
### Dépendances
|
||||
* Ajout de jQuery, début de la transition.
|
||||
* Migration vers Java 11
|
||||
|
||||
# v1.1.3
|
||||
### Corrections
|
||||
|
|
Loading…
Reference in New Issue