diff --git a/installtools/.classpath b/installtools/.classpath
index 73accf64d4..388b55cd82 100644
--- a/installtools/.classpath
+++ b/installtools/.classpath
@@ -1,5 +1,6 @@
+
diff --git a/owlcms-docker/.classpath b/owlcms-docker/.classpath
index 59a22644cf..867db10d1e 100644
--- a/owlcms-docker/.classpath
+++ b/owlcms-docker/.classpath
@@ -36,22 +36,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/owlcms-windows/.classpath b/owlcms-windows/.classpath
index 977bb34842..a012d978d7 100644
--- a/owlcms-windows/.classpath
+++ b/owlcms-windows/.classpath
@@ -36,22 +36,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/owlcms/pom.xml b/owlcms/pom.xml
index 4dfd523404..67f439bb3c 100644
--- a/owlcms/pom.xml
+++ b/owlcms/pom.xml
@@ -194,11 +194,26 @@
commons-io
2.14.0
+
+ commons-fileupload
+ commons-fileupload
+ 1.5
+
+
+ org.apache.commons
+ commons-compress
+ 1.21
+
org.apache.commons
commons-text
1.10.0
+
+ org.apache.commons
+ commons-compress
+ 1.26.0
+
diff --git a/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialReader.java b/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialReader.java
index 64dce3a4b6..079fec62fc 100644
--- a/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialReader.java
+++ b/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialReader.java
@@ -25,6 +25,7 @@ public class TechnicalOfficialReader {
private static final String FEDERATION_ID = "FederationId";
public static List importFromXLS(InputStream is) {
+ logger.warn("importFromXLS");
List officials = new ArrayList<>();
try {
@@ -41,9 +42,14 @@ public static List importFromXLS(InputStream is) {
Row row = sheet.getRow(i);
if (row == null) continue;
+ logger.warn("row[{}] {}", i, colIndices);
TechnicalOfficial official = readRow(row, colIndices);
+
if (official != null) {
- officials.add(official);
+ var mergedOff = TechnicalOfficialRepository.save(official);
+ officials.add(mergedOff);
+ } else {
+ break;
}
}
workbook.close();
@@ -74,15 +80,17 @@ private static int[] findColumnIndices(Row headerRow) {
private static TechnicalOfficial readRow(Row row, int[] colIndices) {
// Check required fields
- if (isEmptyCell(row.getCell(colIndices[0])) ||
- isEmptyCell(row.getCell(colIndices[1])) ||
- isEmptyCell(row.getCell(colIndices[2]))) {
+ if (isEmptyCell(row.getCell(colIndices[0]))) {
return null;
}
String lastName = getCellValueAsString(row.getCell(colIndices[0]));
String firstName = getCellValueAsString(row.getCell(colIndices[1]));
- TOLevel level = TOLevel.valueOf(getCellValueAsString(row.getCell(colIndices[2])));
+ TOLevel level = null;
+ try {
+ level = TOLevel.valueOf(getCellValueAsString(row.getCell(colIndices[2])));
+ } catch (IllegalArgumentException e) {
+ }
String iwfId = getCellValueAsString(row.getCell(colIndices[3]));
String federation = getCellValueAsString(row.getCell(colIndices[4]));
String federationId = getCellValueAsString(row.getCell(colIndices[5]));
diff --git a/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialRepository.java b/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialRepository.java
index 173de3809c..1d90486319 100644
--- a/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialRepository.java
+++ b/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialRepository.java
@@ -14,6 +14,7 @@
import org.slf4j.LoggerFactory;
import app.owlcms.data.jpa.JPAService;
+import app.owlcms.utils.LoggerUtils;
import ch.qos.logback.classic.Logger;
/**
@@ -33,6 +34,7 @@ public static void delete(TechnicalOfficial to) {
}
public static List findAll() {
+ logger.warn("====== findall {}",LoggerUtils.stackTrace());
return JPAService
.runInTransaction(em -> em.createQuery("select c from TechnicalOfficial c order by c.id", TechnicalOfficial.class)
.getResultList());
@@ -52,10 +54,11 @@ public static TechnicalOfficial getById(Long id, EntityManager em) {
TechnicalOfficial.class);
query.setParameter("id", id);
- return (TechnicalOfficial) query.getResultList().stream().findFirst().orElse(null);
+ return query.getResultList().stream().findFirst().orElse(null);
}
public static TechnicalOfficial save(TechnicalOfficial technicalOfficial) {
+ logger.warn("saving {}", technicalOfficial);
TechnicalOfficial nTechnicalOfficial = JPAService.runInTransaction(em -> em.merge(technicalOfficial));
return nTechnicalOfficial;
}
diff --git a/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialWriter.java b/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialWriter.java
new file mode 100644
index 0000000000..5282010af3
--- /dev/null
+++ b/owlcms/src/main/java/app/owlcms/data/technicalofficial/TechnicalOfficialWriter.java
@@ -0,0 +1,70 @@
+package app.owlcms.data.technicalofficial;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Logger;
+
+public class TechnicalOfficialWriter {
+ private final static Logger logger = (Logger) LoggerFactory.getLogger(TechnicalOfficialWriter.class);
+
+ public static InputStream write() {
+ try (Workbook workbook = new XSSFWorkbook()) {
+ Sheet sheet = workbook.createSheet("Technical Officials");
+
+ // Create header style
+ CellStyle headerStyle = workbook.createCellStyle();
+ Font headerFont = workbook.createFont();
+ headerFont.setBold(true);
+ headerStyle.setFont(headerFont);
+
+ // Create headers
+ Row headerRow = sheet.createRow(0);
+ String[] headers = {"LastName", "FirstName", "Level", "IWFId", "Federation", "FederationId"};
+ for (int i = 0; i < headers.length; i++) {
+ Cell cell = headerRow.createCell(i);
+ cell.setCellValue(headers[i]);
+ cell.setCellStyle(headerStyle);
+ }
+
+ // Add data rows
+ List officials = TechnicalOfficialRepository.findAll();
+ int rowNum = 1;
+ for (TechnicalOfficial official : officials) {
+ Row row = sheet.createRow(rowNum++);
+ row.createCell(0).setCellValue(official.getLastName() != null ? official.getLastName() : "");
+ row.createCell(1).setCellValue(official.getFirstName() != null ? official.getFirstName() : "");
+ row.createCell(2).setCellValue(official.getLevel() != null ? official.getLevel().toString() : "");
+ row.createCell(3).setCellValue(official.getIwfId() != null ? official.getIwfId() : "");
+ row.createCell(4).setCellValue(official.getFederation() != null ? official.getFederation() : "");
+ row.createCell(5).setCellValue(official.getFederationId() != null ? official.getFederationId() : "");
+ }
+
+ // Autosize columns
+ for (int i = 0; i < headers.length; i++) {
+ sheet.autoSizeColumn(i);
+ }
+
+ // Write to byte array
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ workbook.write(outputStream);
+ return new ByteArrayInputStream(outputStream.toByteArray());
+
+ } catch (IOException e) {
+ logger.error("Error writing technical officials: {}", e);
+ return null;
+ }
+ }
+}
diff --git a/owlcms/src/main/java/app/owlcms/nui/preparation/TechnicalOfficialContent.java b/owlcms/src/main/java/app/owlcms/nui/preparation/TechnicalOfficialContent.java
index 719875366d..19bbfee959 100644
--- a/owlcms/src/main/java/app/owlcms/nui/preparation/TechnicalOfficialContent.java
+++ b/owlcms/src/main/java/app/owlcms/nui/preparation/TechnicalOfficialContent.java
@@ -16,6 +16,7 @@
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Div;
+import com.vaadin.flow.component.html.Hr;
import com.vaadin.flow.component.html.NativeLabel;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
@@ -32,9 +33,10 @@
import app.owlcms.nui.crudui.OwlcmsCrudFormFactory;
import app.owlcms.nui.crudui.OwlcmsCrudGrid;
import app.owlcms.nui.crudui.OwlcmsGridLayout;
+import app.owlcms.nui.shared.DownloadButtonFactory;
import app.owlcms.nui.shared.OwlcmsContent;
import app.owlcms.nui.shared.OwlcmsLayout;
-import app.owlcms.spreadsheet.JXLSExportRecords;
+import app.owlcms.spreadsheet.JXLSExportTechnicalOfficials;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
@@ -54,14 +56,14 @@ public class TechnicalOfficialContent extends BaseContent implements CrudListene
private OwlcmsCrudFormFactory editingFormFactory;
private OwlcmsLayout routerLayout;
private FlexLayout topBar;
+ private GridCrud crud;
/**
* Instantiates the TechnicalOfficial crudGrid.
*/
public TechnicalOfficialContent() {
OwlcmsCrudFormFactory crudFormFactory = createFormFactory();
- GridCrud crud = createGrid(crudFormFactory);
- // defineFilters(crudGrid);
+ crud = createGrid(crudFormFactory);
fillHW(crud, this);
}
@@ -78,23 +80,30 @@ public TechnicalOfficial add(TechnicalOfficial domainObjectToAdd) {
public FlexLayout createMenuArea() {
this.topBar = new FlexLayout();
+ // Export current officials button using the age groups pattern
+ Div exportOfficials = DownloadButtonFactory.createDynamicXLSXDownloadButton(
+ "TechnicalOfficials",
+ Translator.translate("TechnicalOfficials.Export"),
+ new XLSXTechnicalOfficialsExport());
+ exportOfficials.getStyle().set("margin-left", "1em");
+
Button uploadCustom = new Button(Translator.translate("TechnicalOfficials.Upload"),
new Icon(VaadinIcon.UPLOAD_ALT),
buttonClickEvent -> {
- AgeGroupsFileUploadDialog ageGroupsFileUploadDialog = new AgeGroupsFileUploadDialog();
- ageGroupsFileUploadDialog.setCallback(() -> loadOfficials());
- ageGroupsFileUploadDialog.open();
+ TechnicalOfficialsUploadDialog dialog = new TechnicalOfficialsUploadDialog();
+ dialog.setCallback(() -> loadOfficials());
+ dialog.open();
});
- var recordsWriter1 = new JXLSExportRecords(UI.getCurrent(), true, true);
+ var toAssignmentsWriter = new JXLSExportTechnicalOfficials(UI.getCurrent(), true, true);
JXLSDownloader dd1 = new JXLSDownloader(
() -> {
- return recordsWriter1;
+ return toAssignmentsWriter;
},
- "/templates/records",
+ "/templates/toAssignments",
Competition::getComputedTechnicalOfficialsTemplateFileName,
Competition::setTechnicalOfficialsTemplateFileName,
- Translator.translate("Records.exportCurrentRecordsTitle"),
+ Translator.translate("TechnicalOfficials.ExportAssignementReports"),
Translator.translate("Download"));
Div allRecords1 = new Div();
Button downloadButton = dd1.createDownloadButton();
@@ -102,8 +111,12 @@ public FlexLayout createMenuArea() {
allRecords1.add(downloadButton);
FlexLayout buttons = new FlexLayout(
- new NativeLabel(Translator.translate("AgeGroups.Custom")),
- allRecords1, uploadCustom);
+ new NativeLabel(Translator.translate("TechnicalOfficials.ImportExport")),
+ exportOfficials,
+ uploadCustom,
+ hr(),
+ new NativeLabel(Translator.translate("TechnicalOfficials.AssignmentReports")),
+ allRecords1);
buttons.getStyle().set("flex-wrap", "wrap");
buttons.getStyle().set("gap", "1ex");
buttons.getStyle().set("margin-left", "5em");
@@ -117,11 +130,20 @@ public FlexLayout createMenuArea() {
return this.topBar;
}
- private Object loadOfficials() {
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Unimplemented method 'loadOfficials'");
+ private Hr hr() {
+ Hr hr = new Hr();
+ hr.setWidthFull();
+ hr.getStyle().set("margin", "0");
+ hr.getStyle().set("padding", "0");
+ return hr;
}
+ private Object loadOfficials() {
+ logger.warn("refreshing");
+ crud.refreshGrid();
+ return null;
+ }
+
@Override
public void delete(TechnicalOfficial domainObjectToDelete) {
this.editingFormFactory.delete(domainObjectToDelete);
diff --git a/owlcms/src/main/java/app/owlcms/nui/preparation/TechnicalOfficialsUploadDialog.java b/owlcms/src/main/java/app/owlcms/nui/preparation/TechnicalOfficialsUploadDialog.java
new file mode 100644
index 0000000000..e2a041327c
--- /dev/null
+++ b/owlcms/src/main/java/app/owlcms/nui/preparation/TechnicalOfficialsUploadDialog.java
@@ -0,0 +1,48 @@
+package app.owlcms.nui.preparation;
+
+import java.io.InputStream;
+
+import org.slf4j.LoggerFactory;
+
+import com.vaadin.flow.component.button.Button;
+import com.vaadin.flow.component.dialog.Dialog;
+import com.vaadin.flow.component.html.NativeLabel;
+import com.vaadin.flow.component.upload.Upload;
+import com.vaadin.flow.component.upload.receivers.MemoryBuffer;
+
+import app.owlcms.data.technicalofficial.TechnicalOfficialReader;
+import app.owlcms.i18n.Translator;
+import ch.qos.logback.classic.Logger;
+
+@SuppressWarnings("serial")
+public class TechnicalOfficialsUploadDialog extends Dialog {
+ Logger logger = (Logger) LoggerFactory.getLogger(TechnicalOfficialsUploadDialog.class);
+ private Runnable callback;
+ private MemoryBuffer buffer = new MemoryBuffer();
+ private Upload upload;
+
+ public TechnicalOfficialsUploadDialog() {
+ Button uploadButton = new Button(Translator.translate("TechnicalOfficials.Upload"));
+ upload = new Upload(buffer);
+ upload.setUploadButton(uploadButton);
+ upload.setDropLabel(new NativeLabel(Translator.translate("TechnicalOfficials.UploadDropZone")));
+ upload.addSucceededListener(e -> {
+ try {
+ InputStream is = buffer.getInputStream();
+ TechnicalOfficialReader.importFromXLS(is);
+ logger.warn("imported");
+ close();
+ if (callback != null) {
+ callback.run();
+ }
+ } catch (Exception ex) {
+ // Handle error
+ }
+ });
+ add(upload);
+ }
+
+ public void setCallback(Runnable callback) {
+ this.callback = callback;
+ }
+}
diff --git a/owlcms/src/main/java/app/owlcms/nui/preparation/XLSXTechnicalOfficialsExport.java b/owlcms/src/main/java/app/owlcms/nui/preparation/XLSXTechnicalOfficialsExport.java
index 626116f920..806f4779fc 100644
--- a/owlcms/src/main/java/app/owlcms/nui/preparation/XLSXTechnicalOfficialsExport.java
+++ b/owlcms/src/main/java/app/owlcms/nui/preparation/XLSXTechnicalOfficialsExport.java
@@ -1,16 +1,75 @@
package app.owlcms.nui.preparation;
+import java.io.IOException;
import java.io.OutputStream;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.slf4j.LoggerFactory;
+
+import app.owlcms.data.technicalofficial.TechnicalOfficial;
+import app.owlcms.data.technicalofficial.TechnicalOfficialRepository;
import app.owlcms.spreadsheet.XLSXWorkbookStreamSource;
+import ch.qos.logback.classic.Logger;
@SuppressWarnings("serial")
public class XLSXTechnicalOfficialsExport extends XLSXWorkbookStreamSource {
+ final private static Logger logger = (Logger) LoggerFactory.getLogger(XLSXTechnicalOfficialsExport.class);
+
@Override
protected void writeStream(OutputStream stream) {
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Unimplemented method 'writeStream'");
- }
+ Workbook workbook = new XSSFWorkbook();
+ try {
+ Sheet sheet = workbook.createSheet("Technical Officials");
+
+ // Create header style
+ CellStyle headerStyle = workbook.createCellStyle();
+ Font headerFont = workbook.createFont();
+ headerFont.setBold(true);
+ headerStyle.setFont(headerFont);
+
+ // Create headers
+ Row headerRow = sheet.createRow(0);
+ String[] headers = {"LastName", "FirstName", "Level", "IWFId", "Federation", "FederationId"};
+ for (int i = 0; i < headers.length; i++) {
+ Cell cell = headerRow.createCell(i);
+ cell.setCellValue(headers[i]);
+ cell.setCellStyle(headerStyle);
+ }
+ // Add data rows
+ int rowNum = 1;
+ for (TechnicalOfficial official : TechnicalOfficialRepository.findAll()) {
+ Row row = sheet.createRow(rowNum++);
+ row.createCell(0).setCellValue(official.getLastName() != null ? official.getLastName() : "");
+ row.createCell(1).setCellValue(official.getFirstName() != null ? official.getFirstName() : "");
+ row.createCell(2).setCellValue(official.getLevel() != null ? official.getLevel().toString() : "");
+ row.createCell(3).setCellValue(official.getIwfId() != null ? official.getIwfId() : "");
+ row.createCell(4).setCellValue(official.getFederation() != null ? official.getFederation() : "");
+ row.createCell(5).setCellValue(official.getFederationId() != null ? official.getFederationId() : "");
+ }
+
+ // Autosize columns
+ for (int i = 0; i < headers.length; i++) {
+ sheet.autoSizeColumn(i);
+ }
+
+ workbook.write(stream);
+ } catch (IOException e) {
+ logger.error("Error writing technical officials: {}", e);
+ throw new RuntimeException("Error writing technical officials", e);
+ } finally {
+ try {
+ workbook.close();
+ } catch (IOException e) {
+ logger.error("Error closing workbook: {}", e);
+ }
+ }
+ }
}
diff --git a/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSExportTechnicalOfficials.java b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSExportTechnicalOfficials.java
new file mode 100644
index 0000000000..9dbf2ca5a5
--- /dev/null
+++ b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSExportTechnicalOfficials.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright © 2009-present Jean-François Lamy
+ *
+ * Licensed under the Non-Profit Open Software License version 3.0 ("NPOSL-3.0")
+ * License text at https://opensource.org/licenses/NPOSL-3.0
+ *******************************************************************************/
+package app.owlcms.spreadsheet;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.slf4j.LoggerFactory;
+
+import com.vaadin.flow.component.UI;
+
+import app.owlcms.data.athlete.Athlete;
+import app.owlcms.data.category.Category;
+import app.owlcms.data.competition.Competition;
+import app.owlcms.data.group.Group;
+import app.owlcms.data.group.GroupRepository;
+import app.owlcms.data.records.RecordEvent;
+import app.owlcms.data.records.RecordRepository;
+import app.owlcms.i18n.Translator;
+import app.owlcms.utils.LoggerUtils;
+import ch.qos.logback.classic.Logger;
+
+/**
+ * @author jflamy
+ *
+ */
+@SuppressWarnings("serial")
+public class JXLSExportTechnicalOfficials extends JXLSWorkbookStreamSource {
+
+ Logger logger = (Logger) LoggerFactory.getLogger(JXLSExportTechnicalOfficials.class);
+ Group group;
+ private List records;
+ // private List bestRecords;
+ private boolean allRecords;
+ private boolean currentOnly;
+
+ public JXLSExportTechnicalOfficials(Group group, boolean excludeNotWeighed, UI ui) {
+ }
+
+ public JXLSExportTechnicalOfficials(UI ui, boolean allRecords, boolean currentOnly) {
+ this.setAllRecords(allRecords);
+ this.currentOnly = currentOnly;
+ }
+
+ @Override
+ public Group getGroup() {
+ return this.group;
+ }
+
+ /**
+ * Must be called immediately after getSortedAthletes due to reliance on "records" variable side-effect.
+ *
+ * @param cat
+ * @return
+ */
+ public List getRecords(Category cat) {
+ if (cat == null) {
+ return this.records.isEmpty() ? null : this.records;
+ }
+ this.logger.debug("category {} age >= {} <= {} bw > {} <= {}",
+ cat.getGender(),
+ cat.getAgeGroup().getMinAge(),
+ cat.getAgeGroup().getMaxAge(),
+ cat.getMinimumWeight(),
+ cat.getMaximumWeight());
+ List catRecords = new ArrayList<>();
+ for (RecordEvent record : this.records) {
+ Integer athleteAge = record.getAthleteAge();
+ Double athleteBW = record.getAthleteBW();
+ try {
+ if (record.getGender() == cat.getGender()
+ && athleteAge >= cat.getAgeGroup().getMinAge()
+ && athleteAge <= cat.getAgeGroup().getMaxAge()
+ && athleteBW > cat.getMinimumWeight()
+ && athleteBW <= cat.getMaximumWeight()) {
+ catRecords.add(record);
+ }
+ } catch (Exception e) {
+ this.logger.error("faulty record {}", record);
+ }
+ }
+ return catRecords.isEmpty() ? null : catRecords;
+ }
+
+ @Override
+ public List getSortedAthletes() {
+ HashMap reportingBeans = getReportingBeans();
+
+ // prevent irrelevant "No Athletes" error message.
+ List athletes = List.of(new Athlete());
+
+ String groupName = this.group != null ? this.group.getName() : null;
+ this.records = RecordRepository.findFiltered(null, null, null, groupName, !this.isAllRecords());
+ if (this.currentOnly) {
+ var recordMap = this.keepNewest();
+ this.records = new ArrayList<>(recordMap.values().stream().toList());
+ this.records.sort(sortRecords());
+ } else {
+ this.records.sort(sortRecords());
+ }
+ Map> grouped = groupByAgeGroup(this.records);
+ List>> list = new ArrayList<>();
+ for (Entry> v : grouped.entrySet()) {
+ list.add(v);
+ }
+ reportingBeans.put("agegroups", list);
+ reportingBeans.put("records", this.records);
+ return athletes;
+ }
+
+ @Override
+ public InputStream getTemplate(Locale locale) throws IOException {
+ if (this.inputStream != null) {
+ this.logger.debug("explicitly set template {}", this.inputStream);
+ return new BufferedInputStream(this.inputStream);
+ }
+ this.logger.debug("getTemplate {}", LoggerUtils.whereFrom());
+ return getLocalizedTemplate("/templates/records/exportRecords", ".xls", locale);
+ }
+
+ public Map keepNewest() {
+ return this.records.stream()
+ .collect(Collectors.groupingBy(
+ RecordEvent::getKey,
+ Collectors.collectingAndThen(
+ Collectors.maxBy((r1, r2) -> r1.getRecordLift().compareTo(r2.getRecordLift())),
+ record -> record.orElseThrow(() -> new IllegalStateException("No record found")))));
+ }
+
+ @Override
+ public void setGroup(Group group) {
+ this.group = group;
+ }
+
+ public Comparator sortRecords() {
+ return Comparator
+ .comparing(RecordEvent::getRecordFederation) // all records for a federation go together (masters are
+ // separate)
+ .thenComparing(RecordEvent::getRecordName) // sometimes several record names for same federation
+ // (example: event-specific)
+ .thenComparing(RecordEvent::getGender) // all women, then all men
+ .thenComparing(RecordEvent::getAgeGrpUpper) // U13 U15 U17 U20 U23 SR
+ // open has biggest age gap, goes after masters M85 and W85
+ .thenComparing((a, b) -> ObjectUtils.compare((a.getAgeGrpUpper() - a.getAgeGrpLower()), (b.getAgeGrpUpper() - b.getAgeGrpLower())))
+ .thenComparing(RecordEvent::getAgeGrpLower) // increasing age groups for masters (35, 40, 45...)
+ .thenComparing(RecordEvent::getBwCatUpper) // increasing body weights
+ .thenComparing((r) -> r.getRecordLift().ordinal()) // SNATCH, CJ, TOTAL
+ .thenComparing(RecordEvent::getRecordValue) // increasing records
+ ;
+ }
+
+ @Override
+ protected void setReportingInfo() {
+ List athletes = getSortedAthletes();
+ if (athletes != null) {
+ getReportingBeans().put("athletes", athletes);
+ getReportingBeans().put("lifters", athletes); // legacy
+ }
+ Competition competition = Competition.getCurrent();
+ getReportingBeans().put("t", Translator.getMap());
+ getReportingBeans().put("competition", competition);
+ getReportingBeans().put("session", getGroup()); // legacy
+ getReportingBeans().put("group", getGroup());
+
+ // reuse existing logic for processing records
+ JXLSExportTechnicalOfficials jxlsExportRecords = this;
+ // jxlsExportRecords.setGroup(getGroup());
+ this.logger.debug("fetching records for session {} category {}", getGroup(), getCategory());
+ try {
+ // Must be called as soon as possible after getSortedAthletes()
+ List records = jxlsExportRecords.getRecords(getCategory());
+ this.logger.debug("{} records found", records.size());
+ for (RecordEvent e : records) {
+ if (e.getBwCatUpper() > 250) {
+ e.setBwCatString(">" + e.getBwCatLower());
+ } else {
+ e.setBwCatString(Integer.toString(e.getBwCatUpper()));
+ }
+ }
+ getReportingBeans().put("records", records);
+ } catch (Exception e) {
+ // no records
+ }
+
+ getReportingBeans().put("masters", Competition.getCurrent().isMasters());
+ List sessions = GroupRepository.findAll().stream().sorted((a, b) -> {
+ int compare = ObjectUtils.compare(a.getWeighInTime(), b.getWeighInTime(), true);
+ if (compare != 0) {
+ return compare;
+ }
+ return compare = ObjectUtils.compare(a.getPlatform(), b.getPlatform(), true);
+ }).collect(Collectors.toList());
+ getReportingBeans().put("groups", sessions);
+ getReportingBeans().put("sessions", sessions);
+ }
+
+ private Map> groupByAgeGroup(List events) {
+ Map> groupedEvents = new LinkedHashMap<>();
+ for (RecordEvent record : events) {
+ String ageGroup = record.getAgeGrp();
+ boolean masters = record.getAgeGrpLower() >= 30 && (record.getAgeGrp().startsWith("W") || record.getAgeGrp().startsWith("M"));
+ groupedEvents.computeIfAbsent(masters ? ageGroup : ageGroup + " " + record.getTranslatedGender(), k -> new ArrayList<>()).add(record);
+ }
+ return groupedEvents;
+ }
+
+ private boolean isAllRecords() {
+ return this.allRecords;
+ }
+
+ private void setAllRecords(boolean allRecords) {
+ // logger.debug("***** allRecords = {} {}", allRecords, LoggerUtils.whereFrom());
+ this.allRecords = allRecords;
+ }
+
+}
diff --git a/playwright/.classpath b/playwright/.classpath
index a6e7009b01..379c3fc128 100644
--- a/playwright/.classpath
+++ b/playwright/.classpath
@@ -36,22 +36,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/publicresults-windows/.classpath b/publicresults-windows/.classpath
index 977bb34842..a012d978d7 100644
--- a/publicresults-windows/.classpath
+++ b/publicresults-windows/.classpath
@@ -36,22 +36,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/publicresults/.classpath b/publicresults/.classpath
index ce4f474237..1b228dacc8 100644
--- a/publicresults/.classpath
+++ b/publicresults/.classpath
@@ -42,22 +42,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/shared/.classpath b/shared/.classpath
index 273f587ba5..c329ff24c8 100644
--- a/shared/.classpath
+++ b/shared/.classpath
@@ -36,22 +36,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-