Dépôt officiel du code source de l'ERP OpenConcerto
Rev 150 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
package org.openconcerto.modules.operation;
import java.awt.FileDialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jopencalendar.model.JCalendarItem;
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.generationDoc.TemplateManager;
import org.openconcerto.openoffice.OOUtils;
import org.openconcerto.openoffice.spreadsheet.Sheet;
import org.openconcerto.openoffice.spreadsheet.SpreadSheet;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.FieldMapper;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.sqlobject.SQLTextCombo.ITextComboCacheSQL;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.date.DateRangePlannerPanel;
import org.openconcerto.utils.CollectionMap2.Mode;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.StreamUtils;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.TimeUtils;
import org.openconcerto.xml.JDOM2Utils;
import net.jcip.annotations.GuardedBy;
public class OperationExportPanel extends JPanel {
@GuardedBy("EDT")
static private final DateFormat DF = new SimpleDateFormat("yyyyMMdd");
final JCheckBox lockedCheckBox = new JCheckBox("verrouillées uniquement");
final JButton bPrint = new JButton("Exporter");
public OperationExportPanel(final OperationCalendarManager manager, final List<SQLRowValues> rowsSite) {
lockedCheckBox.setSelected(true);
//
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new DefaultGridBagConstraints();
final JLabel l = new JLabel("Date de début", SwingConstants.RIGHT);
this.add(l, c);
c.gridx++;
final JDate d1 = new JDate(false, true);
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
d1.setDate(cal.getTime());
c.weightx = 1;
this.add(d1, c);
c.gridx = 0;
c.gridy++;
c.weightx = 0;
final JLabel l2 = new JLabel("Date de fin", SwingConstants.RIGHT);
this.add(l2, c);
c.gridx++;
final JDate d2 = new JDate(false, true);
cal.add(Calendar.MONTH, 1);
cal.add(Calendar.SECOND, -1);
d2.setDate(cal.getTime());
c.weightx = 1;
this.add(d2, c);
final OperationSQLElement operationElem = manager.getDirectory().getElement(OperationSQLElement.class);
final OperationSQLComponent operationSQLComp = new OperationSQLComponent(operationElem);
final String statusID = "operation.status";
c.gridy++;
c.gridx = 0;
c.gridwidth = 1;
this.add(operationSQLComp.getLabel(statusID), c);
c.gridx++;
final SQLTextCombo statusCombo = (SQLTextCombo) operationSQLComp.createEditor(statusID);
final FieldMapper fieldMapper = PropsConfiguration.getInstance().getFieldMapper();
statusCombo.initCache(new ITextComboCacheSQL(fieldMapper.getSQLFieldForItem(statusID)));
this.add(statusCombo, c);
//
c.gridwidth = 2;
c.gridx = 0;
c.gridy++;
final JRadioButton radio1 = new JRadioButton("interventions");
radio1.setSelected(true);
this.add(radio1, c);
final JRadioButton radio2 = new JRadioButton("planifications");
c.gridy++;
this.add(radio2, c);
final ButtonGroup g = new ButtonGroup();
g.add(radio1);
g.add(radio2);
//
final JPanel p = new JPanel();
p.setLayout(new FlowLayout(FlowLayout.RIGHT));
p.add(lockedCheckBox);
p.add(bPrint);
c.gridwidth = 2;
c.gridx = 0;
c.gridy++;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.SOUTHEAST;
this.add(p, c);
//
bPrint.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (d1.getDate().after(d2.getDate())) {
return;
}
final String statusVal = statusCombo.getValue();
final List<String> states = StringUtils.isEmpty(statusVal, true) ? null : Collections.singletonList(statusVal);
final List<JCalendarItem> items = manager.getItemIn(d1.getDate(), d2.getDate(), null, states);
final List<JCalendarItemDB> itemsToExport = new ArrayList<JCalendarItemDB>(items.size());
if (lockedCheckBox.isSelected()) {
for (JCalendarItem jCalendarItem : items) {
JCalendarItemDB i = (JCalendarItemDB) jCalendarItem;
if (i.getFlagsString().contains("locked")) {
itemsToExport.add(i);
}
}
} else {
for (JCalendarItem jCalendarItem : items) {
JCalendarItemDB i = (JCalendarItemDB) jCalendarItem;
itemsToExport.add(i);
}
}
if (rowsSite != null && !rowsSite.isEmpty()) {
final Set<String> allowedSites = new HashSet<String>();
for (SQLRowValues r : rowsSite) {
String siteName = r.getString("NAME");
allowedSites.add(siteName);
}
final List<JCalendarItemDB> filtered = new ArrayList<JCalendarItemDB>(itemsToExport.size());
for (JCalendarItemDB i : itemsToExport) {
if (allowedSites.contains(i.getSiteName())) {
filtered.add(i);
}
}
itemsToExport.clear();
itemsToExport.addAll(filtered);
}
if (itemsToExport.isEmpty()) {
JOptionPane.showMessageDialog(OperationExportPanel.this, "Aucune intervention trouvée.\nMerci de vérifier la période et le verrouillage des interventions.");
return;
}
Collections.sort(itemsToExport, new Comparator<JCalendarItem>() {
@Override
public int compare(JCalendarItem o1, JCalendarItem o2) {
if (o1.getUserId().equals(o2.getUserId())) {
return o1.getDtStart().getTime().compareTo(o2.getDtStart().getTime());
}
return (int) (((Number) o1.getUserId()).longValue() - ((Number) o2.getUserId()).longValue());
}
});
final String dates = " " + DF.format(d1.getDate()) + '-' + DF.format(d2.getDate());
if (radio1.isSelected()) {
export(itemsToExport, "export " + radio1.getText() + dates);
} else {
exportPlan(itemsToExport, "export " + radio2.getText() + dates);
}
closeFrame();
}
});
}
static private final class Planner implements Comparable<Planner> {
static private final BigDecimal MS_PER_HOUR = BigDecimal.valueOf(1000 * 3600);
private final String uid;
private final String xml;
private Date rangeStart;
private Date startTime;
private BigDecimal hours;
protected Planner(String uid, String xml) {
super();
this.uid = uid;
this.xml = xml;
}
public final String getUID() {
return this.uid;
}
public final String getDescription() {
return DateRangePlannerPanel.getDescriptionFromXML(this.xml, false);
}
public final Date getRangeStart() {
if (this.rangeStart == null) {
parse();
}
return this.rangeStart;
}
protected void parse() {
try {
final Document doc = JDOM2Utils.parseStringDocument(this.xml);
this.rangeStart = new Date(Long.valueOf(doc.getRootElement().getChild("range").getAttributeValue("start")));
final Element scheduleElem = doc.getRootElement().getChild("schedule");
this.startTime = new Date(Long.valueOf(scheduleElem.getAttributeValue("start")));
final long endTime = Long.valueOf(scheduleElem.getAttributeValue("end"));
this.hours = DecimalUtils.round(BigDecimal.valueOf(endTime - this.startTime.getTime()).divide(MS_PER_HOUR, DecimalUtils.HIGH_PRECISION), 5);
} catch (Exception e) {
throw new IllegalStateException("couldn't get start for " + this.xml, e);
}
}
public final Date getStartTime() {
if (this.startTime == null) {
parse();
}
return this.startTime;
}
public final BigDecimal getHours() {
if (this.hours == null) {
parse();
}
return this.hours;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + this.uid.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Planner other = (Planner) obj;
return this.uid.equals(other.uid);
}
@Override
public int compareTo(Planner o) {
if (this.equals(o))
return 0;
final int startComparison = this.getRangeStart().compareTo(o.getRangeStart());
if (startComparison != 0)
return startComparison;
return this.getUID().compareTo(o.getUID());
}
}
protected void exportPlan(List<JCalendarItemDB> itemsToExport, final String name) {
final List<Long> ids = ModuleOperation.getOperationIdsFrom(new HashSet<JCalendarItemDB>(itemsToExport));
final DBRoot root = ComptaPropsConfiguration.getInstanceCompta().getRootSociete();
final SQLTable table = root.getTable(ModuleOperation.TABLE_OPERATION);
final SQLRowValues valOperation = new SQLRowValues(table);
final SQLRowValues valSite = new SQLRowValues(root.getTable(ModuleOperation.TABLE_SITE));
valSite.putNulls("NAME", "COMMENT");
valOperation.putRowValues("ID_USER_COMMON").putNulls("NOM", "PRENOM");
// valOperation.put("ID_CALENDAR_ITEM_GROUP", valsCalendarItemsGroup);
valOperation.put("ID_SITE", valSite);
valOperation.putNulls("STATUS", "DESCRIPTION", "TYPE", "PLANNER_XML", "PLANNER_UID");
final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(valOperation);
fetcher.setFullOnly(true);
final List<SQLRowValues> itemsFetched = fetcher.fetch(new Where(table.getKey(), ids).and(Where.createRaw("length(" + table.getField("PLANNER_UID").getFieldRef() + ")>2")));
final ListMap<Planner, SQLRowValues> operationsByPlanner = new ListMap<>(new TreeMap<Planner, List<SQLRowValues>>(), Mode.NULL_FORBIDDEN);
for (SQLRowValues d : itemsFetched) {
operationsByPlanner.add(new Planner(d.getString("PLANNER_UID"), d.getString("PLANNER_XML")), d);
}
final List<Entry<Planner, List<SQLRowValues>>> items = new ArrayList<>(operationsByPlanner.entrySet());
final DatatypeFactory dataTypeFactory;
try {
dataTypeFactory = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException e) {
throw new IllegalStateException(e);
}
TableModel model = new AbstractTableModel() {
@Override
public int getRowCount() {
return items.size();
}
@Override
public int getColumnCount() {
return 7;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
final Entry<Planner, List<SQLRowValues>> rows = items.get(rowIndex);
final Planner planner = rows.getKey();
// for now, only the "Employé" column check all operations for a planner, the other
// columns just take the first one.
final SQLRowValues i = rows.getValue().get(0);
switch (columnIndex) {
case 0:
return dataTypeFactory.newDurationDayTime(planner.getStartTime().getTime());
case 1:
return planner.getHours();
case 2:
// Plannif
return planner.getDescription();
case 3:
// Employé
final ListMap<Integer, SQLRowValues> operationsByUserID = new ListMap<>();
for (final SQLRowValues r : rows.getValue()) {
operationsByUserID.add(r.getForeignID("ID_USER_COMMON"), r);
}
final List<Entry<Integer, List<SQLRowValues>>> entries = new ArrayList<>(operationsByUserID.entrySet());
// the users with the most operations first
Collections.sort(entries, new Comparator<Entry<Integer, List<SQLRowValues>>>() {
@Override
public int compare(Entry<Integer, List<SQLRowValues>> o1, Entry<Integer, List<SQLRowValues>> o2) {
final int sizeComparison = CompareUtils.compareInt(o1.getValue().size(), o2.getValue().size());
if (sizeComparison != 0)
return -sizeComparison;
return o1.getKey().compareTo(o2.getKey());
}
});
final ListIterator<Entry<Integer, List<SQLRowValues>>> listIter = entries.listIterator();
final StringBuilder sb = new StringBuilder(128);
while (listIter.hasNext()) {
final Entry<Integer, List<SQLRowValues>> element = listIter.next();
final SQLRowValues operationR = element.getValue().get(0);
final SQLRowAccessor userR = operationR.getForeign("ID_USER_COMMON");
sb.append(userR.getString("PRENOM") + " " + userR.getString("NOM"));
if (listIter.previousIndex() > 0) {
sb.append(" (");
sb.append(element.getValue().size());
sb.append(")");
}
if (listIter.hasNext()) {
sb.append(", ");
}
}
return sb.toString();
case 4:
// Nature
final String type = i.getString("TYPE");
return type;
case 5:
// Chantier
final String siteName = i.getForeign("ID_SITE").getString("NAME");
return siteName;
case 6:
// Description
final String desc = i.getString("DESCRIPTION");
return desc;
default:
break;
}
return "?";
}
};
// Save the data to an ODS file and open it.
final String templateId = ModuleOperation.OPERATIONS_REPORT_TEMPLATE2_ID;
saveAsODS(model, templateId, name);
}
protected void export(final List<JCalendarItemDB> items, final String name) {
TableModel model = new AbstractTableModel() {
@Override
public int getRowCount() {
return items.size();
}
@Override
public int getColumnCount() {
return 7;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
JCalendarItemDB i = items.get(rowIndex);
switch (columnIndex) {
case 0:
// Date
Date start = TimeUtils.clearTime((Calendar) i.getDtStart().clone()).getTime();
return start;
case 1:
// Heure
Calendar h = i.getDtStart();
return h;
case 2:
// Durée
long m = (i.getDtEnd().getTimeInMillis() - i.getDtStart().getTimeInMillis()) / (1000 * 60);
return m;
case 3:
// Employé
final SQLRowValues user = i.getUserRow();
return user.getString("PRENOM") + " " + user.getString("NOM");
case 4:
// Nature
final String type = i.getType();
return type;
case 5:
// Chantier
final String siteName = i.getSiteName();
return siteName;
case 6:
// Description
final String desc = i.getDescription();
return desc;
default:
break;
}
return "?";
}
};
// Save the data to an ODS file and open it.
final String templateId = ModuleOperation.OPERATIONS_REPORT_TEMPLATE_ID;
saveAsODS(model, templateId, name);
}
public void saveAsODS(TableModel model, final String templateId, final String name) {
try {
final InputStream inStream = TemplateManager.getInstance().getTemplate(templateId);
final File templateFile = File.createTempFile(templateId, ".ods");
if (inStream == null) {
JOptionPane.showMessageDialog(this, "Modèle introuvable");
return;
}
StreamUtils.copy(inStream, templateFile);
inStream.close();
final Sheet sheet = SpreadSheet.createFromFile(templateFile).getSheet(0);
final int rowCount = model.getRowCount();
sheet.ensureRowCount(rowCount + 1);
final int columnCount = model.getColumnCount();
for (int x = 0; x < columnCount; x++) {
for (int y = 0; y < rowCount; y++) {
sheet.setValueAt(model.getValueAt(y, x), x, y + 1);
}
}
final FileDialog d = new FileDialog((Frame) SwingUtilities.getWindowAncestor(this), "Exporter sous...", FileDialog.SAVE);
d.setFile(name + ".ods");
d.setVisible(true);
String fileName = d.getFile();
if (fileName != null) {
fileName = fileName.trim();
if (!fileName.toLowerCase().endsWith(".ods")) {
fileName += ".ods";
}
File outputFile = new File(d.getDirectory(), fileName);
final File saveAs = sheet.getSpreadSheet().saveAs(outputFile);
OOUtils.open(saveAs);
} else {
JOptionPane.showMessageDialog(this, "Fichier non spécifié");
}
} catch (Exception e) {
ExceptionHandler.handle("Export error", e);
}
}
protected void closeFrame() {
SwingUtilities.getWindowAncestor(this).dispose();
}
}