# v1.1.3
### Corrections * Correction de fautes de syntaxe. * Correction d'un bug qui empêchait d'utiliser une recette. ### Ajouts * Traduction complète de l'application. * Amélioration des recherches. * Ajout d'une confirmation avant l'utilisation d'un mélange ou d'une recette. * Le nom des mélanges peut maintenant être modifié. * Le bouton retour envoie maintenant vers la dernière page visitée.
This commit is contained in:
parent
f21cfd94c1
commit
6fb6a4829c
2
pom.xml
2
pom.xml
|
@ -10,7 +10,7 @@
|
|||
</parent>
|
||||
<groupId>dev.fyloz.trial.colorrecipesexplorer</groupId>
|
||||
<artifactId>ColorRecipesExplorer</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<version>1.1.3</version>
|
||||
<name>Color Recipes Explorer</name>
|
||||
|
||||
<properties>
|
||||
|
|
|
@ -23,6 +23,7 @@ public abstract class ResponseBuilder<T extends ResponseBuilder, R> {
|
|||
|
||||
// Ajoute l'URL de base à toutes les réponses
|
||||
attributes.put("baseUrl", ControllerUtils.getCurrentBaseUrl());
|
||||
attributes.put("referer", ControllerUtils.getLatestUrl());
|
||||
}
|
||||
|
||||
protected abstract void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters);
|
||||
|
|
|
@ -104,11 +104,8 @@ public class Material extends BeanModel implements Serializable {
|
|||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Material material = (Material) o;
|
||||
return Float.compare(material.inventoryQuantity, inventoryQuantity) == 0 &&
|
||||
isMixType == material.isMixType &&
|
||||
Objects.equals(materialID, material.materialID) &&
|
||||
Objects.equals(materialCode, material.materialCode) &&
|
||||
Objects.equals(materialType, material.materialType);
|
||||
return Objects.equals(materialID, material.materialID) &&
|
||||
Objects.equals(materialCode, material.materialCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -101,8 +101,7 @@ public class MaterialType extends BeanModel implements Serializable {
|
|||
MaterialType that = (MaterialType) o;
|
||||
return Objects.equals(materialTypeID, that.materialTypeID) &&
|
||||
Objects.equals(materialTypeName, that.materialTypeName) &&
|
||||
Objects.equals(prefix, that.prefix) &&
|
||||
Objects.equals(usePercentages, that.usePercentages);
|
||||
Objects.equals(prefix, that.prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,7 +6,6 @@ import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
|
|||
import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -22,7 +21,7 @@ public class InventoryService {
|
|||
public String checkQuantities(Mix mix, Map<Material, Float> quantities) {
|
||||
for (Material material : mix.getMixQuantities().stream().map(MixQuantity::getMaterial).collect(Collectors.toList())) {
|
||||
if (!material.isMixType()) {
|
||||
float quantity = quantities.get(material);
|
||||
Float quantity = quantities.get(material);
|
||||
|
||||
if (quantity > material.getInventoryQuantity()) {
|
||||
return String.format("%s-%s", mix.getMixID(), material.getMaterialID());
|
||||
|
@ -34,12 +33,11 @@ public class InventoryService {
|
|||
}
|
||||
|
||||
public boolean useMix(Mix mix, Map<Material, Float> quantities) {
|
||||
List<Material> materials = mix.getMixQuantities().stream().map(MixQuantity::getMaterial).collect(Collectors.toList());
|
||||
for (Material material : materials) {
|
||||
if (!material.isMixType()) {
|
||||
float quantity = quantities.get(material);
|
||||
for (Map.Entry<Material, Float> entry : quantities.entrySet()) {
|
||||
Material material = entry.getKey();
|
||||
|
||||
material.setInventoryQuantity(material.getInventoryQuantity() - quantity);
|
||||
if (!material.isMixType()) {
|
||||
material.setInventoryQuantity(material.getInventoryQuantity() - entry.getValue());
|
||||
if (!materialService.update(material).isPresent()) return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -37,6 +38,12 @@ public class MaterialService extends GenericService<Material, MaterialDao> {
|
|||
return dao.findAllByMaterialType(materialType);
|
||||
}
|
||||
|
||||
public List<Material> getAllOrdered() {
|
||||
return getAll().stream()
|
||||
.sorted(Comparator.comparing(Material::getMaterialCode))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si un produit est lié à un ou plusieurs mélanges.
|
||||
*
|
||||
|
|
|
@ -86,6 +86,8 @@ public class MixService extends GenericService<Mix, MixDao> {
|
|||
materials.add(found.get());
|
||||
}
|
||||
|
||||
mix.getMixType().setTypeName(formDto.getMixTypeName());
|
||||
|
||||
List<MixQuantity> mixQuantities = createMixQuantities(mix, materials, formDto.getQuantities());
|
||||
|
||||
// Supprime les anciens MixQuantity pour éviter les doublons et les entrées inutiles dans la base de données
|
||||
|
|
|
@ -5,6 +5,8 @@ import org.springframework.web.context.request.RequestContextHolder;
|
|||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
public class ControllerUtils {
|
||||
|
||||
|
@ -12,15 +14,44 @@ public class ControllerUtils {
|
|||
return String.format("redirect:/%s", viewName);
|
||||
}
|
||||
|
||||
public static URI getUri(HttpServletRequest request) throws URISyntaxException {
|
||||
return new URI(request.getRequestURL().toString());
|
||||
}
|
||||
|
||||
public static String getUrlFromURI(URI uri) {
|
||||
String scheme = uri.getScheme();
|
||||
String host = uri.getHost();
|
||||
int port = uri.getPort();
|
||||
|
||||
return String.format("%s://%s:%s", scheme, host, port);
|
||||
}
|
||||
|
||||
public static String getCurrentBaseUrl() {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
if (attributes == null) return "";
|
||||
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
|
||||
String port = ":" + (ColorRecipesExplorerApplication.USE_PORT ? request.getServerPort() : "");
|
||||
return String.format("%s://%s%s%s", request.getScheme(), request.getServerName(), port, request.getContextPath());
|
||||
}
|
||||
|
||||
public static String getLatestUrl() {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes == null) return "";
|
||||
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
|
||||
try {
|
||||
String currentDomainName = getUrlFromURI(getUri(request));
|
||||
String referer = request.getHeader("referer");
|
||||
if (referer == null) return currentDomainName;
|
||||
|
||||
String refererURL = getUrlFromURI(new URI(referer));
|
||||
|
||||
return refererURL.equals(currentDomainName) ? referer : currentDomainName;
|
||||
} catch (URISyntaxException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,27 +2,6 @@ package dev.fyloz.trial.colorrecipesexplorer.web;
|
|||
|
||||
public class StringBank {
|
||||
|
||||
public static final String SUCCESS_USING_MATERIALS = "Les quantités de chaque produits utilisés ont été déduites de l'inventaire";
|
||||
public static final String SUCCESS_SAVING_RECIPE_INFORMATIONS = "Les informations de la recette ont été sauvegardées";
|
||||
public static final String ERROR_SAVING = "Une erreur est survenue lors de l'enregistrement";
|
||||
public static final String ERROR_SAVING_IMAGE = "Une erreur est survenue lors de l'enregistrement de l'image";
|
||||
public static final String ERROR_SAVING_SIMDUT = "Une erreur est survenue lors de l'enregistrement du fichier SIMDUT";
|
||||
public static final String AUTH_ERROR = "Votre mot de passe n'est pas valide";
|
||||
|
||||
// À formatter
|
||||
public static final String RECIPE_NOT_FOUND = "Aucune recette ayant l'identifiant '%s' n'a été trouvée";
|
||||
public static final String MIX_NOT_FOUND = "Aucun mélange ayant l'identifiant '%s' n'a été trouvé";
|
||||
public static final String MATERIAL_NOT_FOUND = "Aucun produit ayant l'identifiant '%s' n'a été trouvé";
|
||||
public static final String MATERIAL_ALREADY_EXIST = "Il y a déjà un produit s'appellant '%s'";
|
||||
public static final String MATERIAL_TYPE_ALREADY_EXIST = "Il y a déjà un type de produit s'appellant '%s'";
|
||||
public static final String COMPANY_NOT_FOUND = "Aucune bannière ayant l'identifiant '%s' n'a été trouvée";
|
||||
public static final String COMPANY_ALREADY_EXIST = "Il y a déjà une bannière s'appellant '%s'";
|
||||
public static final String MATERIAL_LINKED = "Le produit '%s' est lié à une ou plusieurs recettes, veuillez les supprimer d'abord";
|
||||
public static final String COMPANY_LINKED = "La bannière '%s' est liée à une ou plusieurs recettes, veuillez les supprimer d'abord";
|
||||
public static final String MIX_NOT_ASSOCIATED_WITH_RECIPE = "Le mélange ayant l'identifiant '%s' n'est pas associé à la recette ayant l'identifiant '%s'";
|
||||
public static final String NOT_ENOUGH_MATERIAL = "Il n'y a pas assez de '%s' en inventaire pour cette recette";
|
||||
public static final String MIX_TYPE_ALREADY_USED = "Cette recette contient déjà un mélange du type '%s'";
|
||||
|
||||
// Types de réponse
|
||||
public static final String RESPONSE_ERROR = "error";
|
||||
public static final String RESPONSE_SUCCESS = "success";
|
||||
|
|
|
@ -44,7 +44,7 @@ public class InventoryController {
|
|||
public ModelAndView getInventory(ModelAndView model) {
|
||||
return new ModelResponseBuilder(model)
|
||||
.withView(INVENTORY)
|
||||
.addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
|
||||
.addResponseData(ResponseDataType.MATERIALS, materialService.getAllOrdered().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
|
||||
.addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
|
||||
.build();
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public class InventoryController {
|
|||
@PostMapping(value = USE_INVENTORY, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
@Transactional
|
||||
// TODO traduit les méthodes JSON
|
||||
// TODO vers DTO
|
||||
public Map<String, Object> consumeMaterials(@RequestBody Map<String, Object> form) {
|
||||
JSONResponseBuilder responseBuilder = new JSONResponseBuilder();
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ mix.location=Location
|
|||
material.code=Code
|
||||
material.inventoryQuantity=Inventory quantity
|
||||
material.type=Material type
|
||||
material.SIMDUTFile=SIMDUT File
|
||||
material.simdutFile=SIMDUT File
|
||||
units.milliliters=Milliliters
|
||||
units.liters=Liters
|
||||
units.gallons=Gallons
|
||||
|
@ -94,3 +94,9 @@ 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
|
||||
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?
|
||||
|
|
|
@ -27,7 +27,7 @@ mix.location=Position
|
|||
material.code=Code
|
||||
material.inventoryQuantity=Quantité en inventaire
|
||||
material.type=Type de produit
|
||||
material.SIMDUTFile=Fichier SIMDUT
|
||||
material.simdutFile=Fichier SIMDUT
|
||||
units.milliliters=Millilitres
|
||||
units.liters=Litres
|
||||
units.gallons=Gallons
|
||||
|
@ -94,4 +94,10 @@ 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é
|
||||
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?
|
||||
|
||||
|
|
|
@ -119,6 +119,8 @@ textarea {
|
|||
border-style: solid;
|
||||
border-color: #7a7a7a;
|
||||
border-width: 1px;
|
||||
margin-left: 20px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
|
@ -201,12 +203,14 @@ nav a:hover, .dropdown:hover .dropbtn {
|
|||
}
|
||||
|
||||
#researchBoxContainer {
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#researchBox {
|
||||
margin-top: 10px;
|
||||
margin-right: 50px;
|
||||
margin-left: -200px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.errorBox {
|
||||
|
|
|
@ -21,7 +21,7 @@ const successMsgBoxText = successMsgBox.querySelector("p");
|
|||
.catch(err => {
|
||||
if (err.response.status === 404) {
|
||||
e.parentElement.classList.add("nosimdut");
|
||||
e.parentElement.title = "Aucun fichier SIMDUT trouvé";
|
||||
e.parentElement.title = simdutNotFoundText;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -33,9 +33,9 @@ const successMsgBoxText = successMsgBox.querySelector("p");
|
|||
|
||||
window.addEventListener("load", () => {
|
||||
|
||||
document.querySelectorAll(".returnIndex").forEach((e) => {
|
||||
document.querySelectorAll(".returnButton").forEach((e) => {
|
||||
e.addEventListener("click", () => {
|
||||
document.location.href = "/";
|
||||
document.location.href = referer;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -84,11 +84,10 @@ window.addEventListener("load", () => {
|
|||
});
|
||||
});
|
||||
|
||||
window.addEventListener("change", e => {
|
||||
window.addEventListener("keyup", e => {
|
||||
if (e.target) {
|
||||
if (e.target.classList.contains("toSave")) {
|
||||
// TODO traductions
|
||||
warningMsgBoxText.innerText = "Des modifications ne sont pas été sauvegardées";
|
||||
warningMsgBoxText.innerText = changesNotSavedText;
|
||||
showElement(warningMsgBox);
|
||||
}
|
||||
}
|
||||
|
@ -102,13 +101,13 @@ window.addEventListener("load", () => {
|
|||
});
|
||||
|
||||
function askDatabaseExport() {
|
||||
return confirm("Voulez-vous vraiment exporter toutes les couleurs? Cela peut prendre un certain temps et ralentir l'application pendant un certain temps.");
|
||||
return confirm(exportAllWarningText);
|
||||
}
|
||||
|
||||
function checkPassword(form, callback) {
|
||||
hideElement(errorMsgBox);
|
||||
|
||||
const password = prompt("Quel est votre mot de passe?");
|
||||
const password = prompt(askPasswordText);
|
||||
|
||||
let data = {};
|
||||
data.password = password;
|
||||
|
@ -120,13 +119,13 @@ function checkPassword(form, callback) {
|
|||
if (callback != null) callback();
|
||||
return true;
|
||||
} else {
|
||||
errorMsgBoxText.innerText = "Votre mot de passe n'est pas valide";
|
||||
errorMsgBoxText.innerText = invalidPasswordText;
|
||||
showElement(errorMsgBox);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
errorMsgBoxText.innerText = "Une erreur est survenue lors de l'envoie des informations vers le serveur.";
|
||||
errorMsgBoxText.innerText = generalErrorText;
|
||||
showElement(errorMsgBox);
|
||||
console.log(e);
|
||||
return false;
|
||||
|
@ -185,3 +184,7 @@ function round(x) {
|
|||
function percentageOf(percentage, number) {
|
||||
return (percentage / 100) * number;
|
||||
}
|
||||
|
||||
function searchIn(searchString, str) {
|
||||
return str.toUpperCase().indexOf(searchString.toUpperCase()) > -1;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ window.addEventListener("load", () => {
|
|||
init();
|
||||
})
|
||||
.catch(e => {
|
||||
errorMsgBoxText.innerText = "Une erreur est survenue lors de la récupération des produits";
|
||||
errorMsgBoxText.innerText = generalErrorText;
|
||||
showElement(errorMsgBox);
|
||||
console.log(e);
|
||||
});
|
||||
|
@ -149,12 +149,10 @@ function searchMaterial(input) {
|
|||
let filter, filterUpper, materials;
|
||||
|
||||
filter = input.value;
|
||||
filterUpper = filter.toUpperCase();
|
||||
materials = input.parentElement.querySelectorAll(".materialList p");
|
||||
|
||||
materials.forEach(e => {
|
||||
if (e.innerText.toUpperCase().indexOf(filterUpper) > -1 ||
|
||||
e.dataset.materialtype.toUpperCase().indexOf(filterUpper) > -1) e.style.display = "";
|
||||
if (searchIn(filter, e.textContent) || searchIn(filter, e.dataset.materialType)) e.style.display = "";
|
||||
else e.style.display = "none";
|
||||
});
|
||||
|
||||
|
|
|
@ -13,12 +13,11 @@
|
|||
<section>
|
||||
<h1 th:text="#{company.add.title}"></h1>
|
||||
<p th:text="#{company.success.created(${companyName})}"></p>
|
||||
<button class="returnIndex" th:text="#{keyword.back}"></button>
|
||||
<button class="returnButton" th:text="#{keyword.back}"></button>
|
||||
</section>
|
||||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -23,14 +23,7 @@
|
|||
th:text="#{company.form.companyName} + ':'"></label></b></td>
|
||||
<td><input type="text" th:field="*{companyName}" required /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button class="returnIndex" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="submit" th:text="#{keyword.save}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -39,6 +32,5 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -59,6 +59,5 @@
|
|||
<footer th:include="fragments.html :: footer('/company/remover', true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, false)"></footer>
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
(() => {
|
||||
|
@ -26,4 +26,4 @@
|
|||
/*]]>*/
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -104,6 +104,30 @@
|
|||
<a th:unless="${link == null}" th:href="@{${link + '?lang=__${#locale.toString() == 'en' ? 'fr' : 'en'}__'}}"
|
||||
th:text="#{footer.lang}"></a>
|
||||
</th:block>
|
||||
|
||||
<script src="/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 referer = "[[${referer}]]";
|
||||
/*]]>*/
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div th:fragment="mainTableButtons">
|
||||
<td class="centerTd">
|
||||
<button class="returnButton" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td class="centerTd">
|
||||
<button type="submit" th:text="#{keyword.save}"></button>
|
||||
</td>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -23,6 +23,5 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<!-- Corps de la page -->
|
||||
<section>
|
||||
<div id="researchBoxContainer">
|
||||
<input id="researchBox" type="text" th:placeholder="#{keyword.search}" onchange="performSearch(this.value)"/>
|
||||
<input id="researchBox" type="text" th:placeholder="#{keyword.search}" onkeyup="performSearch(this.value)"/>
|
||||
</div>
|
||||
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
@ -85,10 +85,8 @@
|
|||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
<script th:inline="javascript">
|
||||
/*<![CDATA[*/
|
||||
|
||||
(() => {
|
||||
document.querySelectorAll(".gotoRecipe").forEach(e => {
|
||||
e.addEventListener("click", () => {
|
||||
|
@ -103,62 +101,73 @@
|
|||
|
||||
if (approbationDate === null) {
|
||||
e.classList.add("unapproved");
|
||||
e.title = /*[[#{recipe.warning.notApproved}]]*/ "Cette recette n'est pas approuvée";
|
||||
e.title = [[#{recipe.warning.notApproved}]];
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
const companyRows = document.querySelectorAll(".companyTab");
|
||||
|
||||
function performSearch(searchString) {
|
||||
if (!searchString || !searchString.replace(/\s/g, '').length) {
|
||||
document.querySelectorAll(".companyTab").forEach(c => {
|
||||
c.classList.add("researchResult");
|
||||
let found = false;
|
||||
let emptySearch = false;
|
||||
|
||||
c.querySelectorAll(".recipeRow").forEach(r => {
|
||||
r.classList.add("researchResult");
|
||||
});
|
||||
});
|
||||
|
||||
closeTabs();
|
||||
return;
|
||||
const recipesContainer = document.querySelector(".recipesContainer:not(.researchEnabled)");
|
||||
if (recipesContainer !== undefined && recipesContainer !== null) {
|
||||
recipesContainer.classList.add("researchEnabled");
|
||||
}
|
||||
|
||||
hideElement(errorMsgBox);
|
||||
axios.get(`/search?searchString=${searchString}`)
|
||||
.then(r => {
|
||||
const result = r.data.result;
|
||||
document.querySelectorAll(".researchResult").forEach(t => {
|
||||
t.classList.remove("researchResult");
|
||||
});
|
||||
|
||||
const recipesContainer = document.querySelector(".recipesContainer:not(.researchEnabled)");
|
||||
if (recipesContainer !== undefined && recipesContainer !== null) {
|
||||
recipesContainer.classList.add("researchEnabled");
|
||||
companyRows.forEach(c => {
|
||||
const recipeRows = c.querySelectorAll(".recipeRow");
|
||||
|
||||
hideElement(warningMsgBox);
|
||||
|
||||
if (!searchString || !searchString.replace(/\s/g, '').length) {
|
||||
c.classList.add("researchResult");
|
||||
|
||||
recipeRows.forEach(r => {
|
||||
r.classList.add("researchResult");
|
||||
});
|
||||
|
||||
found = true;
|
||||
emptySearch = true;
|
||||
} else if (searchIn(searchString, c.querySelector("h1").dataset.companyname)) {
|
||||
c.classList.add("researchResult");
|
||||
recipeRows.forEach(r => r.classList.add("researchResult"));
|
||||
found = true;
|
||||
} else {
|
||||
recipeRows.forEach(r => {
|
||||
r.querySelectorAll(".descriptionCell").forEach(d => {
|
||||
if (searchIn(searchString, d.textContent)) {
|
||||
r.classList.add("researchResult");
|
||||
c.classList.add("researchResult");
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll(".researchResult").forEach(t => {
|
||||
t.classList.remove("researchResult");
|
||||
});
|
||||
if (!found) {
|
||||
warningMsgBoxText.innerText = researchNotFound;
|
||||
showElement(warningMsgBox);
|
||||
}
|
||||
|
||||
Object.keys(result).forEach(c => {
|
||||
const companyTab = document.querySelector(`.companyTab[data-companyID=\"${c}\"]`);
|
||||
companyTab.classList.add("researchResult");
|
||||
companyTab.querySelector(".recipesList").style.display = "table";
|
||||
|
||||
for (let r = 0; r < result[c].length; r++) {
|
||||
const recipeRow = companyTab.querySelector(`.recipeRow[data-recipeID=\"${result[c][r]}\"]`);
|
||||
recipeRow.classList.add("researchResult");
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
|
||||
errorMsgBoxText.innerText = /*[[#{error.serverError}]]*/ "Erreur";
|
||||
showElement(errorMsgBox);
|
||||
});
|
||||
if (emptySearch) closeTabs();
|
||||
else openTabs();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function closeTabs() {
|
||||
document.querySelectorAll(".recipesList").forEach(l => {
|
||||
l.style.display = "none";
|
||||
});
|
||||
document.querySelectorAll(".recipesList").forEach(l => l.style.display = "none");
|
||||
}
|
||||
|
||||
function openTabs() {
|
||||
document.querySelectorAll(".recipesList").forEach(l => l.style.display = "");
|
||||
}
|
||||
|
||||
/*]]>*/
|
||||
|
|
|
@ -55,10 +55,11 @@
|
|||
th:if="${materialType.materialTypeName.equalsIgnoreCase('aucun')}">
|
||||
<input id="anyTypeId" th:value="${materialType.materialTypeID}" type="hidden"/>
|
||||
</th:block>
|
||||
|
||||
<h1 th:text="#{menu.inventory}"></h1>
|
||||
|
||||
<div id="researchBoxContainer">
|
||||
<input type="text" id="researchBox" th:placeholder="#{keyword.search}" onchange="performSearch(this.value)"/>
|
||||
<input type="text" id="researchBox" th:placeholder="#{keyword.search}" onkeyup="performSearch(this.value)"/>
|
||||
</div>
|
||||
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
|
@ -190,45 +191,46 @@
|
|||
});
|
||||
}
|
||||
|
||||
function performSearch(searchString) {
|
||||
if (!searchString || !searchString.replace(/\s/g, '').length) {
|
||||
document.querySelectorAll(".materialRow").forEach(m => {
|
||||
m.classList.add("researchResult");
|
||||
});
|
||||
const materialRows = document.querySelectorAll(".materialRow");
|
||||
|
||||
return;
|
||||
function performSearch(searchString) {
|
||||
hideElement(warningMsgBox);
|
||||
|
||||
let found = false;
|
||||
|
||||
const recipesContainer = document.querySelector(".materialsContainer:not(.researchEnabled)");
|
||||
if (recipesContainer !== undefined && recipesContainer !== null) {
|
||||
recipesContainer.classList.add("researchEnabled");
|
||||
}
|
||||
|
||||
hideElement(errorMsgBox);
|
||||
axios.get(`inventory/search?searchString=${searchString}`)
|
||||
.then(r => {
|
||||
const result = r.data.result;
|
||||
document.querySelectorAll(".researchResult").forEach(t => {
|
||||
t.classList.remove("researchResult");
|
||||
});
|
||||
|
||||
const recipesContainer = document.querySelector(".materialsContainer:not(.researchEnabled)");
|
||||
if (recipesContainer !== undefined && recipesContainer !== null) {
|
||||
recipesContainer.classList.add("researchEnabled");
|
||||
materialRows.forEach(row => {
|
||||
if (!searchString || !searchString.replace(/\s/g, '').length) {
|
||||
row.classList.add("researchResult");
|
||||
found = true;
|
||||
} else {
|
||||
|
||||
const materialCode = row.querySelector(".materialCode").textContent;
|
||||
const materialType = row.querySelector(".materialType").textContent;
|
||||
|
||||
if (searchIn(searchString, materialCode) || searchIn(searchString, materialType)) {
|
||||
row.classList.add("researchResult");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll(".researchResult").forEach(t => {
|
||||
t.classList.remove("researchResult");
|
||||
});
|
||||
|
||||
result.forEach(m => {
|
||||
console.log(`.materialRow[data-materialID=\"${m}\"]`);
|
||||
const materialRow = document.querySelector(`.materialRow[data-materialID=\"${m}\"]`);
|
||||
materialRow.classList.add("researchResult");
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
|
||||
errorMsgBoxText.innerText = /*[[#{error.serverError}]]*/ "Erreur";
|
||||
showElement(errorMsgBox);
|
||||
});
|
||||
if (!found) {
|
||||
warningMsgBoxText.innerText = researchNotFound;
|
||||
showElement(warningMsgBox);
|
||||
}
|
||||
}
|
||||
|
||||
/*]]>*/
|
||||
</script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -14,12 +14,11 @@
|
|||
<p th:text="#{material.success.created(${materialCode})}"></p>
|
||||
<h1 th:text="#{material.add.title}"></h1>
|
||||
|
||||
<button class="returnIndex" th:text="#{keyword.back}"></button>
|
||||
<button class="returnButton" th:text="#{keyword.back}"></button>
|
||||
</section>
|
||||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -59,18 +59,11 @@
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b><label for="simdut" th:text="#{material.SIMDUTFile} + ':'"></label></b></td>
|
||||
<td><b><label for="simdut" th:text="#{material.simdutFile} + ':'"></label></b></td>
|
||||
<td><input id="simdut" name="simdut" type="file"/></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<button class="returnIndex" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="submit" th:text="#{keyword.save}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -78,7 +71,7 @@
|
|||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
<script>
|
||||
function switchUnits(unitSelect) {
|
||||
const quantityElem = document.querySelector("#quantity");
|
||||
|
|
|
@ -56,20 +56,13 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="showSIMDUT" type="button" th:text="#{material.SIMDUTFile}">Fichier SIMDUT</button>
|
||||
<button id="showSIMDUT" type="button" th:text="#{material.simdutFile}">Fichier SIMDUT</button>
|
||||
</td>
|
||||
<td>
|
||||
<button id="editSIMDUT" type="button" th:text="#{keyword.edit}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button class="returnIndex" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="submit" th:text="#{keyword.save}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -77,7 +70,7 @@
|
|||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
<script>
|
||||
(() => {
|
||||
const materialID = document.querySelector("#materialID").value;
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
(() => {
|
||||
|
|
|
@ -52,6 +52,5 @@
|
|||
<footer th:include="fragments.html :: footer('/material/remover', true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -30,6 +30,6 @@
|
|||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -34,14 +34,7 @@
|
|||
th:text="#{materialType.usePercents} + ':'"></label></b></td>
|
||||
<td><input type="checkbox" th:field="*{usePercentages}"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button class="returnIndex" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="submit" th:text="#{keyword.save}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -50,6 +43,5 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -40,14 +40,7 @@
|
|||
th:text="#{materialType.usePercents} + ':'"></label></b></td>
|
||||
<td><input type="checkbox" th:field="*{usePercentages}"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button class="returnIndex" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="submit" th:text="#{keyword.save}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -55,6 +48,6 @@
|
|||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
(() => {
|
||||
|
|
|
@ -49,6 +49,6 @@
|
|||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer('/materialType/remover', true)"></footer>
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
<section>
|
||||
<div th:include="fragments.html :: messages"></div>
|
||||
<h1 th:text="#{mix.add.subtitle(${recipe.recipeCode})}"></h1>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="form">
|
||||
<form th:action="@{/mix/creator}" class="requireAuth" method="POST">
|
||||
|
@ -45,14 +47,7 @@
|
|||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button class="returnIndex" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="submit" th:text="#{keyword.save}" th:disabled="${blockButton}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -60,7 +55,7 @@
|
|||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
<script src="/js/mix.js"></script>
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
|
|
|
@ -27,9 +27,15 @@
|
|||
<form th:action="@{/mix/editor}" class="requireAuth" method="POST">
|
||||
<!-- Information nécessaire à la création des mélanges -->
|
||||
<input name="mixID" th:value="${mix.mixID}" type="hidden"/>
|
||||
<input name="mixTypeName" th:value="${mix.mixType.typeName}" type="hidden"/>
|
||||
<input name="recipeID" id="recipeID" th:value="${mix.recipe.recipeID}" type="hidden"/>
|
||||
|
||||
<label for="mixType" th:text="#{mix.mixType} + ':'"></label>
|
||||
<input type="text"
|
||||
id="mixType"
|
||||
name="mixTypeName"
|
||||
th:value="${mix.mixType.typeName}"
|
||||
required/>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
|
@ -44,14 +50,7 @@
|
|||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button class="returnIndex" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="submit" th:text="#{keyword.save}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -60,7 +59,6 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
<script src="/js/mix.js"></script>
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
|
|
|
@ -20,6 +20,5 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -44,16 +44,9 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><b><label th:for="${#ids.next('remark')}" th:text="#{recipe.remark}"></label></b></td>
|
||||
<td><textarea cols="30" form="recipe-form" rows="10" th:field="*{remark}"></textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button class="returnIndex" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="submit" th:text="#{keyword.save}" th:disabled="${blockButton}"></button>
|
||||
</td>
|
||||
<td><textarea cols="20" form="recipe-form" rows="2" th:field="*{remark}"></textarea></td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -62,6 +55,5 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -107,13 +107,18 @@
|
|||
<tr>
|
||||
<td><b><label th:for="${#ids.next('remark')}" th:text="#{recipe.remark} + ':'"></label></b>
|
||||
</td>
|
||||
<td><textarea cols="30" rows="10" th:field="*{remark}"></textarea>
|
||||
<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">
|
||||
|
@ -149,13 +154,6 @@
|
|||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
</th:block>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button id="newMix" type="button" th:text="#{recipe.edit.addMix}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -206,14 +204,7 @@
|
|||
th:text="#{recipe.edit.addImage}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="mainTableEndButtons">
|
||||
<td class="centerTd">
|
||||
<button class="returnIndex" type="button" th:text="#{keyword.back}"></button>
|
||||
</td>
|
||||
<td class="centerTd">
|
||||
<button type="submit" th:text="#{keyword.save}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: mainTableButtons"></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -222,7 +213,6 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
<script>
|
||||
(() => {
|
||||
document.querySelectorAll(".editRecipe").forEach((e) => {
|
||||
|
|
|
@ -14,10 +14,6 @@
|
|||
border-collapse: separate;
|
||||
}
|
||||
|
||||
textarea {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
section {
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -176,8 +172,8 @@
|
|||
<tr>
|
||||
<td><b th:text="#{recipe.notice} + ':'"></b></td>
|
||||
<td>
|
||||
<textarea class="toSave" cols="30" id="note" name="note" rows="10"
|
||||
th:text="${recipe.note}"></textarea>
|
||||
<textarea class="toSave" cols="20" id="note" name="note" rows="2"
|
||||
th:text="${recipe.note}" style="margin: 0"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -190,103 +186,106 @@
|
|||
</table>
|
||||
</td>
|
||||
<td>
|
||||
<table style="border-spacing: 20px;">
|
||||
<th:block th:each="mix : ${mixes}">
|
||||
<tr>
|
||||
<td><b th:text="${mix.mixType.typeName} + ':'"></b><br/><br/>
|
||||
<label
|
||||
th:for="'location' + ${mix.mixID}"
|
||||
th:text="' ' + #{mix.location} + ': '">
|
||||
<!-- Formulaires sans autocomplétion pour éviter que le navigateur cache les valeurs lors d'un rafraichissement et invalide les données dans data-quantityML -->
|
||||
<form action="#" autocomplete="off">
|
||||
<table style="border-spacing: 20px;">
|
||||
<th:block th:each="mix : ${mixes}">
|
||||
<tr>
|
||||
<td><b th:text="${mix.mixType.typeName} + ':'"></b><br/><br/>
|
||||
<label
|
||||
th:for="'location' + ${mix.mixID}"
|
||||
th:text="' ' + #{mix.location} + ': '">
|
||||
|
||||
</label>
|
||||
<input
|
||||
class="recipeLocation toSave"
|
||||
th:id="'location' + ${mix.mixID}"
|
||||
name="location"
|
||||
th:data-mixID="${mix.mixID}"
|
||||
th:value="${mix.location}"
|
||||
placeholder="N/A"
|
||||
type="text"/>
|
||||
</td>
|
||||
<td>
|
||||
<table class="mixes" th:id="'mix-' + ${mix.mixID}">
|
||||
<tr>
|
||||
<th th:text="#{keyword.material}"></th>
|
||||
<th th:text="#{keyword.type}"></th>
|
||||
<th style="min-width: auto !important;">
|
||||
<button
|
||||
type="button"
|
||||
data-hidden="true"
|
||||
onclick="hideQuantities(this)">
|
||||
->
|
||||
</button>
|
||||
</th>
|
||||
<!-- Changement des quantités -->
|
||||
<th></th>
|
||||
<th th:text="#{keyword.units}"></th>
|
||||
<th th:text="#{keyword.calculation}"></th>
|
||||
</tr>
|
||||
<!-- Produits -->
|
||||
<tr th:each="mixQuantity : ${mix.mixQuantities}"
|
||||
th:with="material = ${mixQuantity.material}"
|
||||
th:id="'material-' + ${material.materialID}">
|
||||
<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 class="inventoryQuantityColumn">
|
||||
<p class="inventoryQuantity"
|
||||
th:data-quantityML="${mixQuantity.quantity}"
|
||||
th:text="${mixQuantity.quantity}"></p>
|
||||
</td>
|
||||
<td class="quantityColumn">
|
||||
<input th:if="${!material.isMixType()}" class="quantityCustomizer"
|
||||
min="0.001" step="0.001"
|
||||
th:data-materialID="${material.materialID}"
|
||||
th:data-mixID="${mix.mixID}"
|
||||
</label>
|
||||
<input
|
||||
class="recipeLocation toSave"
|
||||
th:id="'location' + ${mix.mixID}"
|
||||
name="location"
|
||||
th:data-mixID="${mix.mixID}"
|
||||
th:value="${mix.location}"
|
||||
placeholder="N/A"
|
||||
type="text"/>
|
||||
</td>
|
||||
<td>
|
||||
<table class="mixes" th:id="'mix-' + ${mix.mixID}">
|
||||
<tr>
|
||||
<th th:text="#{keyword.material}"></th>
|
||||
<th th:text="#{keyword.type}"></th>
|
||||
<th style="min-width: auto !important;">
|
||||
<button
|
||||
type="button"
|
||||
data-hidden="true"
|
||||
onclick="hideQuantities(this)">
|
||||
->
|
||||
</button>
|
||||
</th>
|
||||
<!-- Changement des quantités -->
|
||||
<th></th>
|
||||
<th th:text="#{keyword.units}"></th>
|
||||
<th th:text="#{keyword.calculation}"></th>
|
||||
</tr>
|
||||
<!-- Produits -->
|
||||
<tr th:each="mixQuantity : ${mix.mixQuantities}"
|
||||
th:with="material = ${mixQuantity.material}"
|
||||
th:id="'material-' + ${material.materialID}">
|
||||
<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 class="inventoryQuantityColumn">
|
||||
<p class="inventoryQuantity"
|
||||
th:data-quantityML="${mixQuantity.quantity}"
|
||||
th:data-usePercentages="${material.materialType.usePercentages}"
|
||||
th:value="${mixQuantity.quantity}"
|
||||
th:disabled="${material.materialType.usePercentages}"
|
||||
type="number"/></td>
|
||||
<td class="unitsColumn">
|
||||
<p class="inventoryQuantityUnits"
|
||||
th:unless="${material.materialType.usePercentages}">mL</p>
|
||||
<p th:if="${material.materialType.usePercentages}">%</p>
|
||||
</td>
|
||||
<td class="calculationColumn">
|
||||
<p class="calculation" th:data-mixID="${mix.mixID}"
|
||||
th:data-materialID="${material.materialID}"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="totalQuantityLabel" colspan="3">
|
||||
Total:
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="totalQuantityCustomizer"
|
||||
type="number"
|
||||
min="0.001"
|
||||
step="0.001"
|
||||
th:data-mixID="${mix.mixID}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<p class="inventoryQuantityUnits">mL</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td>
|
||||
<button class="useMixSubmit" type="button" th:text="#{keyword.use}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
</th:block>
|
||||
</table>
|
||||
th:text="${mixQuantity.quantity}"></p>
|
||||
</td>
|
||||
<td class="quantityColumn">
|
||||
<input th:if="${!material.isMixType()}" class="quantityCustomizer"
|
||||
min="0.001" step="0.001"
|
||||
th:data-materialID="${material.materialID}"
|
||||
th:data-mixID="${mix.mixID}"
|
||||
th:data-quantityML="${mixQuantity.quantity}"
|
||||
th:data-usePercentages="${material.materialType.usePercentages}"
|
||||
th:value="${mixQuantity.quantity}"
|
||||
th:disabled="${material.materialType.usePercentages}"
|
||||
type="number"/></td>
|
||||
<td class="unitsColumn">
|
||||
<p class="inventoryQuantityUnits"
|
||||
th:unless="${material.materialType.usePercentages}">mL</p>
|
||||
<p th:if="${material.materialType.usePercentages}">%</p>
|
||||
</td>
|
||||
<td class="calculationColumn">
|
||||
<p class="calculation" th:data-mixID="${mix.mixID}"
|
||||
th:data-materialID="${material.materialID}"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="totalQuantityLabel" colspan="3">
|
||||
Total:
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="totalQuantityCustomizer"
|
||||
type="number"
|
||||
min="0.001"
|
||||
step="0.001"
|
||||
th:data-mixID="${mix.mixID}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<p class="inventoryQuantityUnits">mL</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td>
|
||||
<button class="useMixSubmit" type="button" th:text="#{keyword.use}"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:include="fragments.html :: separator"></tr>
|
||||
</th:block>
|
||||
</table>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -315,12 +314,8 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
<script>
|
||||
// TODO Le navigateur ne reset pas nécessairement les quantités dans les inputs lors d'un rafraichissement de la page, donc les données dans data-quantityml deviennent fausses.
|
||||
|
||||
/*<![CDATA[*/
|
||||
|
||||
const quantityKeyword = "[[#{keyword.quantity}]]";
|
||||
|
||||
(() => {
|
||||
|
@ -338,7 +333,6 @@
|
|||
|
||||
e.addEventListener("change", () => {
|
||||
// Les 3 parentElement récupèrent la table dans laquelle le produit se trouve
|
||||
// TODO simplifier ?
|
||||
const parentTable = e.parentElement.parentElement.parentElement;
|
||||
const firstInput = parentTable.querySelectorAll(".quantityCustomizer")[0];
|
||||
if (e.dataset.usepercentages === "false") {
|
||||
|
@ -410,6 +404,9 @@
|
|||
});
|
||||
|
||||
document.querySelector("#useSubmit").addEventListener("click", () => {
|
||||
const shouldContinue = confirm("[[#{inventory.askUseRecipe}]]".replace("'", "'"));
|
||||
if (!shouldContinue) return;
|
||||
|
||||
let formData = {};
|
||||
|
||||
document.querySelectorAll(".quantityCustomizer").forEach(e => {
|
||||
|
@ -430,6 +427,9 @@
|
|||
|
||||
document.querySelectorAll(".useMixSubmit").forEach(e => {
|
||||
e.addEventListener("click", () => {
|
||||
const shouldContinue = confirm("[[#{inventory.askUseMix}]]".replace("'", "'"));
|
||||
if (!shouldContinue) return;
|
||||
|
||||
let formData = {};
|
||||
|
||||
e.parentElement.parentElement.querySelectorAll(".quantityCustomizer").forEach(elem => {
|
||||
|
|
|
@ -82,6 +82,5 @@
|
|||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<!-- Fragment du pied de page -->
|
||||
<footer th:include="fragments.html :: footer(null, true)"></footer>
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
window.addEventListener("load", e => {
|
||||
|
@ -34,7 +34,7 @@
|
|||
document.querySelector("#markdown").innerHTML = r.data;
|
||||
})
|
||||
.catch(e => {
|
||||
errorMsgBoxText.innerText = "Une erreur est survenue lors de la récupération des mises à jour";
|
||||
errorMsgBoxText.innerText = generalErrorText;
|
||||
showElement(errorMsgBox);
|
||||
console.log(e);
|
||||
});
|
||||
|
|
|
@ -1,5 +1,22 @@
|
|||
# v1.1.3
|
||||
# v1.2.0 (Imprimante P-touch)
|
||||
### Corrections
|
||||
* +++ Correction d'un bug qui empêchait la suppression des mélanges.
|
||||
|
||||
### Ajouts
|
||||
* +++ Ajout du support pour l'imprimante P-touch
|
||||
* Les produits dans l'inventaire sont maintenant ordonnés alphabétiquement.
|
||||
|
||||
# v1.1.3
|
||||
### Corrections
|
||||
* Correction de fautes de syntaxe.
|
||||
* Correction d'un bug qui empêchait d'utiliser une recette.
|
||||
|
||||
### Ajouts
|
||||
* Traduction complète de l'application.
|
||||
* Amélioration des recherches.
|
||||
* Ajout d'une confirmation avant l'utilisation d'un mélange ou d'une recette.
|
||||
* Le nom des mélanges peut maintenant être modifié.
|
||||
* Le bouton retour envoie maintenant vers la dernière page visitée.
|
||||
|
||||
# v1.1.2
|
||||
### Corrections
|
||||
|
|
Loading…
Reference in New Issue