Преглед изворни кода

PlantillaService.java fully added

Drowsito пре 5 месеци
родитељ
комит
332fbb593d

+ 18 - 0
pom.xml

@@ -17,7 +17,20 @@
 	<properties>
 		<java.version>17</java.version>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<spring-cloud.version>2023.0.3</spring-cloud.version>
 	</properties>
+
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>org.springframework.cloud</groupId>
+				<artifactId>spring-cloud-dependencies</artifactId>
+				<version>${spring-cloud.version}</version>
+				<type>pom</type>
+				<scope>import</scope>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
 	
 	<dependencies>
 		<dependency>
@@ -134,6 +147,11 @@
 		    <artifactId>commons-io</artifactId>
 		    <version>2.16.1</version>
 		</dependency>
+
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-starter-openfeign</artifactId>
+		</dependency>
 		<!-- 
 		<dependency>
 		    <groupId>org.jacoco</groupId> 

+ 2 - 0
src/main/java/es/uv/saic/SaicApplication.java

@@ -2,10 +2,12 @@ package es.uv.saic;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.scheduling.annotation.EnableScheduling;
 
 @SpringBootApplication
 @EnableScheduling
+@EnableFeignClients
 public class SaicApplication {
 	
 	public static void main(String[] args) {

+ 60 - 0
src/main/java/es/uv/saic/dto/NomProcesOrganDTO.java

@@ -0,0 +1,60 @@
+package es.uv.saic.dto;
+
+public class NomProcesOrganDTO {
+    private String nomProces;
+    private String tlugar;
+    private Integer lugar;
+    private Integer centre;
+    private Integer titulacio;
+
+    public NomProcesOrganDTO() {
+    }
+
+    public NomProcesOrganDTO(String nomProces, String tlugar, Integer lugar, Integer centre, Integer titulacio) {
+        this.nomProces = nomProces;
+        this.tlugar = tlugar;
+        this.lugar = lugar;
+        this.centre = centre;
+        this.titulacio = titulacio;
+    }
+
+    public String getNomProces() {
+        return nomProces;
+    }
+
+    public void setNomProces(String nomProces) {
+        this.nomProces = nomProces;
+    }
+
+    public String getTlugar() {
+        return tlugar;
+    }
+
+    public void setTlugar(String tlugar) {
+        this.tlugar = tlugar;
+    }
+
+    public Integer getLugar() {
+        return lugar;
+    }
+
+    public void setLugar(Integer lugar) {
+        this.lugar = lugar;
+    }
+
+    public Integer getCentre() {
+        return centre;
+    }
+
+    public void setCentre(Integer centre) {
+        this.centre = centre;
+    }
+
+    public Integer getTitulacio() {
+        return titulacio;
+    }
+
+    public void setTitulacio(Integer titulacio) {
+        this.titulacio = titulacio;
+    }
+}

+ 41 - 0
src/main/java/es/uv/saic/feign/CoreClient.java

@@ -0,0 +1,41 @@
+package es.uv.saic.feign;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import es.uv.saic.domain.Indicador;
+import es.uv.saic.domain.InstanciaTasca;
+import es.uv.saic.domain.Organ;
+import es.uv.saic.dto.IndicadorEnquestaDTO;
+import es.uv.saic.dto.IndicadorEnquestaValorDTO;
+import es.uv.saic.dto.NomProcesOrganDTO;
+
+@FeignClient(value = "core-service", url = "${saic.url.core.domain}")
+public interface CoreClient {
+    //IndicadorController.java
+    @GetMapping("/getFromTitulacio/{idTitulacio}/{curs}")
+    List<Indicador> getFromTitulacion(@PathVariable("idTitulacio") Integer idTitulacio, @PathVariable("curs") Integer curs);
+
+    @PostMapping("/allInds2")
+    List<IndicadorEnquestaValorDTO> getAllInds2(@RequestBody IndicadorEnquestaDTO indicadorEnquestaDTO);
+
+    //TascaController.java
+    @GetMapping("/instanciatasca2/{id}")
+    InstanciaTasca findInstanciaTascaById2(@PathVariable("id") BigInteger id);
+
+    @GetMapping("/getReportFromNomProcesOrgan")
+    InstanciaTasca getReportFromNomProcesOrgan(@RequestBody NomProcesOrganDTO nomProcesOrganDTO);
+
+    //OrganController.java
+    @GetMapping("/getTitulacionsByCentreTambit/{centre}/{tambit}")
+    List<Organ> getTitulacionsByCentreTambit(@PathVariable("centre") Integer lugar, @PathVariable("tambit") String tambit);
+
+    @GetMapping("/findById/{tlugar}/{idTitulacio}")
+    Organ findOrganById(@PathVariable("tlugar") String tlugar,  @PathVariable("idTitulacio") Integer idTitulacio);
+}

+ 510 - 41
src/main/java/es/uv/saic/service/PlantillaService.java

@@ -2,15 +2,15 @@ package es.uv.saic.service;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.UncheckedIOException;
 import java.math.BigInteger;
-import java.net.HttpURLConnection;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
 import java.nio.file.Files;
+import java.text.DecimalFormat;
 import java.util.Base64;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Optional;
 import java.util.regex.Matcher;
@@ -19,30 +19,435 @@ import java.util.regex.Pattern;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
 import org.springframework.stereotype.Service;
+import org.springframework.util.FileCopyUtils;
 
 import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
+import es.uv.saic.domain.Indicador;
 import es.uv.saic.domain.InstanciaTasca;
+import es.uv.saic.domain.Organ;
+import es.uv.saic.domain.Plantilla;
 import es.uv.saic.domain.PlantillaComentario;
 import es.uv.saic.domain.PlantillaConversation;
-
+import es.uv.saic.domain.PlantillaRepository;
+import es.uv.saic.domain.Proces;
+import es.uv.saic.dto.IndicadorEnquestaDTO;
+import es.uv.saic.dto.IndicadorEnquestaValorDTO;
+import es.uv.saic.dto.NomProcesOrganDTO;
+import es.uv.saic.feign.CoreClient;
 
 @Service
 public class PlantillaService {
+
+	@Autowired
+	private PlantillaRepository r;
+	@Value("${saic.data.filePath}")
+	private String filePath;
 	@Value("${saic.data.tmpPath}")
 	private String tmpPath;
+	@Value("${saic.data.templates.fileNotFound}")
+	private String fileNotFound;
+	@Value("${saic.data.templates.filePath}")
+	private String templatePath;
 	@Value("${saic.data.templates.logoPath}")
 	private String logoPath;
+	@Autowired
+	private CoreClient core;
+	
+	private static final DecimalFormat df = new DecimalFormat("0.00");
+	
+	public List<Plantilla> findAll(){
+		return this.r.findAll();
+	}
+	
+	public Plantilla findByID(Integer id) {
+		return this.r.findByIdPlantilla(id);
+	}
+	
+	public Plantilla findByVersioCodiAmbit(Integer versio, String codi, String ambit) {
+		return this.r.findByVersioCodiAmbit(versio, codi, ambit);
+	}
+	
+	public void save(Plantilla p) {
+		this.r.save(p);
+		this.r.flush();
+	}
+	
+	public void delete(Plantilla p) {
+		this.r.delete(p);
+	}
+	
+	public boolean isUsed(Integer idPlantilla) {
+		List<Plantilla> l = this.r.findUsedByIdPlantilla(idPlantilla);
+		if(l.size() > 0) {
+			return true;
+		}
+		return false;
+	}
+	
+	public String addTemplateData(InstanciaTasca it, String template){
+		HashMap<String, String> context = new HashMap<String, String>();
+		HashMap<String, String> header = new HashMap<String, String>();
+		HashMap<String, String> img = new HashMap<String, String>();
+		 
+		Integer idTitulacio = it.getInstancia().getTitulacio();
+		Proces proces = it.getInstancia().getProces();
+		Integer idCentre = it.getInstancia().getCentre();
+		String ambit = "G";
+		String opcionsStr = it.getTasca().getOpcions().replaceAll("^\\.$", "");
+		String [] opcions = new String[0];
+		if(!opcionsStr.isEmpty()) {
+			opcions = opcionsStr.split(";");
+		}
+		if(it.getInstancia().getOrgan().getId().getTlugar().equals("C")) {
+			if(it.getInstancia().getTitulacio() == 2) {
+				ambit = "M";
+			}
+		}
+		
+		/** Add header information **/
+		addHeaderData(it.getInstancia().getOrgan().getOrgan(), it.getInstancia().getOrgan(), it.getInstancia().getProces().getCursAvaluat(), header, img);
+		
+		/** Iterate elements inside {[loop]} ... {[endloop]} **/
+		template = this.iterateLoopTag(template, idCentre, ambit, proces.getCursAvaluat(), context);
+		
+		/** Iterate elements with data-loop attribute **/
+		Document doc = Jsoup.parse(template);
+		doc = iterateLoopAttr(idCentre, proces.getCursAvaluat(), doc, context);
+		
+		/** Add template data (non iterated data)**/
+		getTemplateData(idTitulacio, idCentre, proces.getCursAvaluat(), context);	
+		this.replaceValues(doc, context, header, img);
+		
+		/** Replace sections if specified in options **/
+		this.replaceSection(opcions, it, doc);
+		
+		return doc.html();	
+	}
+	
+	public String addTemplateData(Integer idTitulacio, Integer idCentre, Integer curs, String template){
+		
+		HashMap<String, String> context = new HashMap<String, String>();
+		HashMap<String, String> header = new HashMap<String, String>();
+		HashMap<String, String> img = new HashMap<String, String>();
+		 
+		Organ centre = core.findOrganById("C", idCentre);
+		Organ titulacio = core.findOrganById("T", idTitulacio);
+		
+		/** Add header information **/
+		addHeaderData(centre, titulacio, curs, header, img);
+							
+		/** Iterate elements inside {[loop]} ... {[endloop]} **/
+		template = this.iterateLoopTag(template, idCentre, titulacio.getTambit(), curs, context);
+		
+		/** Iterate elements with data-loop attribute **/
+		Document doc = Jsoup.parse(template);
+		doc = iterateLoopAttr(idCentre, curs, doc, context);
+		
+		/** Add template data (non iterated data)**/
+		getTemplateData(idTitulacio, idCentre, curs, context);	
+		this.replaceValues(doc, context, header, img);
+		
+		return doc.html();	
+	}
+	
+	private void addHeaderData(Organ centre, Organ titulacio, Integer curs, HashMap<String, String> header, HashMap<String, String> img) {
+		header.put("centre", centre.getNomVal());
+		header.put("titulacio", titulacio.getNomVal());
+		header.put("curs", "CURSO "+Integer.toString(curs-1)+" - "+Integer.toString(curs));
+		header.put("curs_anterior", Integer.toString(curs-2)+" - "+Integer.toString(curs-1));
+		header.put("conv-ant1", "CONVOCATORIA "+Integer.toString(curs-1)+" - "+Integer.toString(curs));
+		header.put("conv-ant2", "CONVOCATORIA "+Integer.toString(curs-2)+" - "+Integer.toString(curs-1));
+		header.put("periode-ant1", Integer.toString(curs-6)+" - "+Integer.toString(curs-1));
+		header.put("periode-ant2", Integer.toString(curs-7)+" - "+Integer.toString(curs-2));
+		ClassPathResource fuv = new ClassPathResource("/static/logos/UV.png");
+		ClassPathResource fc = new ClassPathResource("/static/logos/C"+Integer.toString(centre.getId().getLugar())+".png");
+		String logouv_b64;
+		String logoc_b64;
+		try {
+			logouv_b64 = "data:image/png;base64, "+Base64.getEncoder().encodeToString(fuv.getInputStream().readAllBytes());
+		} catch (IOException e) {
+			logouv_b64 = "https://saic.uv.es/public/logos/UV.png";
+		}
+		try {
+			logoc_b64 = "data:image/png;base64, "+Base64.getEncoder().encodeToString(fc.getInputStream().readAllBytes());
+		} catch (IOException e) {
+			logoc_b64 = "https://saic.uv.es/public/logos/C"+Integer.toString(centre.getId().getLugar())+".png";
+		}
+		img.put("logo_centre", logoc_b64);
+		img.put("logo_uv", logouv_b64);
+	}
+	
+	private Document iterateLoopAttr(Integer idCentre, Integer curs, Document doc, HashMap<String, String> context) {
+		Elements loop_elements = doc.select("*[data-loop]");
+		for(Element e : loop_elements) {
+			String Tambit = e.attr("data-loop");
+			List<Organ> tits = core.getTitulacionsByCentreTambit(idCentre, Tambit);
+			for(Organ org : tits) {
+				context.clear();
+				Element e_copy = e.clone();
+				getTemplateData(org.getId().getLugar(), org.getOrgan().getId().getLugar(), curs, context);
+				context.put("titulacio_loop", org.getNomVal());
+				Elements ielements = e_copy.select("*:matchesWholeOwnText(\\{\\{([^\\}]*)\\}\\})");
+				for(Element ielem : ielements) {
+					String t = ielem.html().replace("{", "").replace("}", "");
+					String i = this.formatValue(context.get(t));
+					if(i != null) {
+						if(ielem.tagName().equals("td")) {
+							ielem.attr("class", "mceEditable");
+							ielem.attr("id", "ind_"+t);
+							ielem.html(i);
+						}
+						else {
+							ielem.html(i);
+						}
+					}
+					else {
+						if(ielem.tagName().equals("td")) {
+							ielem.attr("class", "mceEditable");
+							ielem.attr("id", "ind_"+t);
+							ielem.html("");
+						}
+						else {
+							ielem.html("");
+						}
+					}
+				}		
+				e.after(e_copy);
+			}
+			e.remove();
+		}
+		context.clear();
+		return doc;
+	}
+	
+	private String iterateLoopTag(String template, Integer idCentre, String Tambit, Integer curs, HashMap<String, String> context) {
+		Pattern pattern = Pattern.compile(".*<p>\\{\\[loop\\]\\}</p>([\\S\\s]*)<p>\\{\\[endloop\\]\\}</p>.*");
+		Matcher matcher = pattern.matcher(template);
+		String replaced = "";
+		
+		while(matcher.find()) {
+			String group = matcher.group(1);
+			Document tab = Jsoup.parse(group);
+			List<Organ> tits = core.getTitulacionsByCentreTambit(idCentre, Tambit);
+			for(Organ t : tits) {
+				Document tabcopy = Jsoup.parse(tab.html());
+				context.clear();
+				getTemplateData(t.getId().getLugar(), t.getOrgan().getId().getLugar(), curs, context);
+				context.put("titulacio_loop", t.getNomVal());
+				tabcopy = this.replaceValuesLoop(tabcopy, context);
+				replaced += tabcopy.html()+"<p></p>";
+			}
+			template = template.replace("<p>{[loop]}</p>"+group+"<p>{[endloop]}</p>", replaced);
+		}
+		context.clear();
+		return template;
+	}
+	
+	private Document replaceValues(Document doc, HashMap<String, String> context, HashMap<String, String> header, HashMap<String, String> img) {
+		Elements elems = doc.select("*:matchesWholeOwnText(\\{\\{([^\\}]*)\\}\\})");
+		for(Element e : elems) {
+			String t = e.html().replace("{", "").replace("}", "");
+			if(header.containsKey(t)) {
+				e.html(header.get(t));
+			}
+			else if(img.containsKey(t)) {
+				Element x = new Element("img");
+				x.attr("src", img.get(t));
+				x.attr("style", "display:block; margin-left:auto; margin-right:auto; width:100px; max-width:100px;");
+				x.attr("class", "logo");
+				e.html("");
+				e.appendChild(x);	
+			}
+			else {
+				String i = this.formatValue(context.get(t));
+				if(i != null) {
+					if(e.parent().tagName().equals("td")) {
+						e.parent().attr("class", "mceEditable");
+						e.parent().attr("id", "ind_"+t);
+						e.parent().attr("style", e.attr("style"));
+						e.parent().html(i);
+					}
+					else {
+						e.attr("class", "mceEditable");
+						e.attr("ind", "ind_"+t);
+						e.html(i);
+					}
+				}
+				else {
+					if(e.parent().tagName().equals("td")) {
+						e.parent().attr("class", "mceEditable");
+						e.parent().attr("id", "ind_"+t);
+						e.parent().attr("style", e.attr("style"));
+						e.parent().html("");
+					}
+					else {
+						e.attr("class", "mceEditable");
+						e.attr("ind", "ind_"+t);
+						e.html("");
+					}
+				}
+			}
+		}
+		return doc;
+	}
+	
+	private void getTemplateData(Integer idTitulacio, Integer idCentre, Integer curs, HashMap<String, String> context) {
+		
+		/*  Indicadores del data warehouse */
+		try {
+			List<Indicador> indicadores;
+			indicadores = core.getFromTitulacion(idTitulacio, curs);
+			for(Indicador i : indicadores) { 
+				context.put(i.getIndicador(), i.getValor());
+			}
+		} 
+		catch(Exception e) { }
+		
+		/*  Indicadores de encuestas y otros almacenados en BD  */
+		IndicadorEnquestaDTO indicadorEnquestaDTO = new IndicadorEnquestaDTO(idTitulacio, idCentre, curs);
+		List<IndicadorEnquestaValorDTO> enquestesT = core.getAllInds2(indicadorEnquestaDTO);
 
-	@Value("${saic.url.core.domain}")
-	private String uriCore;
-
-
+				
+		for(IndicadorEnquestaValorDTO i : enquestesT) {
+			String indicador = i.getAmbit().toLowerCase().equals("t") ? (i.getEnquesta().toLowerCase()+"_"+i.getIndicador().toLowerCase()) : (i.getEnquesta().toLowerCase()+"_"+i.getIndicador().toLowerCase()+"_"+i.getAmbit().toLowerCase());
+			if(i.getNum() == null) {
+				indicador = i.getTipus().toLowerCase().equals("avg") ? indicador : (indicador += "_"+i.getTipus().toLowerCase());		
+				indicador = i.getCursd() == null ? indicador : (indicador += "_"+i.getCursd().toLowerCase());
+				context.put(indicador, formatValue(i.getValor()));
+			}
+			else {
+				context.put(indicador, i.getNum());
+			}
+			
+		}
+	}
+	
+	private Document replaceValuesLoop(Document doc, HashMap<String, String> context) {
+		Elements elems = doc.select("*:matchesWholeOwnText(\\{\\{([^\\}]*)\\}\\})");
+		for(Element e : elems) {
+			String t = e.html().replace("{", "").replace("}", "");
+			String i = this.formatValue(context.get(t));
+			if(i != null) {
+				if(e.parent().tagName().equals("td")) {
+					e.parent().attr("class", "mceEditable");
+					e.parent().attr("id", "ind_"+t);
+					e.parent().attr("style", e.attr("style"));
+					e.parent().html(i);
+				}
+				else {
+					e.attr("class", "mceEditable");
+					e.attr("ind", "ind_"+t);
+					e.html(i);
+				}
+			}
+			else {
+				if(e.parent().tagName().equals("td")) {
+					e.parent().attr("class", "mceEditable");
+					e.parent().attr("id", "ind_"+t);
+					e.parent().attr("style", e.attr("style"));
+					e.parent().html("");
+				}
+				else {
+					e.attr("class", "mceEditable");
+					e.attr("ind", "ind_"+t);
+					e.html("");
+				}
+			}
+		}
+		return doc;
+	}
+	
+	private String formatValue(String v) {	
+		if(v == null) return ""; 
+		if(v.isEmpty() | v.isBlank()) return "";
+		if(v.equals("NP")) return "NP";
+				
+		try {
+		    double d = Double.parseDouble(v);
+		    return (Integer.toString((int)d).equals(v) ? v : df.format(d).replace(",", "."));
+		} 
+		catch (NumberFormatException e) { }
+		
+		if(v.endsWith("%") && v.startsWith(".")) {
+			return "0"+v;
+		}
+		
+		return v;
+		
+	}
+	
+	public String savePDF(String content, BigInteger idtascai) throws IOException, InterruptedException {
+		content = content.replace("<p><!-- pagebreak --></p>", "<p class=\"pagebreak\"><!-- pagebreak --></p>");
+		Document d = Jsoup.parse(content, "UTF8");
+		d.head().append("<style>"
+				+ "@page{size: 297mm 210mm;} "
+				+ "html{ max-width:297mm; max-height:210mm; margin:0; padding:0; transform:scale(0.925); transform-origin:left top; } "
+				+ "table { padding:2px !important; }"
+				+ "th, td { padding:2px !important; }"
+				+ ".pagebreak { page-break-before:always; }"
+				+ "</style>");
+		List<Element> trs = d.getElementsByTag("tr");
+		for(Element t : trs) {
+			if(t.hasAttr("height")) {
+				t.removeAttr("height");
+			}
+			if(t.hasAttr("style")) {
+				String style = t.attr("style");
+				style = style.replaceAll("height:[ \\d.pxcmin]{1,};", "");
+				t.attr("style", style);
+			}
+		}
+		List<Element> tds = d.getElementsByTag("td");
+		for(Element t : tds) {
+			if(t.hasAttr("height")) {
+				t.removeAttr("height");
+			}
+			if(t.hasAttr("style")) {
+				String style = t.attr("style");
+				style = style.replaceAll("height:[ \\d.pxcmin]{1,};", "");
+				t.attr("style", style);
+			}
+		}
+		List<Element> ignore = d.getElementsByClass("pdfignore");
+		for(Element e: ignore) {
+			e.remove();
+		}
+		
+		InstanciaTasca ita = core.findInstanciaTascaById2(idtascai);
+		if(ita.getTasca().getRol().getNomRol().equals("u_uq")) {
+			d.body().append(this.parseComments(d.html()));
+		}
+		
+		String basecommand = "google-chrome --headless --disable-gpu --no-pdf-header-footer --run-all-compositor-stages-before-draw --no-sandbox";
+		String dst = idtascai.toString()+".pdf";		
+		File src = File.createTempFile("saic-pdfexport-", ".tmp.html", new File(tmpPath));
+		src.deleteOnExit();
+		PrintWriter out = new PrintWriter(src.getAbsolutePath());
+		out.println(d.html());
+		out.flush();
+		out.close();
+		System.out.println(basecommand+" --print-to-pdf='"+filePath+dst+"' "+src.getAbsolutePath());
+		
+		ProcessBuilder pb = new ProcessBuilder("bash", "-c", basecommand+" --print-to-pdf='"+filePath+dst+"' "+src.getAbsolutePath());
+		Process pr = pb.start();
+		pr.waitFor();
+		src.delete();
+		
+		return dst;
+	}
+	
 	public byte[] toPDF(String content, Optional<BigInteger> idtascai) throws IOException, InterruptedException {
 		content = content.replace("<p><!-- pagebreak --></p>", "<p class=\"pagebreak\"><!-- pagebreak --></p>");
 		Document d = Jsoup.parse(content, "UTF8");
@@ -81,7 +486,7 @@ public class PlantillaService {
 		}
 		
 		if(idtascai.isPresent()) {
-			InstanciaTasca ita = findById(idtascai.get());
+			InstanciaTasca ita = core.findInstanciaTascaById2(idtascai.get());
 			if(ita.getTasca().getRol().getNomRol().equals("u_uq")) {
 				d.body().append(this.parseComments(d.html()));
 			}
@@ -110,36 +515,6 @@ public class PlantillaService {
 		return bytes;
 	}
 	
-	private InstanciaTasca findById(BigInteger id) {
-		URI uriObj = URI.create(uriCore + "/instanciatasca/" + id);
-		ObjectMapper mapper = new ObjectMapper();
-		InstanciaTasca instanciaTasca = null;
-
-		try {
-			HttpClient httpClient = HttpClient.newHttpClient();
-
-			HttpRequest request = HttpRequest.newBuilder()
-					.uri(uriObj)
-					.header("Content-Type", "application/json")
-					.POST(HttpRequest.BodyPublishers.noBody())
-					.build();
-
-			HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
-
-			if (response.statusCode() == HttpURLConnection.HTTP_OK) {
-				instanciaTasca = mapper.readValue(response.body(), InstanciaTasca.class);
-			} else {
-				System.err.println("Error al obtener instancia: " + response.statusCode() + " -> " + response.body());
-			}
-
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-
-		return instanciaTasca;
-	}
-
-
 	private String parseComments(String content) throws JsonParseException, JsonMappingException, IOException {
 		// <!--tinycomments\|2\.1\|data:application\/json;base64,([A-Za-z0-9]*)=-->
 		Pattern pattern = Pattern.compile("\\<\\!\\-\\-tinycomments\\|2\\.1\\|data\\:application\\/json\\;base64\\,([A-Za-z0-9\\/\\+\\\\]*)\\=*\\-\\-\\>");
@@ -188,5 +563,99 @@ public class PlantillaService {
 		return "";
 	}
 	
+	public Document replaceSection(String[] opcions, InstanciaTasca it, Document doc) {
+		if(opcions.length > 0) {
+			NomProcesOrganDTO nomProcesOrganDTO = new NomProcesOrganDTO(opcions[0], 
+																		it.getInstancia().getOrgan().getId().getTlugar(), 
+																		it.getInstancia().getOrgan().getId().getLugar(), 
+																		it.getInstancia().getCentre(), 
+																		it.getInstancia().getTitulacio());
+			InstanciaTasca itOld = core.getReportFromNomProcesOrgan(nomProcesOrganDTO);
+			try {
+				Document doc2 = Jsoup.parse(itOld.getText());
+				Elements target = null;
+				Elements source = null;
+				if(opcions.length == 2) {
+					target = this.extractTemplateAnchor(doc2, true, opcions[1]);
+					source = this.extractTemplateAnchor(doc, false, opcions[1]);
+				}
+				else {
+					target = this.extractTemplateAnchor(doc2, true, opcions[1], opcions[2]);
+					source = this.extractTemplateAnchor(doc, false, opcions[1], opcions[2]);
+				}
+				
+				if(target == null || source == null) {
+					return doc;
+				}
+				Element e = source.get(0);
+				e.before(this.clear(target.outerHtml()));
+				source.remove();
+			}
+			catch(NullPointerException e){
+				System.out.println("No previous version found for "+it.getIdInstanciaTasca().toString());
+			}
+			
+		}
+		return doc;
+	}
+	
+	public Elements extractTemplateAnchor(Document doc, Boolean target, String... args) {
+		// <a id="pam"></a>		
+		
+		/* Hardcoded to fix anchor positions in existing templates */
+		try{
+			String anchor_ini = args[0];
+			Element eFirst = doc.select("p:has(a#"+anchor_ini+")").first();
+			Elements elems = eFirst.nextElementSiblings();
+			Elements table = elems.select("table:not(.pdfignore)");
+			return table;
+		}
+		catch(Exception e){
+			return null;
+		}
+		
+		/* Use this code in future */
+		/* 
+		if(args.length == 2){
+			String anchor_end = args[1];
+			Element eLast = doc.select("p:has(a#"+anchor_end+")").first();
+			boolean remove = false;
+			for(Iterator<Element> iter = elems.iterator(); iter.hasNext();){
+				Element x = iter.next();
+				if(remove){
+					iter.remove();
+				}
+				if(x.id().equals(anchor_end) || x.html().contains(anchor_end)){
+					remove = true;
+				}
+			}
+		}
+		*/
+		
+	}
+
+	public String clear(String html){
+		return html.replaceAll("data-mce-style=\"[ ,;:.\\d\\w\\(\\)\\#\\%-]{1,}\"", "")
+				   .replaceAll("font-family:[ \\d\\w-,]{1,};", "")
+				   .replaceAll("font-size:[ \\d\\w,\\.]{1,};", "")
+				   .replaceAll("\\<\\!\\-\\-tinycomments\\|2\\.1\\|data\\:application\\/json\\;base64\\,[A-Za-z0-9\\/\\+\\\\]*\\=*\\-\\-\\>", "")
+				   .replaceAll("data\\-mce\\-annotation\\-uid\\=\"mce\\-conversation\\_[a-zA-Z0-9]+\"", "")
+				   .replaceAll("data\\-mce\\-annotation\\=\"tinycomments\"", "")
+				   .replaceAll("class=\"mce-annotation\"", "");
+	}
+		
+	public static String asString(Resource resource) {
+        try (Reader reader = new InputStreamReader(resource.getInputStream(), "UTF-8")) {
+            return FileCopyUtils.copyToString(reader);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
 	
+	public static String readFileToString(String path) {
+	    ResourceLoader resourceLoader = new DefaultResourceLoader();
+	    Resource resource = resourceLoader.getResource(path);
+	    return asString(resource);
+	}
+		
 }

+ 18 - 0
src/main/java/es/uv/saic/web/PlantillaController.java

@@ -1,12 +1,17 @@
 package es.uv.saic.web;
 
+import java.math.BigInteger;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.RestController;
 
+import es.uv.saic.domain.InstanciaTasca;
+import es.uv.saic.domain.Plantilla;
 import es.uv.saic.dto.PdfDTO;
 import es.uv.saic.service.PlantillaService;
 
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 
@@ -27,4 +32,17 @@ public class PlantillaController {
         }
     }
     
+    // @PostMapping("/plantilla/{id}")
+    // public ResponseEntity<?> findByID(@PathVariable BigInteger idPlantilla) {
+    //     try {
+    //         InstanciaTasca plantilla = ps.findById(idPlantilla);
+            
+    //     } catch (Exception e) {
+    //         // TODO: handle exception
+    //     }
+        
+    //     return entity;
+    // }
+    
+    
 }