OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Compare Revisions

Regard whitespace Rev 150 → Rev 151

/trunk/OpenConcerto/lib/poi-3.17.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/lib/poi-3.17.jar
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/lib/jOpenDocument-1.4rc2.badSecurity.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/lib/jOpenDocument-1.4rc2.badSecurity.jar
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/lib/jOpenCalendar.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.odsp
1,9 → 1,6
<odsp>
<spliteveryrow>
<sheet number="0">60</sheet>
<sheet number="0">61</sheet>
</spliteveryrow>
<offset x="20" y ="20"/>
<resize percent="92"/>
 
 
</odsp>
/trunk/OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.xml
126,50 → 126,54
<field name="NET_A_PAYER"/>
</element>
<element location="D57" type="fill">
<element location="I55" type="fill">
<field name="REDUCTION_GVT" />
</element>
 
<element location="D58" type="fill">
<field name="SAL_BRUT"/>
</element>
<element location="E57" type="fill">
<element location="E58" type="fill">
<field name="COT_SAL"/>
</element>
<element location="F57" type="fill">
<element location="F58" type="fill">
<field name="COT_PAT"/>
</element>
<element location="G57" type="fill">
<element location="G58" type="fill">
<field name="AVANTAGE_NATURE"/>
</element>
<element location="H57" type="fill">
<element location="H58" type="fill">
<field name="NET_IMP"/>
</element>
<element location="I57" type="fill">
<element location="I58" type="fill">
<field name="ALLEGEMENT_COTISATION"/>
</element>
<element location="D58" type="fill">
<element location="D59" type="fill">
<field name="SAL_BRUT" type="cumulPaye"/>
</element>
<element location="E58" type="fill">
<element location="E59" type="fill">
<field name="COT_SAL" type="cumulPaye"/>
</element>
<element location="F58" type="fill">
<element location="F59" type="fill">
<field name="COT_PAT" type="cumulPaye"/>
</element>
<element location="G58" type="fill">
<element location="G59" type="fill">
<field name="AVANTAGE_NATURE" type="cumulPaye"/>
</element>
<element location="H58" type="fill">
<element location="H59" type="fill">
<field name="NET_IMP" type="cumulPaye"/>
</element>
<element location="I58" type="fill">
<element location="I59" type="fill">
<field name="ALLEGEMENT_COTISATION" type="cumulPaye"/>
</element>
<table endPageLine="60" firstLine="15" endLine="51" lastColumn="J" base="Societe" table="FICHE_PAYE_ELEMENT"
<table endPageLine="61" firstLine="15" endLine="51" lastColumn="J" base="Societe" table="FICHE_PAYE_ELEMENT"
blankLineBeforeStyle="Titre 1,Titre 2" fieldWhere="IMPRESSION" orderBy="POSITION">
<element location="B" type="fill" cellSize="52">
<field name="NOM" />
/trunk/OpenConcerto/Configuration/Template/Default/FichePayeSimplifiee.ods
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/utils/text/CSVReader.java
29,6 → 29,7
 
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
247,4 → 248,11
br.close();
}
 
public static void main(String[] args) throws IOException {
CSVReader reader = new CSVReader(new FileReader("n:\\Sans nom 1.csv"));
String[] s = reader.readNext();
for (int i = 0; i < s.length; i++) {
System.err.println("CSVReader.main() :" + i + " : " + s[i]);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/prog/SVNUtils.java
50,20 → 50,23
}
 
// match placeholder $Rev$ fixed length $Rev:: $ and of course with value $Rev: 12 $
private static final Pattern KEYWORD_PATTERN = Pattern.compile("^\\$\\p{Alpha}+:{0,2}\\p{Blank}*(.*?)\\p{Blank}*\\$$");
// don't require to match to the end to allow callers to only know the start of the substitute
// and to not bother with the pattern
private static final Pattern KEYWORD_PATTERN = Pattern.compile("^\\$\\p{Alpha}+:{0,2}\\p{Blank}*(.*?)\\p{Blank}*\\$");
 
/**
* Return the value of the svn keyword. E.g. use with
* Return the value of the subversion keyword. E.g. use with
* <code>private static final String REV = getKeywordValue("$Rev$")</code> (don't forget to
* <code>svn propset svn:keywords</code>).
*
* @param substitute the svn substitute, e.g. "$Rev: 12 $".
* @param substitute the svn substitute, trailing characters not part of the keyword will be
* ignored, e.g. "$Rev: 12 $ other chars".
* @return the value, empty string if none, e.g. "12".
* @throws IllegalArgumentException if substitute is not valid.
*/
public static String getKeywordValue(String substitute) throws IllegalArgumentException {
final Matcher matcher = KEYWORD_PATTERN.matcher(substitute);
if (!matcher.matches())
if (!matcher.find())
throw new IllegalArgumentException("SVN format not recognized");
 
return matcher.group(1);
/trunk/OpenConcerto/src/org/openconcerto/utils/FeatureMode.java
New file
0,0 → 1,29
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils;
 
public enum FeatureMode {
/**
* The feature is required.
*/
REQUIRED,
/**
* The feature is used if available.
*/
ALLOWED,
/**
* The feature won't be used.
*/
FORBIDDEN
}
/trunk/OpenConcerto/src/org/openconcerto/task/ui/UserRightsPrefPanel.java
72,8 → 72,8
l.setCellRenderer(new UserListCellRenderer());
l.setBorder(BorderFactory.createEmptyBorder());
final JScrollPane scrollPane = new JScrollPane(l);
scrollPane.setMinimumSize(new Dimension(120, 120));
scrollPane.setPreferredSize(new Dimension(120, 120));
scrollPane.setMinimumSize(new Dimension(10 * getFont().getSize(), 120));
scrollPane.setPreferredSize(new Dimension(12 * getFont().getSize(), 120));
this.add(scrollPane, c);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
// Separator
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/ITreeSelection.java
25,6 → 25,7
import org.openconcerto.sql.request.SQLRowItemView;
import org.openconcerto.sql.sqlobject.itemview.RowItemViewComponent;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.FrameUtil;
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.ExceptionHandler;
83,7 → 84,9
renderer.setClosedIcon(null);
renderer.setLeafIcon(null);
this.setCellRenderer(renderer);
 
// HighDPI
this.setRowHeight(FontUtils.getPreferredRowHeight(this));
// Selection
this.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
this.element = element;
 
/trunk/OpenConcerto/src/org/openconcerto/erp/model/EditionFichePayeModel.java
86,6 → 86,7
public void setDateLimit(java.util.Date dateLimit) {
this.dateLimit = dateLimit;
fill();
updateAll();
fireTableDataChanged();
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/model/FamilleArticleTree.java
22,6 → 22,7
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLTableListener;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.ui.FontUtils;
 
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
64,6 → 65,7
this.addMouseListener(this);
this.setTableListener();
this.setDragEnabled(true);
this.setRowHeight(FontUtils.getPreferredRowHeight(this));
}
 
/**
/trunk/OpenConcerto/src/org/openconcerto/erp/model/FichePayeModel.java
72,7 → 72,8
private SQLJavaEditor javaEdit = new SQLJavaEditor(VariablePayeSQLElement.getMapTree());
 
// liste des variable de paye à calculer
private BigDecimal salBrut, salBrutBase, salBrutCotis, salBrutTaxable, cotPat, cotSal, taxCmPat, taxCmSal, netImp, netAPayer, csg, csgSansAbattement, cice, allegmentCotisation, avantage;
private BigDecimal salBrut, salBrutBase, salBrutCotis, salBrutTaxable, cotPat, cotSal, taxCmPat, taxCmSal, netImp, netAPayer, csg, csgSansAbattement, cice, allegmentCotisation, avantage,
reduction;
 
private Map<Integer, String> mapField;
 
82,7 → 83,6
private int mois;
 
public FichePayeModel(int idFiche) {
 
System.err.println("NEW FICHE PAYE MODEL");
this.javaEdit.setModel(this);
this.idFiche = idFiche;
127,6 → 127,8
 
SQLPreferences prefs = new SQLPreferences(tableFichePaye.getTable().getDBRoot());
this.tauxCSG = new BigDecimal(prefs.getDouble(PayeGlobalPreferencePanel.ASSIETTE_CSG, 0.9825D));
final SQLTable tableValidite = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete().getTable("PERIODE_VALIDITE");
SQLBackgroundTableCache.getInstance().getCacheForTable(tableValidite).reloadFromDbIfNeeded();
 
// loadElement();
// methodeTmp();
193,6 → 195,7
*/
this.cice = null;
this.allegmentCotisation = BigDecimal.ZERO;
this.reduction = BigDecimal.ZERO;
this.avantage = BigDecimal.ZERO;
this.salBrut = BigDecimal.ZERO;
this.salBrutCotis = BigDecimal.ZERO;
770,6 → 773,7
}
rowValsFiche.put("CICE", this.cice);
rowValsFiche.put("ALLEGEMENT_COTISATION", this.allegmentCotisation);
rowValsFiche.put("REDUCTION_GVT", this.reduction);
rowValsFiche.put("AVANTAGE_NATURE", this.avantage);
try {
rowValsFiche.update(this.idFiche);
1134,13 → 1138,24
rowVals.put("TAUX_SAL", (tauxSalOb == null) ? null : new BigDecimal(tauxSalOb.toString()));
rowVals.put("TAUX_PAT", (tauxPatOb == null) ? null : new BigDecimal(tauxPatOb.toString()));
rowVals.put("MONTANT_PAT", (montantPatOb == null) ? null : new BigDecimal(montantPatOb.toString()));
rowVals.put("MONTANT_SAL_AJ", (montantAdOb == null) ? null : new BigDecimal(montantAdOb.toString()));
rowVals.put("MONTANT_SAL_DED", (montantDedOb == null) ? null : new BigDecimal(montantDedOb.toString()));
final BigDecimal montantAj = (montantAdOb == null) ? null : new BigDecimal(montantAdOb.toString());
rowVals.put("MONTANT_SAL_AJ", montantAj);
final BigDecimal montantDed = (montantDedOb == null) ? null : new BigDecimal(montantDedOb.toString());
rowVals.put("MONTANT_SAL_DED", montantDed);
 
boolean b = isEltImprimable(rowSource, rowVals);
// System.err.println("Impression --- > " + b);
rowVals.put("IMPRESSION", Boolean.valueOf(b));
 
if (rowSource.getBoolean("REDUCTION_GVT_COM")) {
if (montantAj != null) {
this.reduction = this.reduction.subtract(montantAj);
}
if (montantDed != null) {
this.reduction = this.reduction.add(montantDed);
}
}
 
this.vectRubrique.add(rowVals);
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/translation/messages_fr.properties
1,3 → 1,5
add=Ajouter
modify.or.delete=Modifier/Supprimer
address=Adresse
address.type.invoice=Facturation
address.type.delivery=Livraison
20,4 → 22,13
</ul><p>Si ce n'est pas le cas, merci de vérifier qu'il n'y ait pas plusieurs installations configurées avec le même numéro de caisse (n° {0}).\
<p>Voulez-vous ignorer message et continuer ou alors quitter l\u2019application ?</html>
register.moved.ignore=Ignorer
register.moved.quit=Quitter
register.moved.quit=Quitter
 
sddMessage.generation.noneNeeded=Aucune facture ne nécessite {msgElem__de__singular}.
sddMessage.generation.noneIgnored={msgElem__singularDefiniteArticle} généré inclut {invoiceElem__definiteNumeral}.
sddMessage.generation.someIgnored={invoiceElemCount, plural, =0 {Toutes les factures nécessitant {msgElem__singularIndefiniteArticle} ont été ignorées :}\
other {{msgElem__singularDefiniteArticle} généré inclut {invoiceElem__indefiniteNumeral}, d'autres ont été ignorées :}}
sddMessage.generation.someIgnored.future={futureCount, plural, =1 {une car sa date d\u2019échéance est trop éloignée} other {# car leurs dates d\u2019échéance sont trop éloignées}}
sddMessage.generation.someIgnored.duplicateMandate={duplicateCount, plural, =1 {une car son mandat est partagé avec une autre facture}\
other {# car leurs mandats sont partagés avec d\u2019autres factures}}. Vous devez générer à nouveau {msgElem__singularIndefiniteArticle}.
sddMessage.generation.someIgnored.missingInfo={missingInfoCount, plural, =1 {une car il manquait des informations} other {# car il manquait des informations}}
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/translation/messages_en.properties
1,3 → 1,5
add=Add
modify.or.delete=Modify/Delete
address=Address
address.type.invoice=Invoice
address.type.delivery=Shipment
20,4 → 22,14
</ul><p>If this isn\u2019t the case, please check that there isn\u2019t multiple installations with the same register number (n° {0}).\
<p>Do you want to ignore the message and continue or else quit the application?</html>
register.moved.ignore=Ignore
register.moved.quit=Quit
register.moved.quit=Quit
 
 
sddMessage.generation.noneNeeded=No invoice needs {msgElem__singularIndefiniteArticle}.
sddMessage.generation.noneIgnored=The generated {msgElem__singular} includes {invoiceElem__definiteNumeral}.
sddMessage.generation.someIgnored={invoiceElemCount, plural, =0 {All invoices needing {msgElem__singularIndefiniteArticle} were ignored :}\
other {The generated {msgElem__singular} includes {invoiceElem__indefiniteNumeral}, others were ignored :}}
sddMessage.generation.someIgnored.future={futureCount, plural, =1 {one because its due date was too far} other {# because their due dates were too far}}
sddMessage.generation.someIgnored.duplicateMandate={duplicateCount, plural, =1 {one because its mandate was shared with another invoice}\
other {# because their mandates were shared with other invoices}}. You must generate again {msgElem__singularIndefiniteArticle}.
sddMessage.generation.someIgnored.missingInfo={missingInfoCount, plural, =1 {one because some information was missing} other {# because some information was missing}}
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/HeadlessGestion.java
17,7 → 17,6
import org.openconcerto.erp.config.MainFrame;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.utils.i18n.TranslationManager;
 
import java.util.Locale;
29,7 → 28,25
this.comptaPropsConfiguration = ComptaPropsConfiguration.create();
}
 
public HeadlessGestion setup(int userId, int companyId) {
try {
this.comptaPropsConfiguration.getUserManager().setCurrentUserID(userId);
this.comptaPropsConfiguration.setUpSocieteDataBaseConnexion(companyId);
} catch (Exception e) {
e.printStackTrace();
throw new IllegalStateException("Unable to configure connection for userId: " + userId + " companyId: " + companyId);
 
}
return this;
}
 
public HeadlessGestion setupGlobalState(int userId, int companyId) {
setupGlobalState(userId, companyId);
setGlobalState();
return this;
}
 
public HeadlessGestion setGlobalState() {
System.setProperty("java.awt.headless", "true");
 
TranslationManager.getInstance().addTranslationStreamFromClass(MainFrame.class);
36,14 → 53,6
TranslationManager.getInstance().setLocale(Locale.getDefault());
Configuration.setInstance(this.comptaPropsConfiguration);
 
try {
UserManager.getInstance().setCurrentUserID(userId);
this.comptaPropsConfiguration.setUpSocieteDataBaseConnexion(companyId);
} catch (Exception e) {
e.printStackTrace();
throw new IllegalStateException("Unable to configure connection for userId: " + userId + " companyId: " + companyId);
 
}
System.out.println("HeadlessOpenConcerto ready");
System.out.println(
"Connected to " + this.comptaPropsConfiguration.getServerIp() + " on " + this.comptaPropsConfiguration.getSystemRootName() + "/" + this.comptaPropsConfiguration.getSocieteBaseName());
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/UIPreferencePanel.java
27,6 → 27,7
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
 
45,9 → 46,10
private static final String ALTERNATE_COLOR_BLUE = "ui.list.alternate.color.blue";
private static final String ALTERNATE_COLOR_GREEN = "ui.list.alternate.color.green";
private static final String ALTERNATE_COLOR_RED = "ui.list.alternate.color.red";
private static final String UI_DPI = "ui.default.dpi";
private static final String UI_LOOK = "ui.look";
private JLabel selectedButton;
private JComboBox comboLook;
private JComboBox comboLook, comboDPI;
 
public UIPreferencePanel() {
super("Interface graphique", UI_PROPERTIES);
69,6 → 71,19
 
c.gridx++;
this.add(comboLook, c);
 
c.gridy++;
c.gridx = 0;
this.add(new JLabel("High DPI"), c);
this.comboDPI = new JComboBox(new String[] { "Désactivé", "x1.3", "x2", "x3", "x4" });
String dpi = this.properties.getProperty(UI_DPI);
if (dpi != null && !dpi.equals("1")) {
comboDPI.setSelectedIndex(Float.valueOf(dpi).intValue());
}
 
c.gridx++;
this.add(comboDPI, c);
 
final JLabel labelAlternate = new JLabel("Couleur de fond dans les liste pour l'alternance");
c.gridx = 0;
c.gridwidth = 2;
199,6 → 214,19
} else {
properties.setProperty(UI_LOOK, "nimbus");
}
 
if (this.comboDPI.getSelectedIndex() == 1) {
properties.setProperty(UI_DPI, "1.3");
} else if (this.comboDPI.getSelectedIndex() == 2) {
properties.setProperty(UI_DPI, "2");
} else if (this.comboDPI.getSelectedIndex() == 3) {
properties.setProperty(UI_DPI, "3");
} else if (this.comboDPI.getSelectedIndex() == 4) {
properties.setProperty(UI_DPI, "4");
} else {
properties.setProperty(UI_DPI, "1");
}
 
super.storeValues();
}
 
254,12 → 282,32
} else {
useNimbusLF();
}
 
final String dpi = properties.getProperty(UI_DPI);
if (dpi != null && dpi.length() > 0 && !dpi.equalsIgnoreCase("1")) {
setUIFont(Float.valueOf(dpi));
UIManager.put("dpi.scale", Float.valueOf(dpi));
} else {
UIManager.put("dpi.scale", Float.valueOf(1));
}
} catch (Exception e) {
ExceptionHandler.handle("Unable to restore UI preferences", e);
}
}
 
public static void setUIFont(float factor) {
Enumeration<Object> keys = UIManager.getDefaults().keys();
 
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
Object value = UIManager.get(key);
if (value instanceof javax.swing.plaf.FontUIResource) {
javax.swing.plaf.FontUIResource r = (javax.swing.plaf.FontUIResource) value;
 
UIManager.put(key, r.deriveFont(r.getSize() * factor));
}
}
}
 
private static void useSystemLF() throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException {
LAFUtils.setLookAndFeel();
}
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/TemplateNXProps.java
18,6 → 18,7
import org.openconcerto.erp.core.edm.AttachmentSQLElement;
import org.openconcerto.erp.core.finance.accounting.report.BalanceSheet;
import org.openconcerto.erp.core.finance.accounting.report.GrandLivreSheet;
import org.openconcerto.erp.core.finance.accounting.report.GrandLivreSheetXML;
import org.openconcerto.erp.core.finance.accounting.report.JournauxSheetXML;
import org.openconcerto.erp.core.humanresources.payroll.report.EtatChargesPayeSheet;
import org.openconcerto.erp.core.humanresources.payroll.report.FichePayeSheetXML;
148,7 → 149,7
register(ReleveChequeSheet.TEMPLATE_ID, ReleveChequeSheet.TEMPLATE_PROPERTY_NAME, null);
register(ListeVenteXmlSheet.TEMPLATE_ID, ListeVenteXmlSheet.TEMPLATE_PROPERTY_NAME, null);
register(BalanceSheet.TEMPLATE_ID, BalanceSheet.TEMPLATE_PROPERTY_NAME, BalanceSheet.TEMPLATE_ID);
register(GrandLivreSheet.TEMPLATE_ID, GrandLivreSheet.TEMPLATE_PROPERTY_NAME, GrandLivreSheet.TEMPLATE_ID);
register(GrandLivreSheetXML.TEMPLATE_ID, GrandLivreSheetXML.TEMPLATE_PROPERTY_NAME, GrandLivreSheetXML.TEMPLATE_ID);
register(JournauxSheetXML.TEMPLATE_ID, JournauxSheetXML.TEMPLATE_PROPERTY_NAME, JournauxSheetXML.TEMPLATE_ID);
register(EtatChargesPayeSheet.TEMPLATE_ID, EtatChargesPayeSheet.TEMPLATE_PROPERTY_NAME, "Etat des charges");
register(FichePayeSheetXML.TEMPLATE_ID, FichePayeSheetXML.TEMPLATE_PROPERTY_NAME, "Fiche paye");
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/GenerationDocumentComptaPreferencePanel.java
14,7 → 14,7
package org.openconcerto.erp.preferences;
 
import org.openconcerto.erp.core.finance.accounting.report.BalanceSheet;
import org.openconcerto.erp.core.finance.accounting.report.GrandLivreSheet;
import org.openconcerto.erp.core.finance.accounting.report.GrandLivreSheetXML;
import org.openconcerto.erp.core.finance.accounting.report.JournauxSheetXML;
import org.openconcerto.utils.Tuple2;
 
22,7 → 22,7
 
public GenerationDocumentComptaPreferencePanel() {
super();
this.mapKeyLabel.put(Tuple2.create(GrandLivreSheet.TEMPLATE_ID, GrandLivreSheet.TEMPLATE_PROPERTY_NAME), GrandLivreSheet.TEMPLATE_ID);
this.mapKeyLabel.put(Tuple2.create(GrandLivreSheetXML.TEMPLATE_ID, GrandLivreSheetXML.TEMPLATE_PROPERTY_NAME), GrandLivreSheetXML.TEMPLATE_ID);
this.mapKeyLabel.put(Tuple2.create(JournauxSheetXML.TEMPLATE_ID, JournauxSheetXML.TEMPLATE_PROPERTY_NAME), JournauxSheetXML.TEMPLATE_ID);
this.mapKeyLabel.put(Tuple2.create(BalanceSheet.TEMPLATE_ID, BalanceSheet.TEMPLATE_PROPERTY_NAME), BalanceSheet.TEMPLATE_ID);
// uiInit();
/trunk/OpenConcerto/src/org/openconcerto/erp/config/Gestion.java
58,6 → 58,8
import java.awt.event.HierarchyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
77,7 → 79,9
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
import javax.swing.ImageIcon;
import javax.swing.JDialog;
384,6 → 388,9
// ITableModel.setDefaultOrderEditable(true);
 
AWTEventListener awtListener = new AWTEventListener() {
Set<Integer> frames = new HashSet<Integer>();
String prefix;
 
@Override
public final void eventDispatched(final AWTEvent event) {
assert event != null;
393,13 → 400,32
final HierarchyEvent hevent = (HierarchyEvent) event;
final Component changed = hevent.getChanged();
if (changed instanceof JFrame && ((hevent.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) && changed.isDisplayable()) {
JFrame frame = (JFrame) changed;
final JFrame frame = (JFrame) changed;
frame.setIconImages(getFrameIcon());
if (!frames.contains(frame.hashCode())) {
frames.add(frame.hashCode());
frame.addPropertyChangeListener(new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (prefix == null) {
if (ComptaPropsConfiguration.getInstance() != null && ComptaPropsConfiguration.getInstanceCompta().getRowSociete() != null) {
prefix = "[" + ComptaPropsConfiguration.getInstanceCompta().getRowSociete().getString("NOM") + "] ";
} else {
return;
}
}
String title = frame.getTitle();
if (title != null && !title.startsWith(prefix)) {
frame.setTitle(prefix + title);
}
}
});
}
}
}
}
};
 
final Toolkit toolkit = Toolkit.getDefaultToolkit();
assert toolkit != null;
toolkit.addAWTEventListener(awtListener, AWTEvent.HIERARCHY_EVENT_MASK);
/trunk/OpenConcerto/src/org/openconcerto/erp/config/SQLElementNames_en.xml
2,5 → 2,7
<element refid="CONTACT" name="contact" />
<element refid="CONTACT_FOURNISSEUR" name="supplier contact" namePlural="suppliers contacts" />
<element refid="CONTACT_ADMINISTRATIF" name="administrative contact" />
<element refid="CATEGORIE_CLIENT" nameClass="feminine" name="Customer category" />
<element refid="customerrelationship.customer.category" nameClass="feminine" name="customer category" />
<element refid="finance.payment.SDDMessage" name="SDD message" />
<element refid="finance.payment.SEPAMandate" name="SEPA mandate" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/erp/config/ComptaPropsConfiguration.java
65,6 → 65,8
import org.openconcerto.erp.core.finance.payment.element.ModeDeReglementSQLElement;
import org.openconcerto.erp.core.finance.payment.element.ReglerMontantElementSQLElement;
import org.openconcerto.erp.core.finance.payment.element.ReglerMontantSQLElement;
import org.openconcerto.erp.core.finance.payment.element.SDDMessageSQLElement;
import org.openconcerto.erp.core.finance.payment.element.SEPAMandateSQLElement;
import org.openconcerto.erp.core.finance.payment.element.TypeReglementSQLElement;
import org.openconcerto.erp.core.finance.tax.element.EcoTaxeSQLElement;
import org.openconcerto.erp.core.finance.tax.element.TaxeComplementaireSQLElement;
1039,6 → 1041,8
dir.addSQLElement(new TypeComptePCGSQLElement());
dir.addSQLElement(new TypeLettreRelanceSQLElement());
dir.addSQLElement(new TypeReglementSQLElement());
dir.addSQLElement(new SDDMessageSQLElement(this));
dir.addSQLElement(new SEPAMandateSQLElement(this));
 
dir.addSQLElement(new VariableSalarieSQLElement());
dir.addSQLElement(UniteVenteArticleSQLElement.class);
1178,9 → 1182,9
showAs.show("CODE_REGIME", SQLRow.toList("CODE,NOM"));
showAs.show("COMMANDE", "NUMERO", "DATE", "DATE_RECEPTION_DEMANDEE", "NOM", "ID_FOURNISSEUR");
if (root.contains("AFFAIRE")) {
showAs.show("COMMANDE_CLIENT", "NUMERO", "DATE", "ID_AFFAIRE", "NOM", "T_HT");
showAs.show("COMMANDE_CLIENT", "NUMERO", "DATE", "ID_CLIENT", "ID_AFFAIRE", "NOM", "T_HT");
} else {
showAs.show("COMMANDE_CLIENT", "NUMERO", "DATE", "NOM", "T_HT");
showAs.show("COMMANDE_CLIENT", "NUMERO", "DATE", "NOM", "ID_CLIENT", "T_HT");
}
showAs.show("COMPTE_PCE", "NUMERO", "NOM");
showAs.show("COMPTE_PCG", "NUMERO", "NOM");
/trunk/OpenConcerto/src/org/openconcerto/erp/config/translation_en.xml
110,6 → 110,7
<menu id="customer.payment.followup.list" label="Followup" />
<menu id="customer.payment.check.pending.list" label="Customer checks" />
<menu id="customer.payment.check.pending.create" label="Pending checks" />
<menu id="customer.payment.sddMessage.list" label="SEPA Direct debit messages" />
<menu id="customer.credit.check.list" label="Credit checks" />
<menu id="customer.credit.check.create" label="Pending credit checks" />
<menu id="menu.payment.supplier" label="Supplier" />
226,6 → 227,7
<!-- Customer -->
<item id="customerrelationship.customer.address" label="Addresses" />
<item id="customerrelationship.customer.contact" label="Contacts" />
<item id="customerrelationship.customer.lead" label="Lead" />
<item id="customerrelationship.customer.sales" label="Sales" />
<item id="customerrelationship.customer.payment" label="Payment" />
<item id="customerrelationship.customer.contacts" label="Contacts" />
/trunk/OpenConcerto/src/org/openconcerto/erp/config/mappingCompta_en.xml
428,6 → 428,10
<FIELD name="TEL_P" label="Mobile" />
<FIELD name="FAX" label="Fax" />
<FIELD name="MAIL" label="Email" />
<FIELD name="ACCEPTE_EMAIL" label="Allow e-mail" titlelabel="E-mail OK" />
<FIELD name="ACCEPTE_COURRIER" label="Allow mail" titlelabel="Mail OK" />
<FIELD name="ACCEPTE_SMS" label="Allow SMS" titlelabel="SMS OK" />
<FIELD name="ACCEPTE_TEL" label="Allow voice call" titlelabel="Voice call OK" />
<FIELD name="RESPONSABLE" label="Manager" />
<FIELD name="RESPONSABLE_TECH" label="Technician" />
<FIELD name="RESPONSABLE_COM" label="Saleman" />
449,7 → 453,9
<FIELD name="MARCHE_PUBLIC" label="Public sector" />
<FIELD name="MARCHE_PRIVE" label="Private sector" />
<FIELD name="ID_ADRESSE_L" label="Delivery address" />
<FIELD name="RIB" label="RIB" titlelabel="RIB" />
<FIELD name="RIB" label="RIB" />
<FIELD name="IBAN" label="IBAN" />
<FIELD name="BIC" label="BIC" />
<FIELD name="SIRET" label="SIRET" titlelabel="SIRET" />
<FIELD name="ID_SECTEUR_ACTIVITE" label="Activity" />
<FIELD name="INFOS" label="Additionnal information" />
537,6 → 543,7
<FIELD name="SERVICE" label="Department" />
<FIELD name="PAYS" label="Country" />
<FIELD name="ID_ADRESSE" label="Address" />
<FIELD name="DATE_NAISSANCE" label="Date of birth" />
</TABLE>
 
<TABLE name="CONTACT_FOURNISSEUR">
1684,4 → 1691,19
<FIELD name="NOM" label="Label" />
</TABLE>
 
<TABLE name="SEPA_MANDATE">
<FIELD name="ID_CLIENT" label="Client" />
<FIELD name="MandateIdentification" label="Identifier" />
<FIELD name="DateOfSignature" label="Date of signature" titlelabel="Sign. date" />
<FIELD name="SequenceType" label="Sequence type" titlelabel="Seq. type" />
<FIELD name="ACTIVE" label="Active" />
</TABLE>
 
<TABLE name="SEPA_DIRECT_DEBIT_MESSAGE">
<FIELD name="MessageIdentification" label="Message identifier" />
<FIELD name="CreationDateTime" label="Creation date" />
<FIELD name="NumberOfTransactions" label="Number of transactions" />
<FIELD name="ControlSum" label="Control sum" />
<FIELD name="XML" label="XML message" />
</TABLE>
</ROOT>
/trunk/OpenConcerto/src/org/openconcerto/erp/config/DefaultMenuConfiguration.java
102,11 → 102,13
import org.openconcerto.erp.core.sales.invoice.action.ListeDesElementsFactureAction;
import org.openconcerto.erp.core.sales.invoice.action.ListeDesFactureItemsAction;
import org.openconcerto.erp.core.sales.invoice.action.ListeDesVentesAction;
import org.openconcerto.erp.core.sales.invoice.action.ListeSDDMessageAction;
import org.openconcerto.erp.core.sales.invoice.action.ListeSaisieVenteFactureAction;
import org.openconcerto.erp.core.sales.invoice.action.ListesFacturesClientsImpayeesAction;
import org.openconcerto.erp.core.sales.invoice.action.NouveauSaisieVenteComptoirAction;
import org.openconcerto.erp.core.sales.invoice.action.NouveauSaisieVenteFactureAction;
import org.openconcerto.erp.core.sales.order.action.ListeDesCommandesClientAction;
import org.openconcerto.erp.core.sales.order.action.ListeDesCommandesClientItemsAction;
import org.openconcerto.erp.core.sales.order.action.ListeDesElementsACommanderClientAction;
import org.openconcerto.erp.core.sales.order.action.ListeDesFacturationCommandesClientAction;
import org.openconcerto.erp.core.sales.order.action.NouvelleCommandeClientAction;
371,6 → 373,7
gCustomer.addItem("customer.payment.followup.list");
gCustomer.addItem("customer.payment.check.pending.list");
gCustomer.addItem("customer.payment.check.pending.create");
gCustomer.addItem("customer.payment.sddMessage.list");
gCustomer.addItem("customer.credit.check.list");
gCustomer.addItem("customer.credit.check.create");
group.add(gCustomer);
472,6 → 475,7
 
gCustomer.addItem("customer.order.list");
gCustomer.addItem("customer.order.invoice.list");
gCustomer.addItem("customer.order.list.details");
gCustomer.addItem("customer.delivery.list");
if (configuration.getRootSociete().contains("RELIQUAT_BR")) {
gCustomer.addItem("customer.delivery.reliquat.list");
606,6 → 610,7
 
mManager.putAction(new ListeDesCommandesClientAction(), "customer.order.list");
mManager.putAction(new ListeDesFacturationCommandesClientAction(), "customer.order.invoice.list");
mManager.putAction(new ListeDesCommandesClientItemsAction(), "customer.order.list.details");
mManager.putAction(new ListeDesBonsDeLivraisonAction(), "customer.delivery.list");
if (configuration.getRootSociete().contains("RELIQUAT_BL")) {
mManager.registerAction("customer.delivery.reliquat.list", new ListeDesReliquatsBonsLivraisonsAction());
730,6 → 735,7
mManager.putAction(new ListeDesRelancesAction(), "customer.payment.followup.list");
mManager.putAction(new ListeDesChequesAEncaisserAction(), "customer.payment.check.pending.list");
mManager.putAction(new NouveauListeDesChequesAEncaisserAction(), "customer.payment.check.pending.create");
mManager.putAction(new ListeSDDMessageAction(configuration.getDirectory()), "customer.payment.sddMessage.list");
mManager.putAction(new ListeDesChequesAvoirAction(), "customer.credit.check.list");
mManager.putAction(new NouveauDecaissementChequeAvoirAction(), "customer.credit.check.create");
}
/trunk/OpenConcerto/src/org/openconcerto/erp/config/mapping_fr.xml
283,6 → 283,7
<FIELD name="NUMERO_URSSAF" label="Identifiant personnel URSSAF" />
<FIELD name="ID_DEVISE" label="Devise" />
<FIELD name="ORG_PROTECTION_SOCIAL_ID" label="Siret URSSAF" />
<FIELD name="SEPA_CREDITOR_ID" label="Identifiant Créancier SEPA" />
</TABLE>
<TABLE name="TYPE_MODELE">
<FIELD name="NOM" label="Nom" />
/trunk/OpenConcerto/src/org/openconcerto/erp/config/update/Updater_1_5.java
14,6 → 14,10
package org.openconcerto.erp.config.update;
 
import org.openconcerto.erp.config.InstallationPanel;
import org.openconcerto.erp.core.finance.payment.element.SDDMessageSQLElement;
import org.openconcerto.erp.core.finance.payment.element.SEPAMandateSQLElement;
import org.openconcerto.erp.core.finance.payment.element.TypeReglementSQLElement;
import org.openconcerto.erp.core.sales.invoice.element.SaisieVenteFactureSQLElement;
import org.openconcerto.erp.core.sales.order.ui.TypeFactureCommandeClient;
import org.openconcerto.erp.core.sales.pos.element.TicketCaisseSQLElement;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
32,6 → 36,7
import org.openconcerto.sql.utils.ChangeTable;
import org.openconcerto.sql.utils.SQLCreateTable;
import org.openconcerto.sql.utils.UniqueConstraintCreatorHelper;
import org.openconcerto.utils.CollectionUtils;
 
import java.math.BigDecimal;
import java.sql.SQLException;
80,6 → 85,13
tClient.getSchema().updateVersion();
tClient.fetchFields();
}
if (!tClient.contains("DATE")) {
final AlterTable alterClient = new AlterTable(tClient);
alterClient.addColumn("DATE", "date");
tClient.getBase().getDataSource().execute(alterClient.asString());
tClient.getSchema().updateVersion();
tClient.fetchFields();
}
if (!tClient.contains("COMMENTAIRES")) {
final AlterTable alterClient = new AlterTable(tClient);
alterClient.addVarCharColumn("COMMENTAIRES", 2048);
235,7 → 247,7
tableAttachment.fetchFields();
}
 
List<String> gedTable = Arrays.asList("CLIENT", "MOUVEMENT", "FOURNISSEUR", "ARTICLE", "SALARIE");
List<String> gedTable = Arrays.asList("CLIENT", "MOUVEMENT", "FOURNISSEUR", "ARTICLE", "FACTURE_FOURNISSEUR", "SAISIE_VENTE_FACTURE", "SALARIE");
for (String string : gedTable) {
SQLTable tableGED = root.getTable(string);
if (!tableGED.contains("ATTACHMENTS")) {
273,7 → 285,7
if (!tableCmdElt.contains("LIVRE")) {
AlterTable t = new AlterTable(tableCmdElt);
t.addBooleanColumn("LIVRE_FORCED", Boolean.FALSE, false);
t.addBooleanColumn("LIVRE", Boolean.TRUE, false);
t.addBooleanColumn("LIVRE", Boolean.FALSE, false);
t.addDecimalColumn("QTE_LIVREE", 16, 6, BigDecimal.ZERO, true);
tableCmdElt.getBase().getDataSource().execute(t.asString());
root.refetchTable(tableCmdElt.getName());
299,6 → 311,15
// \"ID_COMMANDE_CLIENT\" IN []";
}
 
// Fix bad default value
if (tableCmdElt.contains("LIVRE")) {
AlterTable t = new AlterTable(tableCmdElt);
t.alterColumnDefault("LIVRE", "false");
tableCmdElt.getBase().getDataSource().execute(t.asString());
root.refetchTable(tableCmdElt.getName());
root.getSchema().updateVersion();
}
 
// Achat
 
SQLTable tableBRElt = root.getTable("BON_RECEPTION_ELEMENT");
864,6 → 885,14
tableArt.fetchFields();
}
 
if (!tableArt.contains("ADDITIONAL_TICKET_COPY")) {
final AlterTable alterArt = new AlterTable(tableArt);
alterArt.addBooleanColumn("ADDITIONAL_TICKET_COPY", Boolean.FALSE, false);
tableArt.getBase().getDataSource().execute(alterArt.asString());
tableArt.getSchema().updateVersion();
tableArt.fetchFields();
}
 
SQLTable tableDevisAcompte = root.getTable("DEVIS");
 
if (!tableDevisAcompte.contains("T_ACOMPTE")) {
1017,9 → 1046,9
}
// Prefs compte AN
SQLTable table = root.findTable("PREFS_COMPTE");
AlterTable t = new AlterTable(table);
 
if (!table.getFieldsName().contains("ID_JOURNAL_AN")) {
AlterTable t = new AlterTable(table);
t.addForeignColumn("ID_JOURNAL_AN", root.getTable("JOURNAL"));
t.addBooleanColumn("CREATE_NUL_SOLDE_ECR", Boolean.TRUE, false);
table.getBase().getDataSource().execute(t.asString());
1027,6 → 1056,14
table.fetchFields();
}
 
if (!table.getFieldsName().contains("AUTO_LETTRAGE")) {
AlterTable t = new AlterTable(table);
t.addBooleanColumn("AUTO_LETTRAGE", Boolean.FALSE, false);
table.getBase().getDataSource().execute(t.asString());
table.getSchema().updateVersion();
table.fetchFields();
}
 
SQLTable tableEcr = root.getTable("ECRITURE");
if (!tableEcr.contains("CLOTURE")) {
final AlterTable alter = new AlterTable(tableEcr);
1046,15 → 1083,72
tkmElt.getSchema().updateVersion();
tkmElt.fetchFields();
}
// Ref bancaires fournisseurs
if (!tableFournisseur.contains("IBAN")) {
final AlterTable alter = new AlterTable(tableFournisseur);
// Ref bancaires fournisseurs et clients
for (final SQLTable bankT : Arrays.asList(tableFournisseur, tClient)) {
if (!bankT.contains("IBAN")) {
final AlterTable alter = new AlterTable(bankT);
alter.addVarCharColumn("IBAN", 128);
alter.addVarCharColumn("BIC", 128);
tableFournisseur.getBase().getDataSource().execute(alter.asString());
tableFournisseur.getSchema().updateVersion();
tableFournisseur.fetchFields();
bankT.getDBSystemRoot().getDataSource().execute(alter.asString());
bankT.getSchema().updateVersion();
bankT.fetchFields();
}
}
final SQLTable typeReglT = root.getTable("TYPE_REGLEMENT");
if (typeReglT.getRow(TypeReglementSQLElement.PRELEVEMENT) == null) {
final SQLRowValues directDebitVals = new SQLRowValues(typeReglT).put("NOM", "Prélèvement");
directDebitVals.put("COMPTANT", Boolean.FALSE).put("ECHEANCE", Boolean.FALSE);
directDebitVals.setID(TypeReglementSQLElement.PRELEVEMENT).insertVerbatim();
}
if (!tableClient.contains("ACCEPTE_EMAIL")) {
final AlterTable alter = new AlterTable(tableClient);
alter.addBooleanColumn("ACCEPTE_EMAIL", Boolean.FALSE, false);
alter.addBooleanColumn("ACCEPTE_COURRIER", Boolean.FALSE, false);
alter.addBooleanColumn("ACCEPTE_SMS", Boolean.FALSE, false);
alter.addBooleanColumn("ACCEPTE_TEL", Boolean.FALSE, false);
exec(alter);
}
final SQLTable contactT = root.getTable("CONTACT");
if (!contactT.contains("DATE_NAISSANCE")) {
final AlterTable alter = new AlterTable(contactT);
alter.addColumn("DATE_NAISSANCE", "date");
exec(alter);
}
final SQLCreateTable createSDDMsgTable = SDDMessageSQLElement.getCreateTable(root);
if (createSDDMsgTable != null) {
final SQLCreateTable createMandate = SEPAMandateSQLElement.getCreateTable(root);
root.createTables(createSDDMsgTable, createMandate);
final SQLTable msgT = root.getTable(createSDDMsgTable.getName());
final SQLTable mandateT = root.getTable(createMandate.getName());
 
final AlterTable alterFact = new AlterTable(root.getTable(SaisieVenteFactureSQLElement.TABLENAME));
alterFact.addForeignColumn(SaisieVenteFactureSQLElement.MESSAGE_FIELD_NAME, msgT);
alterFact.addVarCharColumn(SaisieVenteFactureSQLElement.END2END_FIELD_NAME, 35);
 
final AlterTable alterModeRegl = new AlterTable(root.getTable("MODE_REGLEMENT"));
alterModeRegl.addForeignColumn(null, mandateT);
 
for (final String sql : ChangeTable.cat(Arrays.asList(alterFact, alterModeRegl))) {
root.getDBSystemRoot().getDataSource().execute(sql);
}
root.getSchema().updateVersion();
root.refetch(CollectionUtils.createSet(alterFact.getName(), alterModeRegl.getName()));
root.setMetadata(SDDMessageSQLElement.SERIAL_MD, "0");
}
 
final SQLTable vcT = root.getTable("SAISIE_VENTE_COMPTOIR");
if (!vcT.contains("ID_COMPTE_PCE_PRODUIT")) {
final AlterTable alter = new AlterTable(vcT);
alter.addForeignColumn("ID_COMPTE_PCE_PRODUIT", root.getTable("COMPTE_PCE"));
alter.addForeignColumn("ID_COMPTE_PCE_SERVICE", root.getTable("COMPTE_PCE"));
exec(alter);
}
 
}
 
public static void exec(final AlterTable alter) throws SQLException {
alter.getTable().getDBSystemRoot().getDataSource().execute(alter.asString());
alter.getTable().getSchema().updateVersion();
alter.getTable().fetchFields();
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/config/InstallationPanel.java
903,7 → 903,7
size = 2048;
else
// e.g. IDCC.NOM > 350
size = 1024;
size = 512;
alter.alterColumn(fName, EnumSet.allOf(Properties.class), "varchar(" + size + ")", "''", false);
}
}
918,12 → 918,8
}
 
for (final String sql : ChangeTable.cat(alters, root.getName())) {
try {
// ds.execute(sql);
} catch (Exception e) {
e.printStackTrace();
ds.execute(sql);
}
}
root.refetch();
}
 
3748,37 → 3744,6
 
if (ProductInfo.getInstance().getName().equalsIgnoreCase("OpenConcerto")) {
 
final SQLTable tableExercice = root.getTable("EXERCICE_COMMON");
 
// FIXME UPDATE Base ILM 1.2->1.3 la table EXERCERCIE ne contenait pas la clef
// ID_SOCIETE_COMMON
// if (tableExercice.contains("ID_SOCIETE_COMMON")) {
String reqUp = "UPDATE " + tableExercice.getSQLName().quote() + " SET \"ID_SOCIETE_COMMON\"=1 WHERE ";
reqUp += new Where(tableExercice.getKey(), 3, 49).getClause();
root.getDBSystemRoot().getDataSource().execute(reqUp);
 
String reqUp2 = "UPDATE " + tableExercice.getSQLName().quote() + " SET \"ID_SOCIETE_COMMON\"=1 WHERE ";
reqUp2 += new Where(tableExercice.getKey(), 53, 57).getClause();
root.getDBSystemRoot().getDataSource().execute(reqUp2);
// }
// rm ID 43 - 47 de SOCIETE_COMMON
final SQLTable tableSociete = root.getTable("SOCIETE_COMMON");
String req3 = "DELETE FROM " + tableSociete.getSQLName().quote() + " WHERE ";
req3 += new Where(tableSociete.getKey(), 43, 47).getClause();
root.getDBSystemRoot().getDataSource().execute(req3);
 
// rm ID 3 à 49 de EXERCICE_COMMON
 
String req1a = "DELETE FROM " + tableExercice.getSQLName().quote() + " WHERE ";
req1a += new Where(tableExercice.getKey(), 3, 49).getClause();
root.getDBSystemRoot().getDataSource().execute(req1a);
// et 53-57
root.getDBSystemRoot().getDataSource().execute(req1a);
String req1b = "DELETE FROM " + tableExercice.getSQLName().quote() + " WHERE ";
req1b += new Where(tableExercice.getKey(), 53, 57).getClause();
root.getDBSystemRoot().getDataSource().execute(req1b);
//
 
// TACHE_COMMON, ID_USER_COMMON_*=0 -> 1
for (final String f : Arrays.asList("ID_USER_COMMON_TO", "ID_USER_COMMON_CREATE", "ID_USER_COMMON_ASSIGN_BY")) {
final SQLTable tableTache = root.getTable("TACHE_COMMON");
3799,6 → 3764,13
}
}
 
final SQLTable sociétéT = root.getTable("SOCIETE_COMMON");
if (!sociétéT.contains("SEPA_CREDITOR_ID")) {
final AlterTable alter = new AlterTable(sociétéT);
alter.addVarCharColumn("SEPA_CREDITOR_ID", 16);
Updater_1_5.exec(alter);
}
 
// FK
new AddFK(root.getDBSystemRoot()).changeAll(root);
}
3935,8 → 3907,19
}
}
 
if (!table.getFieldsName().contains("SITE_WEB")) {
AlterTable t2 = new AlterTable(table);
t2.addVarCharColumn("SITE_WEB", 128);
 
t2.alterColumn("CAPITAL", EnumSet.allOf(Properties.class), "numeric(16,2)", "0", false);
table.getBase().getDataSource().execute(t2.asString());
table.getSchema().updateVersion();
table.fetchFields();
 
}
 
}
 
private void updateVille(SQLTable tableAdresse) throws SQLException {
 
if (tableAdresse != null && tableAdresse.getField("CODE_POSTAL").getType().getJavaType() == Integer.class) {
4034,7 → 4017,73
}
 
// Paye simplifiee
List<SQLRow> rowRubriqueReduGvt = new ArrayList<>();
{
 
final SQLTable tableRCom = conf.getRoot().getTable("RUBRIQUE_COMM");
if (!tableRCom.contains("REDUCTION_GVT_COM")) {
final AlterTable alter = new AlterTable(tableRCom);
alter.addBooleanColumn("REDUCTION_GVT_COM", Boolean.FALSE, false);
final String req = alter.asString();
conf.getRoot().getDBSystemRoot().getDataSource().execute(req);
conf.getRoot().refetchTable(tableRCom.getName());
conf.getRoot().getSchema().updateVersion();
 
SQLRowValues rowValsCommChom = new SQLRowValues(tableRCom);
rowValsCommChom.put("TAUX_SAL", "1.45;");
rowValsCommChom.put("NB_BASE", "SAL_BRUT;");
rowValsCommChom.put("NOM", "Assurance chômage reduction 2018");
rowValsCommChom.put("CODE", "OC_REDUCTION_CHOMAGE");
rowValsCommChom.put("MONTANT_SAL_DED", "SAL_BRUT * 0.0145;");
rowValsCommChom.put("NB_BASE", "SAL_BRUT;");
rowValsCommChom.put("ID_IMPRESSION_RUBRIQUE", 4);
rowValsCommChom.put("REDUCTION_GVT_COM", Boolean.TRUE);
rowValsCommChom.putRowValues("ID_PERIODE_VALIDITE").put("JANVIER", Boolean.TRUE);
rowRubriqueReduGvt.add(rowValsCommChom.commit());
 
SQLRowValues rowValsCommMaladie = new SQLRowValues(tableRCom);
rowValsCommMaladie.put("TAUX_SAL", "0.75;");
rowValsCommMaladie.put("NB_BASE", "SAL_BRUT;");
rowValsCommMaladie.put("NOM", "Assurance maladie reduction 2018");
rowValsCommMaladie.put("CODE", "OC_REDUCTION_MALADIE");
rowValsCommMaladie.put("MONTANT_SAL_DED", "SAL_BRUT * 0.0075;");
rowValsCommMaladie.put("NB_BASE", "SAL_BRUT;");
rowValsCommMaladie.put("ID_IMPRESSION_RUBRIQUE", 4);
rowValsCommMaladie.put("REDUCTION_GVT_COM", Boolean.TRUE);
rowValsCommMaladie.putRowValues("ID_PERIODE_VALIDITE").put("JANVIER", Boolean.TRUE);
rowRubriqueReduGvt.add(rowValsCommMaladie.commit());
 
SQLRowValues rowValsCommCSG = new SQLRowValues(tableRCom);
rowValsCommCSG.put("TAUX_SAL", "1.7;");
rowValsCommCSG.put("NB_BASE", "CSG;");
rowValsCommCSG.put("NOM", "CSG augmentation 2018");
rowValsCommCSG.put("CODE", "OC_AUGMENTATION_CSG");
rowValsCommCSG.put("MONTANT_SAL_AJ", "CSG * 0.017;");
rowValsCommCSG.put("NB_BASE", "CSG;");
rowValsCommCSG.put("ID_IMPRESSION_RUBRIQUE", 4);
rowValsCommCSG.put("REDUCTION_GVT_COM", Boolean.TRUE);
rowValsCommCSG.putRowValues("ID_PERIODE_VALIDITE").put("JANVIER", Boolean.TRUE);
rowRubriqueReduGvt.add(rowValsCommCSG.commit());
 
SQLSelect sel = new SQLSelect();
sel.addSelect(conf.getRoot().getTable("PROFIL_PAYE").getKey());
List<SQLRow> rowsProfil = SQLRowListRSH.execute(sel);
int pos = 70;
for (SQLRow rowRub : rowRubriqueReduGvt) {
for (SQLRow rowProfil : rowsProfil) {
 
SQLRowValues rowValsRubGvt = new SQLRowValues(conf.getRoot().getTable("PROFIL_PAYE_ELEMENT"));
rowValsRubGvt.put("ID_PROFIL_PAYE", rowProfil.getID());
rowValsRubGvt.put("POSITION", pos);
rowValsRubGvt.put("IDSOURCE", rowRub.getID());
rowValsRubGvt.put("SOURCE", rowRub.getTable().getName());
rowValsRubGvt.put("NOM", rowRub.getString("NOM"));
rowValsRubGvt.commit();
}
pos++;
}
}
 
final SQLTable tableRB = conf.getRoot().getTable("RUBRIQUE_BRUT");
if (!tableRB.contains("AVANTAGE_NATURE")) {
final AlterTable alter = new AlterTable(tableRB);
4125,7 → 4174,7
alter.addVarCharColumn("NUMERO_COMPTE_PCE_CHARGES", 128);
final String req = alter.asString();
conf.getRoot().getDBSystemRoot().getDataSource().execute(req);
conf.getRoot().refetchTable(tableCaisse.getName());
conf.getRoot().refetchTable(tableRnet.getName());
conf.getRoot().getSchema().updateVersion();
}
 
4314,6 → 4363,37
updateVille(root.getTable("ADRESSE"));
 
Updater_1_5.update(root);
SQLTable tableFpaye = root.getTable("FICHE_PAYE");
if (!tableFpaye.contains("REDUCTION_GVT")) {
final AlterTable alterB = new AlterTable(tableFpaye);
alterB.addDecimalColumn("REDUCTION_GVT", 16, 2, BigDecimal.ZERO, false);
root.getBase().getDataSource().execute(alterB.asString());
root.refetchTable("FICHE_PAYE");
root.getSchema().updateVersion();
 
SQLSelect sel = new SQLSelect();
sel.addSelect(root.getTable("SALARIE").getKey());
sel.addSelect(root.getTable("SALARIE").getField("ID_FICHE_PAYE"));
List<SQLRow> rowsSal = SQLRowListRSH.execute(sel);
int pos = 70;
for (SQLRow rowRub : rowRubriqueReduGvt) {
for (SQLRow rowSal : rowsSal) {
 
SQLRowValues rowValsRubGvt = new SQLRowValues(root.getTable("FICHE_PAYE_ELEMENT"));
rowValsRubGvt.put("ID_FICHE_PAYE", rowSal.getForeignID("ID_FICHE_PAYE"));
rowValsRubGvt.put("POSITION", pos);
rowValsRubGvt.put("IDSOURCE", rowRub.getID());
rowValsRubGvt.put("SOURCE", rowRub.getTable().getName());
rowValsRubGvt.put("NOM", rowRub.getString("NOM"));
rowValsRubGvt.put("IN_PERIODE", Boolean.TRUE);
rowValsRubGvt.put("IMPRESSION", Boolean.FALSE);
rowValsRubGvt.put("VALIDE", Boolean.FALSE);
rowValsRubGvt.commit();
}
pos++;
}
}
 
return null;
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/config/mapping_en.xml
192,6 → 192,7
<FIELD name="CAPITAL" label="Capital" />
<FIELD name="NUMERO_URSSAF" label="URSSAF number" />
<FIELD name="ID_DEVISE" label="Currency" />
<FIELD name="SEPA_CREDITOR_ID" label="SEPA Creditor Identifier" />
</TABLE>
 
<TABLE name="TYPE_MODELE">
/trunk/OpenConcerto/src/org/openconcerto/erp/config/SQLElementNames_fr.xml
2,6 → 2,8
<element refid="CONTACT" nameClass="masculine" name="contact" />
<element refid="CONTACT_FOURNISSEUR" nameClass="masculine" name="contact fournisseur" namePlural="contacts fournisseurs" />
<element refid="CONTACT_ADMINISTRATIF" nameClass="masculine" name="contact administratif" namePlural="contacts administratifs" />
<element refid="CATEGORIE_CLIENT" nameClass="feminine" name="Catégorie de client" />
<element refid="customerrelationship.customer.category" nameClass="feminine" name="catégorie de client" />
<element refid="FAMILLE_ECO_CONTRIBUTION" nameClass="feminine" name="Famille d'éco contribution" />
<element refid="finance.payment.SDDMessage" nameClass="masculine" name="ordre de prélèvement SEPA" namePlural="ordres de prélèvement SEPA" />
<element refid="finance.payment.SEPAMandate" nameClass="masculine" name="mandat SEPA" namePlural="mandats SEPA" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/erp/config/translation_fr.xml
110,6 → 110,7
<menu id="customer.payment.followup.list" label="Liste des relances" />
<menu id="customer.payment.check.pending.list" label="Chèques des clients" />
<menu id="customer.payment.check.pending.create" label="Chèques à encaisser" />
<menu id="customer.payment.sddMessage.list" label="Liste des ordres de prélèvement SEPA" />
<menu id="customer.credit.check.list" label="Chèques d'avoir" />
<menu id="customer.credit.check.create" label="Chèques d'avoir à décaisser" />
<menu id="menu.payment.supplier" label="Fournisseurs" />
247,6 → 248,7
<item id="invoice.address.same.main.address" label="Adresse identique à l'adresse du siège" />
<item id="customerrelationship.customer.address" label="Adresses" />
<item id="customerrelationship.customer.contact" label="Contacts" />
<item id="customerrelationship.customer.lead" label="Prospection" />
<item id="customerrelationship.customer.sales" label="Ventes" />
<item id="customerrelationship.customer.payment" label="Paiements" />
<item id="customerrelationship.customer.contacts" label="Personnes à contacter chez le client" />
290,7 → 292,7
<item id="retraite.trancheC" label="Complémentaire Tranche C" />
<item id="retraite.supplementaire" label="Supplémentaire" />
<item id="famille.famille.allocations" label="Allocations familiales" />
<item id="famille.famille.securite" label="Famille-SECURITE SOCIALE" />
<item id="famille.famille.securite" label="FAMILLE" />
<item id="chomage.chomage" label="Chômage" />
<item id="chomage.apec" label="APEC" />
 
298,7 → 300,7
<item id="autres.contributions.ligne" label="Autres contributions dues par l'employeur" />
<item id="csg.nonimp.ligne" label="CSG non imposable à l'impôt sur le revenu" />
<item id="csg.imp.ligne" label="CSG/CRDS imposable à l'impôt sur le revenu" />
<item id="allegement.cotisations.ligne" label="Allégement de cotisations" />
<item id="allegement.cotisations.ligne" label="Exonération de cotisations employeur" />
<item id="paye.simplifie.ignore" label="Ligne ignorée" />
 
<!-- Groupe Paye Simplifiée -->
311,8 → 313,8
<item id="chomage.cadre" label="ASSURANCE CHÔMAGE" />
<item id="autres" label="AUTRES CONTRIBUTIONS DUES PAR L'EMPLOYEUR" />
<item id="cotisations.convention" label="COTISATIONS DE CONVENTION COLLECTIVE OU STATUAIRES" />
<item id="csg.nonimp" label="CSG/CRDS non imposable à l'impôt sur le revenu" />
<item id="csg.imp" label="CSG/CRDS imposable à l'impôt sur le revenu" />
<item id="csg.nonimp" label="CSG/CRDS déductible de l'impôt sur le revenu" />
<item id="csg.imp" label="CSG/CRDS non déductible à l'impôt sur le revenu" />
<item id="allegement" label="ALLEGEMENT DE COTISATIONS" />
 
</translation>
/trunk/OpenConcerto/src/org/openconcerto/erp/config/mappingCompta_fr.xml
581,6 → 581,9
<FIELD name="NUMERO" label="Numéro" />
</TABLE>
 
<TABLE name="CATEGORIE_CLIENT">
<FIELD name="NOM" label="Catégorie client" />
</TABLE>
 
<TABLE name="CATEGORIE_COMPTABLE">
<FIELD name="NOM" label="Nom" titlelabel="Catégorie" />
676,6 → 679,10
<FIELD name="TEL_P" label="Portable" titlelabel="Portable" />
<FIELD name="FAX" label="Fax" titlelabel="Fax" />
<FIELD name="MAIL" label="Mail" titlelabel="Mail" />
<FIELD name="ACCEPTE_EMAIL" label="Accepte e-mail" titlelabel="E-mail OK" />
<FIELD name="ACCEPTE_COURRIER" label="Accepte courrier" titlelabel="Courrier OK" />
<FIELD name="ACCEPTE_SMS" label="Accepte SMS" titlelabel="SMS OK" />
<FIELD name="ACCEPTE_TEL" label="Accepte appel téléphonique" titlelabel="Appel tél. OK" />
<FIELD name="RESPONSABLE" label="Responsable" titlelabel="Responsable" />
<FIELD name="RESPONSABLE_TECH" label="Responsable tech." titlelabel="Responsable tech." />
<FIELD name="RESPONSABLE_COM" label="Responsable comm." titlelabel="Responsable comm." />
699,7 → 706,9
<FIELD name="ID_ADRESSE_L" label="Adresse de livraison" titlelabel="Adresse livraison" />
<FIELD name="ID_ADRESSE_L_2" label="Adresse de livraison" titlelabel="Adresse livraison 2" />
<FIELD name="ID_ADRESSE_L_3" label="Adresse de livraison" titlelabel="Adresse livraison 3" />
<FIELD name="RIB" label="RIB" titlelabel="RIB" />
<FIELD name="RIB" label="RIB" />
<FIELD name="IBAN" label="IBAN" />
<FIELD name="BIC" label="BIC" />
<FIELD name="SIRET" label="SIRET" titlelabel="SIRET" />
<FIELD name="ID_SECTEUR_ACTIVITE" label="Secteur d'activité" titlelabel="Secteur d'activité" />
<FIELD name="ID_BANQUE_POLE_PRODUIT" label="Banque" titlelabel="Banque" />
822,6 → 831,7
<FIELD name="SERVICE" label="Service" />
<FIELD name="PAYS" label="Pays" />
<FIELD name="ID_ADRESSE" label="Adresse" />
<FIELD name="DATE_NAISSANCE" label="Date de naissance" />
</TABLE>
 
<TABLE name="CONTACT_FOURNISSEUR">
2202,6 → 2212,8
 
 
<TABLE name="SAISIE_VENTE_COMPTOIR">
<FIELD name="ID_COMPTE_PCE_PRODUIT" label="Cpt spécifique produit" />
<FIELD name="ID_COMPTE_PCE_SERVICE" label="Cpt spécifique service" />
<FIELD name="NOM" label="Libellé" />
<FIELD name="ID_ARTICLE" label="Article" titlelabel="Article" />
<FIELD name="DATE" label="Date" titlelabel="Date" />
2273,6 → 2285,7
<FIELD name="COMPTE_SERVICE_AUTO" label="Gestion automatique du compte de service" titlelabel="Gestion automatique du compte de service" />
<FIELD name="ID_TARIF" label="Tarif à appliquer" />
<FIELD name="T_ECO_CONTRIBUTION" label="Dont Eco-Contrib." />
<FIELD name="ID_SDD_MESSAGE" label="Ordre de prélèvement SEPA" titlelabel="Prélèv. SEPA" />
</TABLE>
<TABLE name="SAISIE_VENTE_FACTURE_ELEMENT">
<FIELD name="ID_DEPOT_STOCK" label="Dépôt Stock" />
2439,6 → 2452,8
<FIELD name="ID_COMPTE_PCE_DED" label="Compte TVA déductible" />
<FIELD name="ID_COMPTE_PCE_VENTE" label="Compte produits par défaut (classe 7)" />
<FIELD name="ID_COMPTE_PCE_SERVICE" label="Compte services par défaut (classe 7)" />
<FIELD name="ID_COMPTE_PCE_COLLECTE_INTRA" label="Compte TVA collectée intra." />
<FIELD name="ID_COMPTE_PCE_DED_INTRA" label="Compte TVA déductible intra." />
</TABLE>
 
<TABLE name="TAXE_COMPLEMENTAIRE">
2497,4 → 2512,19
<FIELD name="NOM" label="Libellé" />
</TABLE>
 
<TABLE name="SEPA_MANDATE">
<FIELD name="ID_CLIENT" label="Client" />
<FIELD name="MandateIdentification" label="Identifiant" />
<FIELD name="DateOfSignature" label="Date de signature" titlelabel="Date sign." />
<FIELD name="SequenceType" label="Type de séquence" titlelabel="Type de séq." />
<FIELD name="ACTIVE" label="Actif" />
</TABLE>
 
<TABLE name="SEPA_DIRECT_DEBIT_MESSAGE">
<FIELD name="MessageIdentification" label="Identifiant du message" />
<FIELD name="CreationDateTime" label="Date de création" />
<FIELD name="NumberOfTransactions" label="Nombre de prélèvements" />
<FIELD name="ControlSum" label="Total des prélèvements" />
<FIELD name="XML" label="Message XML" />
</TABLE>
</ROOT>
/trunk/OpenConcerto/src/org/openconcerto/erp/modules/DBContext.java
24,7 → 24,7
import org.openconcerto.sql.utils.SQLCreateTableBase;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.SetMap;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.IExnClosure;
 
import java.io.File;
import java.sql.SQLException;
48,9 → 48,9
private final DBRoot root;
private final SQLElementDirectory elemDir;
private final List<ChangeTable<?>> changeTables;
private int changeTablesIndex = 0;
// subset of this.changeTables
private final List<AlterTableRestricted> alterTables;
// Data Manipulation
private final List<IClosure<? super DBRoot>> dm;
 
private final Set<String> tables;
private final SetMap<String, SQLField> fields;
71,7 → 71,6
this.elemDir = elemDir;
this.changeTables = new ArrayList<ChangeTable<?>>();
this.alterTables = new ArrayList<AlterTableRestricted>();
this.dm = new ArrayList<IClosure<? super DBRoot>>();
}
 
public final File getLocalDirectory() {
102,12 → 101,17
return this.fields.getNonNull(tableName);
}
 
private final List<String> getSQL() {
return ChangeTable.cat(this.changeTables, this.root.getName());
}
 
final void execute() throws SQLException {
final List<String> sql = this.getSQL();
/**
* Allow to execute all pending DDL changes. Automatically called at the end of
* {@link AbstractModule#install(DBContext)} by {@link ModuleManager}. For example, one could
* create a new field, call this method, fill the new field with a function needing another old
* field, and finally drop the old field.
*
* @throws SQLException if an error occurs.
*/
public final void executeSQL() throws SQLException {
final List<ChangeTable<?>> toDo = this.changeTables.subList(this.changeTablesIndex, this.changeTables.size());
final List<String> sql = ChangeTable.cat(toDo, this.root.getName());
// refetch() is costly
if (sql.size() > 0) {
for (final String s : sql)
115,16 → 119,14
 
// perhaps add a Map parameter to getCreateTable() for the undefined row
// for now OK to not use an undefined row since we can't modify List/ComboSQLRequet
SQLTable.setUndefIDs(getRoot().getSchema(), CollectionUtils.<String, Number> createMap(getAddedTables()));
SQLTable.setUndefIDs(getRoot().getSchema(), CollectionUtils.<String, Number> createMap(getCreateTables(toDo).keySet()));
 
// always updateVersion() after setUndefID(), see DBRoot.createTables()
getRoot().getSchema().updateVersion();
getRoot().refetch();
}
for (final IClosure<? super DBRoot> closure : this.dm) {
closure.executeChecked(getRoot());
this.changeTablesIndex = this.changeTables.size();
}
}
 
// DDL
 
165,9 → 167,12
* inserting rows in a created table, since it will be automatically dropped).
*
* @param closure what to do.
* @throws SQLException if an error occurs.
* @deprecated no longer needed, just call {@link #executeSQL()} before accessing the DB.
*/
public final void manipulateData(final IClosure<? super DBRoot> closure) {
this.dm.add(closure);
public final void manipulateData(final IExnClosure<? super DBRoot, SQLException> closure) throws SQLException {
executeSQL();
closure.executeChecked(getRoot());
}
 
/**
176,26 → 181,24
*
* @param name a table name.
* @param closure what to do.
* @see #manipulateData(IClosure)
* @throws SQLException if an error occurs.
* @deprecated no longer needed, just call {@link #executeSQL()} before accessing the DB.
* @see #manipulateData(IExnClosure)
*/
public final void manipulateTable(final String name, final IClosure<SQLTable> closure) {
this.manipulateData(new IClosure<DBRoot>() {
@Override
public void executeChecked(DBRoot input) {
closure.executeChecked(input.getTable(name));
public final void manipulateTable(final String name, final IExnClosure<? super SQLTable, SQLException> closure) throws SQLException {
executeSQL();
closure.executeChecked(getRoot().getTable(name));
}
});
}
 
// getter
 
final List<String> getAddedTables() {
return new ArrayList<String>(getCreateTables().keySet());
return new ArrayList<String>(getCreateTables(this.changeTables).keySet());
}
 
final Map<String, SQLCreateTableBase<?>> getCreateTables() {
private static final Map<String, SQLCreateTableBase<?>> getCreateTables(final List<ChangeTable<?>> l) {
final Map<String, SQLCreateTableBase<?>> res = new LinkedHashMap<String, SQLCreateTableBase<?>>();
for (final ChangeTable<?> a : this.changeTables) {
for (final ChangeTable<?> a : l) {
if (a instanceof SQLCreateTableBase<?>) {
res.put(a.getName(), (SQLCreateTableBase<?>) a);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/modules/ElementContext.java
39,4 → 39,12
}
return element;
}
 
public final <T extends SQLElement> T getElement(final Class<T> clazz) {
final T element = this.dir.getElement(clazz);
if (element == null) {
throw new IllegalArgumentException("Not element found for " + clazz);
}
return element;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/modules/ModulePanel.java
18,6 → 18,7
import org.openconcerto.erp.modules.ModuleTableModel.Columns;
import org.openconcerto.erp.modules.ModuleTableModel.ModuleRow;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.table.AlternateTableCellRenderer;
import org.openconcerto.ui.table.TableCellRendererDecorator.TableCellRendererDecoratorUtils;
import org.openconcerto.utils.ExceptionHandler;
90,6 → 91,7
t.setRowSelectionAllowed(false);
t.setColumnSelectionAllowed(false);
t.setCellSelectionEnabled(false);
t.setRowHeight(FontUtils.getPreferredRowHeight(t));
final TableColumnModel columnModel = t.getColumnModel();
final TableCellRenderer headerDefaultRenderer = t.getTableHeader().getDefaultRenderer();
final EnumSet<Columns> booleanCols = EnumSet.of(ModuleTableModel.Columns.LOCAL, ModuleTableModel.Columns.REMOTE, ModuleTableModel.Columns.DB_REQUIRED, ModuleTableModel.Columns.ADMIN_REQUIRED);
244,13 → 246,14
}
 
if (deniedRefs.size() > 0) {
JOptionPane
.showMessageDialog(ModulePanel.this, "Désinstallation refusée pour les modules :" + formatList(deniedRefs), dialogTitle, JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(ModulePanel.this, "Désinstallation refusée pour les modules :" + formatList(deniedRefs), dialogTitle,
JOptionPane.WARNING_MESSAGE);
return;
}
 
final int selectAnswer = JOptionPane.showConfirmDialog(ModulePanel.this, "Les modules suivants doivent être désinstallés : \n" + formatList(dependentModules)
+ ".\nVoulez-vous également désinstaller ces modules ?", dialogTitle, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
final int selectAnswer = JOptionPane.showConfirmDialog(ModulePanel.this,
"Les modules suivants doivent être désinstallés : \n" + formatList(dependentModules) + ".\nVoulez-vous également désinstaller ces modules ?", dialogTitle,
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if (selectAnswer == JOptionPane.NO_OPTION)
return;
}
311,8 → 314,8
throw new IllegalArgumentException(action + " is neither START nor STOP");
this.action = action;
this.start = action == ModuleAction.START;
this.putValue(Action.SHORT_DESCRIPTION, this.start ? "Démarrer le(s) module(s), maintenir CTRL pour rendre obligatoire le démarrage"
: "Arrête le(s) module(s), maintenir CTRL pour rendre facultatif le démarrage");
this.putValue(Action.SHORT_DESCRIPTION,
this.start ? "Démarrer le(s) module(s), maintenir CTRL pour rendre obligatoire le démarrage" : "Arrête le(s) module(s), maintenir CTRL pour rendre facultatif le démarrage");
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/modules/AbstractModule.java
20,6 → 20,7
 
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
82,8 → 83,10
* necessary in {@link #uninstall(DBRoot)}.
*
* @param ctxt to create database objects.
* @throws SQLException if a DB error occurs.
* @throws IOException if a local error occurs.
*/
protected void install(DBContext ctxt) {
protected void install(DBContext ctxt) throws SQLException, IOException {
 
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/modules/ModuleManager.java
492,8 → 492,8
 
SQLPreferences.getPrefTable(this.getRoot());
 
final List<ModuleReference> requiredModules = this.getDBRequiredModules();
requiredModules.addAll(getAdminRequiredModules());
final List<ModuleReference> requiredModules = new ArrayList<>(this.getAdminRequiredModules());
final List<ModuleReference> dbRequiredModules = new ArrayList<>(this.getDBRequiredModules());
// add modules previously chosen (before restart)
final File toInstallFile = this.getToInstallFile();
Set<ModuleReference> toInstall = Collections.emptySet();
549,6 → 549,20
}
}
}
// handle upgrades : the old version was not uninstalled and thus still in
// dbRequiredModules, and the new version is in toInstall, so the DepSolver will error out
// since both can't be installed at the same time.
for (final ModuleReference toInstallRef : toInstall) {
final Iterator<ModuleReference> iter = dbRequiredModules.iterator();
while (iter.hasNext()) {
final ModuleReference dbReqRef = iter.next();
if (dbReqRef.getID().equals(toInstallRef.getID())) {
L.config("Ignoring DB required " + dbReqRef + " because " + toInstallRef + " was requested from the last exit");
iter.remove();
}
}
}
requiredModules.addAll(dbRequiredModules);
requiredModules.addAll(toInstall);
 
// if there's some choice to make, let the user make it
584,8 → 598,17
}
 
public final boolean needExit(final ModulesStateChange solution) {
return solution.getReferencesToRemove().size() > 0;
final Set<ModuleReference> refsToRemove = solution.getReferencesToRemove();
if (!refsToRemove.isEmpty()) {
// only need to exit if the module is loaded into memory
final Set<ModuleReference> registeredModules = this.getRegisteredModules();
for (final ModuleReference toRemove : refsToRemove) {
if (registeredModules.contains(toRemove))
return true;
}
}
return false;
}
 
// Preferences is thread-safe
private Preferences getPrefs() {
1023,8 → 1046,7
if (!localDir.exists())
throw new IOException("Modules shouldn't remove their directory");
// install in DB
if (!dbOK)
ctxt.execute();
ctxt.executeSQL();
updateModuleFields(factory, graph, ctxt);
return null;
}
1056,7 → 1078,7
assert moduleVersion.equals(getModuleVersionInstalledLocally(factory.getID())) && moduleVersion.equals(getDBInstalledModuleVersion(factory.getID()));
}
 
private void registerSQLElements(final AbstractModule module) throws IOException {
private void registerSQLElements(final AbstractModule module, Map<SQLTable, SQLElement> beforeElements) throws IOException {
final ModuleReference id = module.getFactory().getReference();
synchronized (this.modulesElements) {
// perhaps check that no other version of the module has been registered
1066,7 → 1088,6
final Set<SQLTable> tablesWithMD = loadTranslations(getConf().getTranslator(), module, mdVariant);
 
final SQLElementDirectory dir = getDirectory();
final Map<SQLTable, SQLElement> beforeElements = new HashMap<SQLTable, SQLElement>(dir.getElementsMap());
module.setupElements(dir);
final IdentityHashMap<SQLElement, SQLElement> elements = new IdentityHashMap<SQLElement, SQLElement>();
// use IdentitySet so as not to call equals() since it triggers initFF()
1159,6 → 1180,15
}
}
 
final Set<SQLElement> getRegisteredElements(final ModuleReference ref) {
synchronized (this.modulesElements) {
final IdentityHashMap<SQLElement, SQLElement> map = this.modulesElements.get(ref);
if (map == null || map.isEmpty())
return Collections.emptySet();
return Collections.unmodifiableSet(new HashSet<SQLElement>(map.keySet()));
}
}
 
private void setupComponents(final AbstractModule module, final Tuple2<Set<String>, Set<SQLName>> alreadyCreatedItems, final MenuAndActions ma) throws SQLException {
assert SwingUtilities.isEventDispatchThread();
final String id = module.getFactory().getID();
1513,6 → 1543,9
throw new IllegalStateException("Installation state has changed since getSolutions()");
}
 
// call it before stopping/uninstalling
final boolean exit = this.isExitAllowed() && this.needExit(change);
 
final Set<ModuleReference> toRemove = change.getReferencesToRemove();
final Set<ModuleReference> removed;
if (toRemove.size() > 0) {
1535,7 → 1568,7
 
// MAYBE compare states with targetState to avoid going further (e.g ids are all started)
 
if (this.isExitAllowed() && this.needExit(change)) {
if (exit) {
// restart to make sure the uninstalled modules are really gone from the memory and
// none of its effects present. We could check that the class loader for the module
// is garbage collected, but
1748,6 → 1781,9
private final void installAndRegister(final AbstractModule module, DepSolverGraph graph) throws Exception {
assert Thread.holdsLock(this);
assert !isModuleRunning(module.getFactory().getID());
// Snapshot now to allow install() to register and use its own elements
// Also needed for checks, since install() can do arbitrary changes to the directory
final Map<SQLTable, SQLElement> beforeElements = new HashMap<SQLTable, SQLElement>(getDirectory().getElementsMap());
try {
install(module, graph);
} catch (Exception e) {
1754,7 → 1790,7
throw new Exception("Couldn't install module " + module, e);
}
try {
this.registerSQLElements(module);
this.registerSQLElements(module, beforeElements);
} catch (Exception e) {
throw new Exception("Couldn't register module " + module, e);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/DmdPrixCmdSQLInjector.java
New file
0,0 → 1,27
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.injector;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLInjector;
 
public class DmdPrixCmdSQLInjector extends SQLInjector {
public DmdPrixCmdSQLInjector(final DBRoot root) {
super(root, "DEMANDE_PRIX", "COMMANDE", true);
createDefaultMap();
remove(getSource().getField("DATE"), getDestination().getField("DATE"));
remove(getSource().getField("NUMERO"), getDestination().getField("NUMERO"));
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SpreadSheetCellValueContext.java
64,4 → 64,8
public void put(String name, String value) {
map.put(name, value);
}
 
public Object get(String name) {
return map.get(name);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SheetXml.java
326,7 → 326,7
*/
public String getTemplateId() {
if (this.row != null && this.row.getTable().getFieldsName().contains("ID_MODELE")) {
if (row.isForeignEmpty("ID_MODELE")) {
if (row.getObject("ID_MODELE") == null || row.isForeignEmpty("ID_MODELE")) {
TypeModeleSQLElement typeModele = Configuration.getInstance().getDirectory().getElement(TypeModeleSQLElement.class);
String modele = typeModele.getTemplateMapping().get(this.row.getTable().getName());
if (modele == null) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractSheetXMLWithDate.java
27,9 → 27,13
 
protected final String getYear() {
Calendar cal = null;
 
if (this.row.getTable().contains("DATE")) {
cal = this.row.getDate("DATE");
}
if (this.row.getTable().contains("DU")) {
cal = this.row.getDate("DU");
}
return cal == null ? "Date inconnue" : String.valueOf(cal.get(Calendar.YEAR));
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/TotalAcompteProvider.java
16,7 → 16,6
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueContext;
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueProvider;
import org.openconcerto.erp.generationDoc.SpreadSheetCellValueProviderManager;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
 
import java.math.BigDecimal;
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtReglementChequeClient.java
22,10 → 22,13
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.utils.StringUtils;
 
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
public class GenerationMvtReglementChequeClient extends GenerationEcritures {
 
60,6 → 63,8
SQLRow chequeRow = base.getTable("CHEQUE_A_ENCAISSER").getRow(this.idCheque);
SQLRow clientRow = base.getTable("CLIENT").getRow(chequeRow.getInt("ID_CLIENT"));
 
this.nom = this.nom + " " + StringUtils.limitLength(clientRow.getString("NOM"), 20);
 
// initialisation des valeurs de la map
this.putValue("DATE", new java.sql.Date(this.date.getTime()));
this.putValue("NOM", this.nom);
104,6 → 109,11
this.putValue("DEBIT", new Long(this.montant));
this.putValue("CREDIT", new Long(0));
ajoutEcriture();
 
List<Integer> pieceIDs = new ArrayList<Integer>();
pieceIDs.add(mouvementTable.getRow(idMvt).getForeignID("ID_PIECE"));
lettrageAuto(pieceIDs, this.date);
 
System.err.println("Ecritures générées pour le mouvement " + this.idMvt);
 
}
122,9 → 132,7
rowValsUpdateVF.put("DATE_REGLEMENT", new Timestamp(d.getTime()));
rowValsUpdateVF.update();
}
 
}
 
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationEcritures.java
15,6 → 15,7
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.element.BanqueSQLElement;
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement;
import org.openconcerto.erp.core.common.ui.TotalCalculator;
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.JournalSQLElement;
23,12 → 24,16
import org.openconcerto.erp.preferences.DefaultNXProps;
import org.openconcerto.erp.preferences.GestionPieceCommercialePanel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLBackgroundTableCache;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.utils.ExceptionHandler;
 
579,4 → 584,66
 
this.mEcritures.put("ID_COMPTE_PCE", idPce);
}
 
protected void lettrageAuto(List<Integer> pieceIDs, Date d) {
final SQLTable tablePrefCompte = base.getTable("PREFS_COMPTE");
final SQLRow rowPrefsCompte = SQLBackgroundTableCache.getInstance().getCacheForTable(tablePrefCompte).getRowFromId(2);
 
if (rowPrefsCompte.getBoolean("AUTO_LETTRAGE")) {
SQLSelect selEcr = new SQLSelect();
SQLTable tableEcr = base.getTable("ECRITURE");
selEcr.addSelect(tableEcr.getKey());
selEcr.addSelect(tableEcr.getField("DEBIT"));
selEcr.addSelect(tableEcr.getField("CREDIT"));
selEcr.addSelect(tableEcr.getField("LETTRAGE"));
SQLTable tableCpte = base.getTable("COMPTE_PCE");
Where w2 = new Where(base.getTable("MOUVEMENT").getField("ID_PIECE"), pieceIDs);
w2 = w2.and(new Where(tableEcr.getField("ID_MOUVEMENT"), "=", base.getTable("MOUVEMENT").getKey()));
w2 = w2.and(new Where(tableEcr.getField("ID_COMPTE_PCE"), "=", tableCpte.getKey()));
w2 = w2.and(new Where(tableCpte.getField("NUMERO"), "LIKE", "40%").or(new Where(tableCpte.getField("NUMERO"), "LIKE", "41%")));
w2 = w2.and(new Where(tableEcr.getField("DATE_LETTRAGE"), "=", (Object) null));
selEcr.setWhere(w2);
long solde = -1;
List<SQLRow> ecr = SQLRowListRSH.execute(selEcr);
if (!ecr.isEmpty()) {
solde = 0;
for (SQLRow sqlRow2 : ecr) {
solde += sqlRow2.getLong("DEBIT");
solde -= sqlRow2.getLong("CREDIT");
}
}
if (solde == 0) {
 
String codeLettre = NumerotationAutoSQLElement.getNextCodeLettrage();
 
for (SQLRow sqlRow2 : ecr) {
SQLRowValues rowValsEcr = sqlRow2.asRowValues();
// Lettrage
// On lettre ou relettre la ligne avec le code saisi
if (codeLettre.length() > 0) {
 
rowValsEcr.put("LETTRAGE", codeLettre);
rowValsEcr.put("DATE_LETTRAGE", d);
try {
rowValsEcr.update();
} catch (SQLException e1) {
 
e1.printStackTrace();
}
}
// Mise à jour du code de lettrage
SQLElement elt = Configuration.getInstance().getDirectory().getElement("NUMEROTATION_AUTO");
SQLRowValues rowVals = elt.getTable().getRow(2).createEmptyUpdateRow();
rowVals.put("CODE_LETTRAGE", codeLettre);
try {
rowVals.update();
} catch (SQLException ex) {
ex.printStackTrace();
}
 
}
 
}
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationReglementVenteNG.java
214,8 → 214,18
this.putValue("CREDIT", Long.valueOf(0));
ajoutEcriture();
 
List<Integer> pieceIDs = new ArrayList<Integer>();
if (source.getTable().getName().equals("ENCAISSER_MONTANT")) {
List<SQLRow> l = source.getReferentRows(base.getTable("ENCAISSER_MONTANT_ELEMENT"));
for (SQLRow sqlRow : l) {
pieceIDs.add(sqlRow.getForeign("ID_MOUVEMENT_ECHEANCE").getForeignID("ID_PIECE"));
}
} else {
pieceIDs.add(mvtSource.getForeignID("ID_PIECE"));
}
lettrageAuto(pieceIDs, d);
}
} else {
 
Date dateEch = ModeDeReglementSQLElement.calculDate(modeReglement.getInt("AJOURS"), modeReglement.getInt("LENJOUR"), this.date);
 
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtSaisieVenteFacture.java
59,6 → 59,10
* @param idMvt id du mouvement qui est dejà associé à la facture
*/
public GenerationMvtSaisieVenteFacture(int idSaisieVenteFacture, int idMvt, boolean useComptePCEVente, boolean genereReglement) {
this(idSaisieVenteFacture, idMvt, useComptePCEVente, genereReglement, false);
}
 
public GenerationMvtSaisieVenteFacture(int idSaisieVenteFacture, int idMvt, boolean useComptePCEVente, boolean genereReglement, boolean threadSafe) {
System.err.println("********* init GeneRation");
this.idMvt = idMvt;
this.idSaisieVenteFacture = idSaisieVenteFacture;
65,6 → 69,7
this.useComptePCEVente = useComptePCEVente;
this.genereReglement = genereReglement;
// Submit in sheetxml queue in order to get the good paiement in document
if (!threadSafe)
SheetXml.submitInQueue(GenerationMvtSaisieVenteFacture.this);
}
 
82,11 → 87,15
* @param idSaisieVenteFacture
*/
public GenerationMvtSaisieVenteFacture(int idSaisieVenteFacture) {
this(idSaisieVenteFacture, 1);
this(idSaisieVenteFacture, false);
}
 
private void genereMouvement() throws Exception {
public GenerationMvtSaisieVenteFacture(int idSaisieVenteFacture, final boolean threadSafe) {
this(idSaisieVenteFacture, 1, false, true, threadSafe);
}
 
public final void genereMouvement() throws Exception {
 
SQLRow saisieRow = GenerationMvtSaisieVenteFacture.saisieVFTable.getRow(this.idSaisieVenteFacture);
setRowAnalytiqueSource(saisieRow);
SQLRow clientRow = saisieRow.getForeignRow("ID_CLIENT");
104,6 → 113,7
} else {
this.nom = "Fact. vente " + saisieRow.getObject("NUMERO").toString();
}
this.nom += " " + StringUtils.limitLength(clientRow.getString("NOM"), 20);
this.putValue("NOM", this.nom);
 
// iniatilisation des valeurs de la map
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtSaisieVenteComptoir.java
77,7 → 77,17
}
this.putValue("ID_MOUVEMENT", new Integer(this.idMvt));
 
// generation des ecritures + maj des totaux du compte associe
// Détermination du compte de produits
int idCompteVenteProduit = rowPrefsCompte.getInt("ID_COMPTE_PCE_VENTE_PRODUIT");
if (idCompteVenteProduit <= 1) {
idCompteVenteProduit = ComptePCESQLElement.getIdComptePceDefault("VentesProduits");
}
if (clientRow.getObject("ID_COMPTE_PCE_PRODUIT") != null && !clientRow.isForeignEmpty("ID_COMPTE_PCE_PRODUIT")) {
idCompteVenteProduit = clientRow.getInt("ID_COMPTE_PCE_PRODUIT");
}
if (saisieRow.getObject("ID_COMPTE_PCE_PRODUIT") != null && !saisieRow.isForeignEmpty("ID_COMPTE_PCE_PRODUIT")) {
idCompteVenteProduit = saisieRow.getInt("ID_COMPTE_PCE_PRODUIT");
}
 
// compte Vente
if (service != 0) {
86,6 → 96,13
if (idCompteVenteService <= 1) {
idCompteVenteService = ComptePCESQLElement.getIdComptePceDefault("VentesServices");
}
if (clientRow.getObject("ID_COMPTE_PCE_SERVICE") != null && !clientRow.isForeignEmpty("ID_COMPTE_PCE_SERVICE")) {
idCompteVenteService = clientRow.getInt("ID_COMPTE_PCE_SERVICE");
}
if (saisieRow.getObject("ID_COMPTE_PCE_SERVICE") != null && !saisieRow.isForeignEmpty("ID_COMPTE_PCE_SERVICE")) {
idCompteVenteService = saisieRow.getInt("ID_COMPTE_PCE_SERVICE");
}
 
this.putValue("ID_COMPTE_PCE", new Integer(idCompteVenteService));
this.putValue("DEBIT", new Long(0));
this.putValue("CREDIT", new Long(service));
92,10 → 109,7
ajoutEcriture();
 
if ((prixHT.getLongValue() - service) > 0) {
int idCompteVenteProduit = rowPrefsCompte.getInt("ID_COMPTE_PCE_VENTE_PRODUIT");
if (idCompteVenteProduit <= 1) {
idCompteVenteProduit = ComptePCESQLElement.getIdComptePceDefault("VentesProduits");
}
 
this.putValue("ID_COMPTE_PCE", new Integer(idCompteVenteProduit));
this.putValue("DEBIT", new Long(0));
this.putValue("CREDIT", new Long(prixHT.getLongValue() - service));
104,10 → 118,6
 
} else {
 
int idCompteVenteProduit = rowPrefsCompte.getInt("ID_COMPTE_PCE_VENTE_PRODUIT");
if (idCompteVenteProduit <= 1) {
idCompteVenteProduit = ComptePCESQLElement.getIdComptePceDefault("VentesProduits");
}
this.putValue("ID_COMPTE_PCE", new Integer(idCompteVenteProduit));
this.putValue("DEBIT", new Long(0));
this.putValue("CREDIT", new Long(prixHT.getLongValue()));
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/provider/SalesInvoiceAccountingRecordsProvider.java
18,6 → 18,7
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.utils.StringUtils;
 
import java.util.Map;
 
39,6 → 40,7
} else {
nom = "Fact. vente " + rowSource.getObject("NUMERO").toString();
}
nom += " " + StringUtils.limitLength(rowSource.getForeign("ID_CLIENT").getString("NOM"), 20);
values.put("NOM", nom);
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/edm/FilePanel.java
103,9 → 103,9
label.setOpaque(false);
label.setPreferredSize(new Dimension(label.getPreferredSize().width, new JTextField("a").getPreferredSize().height));
this.add(label, BorderLayout.SOUTH);
 
this.setPreferredSize(new Dimension(PREFERRED_WIDTH, PREFERRED_HEIGHT));
this.setMinimumSize(new Dimension(PREFERRED_WIDTH, PREFERRED_HEIGHT));
int fontSize = label.getFont().getSize();
this.setPreferredSize(new Dimension(10 * fontSize, PREFERRED_HEIGHT));
this.setMinimumSize(new Dimension(10 * fontSize, PREFERRED_HEIGHT));
updateBackgroundFromState();
this.addMouseMotionListener(new MouseAdapter() {
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/quote/action/ListeDesElementsPropositionsAction.java
32,7 → 32,7
final ListeAddPanel listeAddPanel = new ListeAddPanel(Configuration.getInstance().getDirectory().getElement("PROPOSITION_ELEMENT"));
IListFrame frame = new IListFrame(listeAddPanel);
frame.setTextTitle("Liste des missions par propositions");
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
frame.getPanel().setAddVisible(false);
frame.getPanel().setSearchFullMode(true);
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/quote/action/ListeDesElementsDevisAction.java
55,7 → 55,7
 
IListFrame frame = new IListFrame(listeAddPanel);
frame.setTextTitle("Liste des missions proposées");
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
frame.getPanel().setAddVisible(false);
frame.getPanel().setShowReadOnlyFrameOnDoubleClick(false);
frame.getPanel().setModifyVisible(false);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/quote/ui/ListeDesDevisPanel.java
52,6 → 52,7
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.Color;
243,7 → 244,14
if (!this.eltDevis.getTable().contains("DATE_REMISE_DOSSIER")) {
dateEnvoiCol = new SQLTableModelColumnPath(this.eltDevis.getTable().getField("DATE_ENVOI"));
lAttente.getColumns().add(dateEnvoiCol);
dateEnvoiCol.setRenderer(new DateEnvoiRenderer());
dateEnvoiCol.setColumnInstaller(new IClosure<TableColumn>() {
@Override
public void executeChecked(TableColumn columnDateEnvoi) {
columnDateEnvoi.setCellEditor(new org.openconcerto.ui.table.TimestampTableCellEditor());
columnDateEnvoi.setCellRenderer(new DateEnvoiRenderer());
}
});
 
dateEnvoiCol.setEditable(true);
final BaseSQLTableModelColumn colAvancementCmd = new BaseSQLTableModelColumn("Commande", BigDecimal.class) {
 
364,7 → 372,7
 
if (idFilter == EtatDevisSQLElement.ACCEPTE) {
 
pane.getListe().setSQLEditable(true);
pane.getListe().setModificationAllowed(true);
// Edition des dates d'envois
TableColumn columnDateEnvoi = pane.getListe().getJTable().getColumnModel().getColumn(table.getColumnCount() - 1);
columnDateEnvoi.setCellEditor(new org.openconcerto.ui.table.TimestampTableCellEditor());
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/quote/component/DevisSQLComponent.java
467,8 → 467,10
if (this.getTable().getFieldsName().contains("DUNNING_DATE")) {
c.gridx++;
c.weightx = 0;
c.fill = GridBagConstraints.HORIZONTAL;
this.add(new JLabel(getLabelFor("DUNNING_DATE"), SwingConstants.RIGHT), c);
c.gridx++;
c.fill = GridBagConstraints.NONE;
JDate dateRelance = new JDate();
this.add(dateRelance, c);
if (getTable().getDBRoot().contains("TARIF_AGENCE")) {
592,8 → 594,8
cRemise.weightx = 0;
this.textRemiseHT = new DeviseField();
panelRemise.add(this.textRemiseHT, cRemise);
this.textRemiseHT.setMinimumSize(new Dimension(150, 20));
this.textRemiseHT.setPreferredSize(new Dimension(150, 20));
this.textRemiseHT.setMinimumSize(new Dimension(150, this.textRemiseHT.getMinimumSize().height));
this.textRemiseHT.setPreferredSize(new Dimension(150, this.textRemiseHT.getPreferredSize().height));
 
if (prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.ACOMPTE_DEVIS, false)) {
// Acompte
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/quote/element/DevisSQLElement.java
617,6 → 617,7
@Override
protected synchronized void _initTableSource(final SQLTableModelSource table) {
super._initTableSource(table);
 
final BaseSQLTableModelColumn colAdrLiv = new BaseSQLTableModelColumn("Adresse de livraison", String.class) {
 
@Override
655,7 → 656,6
}
};
table.getColumns().add(3, colAdrLiv);
 
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/ProductItemListTable.java
28,6 → 28,7
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
81,8 → 82,11
if (object == null) {
return null;
}
SQLRowAccessor r = row.getForeign("ID_ARTICLE");
return r.getForeignIDNumber("ID_UNITE_VENTE");
final SQLRowAccessor r = row.getForeign("ID_ARTICLE");
final SQLRow rArticle = r.asRow();
// TODO faire en sorte que l'on ne fasse pas de requete dans la thread swing
rArticle.fetchValues();
return rArticle.getForeignIDNumber("ID_UNITE_VENTE");
} else {
return row.getObject("ID_UNITE_VENTE");
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/POSConfiguration.java
260,6 → 260,7
SQLUtils.executeAtomic(Configuration.getInstance().getSystemRoot().getDataSource(), new SQLUtils.SQLFactory<Object>() {
@Override
public Object create() throws SQLException {
 
final int imported = importReceipts(tickets, null);
 
// mark imported
378,7 → 379,7
 
// Paiements
for (Paiement paiement : ticket.getPaiements()) {
if (paiement.getMontantInCents() > 0 && paiement.getType() != Paiement.SOLDE) {
if (paiement.getMontantInCents() != 0 && paiement.getType() != Paiement.SOLDE) {
 
SQLRowValues rowValsElt = new SQLRowValues(eltEnc.getTable());
SQLRowValues rowValsEltMode = new SQLRowValues(eltMode.getTable());
685,10 → 686,14
}
 
public void print(Printable ticket) {
print(ticket, this.ticketPrinterConf1);
print(ticket, this.ticketPrinterConf2);
print(ticket, 0);
}
 
public void print(Printable ticket, int additionnalCopy) {
print(ticket, this.ticketPrinterConf1, additionnalCopy);
print(ticket, this.ticketPrinterConf2, additionnalCopy);
}
 
public void printOnceOnFirstPrinter(Printable ticket) {
if (this.ticketPrinterConf1.isValid()) {
final TicketPrinter prt = this.ticketPrinterConf1.createTicketPrinter();
697,9 → 702,14
}
 
public void print(Printable ticket, TicketPrinterConfiguration conf) {
if (conf.isValid() && conf.getCopyCount() > 0) {
print(ticket, conf, 0);
}
 
public void print(Printable ticket, TicketPrinterConfiguration conf, int additionnalCopy) {
int copyCount = conf.getCopyCount() + additionnalCopy;
if (conf.isValid() && copyCount > 0) {
final TicketPrinter prt = conf.createTicketPrinter();
for (int i = 0; i < conf.getCopyCount(); i++) {
for (int i = 0; i < copyCount; i++) {
ticket.print(prt, conf.getTicketWidth());
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/element/SaisieVenteComptoirSQLElement.java
278,6 → 278,38
c.weightx = 0;
// this.add(this.comboAvoir, c);
 
// Compte spec de produit
JLabel labelCptProduit = new JLabel(getLabelFor("ID_COMPTE_PCE_PRODUIT"));
c.gridy++;
c.gridx = 0;
c.gridwidth = 1;
c.weightx = 0;
labelCptProduit.setHorizontalAlignment(SwingConstants.RIGHT);
this.add(labelCptProduit, c);
 
c.gridx++;
c.gridwidth = GridBagConstraints.REMAINDER;
c.weightx = 0;
ElementComboBox comboCptProduit = new ElementComboBox();
this.add(comboCptProduit, c);
addView(comboCptProduit, "ID_COMPTE_PCE_PRODUIT");
 
// Compte spec de produit
JLabel labelCptService = new JLabel(getLabelFor("ID_COMPTE_PCE_SERVICE"));
c.gridy++;
c.gridx = 0;
c.gridwidth = 1;
c.weightx = 0;
labelCptService.setHorizontalAlignment(SwingConstants.RIGHT);
this.add(labelCptService, c);
 
c.gridx++;
c.gridwidth = GridBagConstraints.REMAINDER;
c.weightx = 0;
ElementComboBox comboCptService = new ElementComboBox();
this.add(comboCptService, c);
addView(comboCptService, "ID_COMPTE_PCE_SERVICE");
 
/***********************************************************************************
* * MONTANT
**********************************************************************************/
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/action/ListeDesCaissesTicketAction.java
31,7 → 31,7
public JFrame createFrame() {
final IListFrame frame = new IListFrame(new ListeAddPanel(Configuration.getInstance().getDirectory().getElement("CAISSE")));
 
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
return frame;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/CaisseControler.java
158,7 → 158,7
}
 
// Articles
void addArticle(Article a) {
public void addArticle(Article a) {
this.t.addArticle(a);
fire();
String price = TicketCellRenderer.centsToString(a.getPriceWithTax().movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue());
310,7 → 310,7
return false;
for (int i = 0; i < paiementCount; i++) {
Paiement p = this.t.getPaiements().get(i);
if (p.getType() == type && p.getMontantInCents() <= 0) {
if (p.getType() == type && p.getMontantInCents() != 0) {
return false;
}
}
324,7 → 324,7
}
 
public static String getCents(int cents) {
String s = String.valueOf(cents % 100);
String s = String.valueOf(Math.abs(cents) % 100);
if (s.length() < 2) {
s = "0" + s;
}
471,7 → 471,7
}
 
public boolean isTicketValid() {
return (!this.t.getArticles().isEmpty()) && (this.getPaidTotal() >= this.getTotal());
return (!this.t.getArticles().isEmpty()) && ((this.getTotal() >= 0 && this.getPaidTotal() >= this.getTotal()) || (this.getTotal() < 0 && this.getPaidTotal() == this.getTotal()));
}
 
public Set<Integer> loadFavoriteProductsIds() {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/RegisterSummary.java
20,8 → 20,8
import org.openconcerto.erp.core.sales.pos.model.Paiement;
import org.openconcerto.erp.core.sales.pos.model.RegisterLog;
import org.openconcerto.erp.core.sales.pos.model.RegisterState;
import org.openconcerto.erp.core.sales.pos.model.RegisterState.Status;
import org.openconcerto.erp.core.sales.pos.model.Ticket;
import org.openconcerto.erp.core.sales.pos.model.RegisterState.Status;
 
import java.math.BigDecimal;
import java.text.DateFormat;
31,8 → 31,8
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.Map.Entry;
import java.util.logging.Level;
 
abstract class RegisterSummary implements Printable {
92,6 → 92,7
total = total.add(receiptValue);
totalPaid = totalPaid.add(receiptPaid);
}
final BigDecimal rendu = totalPaid.subtract(total);
 
prt.addToBuffer(title, TicketPrinter.BOLD_LARGE);
prt.addToBuffer("");
104,12 → 105,12
prt.addToBuffer("");
 
Paiement espece = new Paiement(Paiement.ESPECES);
prt.addToBuffer(DefaultTicketPrinter.formatSides(ticketWidth, "Total des ventes", totalPaid.toPlainString()), TicketPrinter.BOLD);
// TODO same name as "Total TTC"
prt.addToBuffer(DefaultTicketPrinter.formatSides(ticketWidth, "Total des ventes", total.toPlainString()), TicketPrinter.BOLD);
for (final Entry<String, BigDecimal> e2 : totalByType.entrySet()) {
final String typePayment = e2.getKey();
if (typePayment.equals(espece.getTypeAsString())) {
BigDecimal value = e2.getValue();
BigDecimal rendu = totalPaid.subtract(total);
value = value.subtract(rendu);
prt.addToBuffer(DefaultTicketPrinter.formatSides(ticketWidth, " " + typePayment, value.toPlainString()));
} else {
122,7 → 123,7
prt.addToBuffer(DefaultTicketPrinter.formatSides(ticketWidth, " " + e2.getKey(), e2.getValue().toPlainString()));
}
prt.addToBuffer("");
prt.addToBuffer(DefaultTicketPrinter.formatSides(ticketWidth, "Total rendu", totalPaid.subtract(total).toPlainString()), TicketPrinter.BOLD);
prt.addToBuffer(DefaultTicketPrinter.formatSides(ticketWidth, "Total rendu", rendu.toPlainString()), TicketPrinter.BOLD);
prt.addToBuffer("");
prt.addToBuffer(DefaultTicketPrinter.formatSides(ticketWidth, "Total TTC (Euros)", total.toPlainString()), TicketPrinter.BOLD);
prt.addToBuffer(DefaultTicketPrinter.formatSides(ticketWidth, "Nombre de tickets", "" + receipts.size()));
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/TicketPanel.java
124,6 → 124,9
if (selectedValue != null) {
final Article a = ((Pair<Article, Integer>) selectedValue).getFirst();
controler.setArticleSelected(a);
// If the category of the selected article does not match the current category of the categories list,
// then the corresponding article is not selected.
controler.setArticleSelected(a); // Dirty fix : use two refresh
}
}
 
137,6 → 140,12
g.drawImage(this.bg, 0, 0, null);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
try {
// Display caisse and Vendor ID
String InfoCaisseVendeur = "Caisse "+POSConfiguration.getInstance().getPosID() + " Vendeur " + POSConfiguration.getInstance().getUserID();
g.setColor(new Color(230, 230, 230));
g.setFont(getFont().deriveFont(28.0f));
g.drawString(InfoCaisseVendeur, 20, this.getHeight() - 50);
 
g.setColor(Color.LIGHT_GRAY);
g.setFont(getFont().deriveFont(18.0f));
final RegisterState registerState = this.controler.getCaisseFrame().getFiles().getLastLog().getRegisterState();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/TicketCellRenderer.java
114,7 → 114,7
}
 
public static String centsToString(int cents) {
final int c = cents % 100;
final int c = Math.abs(cents) % 100;
String sc = String.valueOf(c);
if (c < 10) {
sc = "0" + sc;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/CaisseMenuPanel.java
139,7 → 139,7
 
@Override
public void actionPerformed(ActionEvent e) {
JPanel p = new JPanel();
final JPanel p = new JPanel();
p.setOpaque(true);
p.setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/NumericKeypadPanel.java
New file
0,0 → 1,203
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.sales.pos.ui;
 
import org.openconcerto.erp.core.common.ui.NumericTextField;
 
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
 
import javax.swing.JPanel;
 
public class NumericKeypadPanel extends JPanel {
 
private NumericTextField numericTextField;
private Map<String, POSButton> buttonMap = new HashMap<>();
private transient NumericKeyListener evt = new NumericKeyListener();
private int maxDecimalDigits;
private static final int INSET = 2;
private static final int PANEL_HEIGHT = (68 * 5) + (INSET * 4);
private static final int PANEL_WIDTH = (68 * 3) + (INSET * 2);
private static final int BUTTON_SIZE = 64;
 
public NumericKeypadPanel() {
this(null, 2);
}
 
public NumericKeypadPanel(NumericTextField dataSource) {
this(dataSource, 2);
}
 
public NumericKeypadPanel(NumericTextField dataSource, int maxDecimalDigits) {
this.setLayout(new GridBagLayout());
drawCalculator();
setNumericTextField(dataSource);
setMaxDecimalDigits(maxDecimalDigits);
}
 
public final int getMaxDecimalDigits() {
return this.maxDecimalDigits;
}
 
public final void setMaxDecimalDigits(int maxDecimalDigits) {
this.maxDecimalDigits = maxDecimalDigits;
updateButtonsValidity();
}
 
public final NumericTextField getNumericTextField() {
return this.numericTextField;
}
 
public final void setNumericTextField(NumericTextField dataSource) {
if (dataSource != null) {
this.numericTextField = dataSource;
final BigDecimal value = dataSource.getValue();
if (value == null || Math.abs(value.longValue()) <= 0) {
this.numericTextField.setText("");
}
updateButtonsValidity();
}
}
 
private void drawCalculator() {
this.setForeground(new Color(250, 250, 250));
// line 1
addKey("C", 0, 0, 3, 1).setBackground(CaissePanel.LIGHT_BLUE);
// line 2
addKey("7", 0, 1, 1, 1);
addKey("8", 1, 1, 1, 1);
addKey("9", 2, 1, 1, 1);
// line 3
addKey("4", 0, 2, 1, 1);
addKey("5", 1, 2, 1, 1);
addKey("6", 2, 2, 1, 1);
// line 4
addKey("1", 0, 3, 1, 1);
addKey("2", 1, 3, 1, 1);
addKey("3", 2, 3, 1, 1);
// line 5
addKey("0", 0, 4, 2, 1);
addKey(".", 2, 4, 1, 1);
}
 
private POSButton addKey(String buttonTitle, int col, int row, int colSpawn, int rowSpawn) {
final GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.CENTER;
c.weightx = 0;
c.weighty = 0;
c.gridwidth = colSpawn;
c.gridheight = rowSpawn;
c.gridx = col;
c.gridy = row;
c.insets = new Insets(2, 2, 2, 2);
 
final POSButton button = new POSButton(buttonTitle);
button.setPreferredSize(new Dimension(BUTTON_SIZE * colSpawn, BUTTON_SIZE * rowSpawn));
button.addActionListener(evt);
buttonMap.put(buttonTitle, button);
this.add(button, c);
 
return button;
}
 
@Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
}
 
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
 
private void updateButtonsValidity() {
if (numericTextField != null) {
final String currentTextValue = numericTextField.getText();
final int length = currentTextValue.length();
final int posDecimalSeparator = currentTextValue.indexOf('.');
final boolean hasDecimalSeparator = (maxDecimalDigits == 0) || (posDecimalSeparator >= 0);
final boolean hasEnoughtDecimals = posDecimalSeparator > 0 && (posDecimalSeparator < (length - maxDecimalDigits));
 
for (Map.Entry<String, POSButton> entry : buttonMap.entrySet()) {
final String k = entry.getKey();
final POSButton button = entry.getValue();
switch (k) {
case "C":
button.setEnabled((length > 0));
break;
case ".":
// Disabled if dot is already present or if text is empty
button.setEnabled(!hasDecimalSeparator && !currentTextValue.isEmpty());
break;
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
button.setEnabled(!hasEnoughtDecimals);
break;
default:
break;
}
}
}
}
 
private class NumericKeyListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
final String digit = e.getActionCommand(); // Get text from button
final String currentTextValue = numericTextField.getText();
switch (digit) {
case "C":
final int length = currentTextValue.length();
if (length > 0) {
numericTextField.setText(currentTextValue.substring(0, length - 1));
}
break;
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
case ".":
numericTextField.setText(currentTextValue + digit);
break;
default:
break;
}
updateButtonsValidity();
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/PaiementPanel.java
256,8 → 256,8
Graphics2D g2 = (Graphics2D) g;
 
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int cents = p.getMontantInCents() % 100;
int euros = p.getMontantInCents() / 100;
int cents = p.getCents();
int euros = p.getEuros();
// Background
g.setColor(new Color(240, 240, 240));
g.fillRect(3, y - 36, this.getWidth() - 5, 44);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/CaisseFrame.java
189,12 → 189,16
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
f.pack();
if (System.getProperty("os.name").toLowerCase().startsWith("mac os x")) {
f.setLocation(0, 24);
} else {
f.setLocation(0, 0);
}
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
if (POSConfiguration.getInstance().getScreenWidth() > 0 && POSConfiguration.getInstance().getScreenHeight() > 0) {
f.setSize(new Dimension(POSConfiguration.getInstance().getScreenWidth(), POSConfiguration.getInstance().getScreenHeight()));
f.setSize(new Dimension(POSConfiguration.getInstance().getScreenWidth() - f.getX(), POSConfiguration.getInstance().getScreenHeight() - f.getY()));
} else {
f.setSize(screenSize);
f.setSize(new Dimension(screenSize.getSize().width - f.getX(), screenSize.getSize().height - f.getY()));
}
System.out.println("Affichage de l'interface");
f.setVisible(true);
375,7 → 379,7
 
}
 
public void showPanel(JPanel panel) {
public void showPanel(final JPanel panel) {
this.invalidate();
final int x = (getWidth() - panel.getPreferredSize().width) / 2;
final int y = 100;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/ListeDesTicketsPanel.java
15,18 → 15,16
 
import org.openconcerto.erp.core.sales.pos.POSConfiguration;
import org.openconcerto.erp.core.sales.pos.TicketPrinterConfiguration;
import org.openconcerto.erp.core.sales.pos.io.DefaultTicketPrinter;
import org.openconcerto.erp.core.sales.pos.io.Printable;
import org.openconcerto.erp.core.sales.pos.io.TicketPrinter;
import org.openconcerto.erp.core.sales.pos.model.Paiement;
import org.openconcerto.erp.core.sales.pos.model.Article;
import org.openconcerto.erp.core.sales.pos.model.RegisterFiles;
import org.openconcerto.erp.core.sales.pos.model.RegisterLog;
import org.openconcerto.erp.core.sales.pos.model.RegisterState;
import org.openconcerto.erp.core.sales.pos.model.RegisterState.Status;
import org.openconcerto.erp.core.sales.pos.model.Ticket;
import org.openconcerto.ui.DefaultListModel;
import org.openconcerto.ui.touch.ScrollableList;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.Pair;
 
import java.awt.Color;
import java.awt.Component;
42,18 → 40,10
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.logging.Level;
 
import javax.swing.JLabel;
import javax.swing.JList;
250,7 → 240,7
c.weighty = 0;
c.fill = GridBagConstraints.NONE;
final Font font = new Font(ARIAL_FONT, Font.PLAIN, 46);
l = new JList(new String[] { "Imprimer" });
l = new JList(new String[] { "Imprimer", "Annuler" });
l.setCellRenderer(new ListCellRenderer() {
 
@Override
273,7 → 263,7
l.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
l.getSelectionModel().addListSelectionListener(this);
 
l.setFixedCellHeight(80);
l.setFixedCellHeight(160);
this.add(l, c);
 
setFont(new Font(ARIAL_FONT, Font.BOLD, 24));
299,7 → 289,16
int selectedIndex = l.getSelectedIndex();
if (selectedIndex == 0 && selectedValue != null) {
POSConfiguration.getInstance().printOnceOnFirstPrinter(((Printable) selectedValue));
} else if (selectedIndex == 1 && selectedValue != null) {
// Annulation du ticket
Ticket t = (Ticket) selectedValue;
for (Pair<Article, Integer> a : t.getArticles()) {
frame.getControler().addArticle(a.getFirst());
frame.getControler().setArticleCount(a.getFirst(), -a.getSecond());
frame.getControler().setArticleHT(a.getFirst(), a.getFirst().getPriceWithoutTax());
}
frame.showCaisse();
}
l.clearSelection();
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/CaissePanel.java
155,7 → 155,7
// Valider
CaissePanel.this.controler.setLCD("Impression de", "votre ticket...", 0);
try {
POSConfiguration.getInstance().print(savedReceipt);
POSConfiguration.getInstance().print(savedReceipt, (savedReceipt.isAdditionnalCopyRequested() ? 1 : 0));
} catch (UnsatisfiedLinkError ex) {
JOptionPane.showMessageDialog(CaissePanel.this, "Erreur de configuration de la liaison à l'imprimante");
} catch (Throwable ex) {
230,7 → 230,7
final SQLSelect selArticle = new SQLSelect();
final SQLTable tableArticle = eltArticle.getTable();
selArticle.addAllSelect(tableArticle.getFields(VirtualFields.PRIMARY_KEY.union(VirtualFields.ARCHIVE)));
selArticle.addAllSelect(tableArticle, Arrays.asList("ID_FAMILLE_ARTICLE", "NOM", "CODE", "CODE_BARRE", "ID_TAXE", "PV_HT", "PV_TTC"));
selArticle.addAllSelect(tableArticle, Arrays.asList("ID_FAMILLE_ARTICLE", "NOM", "CODE", "CODE_BARRE", "ID_TAXE", "PV_HT", "PV_TTC", "ADDITIONAL_TICKET_COPY"));
selArticle.setWhere(new Where(tableArticle.getField("OBSOLETE"), "=", Boolean.FALSE).and(new Where(tableArticle.getField("MASQUE_CAISSE"), "=", Boolean.FALSE)));
 
final Categorie cUnclassified = new Categorie("Non classés", true);
252,6 → 252,7
a.setIdTaxe(row.getInt("ID_TAXE"));
a.setPriceWithoutTax(row.getBigDecimal("PV_HT"));
a.setPriceWithTax(row.getBigDecimal("PV_TTC"));
a.setAdditionalCopyRequested(row.getBoolean("ADDITIONAL_TICKET_COPY"));
final Integer idProduct = a.getId();
if (favoriteProductsIds.contains(idProduct)) {
favoriteProducts.add(a);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/POSButton.java
19,11 → 19,15
import javax.swing.JButton;
 
public class POSButton extends JButton {
private Color enabledBackgroundColor = null;
private Color disabledBackgroundColor = null;
 
public POSButton(String label) {
super(label);
final Font f = getFont().deriveFont(20f);
this.setForeground(Color.WHITE);
this.setBackground(CaissePanel.DARK_BLUE);
this.setDisabledBackground(Color.LIGHT_GRAY);
this.setFont(f);
this.setFocusPainted(false);
this.setBorderPainted(false);
30,4 → 34,52
this.setContentAreaFilled(false);
this.setOpaque(true);
}
 
public void setDisabledBackground(Color bg) {
if (bg == null) {
disabledBackgroundColor = this.getBackground();
} else {
disabledBackgroundColor = bg;
}
}
 
/**
* Enables (or disables) the button changing his background color. + * @param b true to enable
* the button, otherwise false +
*/
 
@Override
public void setEnabled(boolean b) {
super.setEnabled(b);
if (b) {
if ((enabledBackgroundColor != null) && !(enabledBackgroundColor.equals(this.getBackground()))) {
super.setBackground(enabledBackgroundColor);
}
} else {
if ((disabledBackgroundColor != null) && !(disabledBackgroundColor.equals(this.getBackground()))) {
super.setBackground(disabledBackgroundColor);
}
}
}
 
/**
* Sets the background color of this component.
* <p>
* The background color affects each component differently and the parts of the component that
* are affected by the background color may differ between operating systems.
*
* @param c the color to become this component's color; if this parameter is <code>null</code>,
* then this component will inherit the background color of its parent
*
*/
@Override
public void setBackground(Color bg) {
super.setBackground(bg);
if (this.isEnabled()) {
enabledBackgroundColor = this.getBackground();
} else {
disabledBackgroundColor = this.getBackground();
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/PriceEditorPanel.java
19,6 → 19,7
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
26,22 → 27,25
 
import javax.swing.ButtonGroup;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
 
public class PriceEditorPanel extends JPanel {
CaisseFrame frame;
private POSLabel labelPrice;
private Article article;
final POSRadioButton rHT, rTTC, rDiscountPercent, rDiscount;
private NumericTextField htTextField;
private NumericTextField ttcTextField;
private NumericTextField discountPercentTextField;
private NumericTextField discountTextField;
private final transient Article article;
private final POSLabel labelPrice;
private final POSRadioButton rHT;
private final POSRadioButton rTTC;
private final POSRadioButton rDiscountPercent;
private final POSRadioButton rDiscount;
private final NumericTextField htTextField;
private final NumericTextField ttcTextField;
private final NumericTextField discountPercentTextField;
private final NumericTextField discountTextField;
private final NumericKeypadPanel keyPad;
 
public PriceEditorPanel(final CaisseFrame caisseFrame, final Article article) {
this.article = article;
this.frame = caisseFrame;
this.setBackground(Color.WHITE);
this.setOpaque(true);
this.setLayout(new GridBagLayout());
49,7 → 53,7
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.EAST;
c.weightx = 0;
c.weighty = 0;
c.weighty = 1;
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(20, 20, 30, 20);
60,8 → 64,21
// Line 2
c.gridy++;
c.gridwidth = 1;
rTTC = new POSRadioButton("prix TTC");
rTTC.setSelected(true);
c.weightx = 0;
this.add(rTTC, c);
ttcTextField = new NumericTextField();
ttcTextField.setFont(title.getFont());
ttcTextField.setValue(article.getPriceWithTax());
ttcTextField.requestFocusInWindow();
c.gridx++;
c.weightx = 1;
this.add(ttcTextField, c);
// Line 3
c.gridy++;
rHT = new POSRadioButton("prix HT");
rHT.setSelected(true);
c.gridx = 0;
c.weightx = 0;
this.add(rHT, c);
htTextField = new NumericTextField();
70,18 → 87,6
c.gridx++;
c.weightx = 1;
this.add(htTextField, c);
// Line 3
c.gridy++;
rTTC = new POSRadioButton("prix TTC");
htTextField.setValue(article.getPriceWithTax());
c.gridx = 0;
c.weightx = 0;
this.add(rTTC, c);
ttcTextField = new NumericTextField();
ttcTextField.setFont(title.getFont());
c.gridx++;
c.weightx = 1;
this.add(ttcTextField, c);
// Line 4
c.gridy++;
rDiscountPercent = new POSRadioButton("remise en %");
118,9 → 123,7
c.gridx = 0;
c.gridwidth = 2;
final POSLabel labelPriceOld = new POSLabel("Ancien Prix : ");
final BigDecimal ttc = Article.computePriceWithTax(this.article.getPriceWithoutTax(), this.article.getIdTaxe());
ttcTextField.setValue(ttc);
labelPriceOld.setText("Ancien Prix : " + TicketCellRenderer.toString(this.article.getPriceWithoutTax()) + " HT, " + TicketCellRenderer.toString(ttc));
labelPriceOld.setText("Ancien Prix : " + TicketCellRenderer.toString(article.getPriceWithTax()) + "€ TTC, " + TicketCellRenderer.toString(article.getPriceWithoutTax()) + "€ HT");
this.add(labelPriceOld, c);
 
c.gridy++;
133,12 → 136,12
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.SOUTHEAST;
 
final JPanel buttons = new JPanel();
final JPanel buttons = new JPanel(new GridLayout(1, 2, 10, 0));
buttons.setOpaque(false);
POSButton bCancel = new POSButton("Annuler");
buttons.add(bCancel, c);
POSButton bApply = new POSButton("Appliquer");
buttons.add(bApply, c);
POSButton bCancel = new POSButton("Annuler");
buttons.add(bCancel, c);
bApply.addActionListener(new ActionListener() {
 
@Override
156,6 → 159,18
});
 
this.add(buttons, c);
 
c.anchor = GridBagConstraints.CENTER;
c.weightx = 0;
c.weighty = 0;
c.gridx = 3;
c.gridy = 2;
c.insets = new Insets(20, 20, 30, 20);
// Line 1
c.gridheight = 5;
keyPad = new NumericKeypadPanel(ttcTextField);
this.add(keyPad, c);
 
updatePrice(article.getPriceWithoutTax());
updateTextFields();
//
197,7 → 212,13
this.htTextField.getDocument().addDocumentListener(docListener);
this.discountPercentTextField.getDocument().addDocumentListener(docListener);
this.discountTextField.getDocument().addDocumentListener(docListener);
 
SwingUtilities.invokeLater(new Runnable() {
public void run() {
updateTextFields();// This will set focus on the text field
}
});
}
 
protected BigDecimal getHTFromUI() {
BigDecimal r = null;
221,12 → 242,12
return r;
}
 
void updatePrice(BigDecimal ht) {
private void updatePrice(BigDecimal ht) {
BigDecimal ttc = Article.computePriceWithTax(ht, this.article.getIdTaxe());
labelPrice.setText("Nouveau Prix : " + TicketCellRenderer.toString(ht) + " HT, " + TicketCellRenderer.toString(ttc));
labelPrice.setText("Nouveau Prix : " + TicketCellRenderer.toString(ttc) + "€ TTC, " + TicketCellRenderer.toString(ht) + "€ HT");
}
 
public void updateTextFields() {
private void updateTextFields() {
this.invalidate();
htTextField.setVisible(false);
ttcTextField.setVisible(false);
233,15 → 254,21
discountPercentTextField.setVisible(false);
discountTextField.setVisible(false);
if (rHT.isSelected()) {
htTextField.setVisible(true);
enableTextField(htTextField);
} else if (rTTC.isSelected()) {
ttcTextField.setVisible(true);
enableTextField(ttcTextField);
} else if (rDiscountPercent.isSelected()) {
discountPercentTextField.setVisible(true);
enableTextField(discountPercentTextField);
} else if (rDiscount.isSelected()) {
discountTextField.setVisible(true);
enableTextField(discountTextField);
}
this.validate();
repaint();
}
 
private void enableTextField(NumericTextField field) {
field.setVisible(true);
field.requestFocusInWindow();
this.keyPad.setNumericTextField(field);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/RegisterFiles.java
514,15 → 514,21
 
@Override
protected Object updateDir(final Path stagingDir, final RegisterLog lastLog) throws IOException {
final Date now = new Date();
final String lastHash;
try {
lastHash = lastLog.getLastReceiptHash();
// Closure cannot be done (or undone) manually (opening is just a row in
// CAISSE_JOURNAL) so check as much as possible
final RegisterLogEntry lastEvent = lastLog.getLastEvent();
if (isNotChronological(lastEvent.getDate(), now))
throw new IllegalStateException("Previous event date is in the future : " + lastEvent);
} catch (ParseException e) {
throw new IOException("Couldn't find last receipt hash", e);
}
// TODO verify that receipts' files match the log's content
final Document doc = lastLog.getDocument().clone();
doc.getRootElement().addContent(new RegisterLogEntry.RegisterEntry(EventType.REGISTER_CLOSURE, new Date(), userID, getPosID(), lastHash, null).toXML());
doc.getRootElement().addContent(new RegisterLogEntry.RegisterEntry(EventType.REGISTER_CLOSURE, now, userID, getPosID(), lastHash, null).toXML());
save(doc, stagingDir.resolve(LOG_FILENAME));
return null;
}
569,6 → 575,9
throw new IllegalStateException("Non consecutive number");
if (!CompareUtils.equals(expectedHash, t.getPreviousHash()))
throw new IllegalStateException("Previous hash mismatch, expected " + expectedHash + " but previous of receipt was " + t.getPreviousHash());
final RegisterLogEntry lastEvent = lastLog.getLastEvent();
if (isNotChronological(lastEvent.getDate(), t.getCreationDate()))
throw new IllegalStateException("Previous event (" + lastEvent + ") is after the receipt : " + t.getCreationDate());
} catch (ParseException e) {
throw new IOException("Couldn't parse last receipt of log", e);
}
587,4 → 596,9
}
});
}
 
static final boolean isNotChronological(final Date d1, final Date d2) {
// allow equal dates to support programmatic creation (faster than millisecond)
return d1.after(d2);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/RegisterLogEntry.java
49,6 → 49,8
this.userID = userID;
this.registerID = registerID;
this.lastReceiptHash = lastReceiptHash;
if (previousDate != null && RegisterFiles.isNotChronological(previousDate, date))
throw new IllegalArgumentException("Previous date (" + previousDate + ") is after " + date);
this.previousDate = previousDate;
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/CheckIntegrity.java
105,6 → 105,7
System.out.println("OK for " + logFile);
} catch (Exception e) {
// keep checking other files
System.err.println("Error for " + logFile);
e.printStackTrace();
}
lastLog = Value.getSome(log);
126,7 → 127,7
final RegisterEntry previousLogClosure = (RegisterEntry) lastEntry;
if (!Objects.equals(previousLogClosure.getLastReceiptHash(), log.getFirstRegisterEvent().getLastReceiptHash()))
throw new IllegalStateException("Register opening hash mismatch, chain broken");
if (log.getFirstRegisterEvent().getDate().compareTo(previousLogClosure.getDate()) < 0)
if (RegisterFiles.isNotChronological(previousLogClosure.getDate(), log.getFirstRegisterEvent().getDate()))
throw new IllegalStateException("Register opening before previous closure");
cal = previousLogClosure.getDate();
} else {
148,7 → 149,7
final List<RegisterLogEntry> allEvents = log.getAllEvents();
for (final RegisterLogEntry e : allEvents) {
final Date newDate = e.getDate();
if (cal != null && newDate.compareTo(cal) < 0)
if (cal != null && RegisterFiles.isNotChronological(cal, newDate))
throw new IllegalStateException("Later event before last one");
cal = newDate;
}
221,6 → 222,7
final SQLRow row = iter.next();
final ReceiptEntry receiptEvent = receiptEventsIter.next();
 
try {
if (!row.getString("NUMERO").equals(receipt.getCode()))
throw new IllegalStateException("Code in the DB doesn't match log");
if (row.getDate("DATE").compareTo(receipt.getCreationCal()) != 0)
230,8 → 232,11
if (!Objects.equals(row.getString("FILE_HASH_PREVIOUS"), receipt.getPreviousHash()))
throw new IllegalStateException("Previous file hash in the DB doesn't match log");
if (row.getLong("TOTAL_TTC") != receipt.getPaidTotal())
throw new IllegalStateException("TTC in the DB doesn't match log");
throw new IllegalStateException("TTC in the DB " + row.getLong("TOTAL_TTC") + " doesn't match log " + receipt.getPaidTotal());
} catch (Exception exn) {
throw new IllegalStateException("Error while checking " + row + " against " + receipt + " in " + log, exn);
}
}
assert !iter.hasNext() && !receiptEventsIter.hasNext();
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/Paiement.java
24,12 → 24,19
 
}
 
public int getEuros() {
return this.montantInCents / 100;
}
 
public int getCents() {
return Math.abs(this.montantInCents) % 100;
}
 
public int getMontantInCents() {
return montantInCents;
}
 
public void setMontantInCents(int montantInCents) {
if (montantInCents >= 0)
this.montantInCents = montantInCents;
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/Article.java
24,6 → 24,7
public class Article {
private Categorie s;
private String name;
private boolean additionalCopyRequested = false;
private BigDecimal priceTTC;
private int idTaxe;
private BigDecimal priceHT;
50,6 → 51,14
this.s.addArticle(this);
}
 
public boolean isAdditionalCopyRequested() {
return additionalCopyRequested;
}
 
public void setAdditionalCopyRequested(boolean additionalCopyRequested) {
this.additionalCopyRequested = additionalCopyRequested;
}
 
public int getId() {
return this.id;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/Ticket.java
72,6 → 72,7
private Client client = Client.NONE;
private final int number;
private final String previousHash;
private boolean additionnalCopyRequested = false;
 
// Propre à la caisse
private final int caisseNumber;
162,7 → 163,7
 
final String type = element.getAttributeValue("type");
final int montant_cents = Integer.parseInt(element.getAttributeValue("montant"));
if (montant_cents > 0) {
if (montant_cents != 0) {
int tp = Paiement.ESPECES;
if (type.equals("CB")) {
tp = Paiement.CB;
269,7 → 270,7
// Paiements
for (final Paiement paiement : this.paiements) {
final int montantInCents = paiement.getMontantInCents();
if (montantInCents > 0) {
if (montantInCents != 0) {
final Element e = new Element("paiement");
String type = "";
if (paiement.getType() == Paiement.CB) {
357,7 → 358,7
// Date
prt.addToBuffer("");
final SimpleDateFormat df = new SimpleDateFormat("EEEE d MMMM yyyy à HH:mm", Locale.FRENCH);
prt.addToBuffer(DefaultTicketPrinter.formatRight(maxWidth, "Le " + df.format(getCreationDate())));
prt.addToBuffer(DefaultTicketPrinter.formatCenter(maxWidth, "Le " + df.format(getCreationDate())));
prt.addToBuffer("");
List<Pair<Article, Integer>> itemsToPrint = new ArrayList<>(this.items);
Collections.sort(itemsToPrint, new Comparator<Pair<Article, Integer>>() {
385,7 → 386,7
Categorie currentCategorie = null;
for (final Pair<Article, Integer> item : this.items) {
final Article article = item.getFirst();
if (currentCategorie == null || !currentCategorie.equals(article.getCategorie())) {
if (currentCategorie == null || !currentCategorie.getName().equals(article.getCategorie().getName())) {
// Print category name, except for unknown
currentCategorie = article.getCategorie();
if (!currentCategorie.isUnknown()) {
395,22 → 396,26
final Integer nb = item.getSecond();
final Float tauxFromId = TaxeCache.getCache().getTauxFromId(article.getIdTaxe());
final BigDecimal tauxTVA = new BigDecimal(tauxFromId).movePointLeft(2).add(BigDecimal.ONE);
final BigDecimal unitPrice = article.getPriceWithoutTax().multiply(tauxTVA, DecimalUtils.HIGH_PRECISION);
final BigDecimal multiply = article.getPriceWithoutTax().multiply(new BigDecimal(nb), DecimalUtils.HIGH_PRECISION).multiply(tauxTVA, DecimalUtils.HIGH_PRECISION);
 
final String qtyString = DefaultTicketPrinter.formatRight(MAX_QTE_WIDTH, String.valueOf(nb));
final String priceString = DefaultTicketPrinter.formatRight(MAX_PRICE_WIDTH, TicketCellRenderer.centsToString(multiply.movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue()));
String unitPriceString = "";
if (nb != 1) {
unitPriceString = DefaultTicketPrinter.formatRight(MAX_PRICE_WIDTH, TicketCellRenderer.centsToString(unitPrice.movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue()));
}
 
if (article.getCode() != null && !article.getCode().isEmpty()) {
// 2 lines
final String qtyString = DefaultTicketPrinter.formatRight(MAX_QTE_WIDTH, String.valueOf(nb));
final String codeString = DefaultTicketPrinter.formatLeft(maxWidth - 2 - MAX_PRICE_WIDTH - MAX_QTE_WIDTH, article.getCode());
final String priceString = DefaultTicketPrinter.formatRight(MAX_PRICE_WIDTH, TicketCellRenderer.centsToString(multiply.movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue()));
prt.addToBuffer(qtyString + " " + codeString + " " + priceString);
final String codeString = DefaultTicketPrinter.formatLeft(maxWidth - 2 - MAX_PRICE_WIDTH - MAX_QTE_WIDTH - 1 - unitPriceString.length(), article.getCode());
prt.addToBuffer(qtyString + " " + codeString + " " + unitPriceString + " " + priceString);
final String nameString = DefaultTicketPrinter.formatLeft(maxWidth - MAX_QTE_WIDTH - 1, article.getName());
prt.addToBuffer(" " + nameString);
} else {
// 1 line
final String qtyString = DefaultTicketPrinter.formatRight(MAX_QTE_WIDTH, String.valueOf(nb));
final String nameString = DefaultTicketPrinter.formatLeft(maxWidth - 2 - MAX_PRICE_WIDTH - MAX_QTE_WIDTH, article.getName());
final String priceString = DefaultTicketPrinter.formatRight(MAX_PRICE_WIDTH, TicketCellRenderer.centsToString(multiply.movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue()));
prt.addToBuffer(qtyString + " " + nameString + " " + priceString);
final String nameString = DefaultTicketPrinter.formatLeft(maxWidth - 2 - MAX_PRICE_WIDTH - MAX_QTE_WIDTH - 1 - unitPriceString.length(), article.getName());
prt.addToBuffer(qtyString + " " + nameString + " " + unitPriceString + " " + priceString);
}
 
}
447,17 → 452,22
for (final Paiement paiement : this.paiements) {
 
String type = "";
final int montantInCents = paiement.getMontantInCents();
if (montantInCents != 0) {
if (montantInCents > 0) {
type = "Paiement ";
} else {
type = "Remboursement ";
}
if (paiement.getType() == Paiement.CB) {
type = "Paiement CB";
type = "CB";
} else if (paiement.getType() == Paiement.CHEQUE) {
type = "Paiement par chèque";
type = "par chèque";
} else if (paiement.getType() == Paiement.ESPECES) {
type = "Paiement en espèces";
type = "en espèces";
} else if (paiement.getType() == Paiement.SOLDE) {
type = "Paiement depuis solde";
type = "depuis solde";
}
final int montantInCents = paiement.getMontantInCents();
if (montantInCents > 0) {
type += " de " + TicketCellRenderer.centsToString(montantInCents);
if (montantInCents > 100) {
type += " euros";
514,8 → 524,15
 
}
 
public boolean isAdditionnalCopyRequested() {
return additionnalCopyRequested;
}
 
public void addArticle(final Article a) {
boolean alreadyExist = false;
if (a.isAdditionalCopyRequested()) {
this.additionnalCopyRequested = true;
}
for (final Pair<Article, Integer> line : this.items) {
if (line.getFirst().equals(a)) {
alreadyExist = true;
522,6 → 539,7
break;
}
}
 
if (!alreadyExist) {
final Pair<Article, Integer> line = new Pair<Article, Integer>(new Article(a), 1);
this.items.add(line);
595,10 → 613,11
}
 
public void setArticleCount(final Article article, final int count) {
if (count <= 0) {
this.clearArticle(article);
return;
}
// TODO Allow only if annulation?
// if (count <= 0) {
// this.clearArticle(article);
// return;
// }
Pair<Article, Integer> toModify = null;
for (final Pair<Article, Integer> line : this.items) {
if (line.getFirst().equals(article)) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/shipment/ui/BonDeLivraisonItemTable.java
61,6 → 61,7
import org.openconcerto.ui.table.XTableColumnModel;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.Tuple3;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.i18n.TranslationManager;
 
import java.awt.Component;
182,6 → 183,11
final SQLTableElement tableElementDesc = new SQLTableElement(e.getTable().getField("DESCRIPTIF"));
list.add(tableElementDesc);
 
if (e.getTable().getFieldsName().contains("DELAI")) {
final SQLTableElement tableElementDelai = new SQLTableElement(e.getTable().getField("DELAI"));
list.add(tableElementDelai);
}
 
// Valeur des métriques
final SQLTableElement tableElement_ValeurMetrique2 = new SQLTableElement(e.getTable().getField("VALEUR_METRIQUE_2"), Float.class) {
@Override
403,6 → 409,10
 
return new DeliveredQtyRowValuesRenderer();
}
 
protected Object getDefaultNullValue() {
return Integer.valueOf(0);
}
};
list.add(tableElement_QuantiteLivree);
 
643,9 → 653,32
for (String string : completionField) {
m.fill(string, string);
}
final Where w = new Where(sqlTableArticle.getField("OBSOLETE"), "=", Boolean.FALSE);
m.setWhere(w);
// final Where w = new Where(sqlTableArticle.getField("OBSOLETE"), "=", Boolean.FALSE);
// m.setWhere(w);
ITransformer<SQLSelect, SQLSelect> selTrans = new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(SQLSelect input) {
 
// FIXME utiliser le stock sélectionné sur la ligne et non le stock par défaut de
// l'article
final SQLTable tableStock = sqlTableArticle.getTable("STOCK");
input.andWhere(new Where(tableStock.getKey(), "=", sqlTableArticle.getField("ID_STOCK")));
input.setExcludeUndefined(false, tableStock);
Where w = new Where(sqlTableArticle.getField("OBSOLETE"), "=", Boolean.FALSE).or(new Where(input.getAlias(tableStock.getKey()), "=", tableStock.getUndefinedID()))
.or(new Where(input.getAlias(tableStock.getField("QTE_REEL")), ">", 0));
 
if (input.getWhere() != null) {
input.setWhere(input.getWhere().and(w));
} else {
input.setWhere(w);
}
input.asString();
return input;
}
};
 
m.setSelectTransformer(selTrans);
 
if (prefs.getBoolean(GestionArticleGlobalPreferencePanel.CAN_EXPAND_NOMENCLATURE_VT, true)) {
 
table.addMouseListener(new MouseAdapter() {
711,7 → 744,8
m2.fill(string, string);
}
 
m2.setWhere(w);
// m2.setWhere(w);
m2.setSelectTransformer(selTrans);
 
final AutoCompletionManager m3 = new AutoCompletionManager(tableElementArticle, sqlTableArticle.getField("NOM"), this.table, this.table.getRowValuesTableModel(),
ITextWithCompletion.MODE_CONTAINS, true, true, new ValidStateChecker()) {
731,7 → 765,8
m3.fill(string, string);
}
 
m3.setWhere(w);
// m3.setWhere(w);
m3.setSelectTransformer(selTrans);
 
// ECO Contribution
if (this.tableElementEco != null && this.tableElementEcoTotal != null && this.tableElementEcoID != null) {
770,7 → 805,8
tableElement_PrixVente_HT.addModificationListener(totalHT);
this.totalHT.setModifier(new CellDynamicModifier() {
public Object computeValueFrom(final SQLRowValues row, SQLTableElement source) {
int qte = Integer.parseInt(row.getObject("QTE_LIVREE").toString());
final Object qteL = row.getObject("QTE_LIVREE");
int qte = qteL == null ? 0 : Integer.parseInt(qteL.toString());
BigDecimal f = (BigDecimal) row.getObject("PV_HT");
System.out.println("Qte:" + qte + " et PV_HT:" + f);
BigDecimal b = (row.getObject("QTE_UNITAIRE") == null) ? BigDecimal.ONE : (BigDecimal) row.getObject("QTE_UNITAIRE");
788,7 → 824,8
});
this.totalHA.setModifier(new CellDynamicModifier() {
public Object computeValueFrom(final SQLRowValues row, SQLTableElement source) {
int qte = Integer.parseInt(row.getObject("QTE_LIVREE").toString());
final Object qteL = row.getObject("QTE_LIVREE");
int qte = qteL == null ? 0 : Integer.parseInt(qteL.toString());
BigDecimal f = (BigDecimal) row.getObject("PA_HT");
BigDecimal b = (row.getObject("QTE_UNITAIRE") == null) ? BigDecimal.ONE : (BigDecimal) row.getObject("QTE_UNITAIRE");
BigDecimal r = b.multiply(f.multiply(BigDecimal.valueOf(qte)), DecimalUtils.HIGH_PRECISION).setScale(totalHA.getDecimalDigits(), BigDecimal.ROUND_HALF_UP);
881,6 → 918,11
return row.getObject("PRIX_METRIQUE_VT_1");
}
}
// On ne recalcule pas le tarif si la ligne vient d'une commande
boolean noCmdElt = row.getObject("ID_COMMANDE_CLIENT_ELEMENT") == null || row.isForeignEmpty("ID_COMMANDE_CLIENT_ELEMENT");
if (!noCmdElt) {
return row.getObject("PRIX_METRIQUE_VT_1");
}
return tarifCompletion(row.getForeign("ID_ARTICLE"), "PRIX_METRIQUE_VT_1", row);
}
}
909,9 → 951,14
} else if (source != null && source.getField().getName().equalsIgnoreCase("PRIX_METRIQUE_VT_1")) {
return row.getObject("PRIX_METRIQUE_VT_1");
}
// On ne recalcule pas le tarif si la ligne vient d'une commande
boolean noCmdElt = row.getObject("ID_COMMANDE_CLIENT_ELEMENT") == null || row.isForeignEmpty("ID_COMMANDE_CLIENT_ELEMENT");
if (!noCmdElt) {
return row.getObject("PV_U_DEVISE");
}
return row.getObject("PV_U_DEVISE");
}
}
 
});
tableElementRemise.addModificationListener(this.tableElementTotalDevise);
989,13 → 1036,12
if (filterFamilleArticle) {
 
if (row.isForeignEmpty("ID_FAMILLE_ARTICLE")) {
m.setWhere(w);
m2.setWhere(w);
m.setWhere(null);
m2.setWhere(null);
 
} else {
m.setWhere(w.and(new Where(sqlTableArticle.getField("ID_FAMILLE_ARTICLE"), "=", row.getForeignID("ID_FAMILLE_ARTICLE"))));
m2.setWhere(w.and(new Where(sqlTableArticle.getField("ID_FAMILLE_ARTICLE"), "=", row.getForeignID("ID_FAMILLE_ARTICLE"))));
 
m.setWhere(new Where(sqlTableArticle.getField("ID_FAMILLE_ARTICLE"), "=", row.getForeignID("ID_FAMILLE_ARTICLE")));
m2.setWhere(new Where(sqlTableArticle.getField("ID_FAMILLE_ARTICLE"), "=", row.getForeignID("ID_FAMILLE_ARTICLE")));
}
}
SQLRowAccessor foreign = row.getForeign("ID_ARTICLE");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/credit/action/ListeDesAvoirsClientsAction.java
69,7 → 69,7
datePanel.setFilterOnDefault();
frame.getPanel().add(datePanel, c);
 
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
return frame;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/element/CommandeClientSQLElement.java
157,7 → 157,7
public void actionPerformed(ActionEvent e) {
transfertBonLivraisonClient(IListe.get(e).getSelectedRows());
}
}, false, "sales.order.create.deliverynote");
}, true, "sales.order.create.deliverynote");
 
// Transfert vers facture
RowAction factureAction = new RowAction(new AbstractAction() {
164,7 → 164,7
public void actionPerformed(ActionEvent e) {
transfertFactureClient(IListe.get(e).getSelectedRows());
}
}, false, "sales.order.create.invoice") {
}, true, "sales.order.create.invoice") {
 
@Override
public boolean enabledFor(List<SQLRowValues> selection) {
661,7 → 661,7
return TransfertGroupSQLComponent.openTransfertFrame(rows, "SAISIE_VENTE_FACTURE", VenteFactureSoldeSQLComponent.ID);
}
 
private BigDecimal getAvancement(SQLRowAccessor r) {
public BigDecimal getAvancement(SQLRowAccessor r) {
Collection<? extends SQLRowAccessor> rows = r.getReferentRows(r.getTable().getTable("TR_COMMANDE_CLIENT"));
long totalFact = 0;
long total = r.getLong("T_HT");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/element/CommandeClientElementSQLElement.java
93,6 → 93,9
l.add("ID_ARTICLE");
l.add("PA_HT");
l.add("PV_HT");
l.add("T_PA_HT");
l.add("T_PV_HT");
l.add("T_PV_TTC");
l.add("QTE");
l.add("QTE_UNITAIRE");
l.add("QTE_LIVREE");
192,7 → 195,7
@Override
public ListMap<String, String> getShowAs() {
final ListMap<String, String> res = new ListMap<String, String>();
res.putCollection("ID_COMMANDE_CLIENT", "NUMERO", "DATE", "DATE_LIVRAISON_PREV");
res.putCollection("ID_COMMANDE_CLIENT", "NUMERO", "ID_CLIENT", "DATE", "DATE_LIVRAISON_PREV");
if (getTable().contains("ID_ARTICLE")) {
res.putCollection("ID_ARTICLE", "ID_FAMILLE_ARTICLE", "ID_FOURNISSEUR");
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/action/ListeDesCommandesClientItemsAction.java
New file
0,0 → 1,109
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.sales.order.action;
 
import org.openconcerto.erp.action.CreateFrameAbstractAction;
import org.openconcerto.erp.core.common.ui.IListFilterDatePanel;
import org.openconcerto.erp.core.common.ui.IListTotalPanel;
import org.openconcerto.erp.core.common.ui.IListTotalPanel.Type;
import org.openconcerto.erp.core.common.ui.ListeViewPanel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.view.IListFrame;
import org.openconcerto.sql.view.list.BaseSQLTableModelColumn;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.Tuple2;
 
import java.awt.GridBagConstraints;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
 
import javax.swing.Action;
import javax.swing.JFrame;
 
public class ListeDesCommandesClientItemsAction extends CreateFrameAbstractAction {
 
public ListeDesCommandesClientItemsAction() {
super();
this.putValue(Action.NAME, "Liste des articles commandés");
}
 
public JFrame createFrame() {
final SQLElement element = Configuration.getInstance().getDirectory().getElement("COMMANDE_CLIENT_ELEMENT");
 
final SQLTableModelSourceOnline tableSource = element.getTableSource(true);
IListe liste = new IListe(tableSource);
final ListeViewPanel listeAddPanel = new ListeViewPanel(element, liste);
listeAddPanel.getListe().getRequest().setWhere(new Where(element.getTable().getField("ID_COMMANDE_CLIENT"), ">", 1));
 
BaseSQLTableModelColumn colStockR = new BaseSQLTableModelColumn("Qté restante à livrer", BigDecimal.class) {
 
@Override
protected Object show_(SQLRowAccessor r) {
 
BigDecimal qteAlivrer = r.getBigDecimal("QTE_UNITAIRE").multiply(new BigDecimal(r.getInt("QTE")));
BigDecimal qteLivree = BigDecimal.ZERO;
if (r.getObject("QTE_LIVREE") != null) {
qteLivree = r.getBigDecimal("QTE_LIVREE");
}
return qteAlivrer.subtract(qteLivree);
}
 
@Override
public Set<FieldPath> getPaths() {
Path p = new Path(element.getTable());
return CollectionUtils.createSet(new FieldPath(p, "QTE"), new FieldPath(p, "QTE_UNITAIRE"), new FieldPath(p, "QTE_LIVREE"));
}
};
tableSource.getColumns().add(colStockR);
 
List<Tuple2<? extends SQLTableModelColumn, Type>> listField = new ArrayList<Tuple2<? extends SQLTableModelColumn, Type>>();
listField.add(Tuple2.create(tableSource.getColumn(element.getTable().getField("QTE")), IListTotalPanel.Type.SOMME_QTE));
listField.add(Tuple2.create(colStockR, IListTotalPanel.Type.SOMME_QTE));
listField.add(Tuple2.create(tableSource.getColumn(element.getTable().getField("T_PA_HT")), IListTotalPanel.Type.SOMME));
listField.add(Tuple2.create(tableSource.getColumn(element.getTable().getField("T_PV_HT")), IListTotalPanel.Type.SOMME));
listField.add(Tuple2.create(tableSource.getColumn(element.getTable().getField("T_PV_TTC")), IListTotalPanel.Type.SOMME));
IListTotalPanel total = new IListTotalPanel(listeAddPanel.getListe(), listField, null, "Total");
GridBagConstraints c = new DefaultGridBagConstraints();
c.gridy = 2;
c.weightx = 0;
c.weighty = 0;
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.NONE;
listeAddPanel.add(total, c);
IListFrame frame = new IListFrame(listeAddPanel);
frame.setTextTitle("Liste des articles commandés");
frame.getPanel().getListe().setModificationAllowed(false);
frame.getPanel().setAddVisible(false);
frame.getPanel().setSearchFullMode(true);
 
// Date panel
IListFilterDatePanel datePanel = new IListFilterDatePanel(frame.getPanel().getListe(), element.getTable().getTable("COMMANDE_CLIENT").getField("DATE"), IListFilterDatePanel.getDefaultMap());
c.gridy++;
c.anchor = GridBagConstraints.CENTER;
frame.getPanel().add(datePanel, c);
 
return frame;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/element/SaisieVenteFactureSQLElement.java
20,6 → 20,7
import org.openconcerto.erp.core.common.ui.AbstractVenteArticleItemTable;
import org.openconcerto.erp.core.common.ui.DeviseField;
import org.openconcerto.erp.core.common.ui.PanelFrame;
import org.openconcerto.erp.core.edm.AttachmentAction;
import org.openconcerto.erp.core.finance.accounting.element.EcritureSQLElement;
import org.openconcerto.erp.core.sales.account.PartialInvoiceEditGroup;
import org.openconcerto.erp.core.sales.account.VenteFactureSituationSQLComponent;
127,6 → 128,8
public class SaisieVenteFactureSQLElement extends ComptaSQLConfElement {
 
public static final String TABLENAME = "SAISIE_VENTE_FACTURE";
static public final String MESSAGE_FIELD_NAME = "ID_SDD_MESSAGE";
static public final String END2END_FIELD_NAME = "SDD_EndToEndId";
 
public SaisieVenteFactureSQLElement() {
super(TABLENAME, "une facture", "factures");
159,6 → 162,12
}, false, "sales.invoice.create.delivery");
actionBL.setPredicate(IListeEvent.getSingleSelectionPredicate());
l.add(actionBL);
if (getTable().contains("ATTACHMENTS")) {
PredicateRowAction actionAttachment = new PredicateRowAction(new AttachmentAction().getAction(), true);
actionAttachment.setPredicate(IListeEvent.getSingleSelectionPredicate());
getRowActions().add(actionAttachment);
}
 
PredicateRowAction actionAvoir = new PredicateRowAction(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
TransfertBaseSQLComponent.openTransfertFrame(IListe.get(e).getSelectedRows(), "AVOIR_CLIENT");
188,7 → 197,7
((SaisieVenteFactureSQLComponent) editFrame.getSQLComponent()).loadFactureExistante(IListe.get(e).getSelectedId());
editFrame.setVisible(true);
}
}, false, "sales.invoice.clone") {
}, true, "sales.invoice.clone") {
public boolean enabledFor(IListeEvent evt) {
List<? extends SQLRowAccessor> l = evt.getSelectedRows();
if (l != null && l.size() == 1) {
249,7 → 258,6
 
@Override
protected void setupLinks(SQLElementLinksSetup links) {
 
super.setupLinks(links);
if (getTable().contains("ID_ADRESSE")) {
links.get("ID_ADRESSE").setType(LinkType.ASSOCIATION);
257,6 → 265,7
if (getTable().contains("ID_ADRESSE_LIVRAISON")) {
links.get("ID_ADRESSE_LIVRAISON").setType(LinkType.ASSOCIATION);
}
links.get(MESSAGE_FIELD_NAME).setType(LinkType.ASSOCIATION, ReferenceAction.RESTRICT);
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/element/EcheanceClientSQLElement.java
25,6 → 25,7
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLField;
37,6 → 38,8
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.EditPanel.EditMode;
import org.openconcerto.sql.view.list.BaseSQLTableModelColumn;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
77,6 → 80,23
public EcheanceClientSQLElement() {
super("ECHEANCE_CLIENT", "une échéance client", "échéances clients");
{
PredicateRowAction action = new PredicateRowAction(new AbstractAction("Détails client") {
 
@Override
public void actionPerformed(ActionEvent arg0) {
 
SQLElement eltClient = Configuration.getInstance().getDirectory().getElement(((ComptaPropsConfiguration) Configuration.getInstance()).getRootSociete().getTable("CLIENT"));
 
EditFrame edit = new EditFrame(eltClient, EditMode.MODIFICATION);
 
edit.selectionId(IListe.get(arg0).getSelectedRow().asRow().getInt("ID_CLIENT"));
edit.setVisible(true);
}
}, false);
action.setPredicate(IListeEvent.getSingleSelectionPredicate());
getRowActions().add(action);
}
{
PredicateRowAction action = new PredicateRowAction(new AbstractAction("Voir la source") {
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/action/ListeDesElementsFactureAction.java
58,7 → 58,7
listeAddPanel.add(total, c);
IListFrame frame = new IListFrame(listeAddPanel);
frame.setTextTitle("Liste des missions facturées");
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
frame.getPanel().setAddVisible(false);
frame.getPanel().setSearchFullMode(true);
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/action/ListeDesFactureItemsAction.java
46,6 → 46,7
final ListeViewPanel listeAddPanel = new ListeViewPanel(element, liste);
listeAddPanel.getListe().getRequest().setWhere(new Where(element.getTable().getField("ID_SAISIE_VENTE_FACTURE"), ">", 1));
List<SQLField> l = new ArrayList<SQLField>();
l.add(element.getTable().getField("QTE"));
l.add(element.getTable().getField("T_PA_HT"));
l.add(element.getTable().getField("T_PV_HT"));
l.add(element.getTable().getField("T_PV_TTC"));
59,7 → 60,7
listeAddPanel.add(total, c);
IListFrame frame = new IListFrame(listeAddPanel);
frame.setTextTitle("Liste des articles facturés");
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
frame.getPanel().setAddVisible(false);
frame.getPanel().setSearchFullMode(true);
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/action/ListeSDDMessageAction.java
New file
0,0 → 1,43
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.sales.invoice.action;
 
import org.openconcerto.erp.action.CreateFrameAbstractAction;
import org.openconcerto.erp.core.finance.payment.element.SDDMessageSQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.view.IListFrame;
import org.openconcerto.sql.view.ListeAddPanel;
 
import javax.swing.JFrame;
 
public class ListeSDDMessageAction extends CreateFrameAbstractAction {
 
private final SDDMessageSQLElement elem;
 
public ListeSDDMessageAction(SQLElementDirectory dir) {
super();
this.elem = dir.getElement(SDDMessageSQLElement.class);
}
 
public final SDDMessageSQLElement getElem() {
return this.elem;
}
 
@Override
public JFrame createFrame() {
final IListFrame res = new IListFrame(new ListeAddPanel(getElem()));
res.getPanel().setReadWriteButtonsVisible(false);
return res;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/ui/ListPanelEcheancesClients.java
128,7 → 128,7
 
final SQLTableModelSource src = ListPanelEcheancesClients.this.getListe().getSource();
 
ListPanelEcheancesClients.this.getListe().setSQLEditable(true);
ListPanelEcheancesClients.this.getListe().setModificationAllowed(true);
 
SQLField fieldDateEch = elementEchT.getField("DATE");
for (SQLTableModelColumn column : src.getColumns()) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/ui/ListeDesVentesPanel.java
18,19 → 18,25
import org.openconcerto.erp.core.common.ui.IListTotalPanel;
import org.openconcerto.erp.core.common.ui.ListeViewPanel;
import org.openconcerto.erp.core.finance.accounting.ui.ListeGestCommEltPanel;
import org.openconcerto.erp.core.sales.invoice.component.SaisieVenteFactureSQLComponent;
import org.openconcerto.erp.core.finance.payment.element.SDDMessageSQLElement;
import org.openconcerto.erp.core.finance.payment.element.SDDMessageSQLElement.GenerationResult;
import org.openconcerto.erp.core.finance.payment.element.SDDMessageSQLElement.IgnoreReason;
import org.openconcerto.erp.core.sales.invoice.element.SaisieVenteFactureSQLElement;
import org.openconcerto.erp.core.sales.pos.ui.TextAreaTicketPanel;
import org.openconcerto.erp.utils.TM;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.EditPanel;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelColumnPath;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
40,28 → 46,34
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.TableSorter;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.i18n.Grammar_fr;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.TableColumn;
 
public class ListeDesVentesPanel extends JPanel implements ActionListener {
public class ListeDesVentesPanel extends JPanel {
 
private ListeGestCommEltPanel listeFact;
private JButton buttonEnvoye, buttonRegle, buttonDupliquer;
// private JButton buttonEnvoye, buttonRegle, buttonDupliquer;
private JLabelBold textField = new JLabelBold("0");
private JLabelBold textField2 = new JLabelBold("0");
 
112,7 → 124,9
dateEnvoiCol.setColumnInstaller(new IClosure<TableColumn>() {
@Override
public void executeChecked(TableColumn columnDateEnvoi) {
columnDateEnvoi.setCellEditor(new org.openconcerto.ui.table.TimestampTableCellEditor());
final org.openconcerto.ui.table.TimestampTableCellEditor cellEditor = new org.openconcerto.ui.table.TimestampTableCellEditor();
cellEditor.setAllowNull(true);
columnDateEnvoi.setCellEditor(cellEditor);
columnDateEnvoi.setCellRenderer(new DateEnvoiRenderer());
}
});
120,17 → 134,88
// Edition des dates de reglement
if (dateReglCol != null) {
dateReglCol.setColumnInstaller(new IClosure<TableColumn>() {
 
@Override
public void executeChecked(TableColumn columnDateReglement) {
columnDateReglement.setCellEditor(new org.openconcerto.ui.table.TimestampTableCellEditor());
final org.openconcerto.ui.table.TimestampTableCellEditor cellEditor = new org.openconcerto.ui.table.TimestampTableCellEditor();
cellEditor.setAllowNull(true);
columnDateReglement.setCellEditor(cellEditor);
columnDateReglement.setCellRenderer(new DateEnvoiRenderer());
}
});
}
 
src.getColumns().add(new SQLTableModelColumnPath(new FieldPath(new Path(eltFacture.getTable()).addForeignField(SaisieVenteFactureSQLElement.MESSAGE_FIELD_NAME), "MessageIdentification")));
 
this.listeFact = new ListeGestCommEltPanel(eltFacture, new IListe(src), true);
final SDDMessageSQLElement sepaMsgElem = eltFacture.getDirectory().getElement(SDDMessageSQLElement.class);
final String aMessageLabel = sepaMsgElem.getName().getVariant(Grammar_fr.INDEFINITE_ARTICLE_SINGULAR);
this.listeFact.getListe().addIListeAction(new RowAction.PredicateRowAction(new AbstractAction("Générer " + aMessageLabel, null) {
@Override
public void actionPerformed(ActionEvent e) {
final IListe l = IListe.get(e);
final List<Integer> selectedIDs = l.getSelection().getSelectedIDs();
// TODO dialog with label informing of the successful creation of message for n
// invoices/n2 messages too far in the future/n3 messages with collection date
// changed and having a button to open the file chooser
new SwingWorker<GenerationResult, Object>() {
@Override
protected GenerationResult doInBackground() throws Exception {
return sepaMsgElem.generateXML(selectedIDs);
}
 
@Override
protected void done() {
final GenerationResult genRes;
try {
genRes = this.get();
} catch (Exception e) {
ExceptionHandler.handle(l, "Impossible de générer " + aMessageLabel, e);
return;
}
final int includedInvoicesCount = genRes.getIncludedInvoicesCount();
final Map<String, Object> tmMap = new HashMap<>();
tmMap.put("msgElem", sepaMsgElem.getName());
tmMap.put("invoiceElem", elementVF.getName());
tmMap.put("invoiceElemCount", includedInvoicesCount);
if (genRes.getDDInvoicesWithoutMessage().isEmpty()) {
JOptionPane.showMessageDialog(l, TM.getTM().trM("sddMessage.generation.noneNeeded", tmMap));
} else if (genRes.getIgnoredInvoices().isEmpty()) {
JOptionPane.showMessageDialog(l, TM.getTM().trM("sddMessage.generation.noneIgnored", tmMap));
} else {
final int futureCount = genRes.getIgnoredInvoices().getNonNull(IgnoreReason.TOO_FAR_IN_FUTURE).size();
final int duplicateCount = genRes.getIgnoredInvoices().getNonNull(IgnoreReason.DUPLICATE_MANDATE).size();
final int missingInfoCount = genRes.getIgnoredInvoices().getNonNull(IgnoreReason.MISSING_INFO).size();
tmMap.put("futureCount", futureCount);
tmMap.put("duplicateCount", duplicateCount);
tmMap.put("missingInfoCount", missingInfoCount);
final StringBuilder msg = new StringBuilder(256);
msg.append(TM.getTM().trM("sddMessage.generation.someIgnored", tmMap));
msg.append('\n');
if (futureCount > 0) {
msg.append("- ");
msg.append(TM.getTM().trM("sddMessage.generation.someIgnored.future", tmMap));
}
if (duplicateCount > 0) {
msg.append("- ");
msg.append(TM.getTM().trM("sddMessage.generation.someIgnored.duplicateMandate", tmMap));
}
if (missingInfoCount > 0) {
msg.append("- ");
msg.append(TM.getTM().trM("sddMessage.generation.someIgnored.missingInfo", tmMap));
}
final int messageType = duplicateCount == 0 ? JOptionPane.WARNING_MESSAGE : JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(l, msg.toString(), null, messageType);
}
if (genRes.getInsertedMessage() != null) {
sepaMsgElem.exportXML(l, Collections.singletonList(genRes.getInsertedMessage()));
}
}
}.execute();
}
}, false, true).setPredicate(IListeEvent.getNonEmptySelectionPredicate()));
this.listeFact.setOpaque(false);
this.listeFact.getListe().setSQLEditable(true);
this.listeFact.getListe().setModificationAllowed(true);
final JTable tableFact = this.listeFact.getListe().getJTable();
final SQLTableModelColumn numeroCol = src.getColumn(eltFacture.getTable().getField("NUMERO"));
((TableSorter) tableFact.getModel()).setSortingStatus(src.getColumns().indexOf(numeroCol), TableSorter.ASCENDING);
137,25 → 222,6
 
JPanel panelFacture = new JPanel(new GridBagLayout());
GridBagConstraints cFacture = new DefaultGridBagConstraints();
this.buttonEnvoye = new JButton("Facture envoyée");
cFacture.fill = GridBagConstraints.NONE;
this.buttonEnvoye.addActionListener(this);
this.buttonEnvoye.setEnabled(false);
panelFacture.setOpaque(false);
panelFacture.add(this.buttonEnvoye, cFacture);
// Reglé
this.buttonRegle = new JButton("Facture réglée");
this.buttonRegle.addActionListener(this);
this.buttonRegle.setEnabled(false);
cFacture.gridx++;
panelFacture.add(this.buttonRegle, cFacture);
//
this.buttonDupliquer = new JButton("Créer à partir de");
cFacture.fill = GridBagConstraints.NONE;
this.buttonDupliquer.addActionListener(this);
this.buttonDupliquer.setEnabled(false);
cFacture.gridx++;
panelFacture.add(this.buttonDupliquer, cFacture);
 
cFacture.gridy++;
cFacture.gridx = 0;
188,21 → 254,43
panelFacture.add(filterDate, cFacture);
tabbedPane.add("Ventes avec facture", panelFacture);
 
this.listeFact.getListe().addIListener(new org.openconcerto.sql.view.IListener() {
PredicateRowAction actionRegle = new PredicateRowAction(new AbstractAction("Facture réglée") {
 
public void selectionId(int id, int field) {
ListeDesVentesPanel.this.buttonEnvoye.setEnabled(id > 1);
ListeDesVentesPanel.this.buttonRegle.setEnabled(id > 1);
if (id > 1) {
final ITableModel model = ListeDesVentesPanel.this.listeFact.getListe().getModel();
@Override
public void actionPerformed(ActionEvent e) {
final List<SQLRowValues> selectedRows = IListe.get(e).getSelectedRows();
for (SQLRowAccessor sqlRowAccessor : selectedRows) {
final SQLRowValues rowVals = sqlRowAccessor.asRow().createEmptyUpdateRow();
rowVals.put("DATE_REGLEMENT", new Date());
try {
rowVals.update();
} catch (SQLException e1) {
ExceptionHandler.handle("Modification impossible", e1);
}
}
}
}, true);
actionRegle.setPredicate(IListeEvent.getNonEmptySelectionPredicate());
this.listeFact.getListe().addIListeAction(actionRegle);
 
SQLRowAccessor r = model.getRow(model.indexFromID(id)).getRow();
ListeDesVentesPanel.this.buttonDupliquer.setEnabled(!r.getBoolean("PARTIAL") && !r.getBoolean("SOLDE"));
} else {
ListeDesVentesPanel.this.buttonDupliquer.setEnabled(false);
PredicateRowAction actionEnvoye = new PredicateRowAction(new AbstractAction("Facture envoyée") {
 
@Override
public void actionPerformed(ActionEvent e) {
final List<SQLRowValues> selectedRows = IListe.get(e).getSelectedRows();
for (SQLRowAccessor sqlRowAccessor : selectedRows) {
final SQLRowValues rowVals = sqlRowAccessor.asRow().createEmptyUpdateRow();
rowVals.put("DATE_ENVOI", new Date());
try {
rowVals.update();
} catch (SQLException e1) {
ExceptionHandler.handle("Modification impossible", e1);
}
}
});
}
}, true);
actionEnvoye.setPredicate(IListeEvent.getNonEmptySelectionPredicate());
this.listeFact.getListe().addIListeAction(actionEnvoye);
 
 
{
249,7 → 337,7
// Tab Vente comptoir
{
final ListeGestCommEltPanel listeVC = new ListeGestCommEltPanel(Configuration.getInstance().getDirectory().getElement("SAISIE_VENTE_COMPTOIR"), true);
listeVC.getListe().setSQLEditable(false);
listeVC.getListe().setModificationAllowed(false);
listeVC.setOpaque(false);
 
final JTable table = listeVC.getListe().getJTable();
289,43 → 377,4
this.add(tabbedPane, c);
}
 
private EditFrame editFrame;
 
public void actionPerformed(ActionEvent e) {
 
if (e.getSource() == this.buttonEnvoye) {
final List<SQLRowValues> selectedRows = this.listeFact.getListe().getSelectedRows();
for (SQLRowAccessor sqlRowAccessor : selectedRows) {
final SQLRowValues rowVals = sqlRowAccessor.asRow().createEmptyUpdateRow();
rowVals.put("DATE_ENVOI", new Date());
try {
rowVals.update();
} catch (SQLException e1) {
ExceptionHandler.handle("Modification impossible", e1);
}
}
 
} else if (e.getSource() == this.buttonRegle) {
final List<SQLRowValues> selectedRows = this.listeFact.getListe().getSelectedRows();
for (SQLRowAccessor sqlRowAccessor : selectedRows) {
final SQLRowValues rowVals = sqlRowAccessor.asRow().createEmptyUpdateRow();
rowVals.put("DATE_REGLEMENT", new Date());
try {
rowVals.update();
} catch (SQLException e1) {
ExceptionHandler.handle("Modification impossible", e1);
}
}
} else {
if (e.getSource() == this.buttonDupliquer) {
if (this.editFrame == null) {
SQLElement eltFact = Configuration.getInstance().getDirectory().getElement("SAISIE_VENTE_FACTURE");
this.editFrame = new EditFrame(eltFact, EditPanel.CREATION);
}
final SQLRow selectedRow = this.listeFact.getListe().getSelectedRow().asRow();
((SaisieVenteFactureSQLComponent) this.editFrame.getSQLComponent()).loadFactureExistante(selectedRow.getID());
this.editFrame.setVisible(true);
}
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/element/ComptaSQLConfElement.java
16,17 → 16,9
import org.openconcerto.erp.config.Gestion;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.list.TableAction;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.task.config.ComptaBasePropsConfiguration;
 
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.AbstractAction;
 
/**
* SQLElement de la base société
*
35,7 → 27,6
*/
public abstract class ComptaSQLConfElement extends SocieteSQLConfElement {
 
 
private static DBRoot baseSociete;
 
private static DBRoot getBaseSociete() {
53,12 → 44,19
}
 
public ComptaSQLConfElement(String tableName) {
super(getBaseSociete().findTable(tableName, true), null);
this(tableName, null);
}
 
public ComptaSQLConfElement(String tableName, String code) {
super(getBaseSociete().findTable(tableName, true), code);
this(getBaseSociete().findTable(tableName, true), code);
}
 
public ComptaSQLConfElement(SQLTable table) {
this(table, null);
}
 
public ComptaSQLConfElement(SQLTable table, String code) {
super(table, code);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/AbstractAchatArticleItemTable.java.mine
File deleted
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/AbstractAchatArticleItemTable.java.r23577
File deleted
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/AbstractAchatArticleItemTable.java.r23597
File deleted
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/IListTotalPanel.java
52,6 → 52,8
MOYENNE_DEVISE,
// Somme total d'une colonne
SOMME,
// Somme total d'une colonne
SOMME_QTE,
// Marge en pourcentage requiert dans la liste la colonne achat en premier et vente en
// deuxieme
MOYENNE_MARGE,
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/component/SocieteCommonSQLElement.java
13,22 → 13,6
package org.openconcerto.erp.core.common.component;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
 
import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.ui.PanelFrame;
import org.openconcerto.erp.panel.ChargementCreationSocietePanel;
52,6 → 36,22
import org.openconcerto.ui.component.InteractionMode;
import org.openconcerto.utils.ListMap;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
 
import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
 
/**
* Sociétés existantes avec le nom de la base associée
*/
278,7 → 278,7
this.add(fieldIban, c);
this.addView(fieldIban, "IBAN");
 
// Capital
// BIC
c.gridx++;
c.weightx = 0;
JLabel labelBIC = new JLabel(getLabelFor("BIC"));
291,6 → 291,20
this.add(fieldBIC, c);
this.addView(fieldBIC, "BIC");
 
// SEPA creditor
c.gridx = 0;
c.gridy++;
c.weightx = 0;
JLabel labelICS = new JLabel(getLabelFor("SEPA_CREDITOR_ID"));
labelICS.setHorizontalAlignment(SwingConstants.RIGHT);
this.add(labelICS, c);
 
c.gridx++;
c.weightx = 1;
JTextField fieldICS = new JTextField();
this.add(fieldICS, c);
this.addView(fieldICS, "SEPA_CREDITOR_ID");
 
// Assurance
if (getTable().contains("NUMERO_POLICE")) {
c.gridy++;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/credit/action/ListeDesAvoirsFournisseurAction.java
70,7 → 70,7
final IListFrame frame = new IListFrame(panel);
frame.getPanel().setAddVisible(true);
frame.getPanel().getListe().addIListeActions(new MouseSheetXmlListeListener(AvoirFournisseurXmlSheet.class).getRowActions());
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
 
return frame;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/element/FactureFournisseurSQLElement.java
13,18 → 13,19
package org.openconcerto.erp.core.supplychain.order.element;
 
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.erp.core.edm.AttachmentAction;
import org.openconcerto.erp.core.supplychain.order.component.FactureFournisseurSQLComponent;
import org.openconcerto.erp.generationDoc.gestcomm.FactureFournisseurXmlSheet;
import org.openconcerto.erp.model.MouseSheetXmlListeListener;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
import org.openconcerto.utils.ListMap;
 
import java.util.ArrayList;
import java.util.List;
 
public class FactureFournisseurSQLElement extends ComptaSQLConfElement {
 
public FactureFournisseurSQLElement() {
33,7 → 34,12
mouseSheetXmlListeListener.setGenerateHeader(true);
mouseSheetXmlListeListener.setShowHeader(true);
getRowActions().addAll(mouseSheetXmlListeListener.getRowActions());
if (getTable().contains("ATTACHMENTS")) {
PredicateRowAction actionAttachment = new PredicateRowAction(new AttachmentAction().getAction(), true);
actionAttachment.setPredicate(IListeEvent.getSingleSelectionPredicate());
getRowActions().add(actionAttachment);
}
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/order/ui/ListPanelEcheancesFourn.java
86,7 → 86,7
}
this.getListe().getRequest().setWhere(wNotRegle);
 
this.getListe().setSQLEditable(false);
this.getListe().setModificationAllowed(false);
 
final JTable jTable = this.getListe().getJTable();
final int columnCount = jTable.getColumnCount();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/customer/element/CustomerGroup.java
61,9 → 61,18
gContact.addItem("customerrelationship.customer.contacts", new LayoutHints(true, true, true, true, true, true, true, true));
this.add(gContact);
 
final Group gProspect = new Group("customerrelationship.customer.lead", LayoutHints.DEFAULT_SEPARATED_GROUP_HINTS);
gProspect.addItem("ACCEPTE_TEL");
gProspect.addItem("ACCEPTE_SMS");
gProspect.addItem("ACCEPTE_EMAIL");
gProspect.addItem("ACCEPTE_COURRIER");
this.add(gProspect);
final Group gPayment = new Group("customerrelationship.customer.payment", LayoutHints.DEFAULT_SEPARATED_GROUP_HINTS);
gPayment.addItem("RIB", LayoutHints.DEFAULT_LARGE_FIELD_HINTS);
gPayment.addItem("CENTRE_GESTION", LayoutHints.DEFAULT_LARGE_FIELD_HINTS);
gPayment.addItem("IBAN", LayoutHints.DEFAULT_LARGE_FIELD_HINTS);
gPayment.addItem("BIC", LayoutHints.DEFAULT_FIELD_HINTS);
gPayment.addItem("ID_MODE_REGLEMENT", new LayoutHints(true, true, true, true, true, false, true, true));
gPayment.addItem("ID_COMPTE_PCE");
gPayment.addItem("ENCOURS_MAX");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/customer/element/ContactSQLElementBase.java
195,6 → 195,9
if (getTable().contains("N4DS")) {
addView("N4DS");
}
 
if (getTable().contains("DATE_NAISSANCE"))
this.addView("DATE_NAISSANCE");
}
 
public void setIdClient(int idClient) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/customer/element/ContactItemTable.java
21,10 → 21,15
import org.openconcerto.sql.view.list.RowValuesTableModel;
import org.openconcerto.sql.view.list.RowValuesTableRenderer;
import org.openconcerto.sql.view.list.SQLTableElement;
import org.openconcerto.ui.FormatEditor;
import org.openconcerto.utils.FormatGroup;
import org.openconcerto.utils.convertor.DateToSQLConvertor;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.io.File;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Vector;
 
104,6 → 109,20
list.add(tableElementNoMailing);
}
 
if (elt.getTable().contains("DATE_NAISSANCE")) {
list.add(new SQLTableElement(elt.getTable().getField("DATE_NAISSANCE")) {
private final DateToSQLConvertor conv = new DateToSQLConvertor();
{
this.setEditor(new FormatEditor(
new FormatGroup(DateFormat.getDateInstance(DateFormat.SHORT), DateFormat.getDateInstance(DateFormat.MEDIUM), DateFormat.getDateInstance(DateFormat.LONG))));
}
 
@Override
public Object convertEditorValueToModel(Object value, SQLRowValues row) {
return this.conv.convert((Date) value);
}
});
}
final RowValuesTableModel model = new RowValuesTableModel(elt, list, elt.getTable().getField("NOM"), false, defaultRow);
 
this.table = new RowValuesTable(model, new File(Configuration.getInstance().getConfDir(), "Table" + File.separator + "Table_Contact.xml"));
/trunk/OpenConcerto/src/org/openconcerto/erp/core/customerrelationship/customer/element/CustomerSQLComponent.java
141,7 → 141,7
 
}
});
t.addAction(new AbstractAction("Modifier/Supprimer") {
t.addAction(new AbstractAction(TM.tr("modify.or.delete")) {
 
@Override
public void actionPerformed(ActionEvent e) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/element/ComptePCESQLElement.java
27,6 → 27,7
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
344,12 → 345,20
if (field == null) {
throw new IllegalArgumentException("no field NUMERO in table " + compteTable.getName());
}
numero = numero.trim();
SQLRow res = cacheForTable.getFirstRowContains(numero, field);
 
SQLRow res = cacheForTable.getFirstRowContains(numero.trim(), field);
 
if (res != null) {
return res;
} else {
// Verification en BD
SQLSelect sel = new SQLSelect();
sel.addSelectStar(compteTable);
sel.setWhere(new Where(compteTable.getField("NUMERO"), "=", numero));
List<SQLRow> resultInDb = SQLRowListRSH.execute(sel);
if (!resultInDb.isEmpty()) {
return cacheForTable.getRows().get(0);
} else {
 
SQLRowValues rowVals = new SQLRowValues(compteTable);
rowVals.put("NUMERO", numero);
360,9 → 369,9
ExceptionHandler.handle("Erreur lors de la création du compte numéro : " + numero, e);
return null;
}
 
}
}
}
 
/**
* retourne l'id d'un compte en fonction de son numero, si le compte n'existe pas il sera créé
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/element/EcritureSQLElement.java
169,7 → 169,7
Where w = new Where(ecrTable.getField("ID_JOURNAL"), "=", rowEcr.getInt("ID_JOURNAL"));
 
f2.getPanel().getListe().getRequest().setWhere(w);
f2.getPanel().getListe().setSQLEditable(false);
f2.getPanel().getListe().setModificationAllowed(false);
f2.pack();
f2.setVisible(true);
}
202,7 → 202,7
Where w = new Where(ecrTable.getField("ID_COMPTE_PCE"), "=", rowCpt.getID());
f.getPanel().getListe().getRequest().setWhere(w);
 
f.getPanel().getListe().setSQLEditable(false);
f.getPanel().getListe().setModificationAllowed(false);
f.pack();
f.setVisible(true);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/report/Map2033A.java
18,9 → 18,7
import org.openconcerto.erp.core.finance.accounting.model.SommeCompte;
import org.openconcerto.erp.preferences.TemplateNXProps;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.GestionDevise;
 
import java.io.File;
349,15 → 347,12
long v072 = this.sommeCompte.soldeCompteDebiteur(4455, 4455, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteDebiteur(421, 421, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteDebiteur(400, 408, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompte(4096, 4098, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.sommeCompteFils("425", this.dateDebut, this.dateFin) + this.sommeCompte.sommeCompteFils("4287", this.dateDebut, this.dateFin)
+ this.sommeCompte.sommeCompteFils("4374", this.dateDebut, this.dateFin) + this.sommeCompte.sommeCompteFils("4387", this.dateDebut, this.dateFin)
+ this.sommeCompte.sommeCompteFils("441", this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteDebiteur(443, 444, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.sommeCompteFils("4456", this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompte(44581, 44583, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteDebiteur(44586, 44586, true, this.dateDebut, this.dateFin) + this.sommeCompte.sommeCompteFils("4487", this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteDebiteur(43, 43, true, this.dateDebut, this.dateFin) + this.sommeCompte.sommeCompteFils("441", this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteDebiteur(443, 445, true, this.dateDebut, this.dateFin) + this.sommeCompte.sommeCompteFils("4487", this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteDebiteur(451, 451, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteDebiteur(455, 455, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteDebiteur(4560, 4561, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteDebiteur(4563, 4569, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteDebiteur(458, 458, true, this.dateDebut, this.dateFin) + this.sommeCompte.sommeCompteFils("462", this.dateDebut, this.dateFin)
+ this.sommeCompte.sommeCompteFils("465", this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteDebiteur(467, 467, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.sommeCompteFils("4687", this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteDebiteur(478, 478, true, this.dateDebut, this.dateFin);
+ this.sommeCompte.soldeCompteDebiteur(458, 458, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteDebiteur(46, 46, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteDebiteur(478, 478, true, this.dateDebut, this.dateFin);
this.m.put("ACTIF1.9", GestionDevise.currencyToString(v072, false));
 
// 074 -SommeSolde( 495, 499 )
714,7 → 709,7
// Racine = "400-401, 403, 4080-4081, 4088"
// S166=-40(C)...405-40A(C)...40Z-403-4081-4084-4088
long v166 = this.sommeCompte.soldeCompteCrediteur(403, 403, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(401, 401, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(4081, 4081, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(4088, 4088, true, this.dateDebut, this.dateFin);
+ this.sommeCompte.soldeCompteCrediteur(408, 408, true, this.dateDebut, this.dateFin);
// float v166 = this.sommeCompte.soldeCompteCrediteur(400, 401, true) -
// this.sommeCompte.sommeCompteFils("403") +
// this.sommeCompte.soldeCompte(4080, 4081, false)
790,20 → 785,13
+ this.sommeCompte.soldeCompteCrediteur(422, 422, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(424, 424, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(427, 427, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(4282, 4282, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(4284, 4284, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(4286, 4286, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(43, 43, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompteCrediteur(4387, 4387, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(442, 442, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(443, 443, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(444, 444, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(4455, 4455, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(44586, 44586, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(4457, 4457, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(44584, 44584, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(44587, 44587, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(455, 455, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompte(446, 447, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(4482, 4482, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompte(4486, 4486, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(457, 457, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompte(269, 269, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(279, 279, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompte(404, 405, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(4084, 4084, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompte(4088, 4088, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(4196, 4198, true, this.dateDebut, this.dateFin)
 
- this.sommeCompte.soldeCompte(464, 464, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(467, 467, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(4686, 4686, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(478, 478, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(43, 43, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(442, 442, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(443, 445, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(455, 455, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(446, 447, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompte(4482, 4482, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(4486, 4486, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompte(457, 457, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(269, 269, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompte(279, 279, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(404, 405, true, this.dateDebut, this.dateFin) - this.sommeCompte.soldeCompte(4196, 4198, true, this.dateDebut, this.dateFin)
+ this.sommeCompte.soldeCompteCrediteur(46, 46, true, this.dateDebut, this.dateFin) + this.sommeCompte.soldeCompteCrediteur(478, 478, true, this.dateDebut, this.dateFin)
- this.sommeCompte.soldeCompte(509, 509, true, this.dateDebut, this.dateFin);
 
this.m.put("PASSIF3.28", GestionDevise.currencyToString(v172, false));
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/report/GrandLivreSheetXML.java
380,13 → 380,14
} else {
 
// si on change de compte alors on applique le style Titre 1
if (rowFirstEcr != null && idCptFirstEcr != idCpt && (!this.centralFourn || (!(numCptFirstEcr.startsWith("401") && numCpt.startsWith("401"))))
if (rowFirstEcr != null && !numCptFirstEcr.equals(numCpt) && (!this.centralFourn || (!(numCptFirstEcr.startsWith("401") && numCpt.startsWith("401"))))
&& (!this.centralClient || (!(numCptFirstEcr.startsWith("411") && numCpt.startsWith("411"))))) {
 
makeSousTotal(rowFirstEcr.getString("COMPTE_NUMERO"), rowFirstEcr.getString("COMPTE_NOM"), ooLine, style, tableauVals.size() - 1, sousTotalDebit, sousTotalCredit);
 
rowFirstEcr = rowEcr;
idCptFirstEcr = rowFirstEcr.getInt("ID_COMPTE_PCE");
numCptFirstEcr = rowEcr.getString("COMPTE_NUMERO");
makeSousTotal(numCpt, nomCpt, ooLine, style, tableauVals.size() - 1, sousTotalDebit, sousTotalCredit);
 
sousTotalCredit = 0;
sousTotalDebit = 0;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/action/ListeDesEcrituresAction.java
139,7 → 139,7
frame.getPanel().setAddVisible(false);
frame.getPanel().setModifyVisible(false);
frame.getPanel().setReloadVisible(true);
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
 
table.addMouseListener(new MouseAdapter() {
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/LettragePanel.java
36,6 → 36,7
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.TitledSeparator;
import org.openconcerto.ui.warning.JLabelWarning;
285,7 → 286,7
c.gridheight = 3;
this.model = new LettrageModel(this.selCompte.getSelectedId());
JTable table = new JTable(this.model);
 
table.setRowHeight(FontUtils.getPreferredRowHeight(table));
// AlternateTableCellRenderer.setAllColumns(table);
for (int i = 0; i < table.getColumnCount(); i++) {
// if (table.getColumnClass(i) == Long.class || table.getColumnClass(i) ==
693,7 → 694,7
}
 
this.ecriturePanel.getListe().getRequest().setWhere(w);
this.ecriturePanel.getListe().setSQLEditable(false);
this.ecriturePanel.getListe().setModificationAllowed(false);
 
this.model.setIdCompte(Integer.parseInt(idCpt.toString()));
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/BalancePanel.java
17,6 → 17,7
import org.openconcerto.erp.core.finance.accounting.model.BalanceModel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.state.JTableStateManager;
import org.openconcerto.utils.GestionDevise;
 
62,6 → 63,7
 
final BalanceModel model = new BalanceModel();
final JTable table = new JTable(model);
table.setRowHeight(FontUtils.getPreferredRowHeight(table));
new SwingWorker<String, Object>() {
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/PlanComptableEPanel.java
25,6 → 25,7
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.EditPanel;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.TitledSeparator;
 
import java.awt.Dimension;
181,7 → 182,7
final PlanComptableEModel model = new PlanComptableEModel(ccTmp);
 
final JTable table = new JTable(model);
 
table.setRowHeight(FontUtils.getPreferredRowHeight(table));
table.getColumnModel().getColumn(0).setCellRenderer(new PlanComptableCellRenderer(0));
table.getColumnModel().getColumn(1).setCellRenderer(new PlanComptableCellRenderer(0));
// table.getColumnModel().getColumn(0).setPreferredWidth(30);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/PlanComptableGPanel.java
22,6 → 22,7
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.JMultiLineToolTip;
import org.openconcerto.ui.TitledSeparator;
 
251,7 → 252,7
return t;
}
};
 
table.setRowHeight(FontUtils.getPreferredRowHeight(table));
table.getColumnModel().getColumn(0).setCellRenderer(new PlanComptableCellRenderer(0));
table.getColumnModel().getColumn(1).setCellRenderer(new PlanComptableCellRenderer(0));
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/PointagePanel.java
34,6 → 34,7
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.TitledSeparator;
import org.openconcerto.ui.warning.JLabelWarning;
289,7 → 290,7
c.gridheight = 3;
this.model = new PointageModel(this.selCompte.getSelectedId());
JTable table = new JTable(this.model);
 
table.setRowHeight(FontUtils.getPreferredRowHeight(table));
// AlternateTableCellRenderer.setAllColumns(table);
final DeviseNiceTableCellRenderer cellRenderer = new DeviseNiceTableCellRenderer();
for (int i = 0; i < table.getColumnCount(); i++) {
620,7 → 621,7
}
 
this.ecriturePanel.getListe().getRequest().setWhere(w);
this.ecriturePanel.getListe().setSQLEditable(false);
this.ecriturePanel.getListe().setModificationAllowed(false);
 
this.model.setIdCompte(Integer.parseInt(idCpt.toString()));
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/ImportEcriturePanel.java
21,6 → 21,7
import org.openconcerto.openoffice.ContentTypeVersioned;
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLBackgroundTableCache;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowListRSH;
141,9 → 142,11
}
final DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
final String mouvementName = "Import " + format.format(new Date());
SQLBackgroundTableCache.getInstance().getCacheForTable(rootSociete.getTable("COMPTE_PCE")).setEnableReloadIfTableModified(false);
// Vérification des données
boolean ok = importTableModel(model, mouvementName, frame, true);
if (ok) {
 
// Importation des données
importTableModel(model, mouvementName, frame, false);
SwingUtilities.invokeLater(new Runnable() {
155,6 → 158,8
}
} catch (Exception exn) {
ExceptionHandler.handle("Erreur pendant l'importation", exn);
} finally {
SQLBackgroundTableCache.getInstance().getCacheForTable(rootSociete.getTable("COMPTE_PCE")).setEnableReloadIfTableModified(true);
}
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/CompteGestCommPreferencePanel.java
46,6 → 46,7
private final static SQLBase base = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete();
private static final SQLTable tablePrefCompte = base.getTable("PREFS_COMPTE");
private SQLRowValues rowPrefCompteVals = new SQLRowValues(tablePrefCompte);
private JCheckBox checkLettrageAuto = new JCheckBox("Activer le lettrage automatique.");
private JCheckBox checkHideCompteFacture = new JCheckBox("Ne pas afficher les comptes dans les factures.");
private JCheckBox checkHideCompteClient = new JCheckBox("Ne pas afficher les comptes dans les clients.");
private JCheckBox checkHideAnalytique = new JCheckBox("Ne pas afficher l'analytique dans les saisies au kilomètre.");
73,7 → 74,8
c.weighty = 0;
 
c.gridwidth = GridBagConstraints.REMAINDER;
 
this.add(this.checkLettrageAuto, c);
c.gridy++;
this.add(this.checkHideCompteClient, c);
c.gridy++;
this.add(this.checkHideCompteFacture, c);
330,6 → 332,7
this.rowPrefCompteVals.put("ID_COMPTE_PCE_TVA_IMMO", this.selCompteTVAImmo.getValue());
this.rowPrefCompteVals.put("ID_COMPTE_PCE_PORT_SOUMIS", this.selComptePortSoumis.getValue());
this.rowPrefCompteVals.put("ID_COMPTE_PCE_PORT_NON_SOUMIS", this.selComptePortNonSoumis.getValue());
this.rowPrefCompteVals.put("AUTO_LETTRAGE", this.checkLettrageAuto.isSelected());
DefaultNXProps.getInstance().setProperty("HideCompteClient", String.valueOf(this.checkHideCompteClient.isSelected()));
DefaultNXProps.getInstance().setProperty("HideCompteFacture", String.valueOf(this.checkHideCompteFacture.isSelected()));
DefaultNXProps.getInstance().setProperty("HideAnalytique", String.valueOf(this.checkHideAnalytique.isSelected()));
349,6 → 352,8
 
compte = ComptePCESQLElement.getComptePceDefault("Achats");
 
this.checkLettrageAuto.setSelected(false);
 
int value = ComptePCESQLElement.getId(compte);
this.selCompteAchat.setValue(value);
 
458,6 → 463,7
setComboValues(selCompteTVADed, "ID_COMPTE_PCE_TVA_ACHAT", "TVADeductible");
setComboValues(selCompteTVAIntraComm, "ID_COMPTE_PCE_TVA_INTRA", "TVAIntraComm");
setComboValues(selCompteTVAImmo, "ID_COMPTE_PCE_TVA_IMMO", "TVAImmo");
this.checkLettrageAuto.setSelected(rowPrefCompteVals.getBoolean("AUTO_LETTRAGE"));
this.checkHideCompteClient.setSelected(Boolean.valueOf(DefaultNXProps.getInstance().getProperty("HideCompteClient")));
this.checkHideCompteFacture.setSelected(Boolean.valueOf(DefaultNXProps.getInstance().getProperty("HideCompteFacture")));
this.checkHideAnalytique.setSelected(Boolean.valueOf(DefaultNXProps.getInstance().getProperty("HideAnalytique")));
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/ListPanelEcritures.java
45,7 → 45,7
super(element, l);
 
this.buttonAjouter.setVisible(false);
this.getListe().setSQLEditable(false);
this.getListe().setModificationAllowed(false);
 
// TODO verifier que ca fonctionne, si selection d'une ecriture valide alors bouton disable
this.getListe().addIListener(new IListener() {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/accounting/ui/EtatJournauxPanel.java
303,7 → 303,7
this.listEcriture.setModificationVisible(false);
this.listEcriture.setAjoutVisible(false);
this.listEcriture.setSuppressionVisible(false);
this.listEcriture.getListe().setSQLEditable(false);
this.listEcriture.getListe().setModificationAllowed(false);
 
Dimension d;
// Taille limitée à 200 maximum
323,7 → 323,7
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
 
this.listEcriture.getListe().setSQLEditable(false);
this.listEcriture.getListe().setModificationAllowed(false);
 
panelMoisCompte.add(this.listEcriture, c);
this.listEcriture.getListe().getJTable().addMouseListener(new MouseAdapter() {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/payment/element/SDDMessageSQLElement.java
New file
0,0 → 1,673
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.finance.payment.element;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.erp.core.sales.invoice.element.SaisieVenteFactureSQLElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.UISQLComponent;
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSchema;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSelect.LockStrength;
import org.openconcerto.sql.model.SQLSelectJoin;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.sql.request.SQLFieldTranslator;
import org.openconcerto.sql.utils.SQLCreateTable;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.utils.CollectionMap2Itf.ListMapItf;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.TimeUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.XMLDateFormat;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.i18n.Grammar_fr;
import org.openconcerto.xml.JDOM2Utils;
 
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Clob;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import java.util.prefs.Preferences;
 
import javax.swing.AbstractAction;
import javax.swing.JFileChooser;
 
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
 
public final class SDDMessageSQLElement extends ComptaSQLConfElement {
static final String TABLE_NAME = "SEPA_DIRECT_DEBIT_MESSAGE";
static public final String XML_LOCATION_PREF_KEY = "SDD.XML.location";
public static final String SERIAL_MD = "SDD_MESSAGE_SERIAL";
 
public static SQLCreateTable getCreateTable(final DBRoot root) {
if (root.contains(TABLE_NAME))
return null;
final SQLCreateTable res = new SQLCreateTable(root, TABLE_NAME);
res.addVarCharColumn("MessageIdentification", 35);
res.addColumn("CreationDateTime", res.getSyntax().getDateAndTimeType(), null, false);
res.addIntegerColumn("NumberOfTransactions", 0);
res.addDecimalColumn("ControlSum", 16, 6, BigDecimal.ZERO, false);
res.addColumn("XML", res.getSyntax().getTypeNames(Clob.class).iterator().next(), null, false);
return res;
}
 
private final String prefsPath;
private final SQLRow rowSociété;
private final SQLPreferences dbPrefs;
private final SQLFieldTranslator fieldTranslator;
 
public SDDMessageSQLElement(final ComptaPropsConfiguration conf) {
super(conf.getRootSociete().findTable(TABLE_NAME, true));
this.prefsPath = conf.getAppID() + '/' + this.getCode().replace('.', '/');
this.getRowActions().add(new RowAction.PredicateRowAction(new AbstractAction("Exporter…") {
@Override
public void actionPerformed(ActionEvent e) {
final IListe l = IListe.get(e);
// XML field values are quite large so only fetch them when needed
final SQLTable t = l.getSource().getPrimaryTable();
final SQLSelect sel = new SQLSelect().addSelectStar(t);
sel.setWhere(new Where(t.getKey(), l.getSelection().getUserSelectedIDs()));
exportXML(l, SQLRowListRSH.execute(sel));
}
}, true, false).setPredicate(IListeEvent.getNonEmptySelectionPredicate()));
this.rowSociété = conf.getRowSociete();
this.dbPrefs = new SQLPreferences(conf.getRootSociete());
this.fieldTranslator = conf.getTranslator();
}
 
public final Preferences getPreferences() {
return Preferences.userRoot().node(this.prefsPath);
}
 
@Override
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("MessageIdentification");
l.add("CreationDateTime");
l.add("NumberOfTransactions");
l.add("ControlSum");
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("MessageIdentification");
l.add("CreationDateTime");
l.add("ControlSum");
return l;
}
 
@Override
public Set<String> getReadOnlyFields() {
return this.getTable().getFieldsName();
}
 
@Override
protected SQLComponent createComponent() {
return new UISQLComponent(this) {
@Override
protected void addViews() {
this.addView("MessageIdentification");
this.addView("CreationDateTime");
this.addView("NumberOfTransactions");
this.addView("ControlSum");
this.addView("XML");
}
};
}
 
@Override
protected String createCode() {
// TODO rename createCodeFromPackage() to createCodeOfPackage() and change createCode()
// implementation to use a new createCodeFromPackage() which uses the class name (w/o
// SQLElement suffix)
return this.createCodeFromPackage() + ".SDDMessage";
}
 
public final void exportXML(final Component comp, final List<? extends SQLRowAccessor> messages) {
final Preferences sddMsgPrefs = getPreferences();
final String storedPath = sddMsgPrefs.get(XML_LOCATION_PREF_KEY, "");
final JFileChooser fileChooser = new JFileChooser(storedPath);
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
final int answer = fileChooser.showDialog(comp, "Exporter " + getName().getVariant(Grammar_fr.DEFINITE_ARTICLE_PLURAL));
if (answer == JFileChooser.APPROVE_OPTION) {
final String newPath = fileChooser.getSelectedFile().getAbsolutePath();
sddMsgPrefs.put(XML_LOCATION_PREF_KEY, newPath);
final File directDebitDir = new File(newPath);
try {
for (final SQLRowAccessor messageRow : messages) {
FileUtils.write(messageRow.getString("XML"), new File(directDebitDir, messageRow.getString("MessageIdentification") + ".xml"), StringUtils.UTF8, false);
}
} catch (IOException exn) {
ExceptionHandler.handle(comp, "Impossible d'exporter", exn);
}
}
}
 
protected static BigDecimal getInvoiceAmount(final SQLRowValues invoice) {
return BigDecimal.valueOf(invoice.getLong("NET_A_PAYER")).movePointLeft(2);
}
 
static private final class InvoiceElem extends Tuple2<SQLRowValues, Element> {
protected InvoiceElem(SQLRowValues a, Element b) {
super(a, b);
}
}
 
// Un lot est obligatoirement homogène sur les critères suivants :
// - Même type de prélèvement SEPA (index 2.11 « LocalInstrument ») : SDD Core ou
// SDD B2B
// - Même séquence de présentation (index 2.14 « SequenceType ») : FRST ou RCUR
static private final class PaymentInfo {
private final Date collectionDate;
private final String seqType;
private final List<InvoiceElem> invoices;
private final BigDecimal sum;
 
protected PaymentInfo(Date collectionDate, String seqType, List<InvoiceElem> invoices) {
super();
this.collectionDate = collectionDate;
if (!SEPAMandateSQLElement.SEQ_VALUES.contains(seqType))
throw new IllegalArgumentException("Invalid sequence type : " + seqType);
this.seqType = seqType;
this.invoices = invoices;
BigDecimal d = BigDecimal.ZERO;
for (final InvoiceElem invoice : invoices) {
d = d.add(getInvoiceAmount(invoice.get0()));
}
this.sum = d;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " for " + this.invoices.size() + " " + this.seqType + " invoices at " + this.collectionDate;
}
}
 
static private final class InvoicesByPaymentInfo {
private final Date lowerBound, upperBound;
 
private final NavigableMap<Date, ListMap<String, InvoiceElem>> map = new TreeMap<>();
private final Set<Number> lockedInvoicesIDs = new HashSet<>();
private BigDecimal sum = BigDecimal.ZERO;
private final Set<String> invoiceNumbers = new HashSet<>();
private final Set<String> invoiceMandates = new HashSet<>();
private final ElementCreator elemCreator;
 
protected InvoicesByPaymentInfo(Date lowerBound, Date upperBound, final ElementCreator elemCreator) {
super();
if (lowerBound.compareTo(upperBound) >= 0)
throw new IllegalArgumentException("Lower date after upper date : " + lowerBound + " >= " + upperBound);
this.lowerBound = lowerBound;
this.upperBound = upperBound;
this.elemCreator = elemCreator;
}
 
final IgnoreReason addInvoice(final SQLRowValues invoice) {
Date dueDate = ModeDeReglementSQLElement.calculDate(invoice.getForeign("ID_MODE_REGLEMENT"), invoice.getObjectAs("DATE", Date.class));
 
// don't ask direct debit too far in advance
if (dueDate.after(this.upperBound)) {
return IgnoreReason.TOO_FAR_IN_FUTURE;
} else if (dueDate.before(this.lowerBound)) {
dueDate = this.lowerBound;
}
 
final Element elem;
try {
elem = createDDTx(this.elemCreator, invoice);
} catch (MissingInfoException e) {
return IgnoreReason.MISSING_INFO;
}
 
// needed so that EndToEndId is unique
if (!this.invoiceNumbers.add(invoice.getString("NUMERO")))
throw new IllegalStateException("Duplicate invoice number : " + invoice);
final SQLRowAccessor mandate = invoice.getForeign("ID_MODE_REGLEMENT").getForeign("ID_SEPA_MANDATE");
if (!mandate.getBoolean("ACTIVE"))
throw new IllegalStateException("Inactive mandate for " + invoice);
// needed otherwise would have to update seqType while generating
if (!this.invoiceMandates.add(mandate.getString("MandateIdentification")))
return IgnoreReason.DUPLICATE_MANDATE;
 
this.lockedInvoicesIDs.add(invoice.getIDNumber());
ListMap<String, InvoiceElem> bySeqType = this.map.get(dueDate);
if (bySeqType == null) {
bySeqType = new ListMap<>();
this.map.put(dueDate, bySeqType);
}
bySeqType.add(mandate.getString("SequenceType"), new InvoiceElem(invoice, elem));
 
this.sum = this.sum.add(getInvoiceAmount(invoice));
 
return IgnoreReason.NONE;
}
 
public final int getTransactionCount() {
return this.lockedInvoicesIDs.size();
}
 
public final List<PaymentInfo> getPaymentInfos() {
final List<PaymentInfo> res = new ArrayList<>();
for (final Entry<Date, ListMap<String, InvoiceElem>> e : this.map.entrySet()) {
final Date collectionDate = e.getKey();
for (final Entry<String, List<InvoiceElem>> e2 : e.getValue().entrySet()) {
final String seqType = e2.getKey();
res.add(new PaymentInfo(collectionDate, seqType, e2.getValue()));
}
}
return res;
}
}
 
public static enum IgnoreReason {
NONE, TOO_FAR_IN_FUTURE, DUPLICATE_MANDATE, MISSING_INFO;
}
 
public static final class GenerationResult {
private final Collection<? extends Number> passedIDs;
private final List<SQLRowValues> withDDWithoutMessage;
private final ListMapItf<IgnoreReason, SQLRowValues> ignoredInvoices;
private final SQLRow insertedMessage;
private final int invoiceCount;
 
protected GenerationResult(Collection<? extends Number> passedIDs, List<SQLRowValues> withDDWithoutMessage, ListMap<IgnoreReason, SQLRowValues> ignoredInvoices, SQLRow insertedMessage) {
super();
this.passedIDs = passedIDs;
this.withDDWithoutMessage = Collections.unmodifiableList(withDDWithoutMessage);
assert !ignoredInvoices.containsKey(null) && !ignoredInvoices.containsKey(IgnoreReason.NONE);
this.ignoredInvoices = ListMap.unmodifiableMap(ignoredInvoices);
this.insertedMessage = insertedMessage;
this.invoiceCount = insertedMessage == null ? 0 : insertedMessage.getInt("NumberOfTransactions");
assert this.withDDWithoutMessage.size() - this.ignoredInvoices.allValues().size() == this.invoiceCount;
}
 
// OK since both the list and the SQLRowValues are immutable
public final List<SQLRowValues> getDDInvoicesWithoutMessage() {
return this.withDDWithoutMessage;
}
 
// OK since both the list and the SQLRowValues are immutable
public final ListMapItf<IgnoreReason, SQLRowValues> getIgnoredInvoices() {
return this.ignoredInvoices;
}
 
public final SQLRow getInsertedMessage() {
return this.insertedMessage;
}
 
public final int getIncludedInvoicesCount() {
return this.invoiceCount;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + ": of the " + this.passedIDs.size() + " passed, " + this.withDDWithoutMessage.size() + " needed a SDD message, of those "
+ this.ignoredInvoices.allValues().size() + " were ignored (either being too far in the future or duplicate mandates) ; the inserted row was " + this.insertedMessage;
}
}
 
public GenerationResult generateXML(Collection<? extends Number> invoiceIDs) throws SQLException {
final Namespace painNS = Namespace.getNamespace("urn:iso:std:iso:20022:tech:xsd:pain.008.001.02");
final Element rootElem = new Element("Document", painNS);
final Namespace xsiNS = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
rootElem.setAttribute("schemaLocation", "urn:iso:std:iso:20022:tech:xsd:pain.008.001.02 pain.008.001.02.xsd", xsiNS);
final Document doc = new Document(rootElem);
final Element ddElem = new Element("CstmrDrctDbtInitn", painNS);
rootElem.addContent(ddElem);
 
// Lead Time / Time cycle
// https://www.ecb.europa.eu/paym/retpaym/undpaym/qa/html/index.en.html
final Calendar now = Calendar.getInstance();
final Calendar cal = (Calendar) now.clone();
TimeUtils.clearTime(cal);
// perhaps handle business days and difference between FRST/OOFF (5 days) and RCURR/FNAL (2
// days).
cal.add(Calendar.DAY_OF_YEAR, this.dbPrefs.getInt(getCode() + ".leadDays", 7));
final Date lowerBound = cal.getTime();
 
cal.setTime(now.getTime());
cal.add(Calendar.DAY_OF_YEAR, 30);
final Date upperBound = cal.getTime();
 
// TODO use createFetcher()
final SQLRowValuesListFetcher selSociété = SQLRowValuesListFetcher.create(this.getDirectory().getElement(this.rowSociété.getTable()).createGraph());
selSociété.setFullOnly(true);
selSociété.appendSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(SQLSelect sel) {
sel.setLockStrength(LockStrength.SHARE);
return sel;
}
});
 
final SQLTable invoiceT = getDirectory().getElement(SaisieVenteFactureSQLElement.class).getTable();
final SQLField invoiceSDDMessageF = invoiceT.getField(SaisieVenteFactureSQLElement.MESSAGE_FIELD_NAME);
return SQLUtils.executeAtomic(getTable().getDBSystemRoot().getDataSource(), new ConnectionHandlerNoSetup<GenerationResult, SQLException>() {
@Override
public GenerationResult handle(SQLDataSource ds) throws SQLException {
final SQLRowValues lockedSociété = selSociété.fetchOne(SDDMessageSQLElement.this.rowSociété.getIDNumber());
if (lockedSociété == null)
throw new IllegalStateException("Missing société " + SDDMessageSQLElement.this.rowSociété);
 
// find and lock invoices with TYPE_REGLEMENT direct debit and no message
final SQLRowValues invoiceVals = new SQLRowValues(invoiceT);
invoiceVals.putRowValues("ID_CLIENT").putNulls("NOM", "BIC", "IBAN");
invoiceVals.putRowValues("ID_MODE_REGLEMENT").putNulls("AJOURS", "LENJOUR").putRowValues("ID_SEPA_MANDATE").setAllToNull();
invoiceVals.putNulls("NET_A_PAYER", "DATE", "NUMERO");
final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(invoiceVals);
fetcher.setReturnedRowsUnmodifiable(true);
// required for locking rows and to make sure that there's a SEPA Mandate
fetcher.setFullOnly(true);
fetcher.appendSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(SQLSelect sel) {
// we will update FACTURE.ID_MESSAGE
sel.setLockStrength(LockStrength.UPDATE);
final SQLSelectJoin join = sel.getJoin(invoiceT.getField("ID_MODE_REGLEMENT"));
join.setWhere(new Where(join.getJoinedTable().getField("ID_TYPE_REGLEMENT"), "=", TypeReglementSQLElement.PRELEVEMENT));
return sel;
}
});
final List<SQLRowValues> ddInvoices = fetcher
.fetch(new Where(invoiceT.getKey(), invoiceIDs).and(new Where(invoiceSDDMessageF, "=", invoiceSDDMessageF.getForeignTable().getUndefinedIDNumber())));
final InvoicesByPaymentInfo map = new InvoicesByPaymentInfo(lowerBound, upperBound, new ElementCreator(painNS, SDDMessageSQLElement.this.fieldTranslator));
final ListMap<IgnoreReason, SQLRowValues> ignoredInvoices = new ListMap<>();
for (final SQLRowValues invoice : ddInvoices) {
final IgnoreReason ignoredReason = map.addInvoice(invoice);
if (ignoredReason != IgnoreReason.NONE) {
ignoredInvoices.add(ignoredReason, invoice);
}
}
 
final SQLRow newMsg;
final int txCount = map.getTransactionCount();
if (txCount == 0) {
newMsg = null;
} else {
// find and lock message serial
final SQLTable mdT = getTable().getTable(SQLSchema.METADATA_TABLENAME);
final SQLSelect sel = new SQLSelect(true).addSelect(mdT.getField("VALUE"));
sel.setWhere(new Where(mdT.getField("NAME"), "=", SERIAL_MD));
sel.setLockStrength(LockStrength.UPDATE);
final String msgSerial = String.valueOf(Integer.parseInt((String) getTable().getDBSystemRoot().getDataSource().executeScalar(sel.asString())) + 1);
 
// generate XML
final BigDecimal totalSum = map.sum;
final Element groupHeaderElem = createGroupHeader(painNS, lockedSociété, now, msgSerial, txCount, totalSum);
ddElem.addContent(groupHeaderElem);
final String msgID = groupHeaderElem.getChild("MsgId", painNS).getText();
final Map<SQLRow, String> end2endIDs = new HashMap<>();
int index = 1;
for (final PaymentInfo info : map.getPaymentInfos()) {
try {
createPaymentInfo(ddElem, end2endIDs, map.elemCreator, lockedSociété, info, msgID, index++);
} catch (Exception e) {
throw new IllegalStateException("Couldn't create XML for " + info, e);
}
}
assert end2endIDs.size() == txCount : "Expected " + txCount + " transactions but got " + end2endIDs.size() + " rows : " + end2endIDs;
 
// insert message in DB
final SQLRowValues msgVals = new SQLRowValues(getTable());
msgVals.put("MessageIdentification", msgID);
msgVals.put("CreationDateTime", now.getTime());
msgVals.put("NumberOfTransactions", txCount);
msgVals.put("ControlSum", totalSum);
msgVals.put("XML", JDOM2Utils.output(doc));
newMsg = msgVals.insert();
 
// update invoices with new message
for (final Entry<SQLRow, String> e : end2endIDs.entrySet()) {
final SQLRowValues vals = e.getKey().createEmptyUpdateRow();
vals.putForeignID(invoiceSDDMessageF.getName(), newMsg);
vals.put(SaisieVenteFactureSQLElement.END2END_FIELD_NAME, e.getValue());
vals.update();
}
// update message serial
getTable().getDBRoot().setMetadata(SERIAL_MD, msgSerial);
}
 
return new GenerationResult(invoiceIDs, ddInvoices, ignoredInvoices, newMsg);
}
});
}
 
static private Element createGroupHeader(final Namespace painNS, final SQLRowValues lockedSociété, final Calendar now, final String msgSerial, final int txCount, final BigDecimal total) {
final Element res = new Element("GrpHdr", painNS);
res.addContent(new Element("MsgId", painNS).setText("openconcerto-" + now.get(Calendar.YEAR) + "-" + msgSerial));
res.addContent(new Element("CreDtTm", painNS).setText(new XMLDateFormat().format(now)));
res.addContent(new Element("NbOfTxs", painNS).setText(String.valueOf(txCount)));
if (DecimalUtils.decimalDigits(total) > 2)
throw new IllegalArgumentException("Too many decimals : " + total);
res.addContent(new Element("CtrlSum", painNS).setText(total.toPlainString()));
res.addContent(new Element("InitgPty", painNS).addContent(new Element("Nm", painNS).setText(getCompanyName(lockedSociété))));
return res;
}
 
static private String getCompanyName(final SQLRowValues lockedSociété) {
final String companyName = lockedSociété.getString("NOM");
if (StringUtils.isEmpty(companyName))
throw new IllegalStateException("Empty company name : " + lockedSociété);
return lockedSociété.getString("TYPE") + ' ' + companyName;
}
 
static private final DateFormat XML_DATE_FMT = new SimpleDateFormat("yyyy-MM-dd");
 
static synchronized private final String formatDate(final Date date) {
return XML_DATE_FMT.format(date);
}
 
static private void createPaymentInfo(Element ddElem, Map<SQLRow, String> end2endIDs, final ElementCreator elemCreator, final SQLRowValues lockedSociété, final PaymentInfo info,
final String msgID, final int index) throws SQLException, MissingInfoException {
if (info.invoices.isEmpty())
return;
 
final Namespace painNS = elemCreator.painNS;
final String formattedDate = formatDate(info.collectionDate);
 
final Element res = new Element("PmtInf", painNS);
res.addContent(new Element("PmtInfId", painNS).setText("openconcerto-" + formattedDate + '.' + index));
res.addContent(new Element("PmtMtd", painNS).setText("DD"));
res.addContent(new Element("BtchBookg", painNS).setText("false"));
res.addContent(new Element("NbOfTxs", painNS).setText(String.valueOf(info.invoices.size())));
if (DecimalUtils.decimalDigits(info.sum) > 2)
throw new IllegalArgumentException("Too many decimals : " + info.sum);
res.addContent(new Element("CtrlSum", painNS).setText(info.sum.toPlainString()));
 
final Element typeInformation = new Element("PmtTpInf", painNS);
typeInformation.addContent(new Element("SvcLvl", painNS).addContent(new Element("Cd", painNS).setText("SEPA")));
typeInformation.addContent(new Element("LclInstrm", painNS).addContent(new Element("Cd", painNS).setText("CORE")));
typeInformation.addContent(new Element("SeqTp", painNS).setText(info.seqType));
res.addContent(typeInformation);
 
res.addContent(new Element("ReqdColltnDt", painNS).setText(formattedDate));
 
final Element creditor = new Element("Cdtr", painNS);
creditor.addContent(new Element("Nm", painNS).setText(getCompanyName(lockedSociété)));
final Element postalAddr = new Element("PstlAdr", painNS);
final SQLRowAccessor addr = lockedSociété.getNonEmptyForeign("ID_ADRESSE_COMMON");
final String country = addr.getString("PAYS");
final String country2;
if (StringUtils.isEmpty(country, true) || country.trim().equalsIgnoreCase("France")) {
country2 = "FR";
} else {
// TODO map to 2 letter code
throw new IllegalStateException("Unknown country : " + country);
}
postalAddr.addContent(new Element("Ctry", painNS).setText(country2));
postalAddr.addContent(new Element("AdrLine", painNS).setText(addr.getString("RUE")));
postalAddr.addContent(new Element("AdrLine", painNS).setText(addr.getString("CODE_POSTAL") + " " + addr.getString("VILLE")));
creditor.addContent(postalAddr);
res.addContent(creditor);
 
final Element creditorAccount = new Element("CdtrAcct", painNS);
creditorAccount.addContent(new Element("Id", painNS).addContent(elemCreator.createWithNonEmptyText("IBAN", lockedSociété, "IBAN")));
res.addContent(creditorAccount);
 
final Element creditorAgent = new Element("CdtrAgt", painNS);
creditorAgent.addContent(new Element("FinInstnId", painNS).addContent(elemCreator.createWithNonEmptyText("BIC", lockedSociété, "BIC")));
res.addContent(creditorAgent);
 
res.addContent(new Element("ChrgBr", painNS).setText("SLEV"));
 
final Element creditorID = new Element("CdtrSchmeId", painNS);
final Element other = new Element("Othr", painNS);
other.addContent(elemCreator.createWithNonEmptyText("Id", lockedSociété, "SEPA_CREDITOR_ID"));
other.addContent(new Element("SchmeNm", painNS).addContent(new Element("Prtry", painNS).setText("SEPA")));
creditorID.addContent(new Element("Id", painNS).addContent(new Element("PrvtId", painNS).addContent(other)));
res.addContent(creditorID);
 
for (final InvoiceElem invoice : info.invoices) {
final String end2endID = msgID + '.' + invoice.get0().getString("NUMERO");
if (end2endIDs.put(invoice.get0().asRow(), end2endID) != null)
throw new IllegalStateException("Duplicate invoice : " + invoice);
try {
res.addContent(fillDDTx(invoice, elemCreator, end2endID));
} catch (Exception e) {
throw new IllegalStateException("Couldn't create XML for " + invoice, e);
}
}
 
ddElem.addContent(res);
}
 
static private Element fillDDTx(final InvoiceElem invoiceElem, final ElementCreator elemCreator, final String end2endID) throws SQLException, MissingInfoException {
final Element paymentId = new Element("PmtId", elemCreator.painNS);
paymentId.addContent(elemCreator.createWithNonEmptyText("InstrId", end2endID));
paymentId.addContent(elemCreator.createWithNonEmptyText("EndToEndId", end2endID));
invoiceElem.get1().addContent(0, paymentId);
 
// update mandate fields
final SQLRowAccessor mandate = invoiceElem.get0().getForeign("ID_MODE_REGLEMENT").getForeign("ID_SEPA_MANDATE");
final String seqType = mandate.getString("SequenceType");
if (seqType.equals(SEPAMandateSQLElement.SEQ_FIRST)) {
mandate.createEmptyUpdateRow().put("SequenceType", SEPAMandateSQLElement.SEQ_RECURRENT).update();
} else if (seqType.equals(SEPAMandateSQLElement.SEQ_FINAL) || seqType.equals(SEPAMandateSQLElement.SEQ_ONEOFF)) {
mandate.createEmptyUpdateRow().put("ACTIVE", Boolean.FALSE).update();
} // else SEQ_RECURRENT
 
return invoiceElem.get1();
}
 
static private Element createDDTx(final ElementCreator elemCreator, final SQLRowValues invoice) throws MissingInfoException {
final Namespace painNS = elemCreator.painNS;
final Element res = new Element("DrctDbtTxInf", painNS);
 
res.addContent(new Element("InstdAmt", painNS).setAttribute("Ccy", "EUR").setText(getInvoiceAmount(invoice).toPlainString()));
 
final Element mandateRltdInfo = new Element("MndtRltdInf", painNS);
final SQLRowAccessor mandate = invoice.getForeign("ID_MODE_REGLEMENT").getForeign("ID_SEPA_MANDATE");
assert !mandate.isUndefined() : "Undefined mandate returned by fetcher";
mandateRltdInfo.addContent(elemCreator.createWithNonEmptyText("MndtId", mandate, "MandateIdentification"));
mandateRltdInfo.addContent(elemCreator.createWithNonEmptyText("DtOfSgntr", formatDate(mandate.getObjectAs("DateOfSignature", Date.class))));
mandateRltdInfo.addContent(elemCreator.createWithNonEmptyText("AmdmntInd", "false"));
res.addContent(new Element("DrctDbtTx", painNS).addContent(mandateRltdInfo));
 
final SQLRowAccessor clientRow = invoice.getForeign("ID_CLIENT");
res.addContent(new Element("DbtrAgt", painNS).addContent(new Element("FinInstnId", painNS).addContent(elemCreator.createWithNonEmptyText("BIC", clientRow, "BIC"))));
res.addContent(new Element("Dbtr", painNS).addContent(elemCreator.createWithNonEmptyText("Nm", clientRow, "NOM")));
res.addContent(new Element("DbtrAcct", painNS).addContent(new Element("Id", painNS).addContent(elemCreator.createWithNonEmptyText("IBAN", clientRow, "IBAN"))));
 
res.addContent(new Element("Purp", painNS).addContent(new Element("Cd", painNS).setText("OTHR")));
 
// TODO <RmtInf><Ustrd>ligne de facture avec n° d'abonnement et indice de paiement.
 
return res;
}
 
static public final class MissingInfoException extends Exception {
 
private final String label;
 
protected MissingInfoException(final String label) {
super("Empty " + label);
this.label = label;
}
 
public final String getLabel() {
return this.label;
}
}
 
static private final class ElementCreator {
private final Namespace painNS;
private final SQLFieldTranslator fieldTrans;
 
protected ElementCreator(Namespace painNS, final SQLFieldTranslator fieldTrans) {
super();
this.painNS = painNS;
this.fieldTrans = fieldTrans;
}
 
protected Element create(final String elemName) {
return new Element(elemName, this.painNS);
}
 
protected Element createWithNonEmptyText(final String elemName, final SQLRowAccessor r, final String field) throws MissingInfoException {
return this.createWithNonEmptyText(elemName, r.getString(field), this.fieldTrans.getDescFor(r.getTable(), field).getLabel());
}
 
protected Element createWithNonEmptyText(final String elemName, final String text) throws MissingInfoException {
return this.createWithNonEmptyText(elemName, text, null);
}
 
protected Element createWithNonEmptyText(final String elemName, final String text, final String label) throws MissingInfoException {
if (StringUtils.isEmpty(text))
throw new MissingInfoException(label == null ? elemName : label);
return create(elemName).setText(text);
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/payment/element/SEPAMandateSQLElement.java
New file
0,0 → 1,170
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.finance.payment.element;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElementLink.LinkType;
import org.openconcerto.sql.element.SQLElementLinksSetup;
import org.openconcerto.sql.element.UISQLComponent;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.utils.SQLCreateTable;
import org.openconcerto.ui.component.ITextCombo;
import org.openconcerto.ui.component.ImmutableITextComboCache;
import org.openconcerto.utils.CollectionUtils;
 
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
 
public final class SEPAMandateSQLElement extends ComptaSQLConfElement {
static final String TABLE_NAME = "SEPA_MANDATE";
static public final String SEQ_FIRST = "FRST";
static public final String SEQ_RECURRENT = "RCUR";
static public final String SEQ_FINAL = "FNAL";
static public final String SEQ_ONEOFF = "OOFF";
static public final List<String> SEQ_VALUES = Arrays.asList(SEQ_FIRST, SEQ_RECURRENT, SEQ_FINAL, SEQ_ONEOFF);
private static final int IDENTIFICATION_MAX_LENGTH = 35;
 
public static SQLCreateTable getCreateTable(final DBRoot root) {
if (root.contains(TABLE_NAME))
return null;
final SQLCreateTable res = new SQLCreateTable(root, TABLE_NAME);
res.addForeignColumn(null, root.getTable("CLIENT"));
res.addVarCharColumn("MandateIdentification", IDENTIFICATION_MAX_LENGTH);
res.addColumn("DateOfSignature", "date", null, true);
res.addVarCharColumn("SequenceType", 8);
res.addBooleanColumn("ACTIVE", Boolean.TRUE, false);
return res;
}
 
public SEPAMandateSQLElement(final ComptaPropsConfiguration conf) {
super(conf.getRootSociete().findTable(TABLE_NAME, true));
}
 
@Override
protected void setupLinks(SQLElementLinksSetup links) {
super.setupLinks(links);
links.get("ID_CLIENT").setType(LinkType.PARENT);
}
 
@Override
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_CLIENT");
l.add("MandateIdentification");
l.add("DateOfSignature");
l.add("SequenceType");
l.add("ACTIVE");
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("MandateIdentification");
l.add("DateOfSignature");
l.add("SequenceType");
return l;
}
 
@Override
public Set<String> getReadOnlyFields() {
return CollectionUtils.createSet("ID_CLIENT", "MandateIdentification");
}
 
@Override
protected SQLComponent createComponent() {
return new UISQLComponent(this) {
@Override
protected void addViews() {
this.addView("ID_CLIENT");
this.addView("MandateIdentification");
this.addView("DateOfSignature");
final ITextCombo seqTypeCombo = new ITextCombo(true);
seqTypeCombo.initCache(new ImmutableITextComboCache(SEQ_VALUES));
this.addView(seqTypeCombo, "SequenceType");
this.addView("ACTIVE");
}
};
}
 
@Override
protected String createCode() {
// TODO rename createCodeFromPackage() to createCodeOfPackage() and change createCode()
// implementation to use a new createCodeFromPackage() which uses the class name (w/o
// SQLElement suffix)
return this.createCodeFromPackage() + ".SEPAMandate";
}
 
public final SQLRowValues createRecurrent(final Number idClient, final String mandateIdent, final Date dateOfSignature) {
final SQLRowValues res = new SQLRowValues(getTable());
res.put("ID_CLIENT", Objects.requireNonNull(idClient));
if (mandateIdent.length() > IDENTIFICATION_MAX_LENGTH)
throw new IllegalArgumentException("Identification too long (>" + IDENTIFICATION_MAX_LENGTH + ") : " + mandateIdent);
res.put("MandateIdentification", mandateIdent);
res.put("DateOfSignature", Objects.requireNonNull(dateOfSignature));
res.put("SequenceType", SEPAMandateSQLElement.SEQ_FIRST);
res.put("ACTIVE", Boolean.TRUE);
return res;
}
 
public String generateMandateIdentification(String label, final char pad, final boolean padStart, final boolean truncateStart) {
final UUID uuid = UUID.randomUUID();
final ByteBuffer byteBuffer = ByteBuffer.allocate(16);
byteBuffer.putLong(uuid.getMostSignificantBits());
byteBuffer.putLong(uuid.getLeastSignificantBits());
// slash should be legal but don't take any chances
final String uuidS = Base64.getEncoder().withoutPadding().encodeToString(byteBuffer.array()).replace('/', '.');
assert uuidS.length() == 22;
 
// don't add space
if (Character.isSpaceChar(pad))
throw new IllegalArgumentException("Invalid pad : spaces can be hard to debug : '" + pad + "'");
// don't accept space
label = label.trim();
final int numberL = 10;
final int zeroesToAdd = numberL - label.length();
final String fixedLNumber;
if (zeroesToAdd == 0) {
fixedLNumber = label;
} else if (zeroesToAdd > 0) {
final StringBuilder sb = new StringBuilder(numberL);
if (!padStart)
sb.append(label);
for (int i = 0; i < zeroesToAdd; i++) {
sb.append(pad);
}
if (padStart)
sb.append(label);
fixedLNumber = sb.toString();
} else {
fixedLNumber = truncateStart ? label.substring(-zeroesToAdd, label.length()) : label.substring(0, numberL);
}
assert fixedLNumber.length() == numberL;
 
// use both UUID and a meaningful label
final String res = uuidS + '-' + fixedLNumber;
assert res.length() <= IDENTIFICATION_MAX_LENGTH;
return res;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/payment/element/TypeReglementSQLElement.java
39,6 → 39,7
public static final int INDEFINI = 7;
public static final int VIREMENT = 8;
public static final int CESU = 9;
public static final int PRELEVEMENT = 10;
 
public TypeReglementSQLElement() {
super("TYPE_REGLEMENT", "Type de règlement", "Type de règlement");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/payment/action/ListeDesRelancesAction.java
80,7 → 80,7
 
final SQLTableModelSourceOnline src = (SQLTableModelSourceOnline) this.frame.getPanel().getListe().getModel().getReq();
 
this.frame.getPanel().getListe().setSQLEditable(true);
this.frame.getPanel().getListe().setModificationAllowed(true);
 
for (SQLTableModelColumn column : src.getColumns()) {
if (column.getClass().isAssignableFrom(SQLTableModelColumnPath.class)) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/payment/action/ListeDesChequesAction.java
60,7 → 60,7
}
}
});
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
frame.getPanel().setAddVisible(false);
return frame;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/payment/action/ListeDesTraitesAbstractAction.java
54,7 → 54,7
 
IListFrame frame = new IListFrame(new ListeViewPanel(elt, new IListe(src)));
frame.getPanel().setAddVisible(false);
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
 
return frame;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/payment/ui/ChequeListPanel.java
13,6 → 13,7
package org.openconcerto.erp.core.finance.payment.ui;
 
import org.openconcerto.erp.core.common.element.BanqueSQLElement;
import org.openconcerto.erp.core.finance.accounting.element.MouvementSQLElement;
import org.openconcerto.erp.core.finance.payment.element.ChequeType;
import org.openconcerto.erp.model.GestionChequesModel;
57,7 → 58,7
super(elem, new IListe(((ChequeType) elem).createDepositTableSource()));
 
this.setReadWriteButtonsVisible(false);
this.getListe().setSQLEditable(false);
this.getListe().setModificationAllowed(false);
 
// Model
this.model = new GestionChequesModel(getListe(), (ChequeType) elem);
100,7 → 101,7
c.gridx++;
res.add(new JLabel(", sur la banque"), c);
c.gridx++;
banqueSelect.uiInit(element.getDirectory().getElement("BANQUE").getComboRequest());
banqueSelect.uiInit(element.getDirectory().getElement(BanqueSQLElement.class).getComboRequest());
res.add(banqueSelect, c);
} else {
banqueSelect = null;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/finance/payment/component/EncaisserMontantSQLComponent.java
41,6 → 41,7
import org.openconcerto.ui.warning.JLabelWarning;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.GestionDevise;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
import java.awt.GridBagConstraints;
308,11 → 309,11
String s = row.getString("NOM");
SQLRow rowModeRegl = row.getForeignRow("ID_MODE_REGLEMENT");
SQLRow rowTypeRegl = rowModeRegl.getForeignRow("ID_TYPE_REGLEMENT");
String label = "Règlement vente " + ((s == null) ? "" : s) + " (" + rowTypeRegl.getString("NOM") + ")";
 
// Compte Client
SQLRow clientRow = row.getForeignRow("ID_CLIENT");
 
String label = "Règlement vente " + ((s == null) ? "" : s) + " (" + rowTypeRegl.getString("NOM") + ") " + StringUtils.limitLength(clientRow.getString("NOM"), 20);
long montant = row.getLong("MONTANT");
PrixTTC ttc = new PrixTTC(montant);
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/element/ContratSalarieSQLElement.java
377,12 → 377,12
addSQLObject(textDateFin, "DATE_PREV_FIN");
 
this.addRequiredSQLObject(selCodeCatSocio, "ID_CODE_EMPLOI");
this.addSQLObject(selContratTravail, "ID_CODE_CONTRAT_TRAVAIL");
this.addSQLObject(selCaractActivite, "ID_CODE_CARACT_ACTIVITE");
this.addSQLObject(selDroitContrat, "ID_CODE_DROIT_CONTRAT");
this.addSQLObject(selStatutProf, "ID_CODE_STATUT_PROF");
this.addSQLObject(selStatutCat, "ID_CODE_STATUT_CATEGORIEL");
this.addSQLObject(selStatutCatConv, "ID_CODE_STATUT_CAT_CONV");
this.addRequiredSQLObject(selContratTravail, "ID_CODE_CONTRAT_TRAVAIL");
this.addRequiredSQLObject(selCaractActivite, "ID_CODE_CARACT_ACTIVITE");
this.addRequiredSQLObject(selDroitContrat, "ID_CODE_DROIT_CONTRAT");
this.addRequiredSQLObject(selStatutProf, "ID_CODE_STATUT_PROF");
this.addRequiredSQLObject(selStatutCat, "ID_CODE_STATUT_CATEGORIEL");
this.addRequiredSQLObject(selStatutCatConv, "ID_CODE_STATUT_CAT_CONV");
this.addRequiredSQLObject(textNature, "NATURE");
}
};
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/element/FichePayeSQLElement.java
16,10 → 16,14
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.erp.core.common.ui.JNiceButton;
import org.openconcerto.erp.core.common.ui.PanelFrame;
import org.openconcerto.erp.core.humanresources.payroll.component.VariableRowTreeNode;
import org.openconcerto.erp.core.humanresources.payroll.report.FichePayeSheetXML;
import org.openconcerto.erp.core.humanresources.payroll.ui.FichePayeRenderer;
import org.openconcerto.erp.core.humanresources.payroll.ui.PanelCumulsPaye;
import org.openconcerto.erp.generationEcritures.GenerationMvtFichePaye;
import org.openconcerto.erp.model.FichePayeModel;
import org.openconcerto.erp.model.MouseSheetXmlListeListener;
import org.openconcerto.erp.model.RubriquePayeTree;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.BaseSQLComponent;
40,6 → 44,9
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.IListFrame;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.component.ITextArea;
79,8 → 86,25
 
public FichePayeSQLElement() {
super("FICHE_PAYE", "une fiche de paye", "fiches de paye");
 
MouseSheetXmlListeListener l = new MouseSheetXmlListeListener(FichePayeSheetXML.class);
getRowActions().addAll(l.getRowActions());
 
PredicateRowAction actionCumuls = new PredicateRowAction(new AbstractAction("Détails cumuls et variables") {
 
@Override
public void actionPerformed(ActionEvent e) {
final PanelCumulsPaye pCumuls = new PanelCumulsPaye();
final PanelFrame p = new PanelFrame(pCumuls, "Détails cumuls et variables");
pCumuls.selectFiche(IListe.get(e).getSelectedRow().asRow());
p.setVisible(true);
}
}, true);
actionCumuls.setPredicate(IListeEvent.getSingleSelectionPredicate());
getRowActions().add(actionCumuls);
 
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_SALARIE");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/element/InfosSalariePayeSQLElement.java
428,7 → 428,7
c.gridx++;
c.weightx = 1;
panelBase.add(CodeAT, c);
addView(CodeAT, "CODE_AT");
addView(CodeAT, "CODE_AT", REQ);
 
// Code section AT
JLabel labelSectionAT = new JLabel(getLabelFor("CODE_SECTION_AT"));
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/element/RubriqueCommSQLElement.java
241,6 → 241,16
cPanel.weightx = 1;
panelProp.add(comboSelTypeImpression, cPanel);
 
// Impression
JCheckBox boxReduction = new JCheckBox("Avantage baisse des cotisations");
cPanel.gridy++;
cPanel.gridx = 1;
cPanel.gridwidth = 2;
cPanel.weightx = 0;
addView(boxReduction, "REDUCTION_GVT_COM");
panelProp.add(boxReduction, cPanel);
cPanel.gridwidth = 1;
 
// Tabbed Pane
JTabbedPane tab = new JTabbedPane();
tab.add("Calcul", new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, paneTree, panelCalcul));
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/action/ListeDesFichesDePayeAction.java
62,7 → 62,7
 
final IListFrame frame = new IListFrame(liste);
 
frame.getPanel().getListe().setSQLEditable(false);
frame.getPanel().getListe().setModificationAllowed(false);
frame.getPanel().setAddVisible(false);
 
final PanelCumulsPaye pCumuls = new PanelCumulsPaye();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/action/ListeDesVariablesPayes.java
45,7 → 45,7
}
}
};
listeVar.getListe().setSQLEditable(false);
listeVar.getListe().setModificationAllowed(false);
return new IListFrame(listeVar);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/ui/HistoriqueFichePayePanel.java
76,7 → 76,7
w = w.and(new Where(table.getField("ID_" + HistoriqueFichePayePanel.this.jListPanel.getModel().getTable().getName()), "=", id));
}
HistoriqueFichePayePanel.this.listePanel.getListe().getRequest().setWhere(w);
HistoriqueFichePayePanel.this.listePanel.getListe().setSQLEditable(false);
HistoriqueFichePayePanel.this.listePanel.getListe().setModificationAllowed(false);
}
};
 
107,7 → 107,7
this.listePanel = new ListeFichePayeAddPanel(eltFiche, new IListe(src));
this.listePanel.setAddVisible(false);
 
this.listePanel.getListe().setSQLEditable(false);
this.listePanel.getListe().setModificationAllowed(false);
this.listePanel.setOpaque(false);
this.listePanel.setBorder(null);
 
139,50 → 139,6
}
});
 
final PanelCumulsPaye pCumuls = new PanelCumulsPaye();
final PanelFrame p = new PanelFrame(pCumuls, "Détails cumuls et variables");
 
this.listePanel.getListe().addIListener(new IListener() {
 
public void selectionId(int id, int field) {
 
pCumuls.selectFicheFromId(id);
}
});
 
// Menu Clic droit Génération documents
this.listener = new MouseAdapter() {
 
public void mousePressed(MouseEvent mouseEvent) {
 
if (mouseEvent.getButton() == MouseEvent.BUTTON3 && HistoriqueFichePayePanel.this.listePanel.getListe().getSelectedId() > 1) {
 
JPopupMenu menuDroit = new JPopupMenu();
 
final SQLRow rowFiche = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete().getTable("FICHE_PAYE")
.getRow(HistoriqueFichePayePanel.this.listePanel.getListe().getSelectedId());
 
MouseSheetXmlListeListener l = new MouseSheetXmlListeListener(FichePayeSheetXML.class);
 
for (RowAction action : l.getRowActions()) {
menuDroit.add(action.getAction());
}
 
menuDroit.add(new AbstractAction("Détails cumuls et variables") {
public void actionPerformed(ActionEvent e) {
 
pCumuls.selectFiche(rowFiche);
p.setVisible(true);
}
});
 
menuDroit.pack();
menuDroit.show(mouseEvent.getComponent(), mouseEvent.getPoint().x, mouseEvent.getPoint().y);
menuDroit.setVisible(true);
}
}
};
 
this.listePanel.getListe().getJTable().addMouseListener(this.listener);
this.jListPanel.addListSelectionListener(this.listListener);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/payroll/ui/ListeDesRubriquesPanel.java
41,7 → 41,7
 
private void addPane(final JTabbedPane tabbedPane, final String tableName, final String title) {
final ListeAddPanel listeBrut = new ListeAddPanel(Configuration.getInstance().getDirectory().getElement(tableName));
listeBrut.getListe().setSQLEditable(false);
listeBrut.getListe().setModificationAllowed(false);
tabbedPane.add(title, listeBrut);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/employe/action/ListeDesSalariesAction.java
31,7 → 31,7
 
public JFrame createFrame() {
ListeAddPanel listeSal = new ListeAddPanel(Configuration.getInstance().getDirectory().getElement("SALARIE"));
listeSal.getListe().setSQLEditable(false);
listeSal.getListe().setModificationAllowed(false);
return new IListFrame(listeSal);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/employe/action/ListeDesAyantsDroitsAction.java
30,7 → 30,7
 
public JFrame createFrame() {
ListeAddPanel listeSal = new ListeAddPanel(Configuration.getInstance().getDirectory().getElement("AYANT_DROIT"));
listeSal.getListe().setSQLEditable(false);
listeSal.getListe().setModificationAllowed(false);
return new IListFrame(listeSal);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/employe/action/ListeDesContratsPrevoyanceAction.java
30,7 → 30,7
 
public JFrame createFrame() {
ListeAddPanel listeSal = new ListeAddPanel(Configuration.getInstance().getDirectory().getElement("CONTRAT_PREVOYANCE"));
listeSal.getListe().setSQLEditable(false);
listeSal.getListe().setModificationAllowed(false);
return new IListFrame(listeSal);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/employe/action/ListeDesSecretairesAction.java
31,7 → 31,7
 
public JFrame createFrame() {
ListeAddPanel listeSecr = new ListeAddPanel(Configuration.getInstance().getDirectory().getElement("SECRETAIRE"));
listeSecr.getListe().setSQLEditable(false);
listeSecr.getListe().setModificationAllowed(false);
return new IListFrame(listeSecr);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/humanresources/employe/action/ListeDesCaissesCotisationsAction.java
30,7 → 30,7
 
public JFrame createFrame() {
ListeAddPanel listeSal = new ListeAddPanel(Configuration.getInstance().getDirectory().getElement("CAISSE_COTISATION"));
listeSal.getListe().setSQLEditable(false);
listeSal.getListe().setModificationAllowed(false);
return new IListFrame(listeSal);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ftp/updater/UpdateManager.java
284,7 → 284,8
}
String jHome = System.getProperty("java.home");
jHome += File.separatorChar + "bin" + File.separatorChar + "java";
Runtime.getRuntime().exec("\"" + jHome + "\" -jar " + updaterFilename);
ProcessBuilder process = new ProcessBuilder(jHome, "-jar", updaterFilename);
process.start();
JOptionPane.showMessageDialog(null, "Mise à jour terminée");
System.exit(0);
 
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/fleche_d_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/fleche_d_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/fleche_g_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/fleche_g_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/PrefTree.java
13,6 → 13,7
package org.openconcerto.ui.preferences;
 
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.clipboard.ClipboardItems;
 
import java.awt.Color;
72,10 → 73,15
 
c.gridx++;
c.weightx = 0;
this.button = new JButton(new ImageIcon(PrefTree.class.getResource("clear.png")));
String iconNameClear = "clear.png";
if (textComponent.getFont().getSize() > 16) {
iconNameClear = "clear_2x.png";
}
final ImageIcon icon = new ImageIcon(PrefTree.class.getResource(iconNameClear));
this.button = new JButton(icon);
this.button.setDisabledIcon(new ImageIcon(PrefTree.class.getResource("blank.png")));
this.button.setPreferredSize(new Dimension(20, 20));
this.button.setMinimumSize(new Dimension(20, 20));
this.button.setPreferredSize(new Dimension(icon.getIconWidth() + 4, icon.getIconHeight() + 4));
this.button.setMinimumSize(new Dimension(icon.getIconWidth() + 4, icon.getIconHeight() + 4));
this.button.setEnabled(false);
this.button.setBorderPainted(false);
this.button.setFocusPainted(false);
96,6 → 102,8
c.fill = GridBagConstraints.BOTH;
 
this.tree = new JTree(this.root);
// HighDPI
this.tree.setRowHeight(FontUtils.getPreferredRowHeight(tree));
 
// Set the renderer
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer() {
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/MainPrefPanel.java
38,6 → 38,7
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
 
55,7 → 56,7
}
};
private JLabel titleLabel;
private final Vector<PrefTreeNode> history = new Vector<PrefTreeNode>();
private final Vector<PrefTreeNode> history = new Vector<>();
private JButton buttonLeft;
private JButton buttonRight;
private PrefTree tree;
155,7 → 156,7
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
this.titleLabel = new JLabel(TM.tr("prefs.main"));
Font fontTitre = new Font("Arial Gras", Font.PLAIN, 12);
Font fontTitre = titleLabel.getFont().deriveFont(Font.BOLD);
this.titleLabel.setFont(fontTitre);
p.add(this.titleLabel, c);
 
165,7 → 166,14
c.weightx = 0;
c.gridx += 2;
c.gridwidth = 1;
this.buttonLeft = new JButton(new ImageIcon(MainPrefPanel.class.getResource("fleche_g.png")));
String leftIconName = "fleche_g.png";
String rightIconName = "fleche_d.png";
if (titleLabel.getFont().getSize() > 16) {
leftIconName = "fleche_g_2x.png";
rightIconName = "fleche_d_2x.png";
}
 
this.buttonLeft = new JButton(new ImageIcon(MainPrefPanel.class.getResource(leftIconName)));
this.buttonLeft.setBorderPainted(false);
this.buttonLeft.setFocusPainted(false);
this.buttonLeft.setContentAreaFilled(false);
174,7 → 182,8
this.buttonLeft.setEnabled(false);
p.add(this.buttonLeft, c);
c.gridx++;
this.buttonRight = new JButton(new ImageIcon(MainPrefPanel.class.getResource("fleche_d.png")));
 
this.buttonRight = new JButton(new ImageIcon(MainPrefPanel.class.getResource(rightIconName)));
this.buttonRight.setBorderPainted(false);
this.buttonRight.setFocusPainted(false);
this.buttonRight.setContentAreaFilled(false);
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/PreferenceFrame.java
50,8 → 50,9
c.weighty = 1;
 
PrefTree prefTree = new PrefTree(root);
prefTree.setMinimumSize(new Dimension(250, 200));
prefTree.setPreferredSize(new Dimension(250, 200));
final int fontSize = prefTree.getFont().getSize();
prefTree.setMinimumSize(new Dimension(fontSize * 23, fontSize * 18));
prefTree.setPreferredSize(new Dimension(fontSize * 23, fontSize * 18));
this.getContentPane().add(prefTree, c);
 
c.gridx++;
85,8 → 86,8
this.getContentPane().add(p1, c);
this.setBackground(p1.getBackground());
this.getContentPane().setBackground(p1.getBackground());
this.setMinimumSize(new Dimension(880, 680));
this.setPreferredSize(new Dimension(880, 680));
this.setMinimumSize(new Dimension(fontSize * 80, fontSize * 62));
this.setPreferredSize(new Dimension(fontSize * 80, fontSize * 62));
prefTree.addTreeSelectionListener(this.mainPrefPanel);
buttonClose.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/clear_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/clear_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/ui/light/ColumnsSpec.java
45,6 → 45,7
private Boolean allowMove = false;
private Boolean allowResize = false;
 
// ATTENTION : il y a des setters public pour la serialization JSON
public ColumnsSpec() {
// Serialization
}
81,10 → 82,22
return this.id;
}
 
public void setId(String id) {
this.id = id;
}
 
public void setPossibleColumnIds(List<String> possibleColumnIds) {
this.possibleColumnIds = possibleColumnIds;
}
 
public final List<String> getPossibleColumnIds() {
return this.possibleColumnIds;
}
 
public void setSortedIds(List<String> sortedIds) {
this.sortedIds = sortedIds;
}
 
public final List<String> getSortedIds() {
return this.sortedIds;
}
94,6 → 107,10
 
}
 
public void setFixedColumns(int fixedColumns) {
this.fixedColumns = fixedColumns;
}
 
public final int getColumnCount() {
return this.columns.size();
 
139,6 → 156,14
return result;
}
 
public void setColumns(List<ColumnSpec> columns) {
this.columns = columns;
}
 
public List<ColumnSpec> getColumns() {
return columns;
}
 
public final boolean setUserPrefs(final Document columnsPrefs) {
if (columnsPrefs != null) {
// user preferences application
163,22 → 188,23
if (!xmlColumn.getName().equals("column")) {
throw new IllegalArgumentException("ColumnSpec setPrefs - Invalid xml, element node column expected but " + xmlColumn.getName() + " found");
}
if (xmlColumn.getAttribute("width") == null || xmlColumn.getAttribute("min-width") == null || xmlColumn.getAttribute("max-width") == null) {
throw new IllegalArgumentException("ColumnSpec setPrefs - Invalid column node for " + columnId + ", it must have attribute width, min-width, max-width");
if (xmlColumn.getAttribute("width") == null) {
throw new IllegalArgumentException("ColumnSpec setPrefs - Invalid column node for " + columnId + " : missing width");
}
 
final double width = Double.parseDouble(xmlColumn.getAttribute("width").getValue());
final double maxWidth = Double.parseDouble(xmlColumn.getAttribute("max-width").getValue());
final double minWidth = Double.parseDouble(xmlColumn.getAttribute("min-width").getValue());
 
columnSpec.setPrefs(width, maxWidth, minWidth);
if (width <= columnSpec.getMaxWidth() && width >= columnSpec.getMinWidth() && this.allowResize) {
// Only apply valid width
columnSpec.setWidth(width);
}
if (i != j) {
if (this.allowMove) {
final ColumnSpec swap = this.columns.get(i);
this.columns.set(i, this.columns.get(j));
this.columns.set(j, swap);
i--;
}
}
find = true;
break;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIRadioButtons.java
60,6 → 60,10
this.choices.addAll(choices);
}
 
public List<String> getChoices() {
return choices;
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = super.toJSON();
/trunk/OpenConcerto/src/org/openconcerto/ui/TimestampEditorPanel.java
13,8 → 13,6
package org.openconcerto.ui;
 
import org.openconcerto.ui.table.TimestampTableCellEditor;
 
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
29,6 → 27,7
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
56,7 → 55,6
private JPanel panelHour;
private DatePickerPanel pickerPanel;
private List<ActionListener> listeners = new ArrayList<>();
private TimestampTableCellEditor aCellEditor;
private Calendar calendar = Calendar.getInstance();
private JDate dateEditor;
 
65,6 → 63,10
}
 
public TimestampEditorPanel(boolean useSpinner) {
this(useSpinner, null);
}
 
public TimestampEditorPanel(boolean useSpinner, final ActionListener validateListener) {
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
setLayout(new GridBagLayout());
97,14 → 99,8
c.gridx++;
 
final JButton buttonClose = new JButton(new ImageIcon(TimestampEditorPanel.class.getResource("validate_popup.png")));
buttonClose.addActionListener(new ActionListener() {
 
public void actionPerformed(ActionEvent e) {
if (TimestampEditorPanel.this.aCellEditor != null) {
TimestampEditorPanel.this.aCellEditor.stopCellEditing();
}
}
});
if (validateListener != null)
buttonClose.addActionListener(validateListener);
buttonClose.setBorderPainted(false);
buttonClose.setOpaque(false);
buttonClose.setFocusPainted(false);
141,12 → 137,15
@Override
public void propertyChange(PropertyChangeEvent evt) {
final Calendar c = Calendar.getInstance();
c.setTimeInMillis(dateEditor.getDate().getTime());
final Date date = dateEditor.getDate();
if (date != null) {
c.setTimeInMillis(date.getTime());
pickerPanel.setSelectedDate(c);
calendar.set(Calendar.YEAR, c.get(Calendar.YEAR));
calendar.set(Calendar.MONTH, c.get(Calendar.MONTH));
calendar.set(Calendar.DAY_OF_MONTH, c.get(Calendar.DAY_OF_MONTH));
dateOrTimeChanged();
}
 
}
});
206,8 → 205,8
 
@Override
public void keyReleased(KeyEvent e) {
if ((e.getKeyCode() == KeyEvent.VK_TAB || e.getKeyCode() == KeyEvent.VK_ENTER) && aCellEditor != null) {
aCellEditor.stopCellEditing();
if ((e.getKeyCode() == KeyEvent.VK_TAB || e.getKeyCode() == KeyEvent.VK_ENTER) && validateListener != null) {
validateListener.actionPerformed(new ActionEvent(e.getSource(), e.getID(), null));
}
}
 
230,10 → 229,18
}
}
 
public Timestamp getTime() {
return new Timestamp(calendar.getTimeInMillis());
public final Timestamp getTimestamp() {
return new Timestamp(this.calendar.getTimeInMillis());
}
 
public final Time getTime() {
return Time.valueOf(this.calendar.get(Calendar.HOUR_OF_DAY) + ":" + this.calendar.get(Calendar.MINUTE) + ":00");
}
 
public final java.sql.Date getDate() {
return java.sql.Date.valueOf(this.calendar.get(Calendar.YEAR) + "-" + (this.calendar.get(Calendar.MONTH) + 1) + "-" + this.calendar.get(Calendar.DAY_OF_MONTH));
}
 
public void actionPerformed(ActionEvent e) {
dateOrTimeChanged();
}
272,10 → 279,6
this.listeners.remove(listener);
}
 
public void setCellEditor(TimestampTableCellEditor editor) {
this.aCellEditor = editor;
}
 
public void setHourVisible(boolean b) {
this.panelHour.setVisible(b);
}
303,8 → 306,9
 
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("TimestampEditorPanel got :" + t.getTime());
 
System.out.println("TimestampEditorPanel got timestamp :" + t.getTimestamp());
System.out.println("TimestampEditorPanel got date :" + t.getDate());
System.out.println("TimestampEditorPanel got time :" + t.getTime());
}
});
f.setContentPane(t);
/trunk/OpenConcerto/src/org/openconcerto/ui/date/DateRangePlannerPanel.java
1184,6 → 1184,10
}
 
public static String getDescriptionFromXML(String xml) {
return getDescriptionFromXML(xml, true);
}
 
public static String getDescriptionFromXML(String xml, final boolean includeTimes) {
String result = "";
try {
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1190,11 → 1194,13
final DocumentBuilder db = dbf.newDocumentBuilder();
final Document dom = db.parse(new StringInputStream(xml, "UTF8"));
// Schedule
if (includeTimes) {
final NodeList l1 = dom.getElementsByTagName("schedule");
final Node nSchedule = l1.item(0);
final long tStart = getAttributeAsLong(nSchedule, "start");
final long tStop = getAttributeAsLong(nSchedule, "end");
result += "De " + formatTime(tStart) + " à " + formatTime(tStop) + " ";
}
 
// Period
final NodeList l2 = dom.getElementsByTagName("period");
/trunk/OpenConcerto/src/org/openconcerto/ui/date/DateRangeTable.java
69,13 → 69,13
private static final PropertyChangeListener FOCUS_LISTENER = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
Component c = ((KeyboardFocusManager) evt.getSource()).getPermanentFocusOwner();
if (c == null) {
Component focusOwner = ((KeyboardFocusManager) evt.getSource()).getPermanentFocusOwner();
if (focusOwner == null) {
// Personne n'a encore le focus, on ne stoppe pas l'édition dans les tables
// car on est dans ce cas quand on démarre l'édition
return;
}
final Component rootOfNewFocusOwner = SwingUtilities.getRoot(c);
final Component rootOfNewFocusOwner = SwingUtilities.getRoot(focusOwner);
for (final JTable t : FOCUS_TABLES) {
final Component rootOfTable = SwingUtilities.getRoot(t);
if (rootOfNewFocusOwner != rootOfTable) {
82,6 → 82,7
// le focus est dans un autre fenetre, la table doit donc stopper son édition
stopTableCellEditing(t);
} else {
Component c = focusOwner;
while (c != null) {
if (c == t) {
// le focus reste "dans" la table, on ne fait rien
112,7 → 113,9
final String propertyName = "permanentFocusOwner";
if (c.isDisplayable()) {
final boolean wasEmpty = FOCUS_TABLES.isEmpty();
if (!FOCUS_TABLES.contains(c)) {
FOCUS_TABLES.add((JTable) c);
}
if (wasEmpty) {
final KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(propertyName, FOCUS_LISTENER);
288,6 → 291,7
}
// enableFocusLogging();
final JFrame f = new JFrame();
f.setTitle("DateRangeTable");
f.setContentPane(new DateRangeTable(true, false));
f.setSize(400, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/trunk/OpenConcerto/src/org/openconcerto/ui/table/TimestampTableCellEditor.java
51,8 → 51,13
private Calendar calendar;
private JPopupMenu aPopup;
private boolean popupOpen = false;
private final TimestampEditorPanel content = new TimestampEditorPanel();
private boolean allowNull = true;
private final TimestampEditorPanel content = new TimestampEditorPanel(false, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
private boolean allowNull = false;
 
public TimestampTableCellEditor(boolean showHour) {
this();
96,10 → 101,12
this.aPopup.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!allowNull) {
if (evt.getPropertyName().equals("visible") && Boolean.FALSE.equals(evt.getNewValue())) {
stopCellEditing();
}
}
}
});
 
this.popupOpen = true;
134,7 → 141,6
}
});
 
this.content.setCellEditor(this);
this.content.addActionListener(this);
return c;
}
215,7 → 221,7
}
 
public void actionPerformed(ActionEvent e) {
this.delegate.setValue(this.content.getTime());
this.delegate.setValue(this.content.getTimestamp());
}
 
public static void main(String[] args) {
/trunk/OpenConcerto/src/org/openconcerto/ui/FontUtils.java
18,6 → 18,9
import java.awt.Component;
import java.awt.Font;
 
import javax.swing.JTable;
import javax.swing.JTree;
 
public class FontUtils {
 
public static Font setFontFor(Component comp, String toDisplay) {
25,8 → 28,8
}
 
/**
* If the current font for <code>comp</code> cannot handle <code>toDisplay</code>, this
* method set the font to the system LAF (which should have appropriate fallbacks).
* If the current font for <code>comp</code> cannot handle <code>toDisplay</code>, this method
* set the font to the system LAF (which should have appropriate fallbacks).
*
* @param comp the component, eg a JComboBox.
* @param name the name of system LAF font, eg ComboBox.
54,4 → 57,11
return res;
}
 
public static int getPreferredRowHeight(JTree tree) {
return 2 + (int) (tree.getFont().getSize() * 1.4f);
}
 
public static int getPreferredRowHeight(JTable table) {
return 4 + (int) (table.getFont().getSize() * 1.4f);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/DefaultGridBagConstraints.java
18,6 → 18,7
import java.awt.Insets;
 
import javax.swing.JComponent;
import javax.swing.UIManager;
 
public class DefaultGridBagConstraints extends GridBagConstraints {
 
35,6 → 36,10
}
 
public static Insets getDefaultInsets() {
if (UIManager.get("dpi.scale") != null) {
float f = (Float) UIManager.get("dpi.scale");
return new Insets((int) (2 * f), (int) (3 * f), (int) (2 * f), (int) (2 * f));
}
return new Insets(2, 3, 2, 2);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTableOnline.java
14,7 → 14,7
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.IFieldPath;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowValues;
115,19 → 115,19
*/
private final void setWhere(final SQLSelect sel, final SearchInfo sInfo, final List<SQLTableModelColumn> cols) {
if (sInfo != null) {
final Set<SQLField> fields = new HashSet<SQLField>();
final Set<IFieldPath> fields = new HashSet<>(cols.size() * 2);
for (final SQLTableModelColumn sqlTableModelColumn : cols) {
fields.addAll(sqlTableModelColumn.getFields());
fields.addAll(sqlTableModelColumn.getPaths());
}
final List<Where> wheres = new ArrayList<Where>();
final List<Where> wFields = new ArrayList<Where>();
final List<Where> wheres = new ArrayList<>();
final List<Where> wFields = new ArrayList<>();
 
final List<String> texts = sInfo.getTexts();
for (String string : texts) {
wFields.clear();
for (final SQLField sqlField : fields) {
if (sqlField.getType().getJavaType().equals(String.class)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, sel.getAlias(sqlField)), "LIKE", "%" + string.toLowerCase() + "%");
for (final IFieldPath fpath : fields) {
if (fpath.getField().getType().getJavaType().equals(String.class)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, sel.followFieldPath(fpath)), "LIKE", "%" + string.toLowerCase() + "%");
wFields.add(w);
}
}
141,7 → 141,6
w = Where.and(wheres);
}
sel.setWhere(w);
System.err.println(sel.asString());
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightEditFrame.java
292,16 → 292,29
}
}
 
final protected void setMetaData(final int userId) {
// FIXME use SQLRowValues method
protected final void setMetaData(final int userId) {
final SQLTable sqlTable = this.sqlRow.getTable();
final Date now = new Date();
// FIXME only set those fields at insertion time
if (this.sqlRow.getObject(sqlTable.getCreationUserField().getName()) == null || this.sqlRow.getObject(sqlTable.getCreationDateField().getName()) == null) {
this.sqlRow.put(sqlTable.getCreationUserField().getName(), userId);
this.sqlRow.put(sqlTable.getCreationDateField().getName(), new Date());
setFieldValue(this.sqlRow, sqlTable.getCreationUserField(), false, userId);
setFieldValue(this.sqlRow, sqlTable.getCreationDateField(), false, now);
}
this.sqlRow.put(sqlTable.getModifUserField().getName(), userId);
this.sqlRow.put(sqlTable.getModifDateField().getName(), new Date());
setFieldValue(this.sqlRow, sqlTable.getModifUserField(), false, userId);
setFieldValue(this.sqlRow, sqlTable.getModifDateField(), false, now);
}
 
static private boolean setFieldValue(final SQLRowValues vals, final SQLField f, final boolean remove, final Object val) {
if (f == null)
return false;
if (remove)
vals.remove(f.getName());
else
vals.put(f.getName(), val);
return true;
}
 
@Override
public String getClassName() {
return this.getClass().getName();
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/warning_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/warning_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ElementComboBox.java
26,6 → 26,7
import org.openconcerto.sql.view.EditPanelListener;
import org.openconcerto.sql.view.IListButton;
import org.openconcerto.sql.view.IListFrame;
import org.openconcerto.sql.view.IListPanel;
import org.openconcerto.sql.view.ListeAddPanel;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FrameUtil;
44,9 → 45,9
 
import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
 
/**
* A SQLRequestComboBox with an SQLElement allowing it to have buttons for zooming on a selected
61,9 → 62,10
*/
public static final String CAN_MODIFY = "org.openconcerto.sql.comboCanModify";
 
private static ImageIcon icon = null;
private static ImageIcon iconModif = null;
private static ImageIcon iconAdd = null;
private static Icon icon = null;
private static Icon iconModif = null;
private static Icon iconAdd = null;
static int iconSize;
 
private static ITransformer<ElementComboBox, Boolean> globalRowDisplayer = null;
 
70,9 → 72,11
// no need for synchronization, all in EDT
private static void checkLoaded() {
if (icon == null) {
icon = new ImageIcon(ElementComboBox.class.getResource("loupe.png"));
iconAdd = new ImageIcon(ElementComboBox.class.getResource("plus.png"));
iconModif = new ImageIcon(ElementComboBox.class.getResource("pen.png"));
final boolean twoX = UIManager.get("dpi.scale") != null && ((Float) UIManager.get("dpi.scale")) >= 2f;
iconSize = twoX ? 32 : 16;
icon = IListPanel.getIcon(ElementComboBox.class, "loupe.png", twoX);
iconAdd = IListPanel.getIcon(ElementComboBox.class, "plus.png", twoX);
iconModif = IListPanel.getIcon(ElementComboBox.class, "pen.png", twoX);
}
}
 
182,10 → 186,13
if (this.isModif) {
this.viewButton.setToolTipText("Modifier");
this.viewButton.setIcon(getModifIcon());
 
} else {
this.viewButton.setToolTipText("Voir plus de détails");
this.viewButton.setIcon(getDetailsIcon());
}
this.viewButton.setPreferredSize(new Dimension(iconSize + 8, iconSize));
DefaultGridBagConstraints.lockMinimumSize(this.viewButton);
// each time its icon change, otherwise (at least on Mac) the opacity is wrong
IListButton.initButton(this.viewButton);
}
216,18 → 223,14
if (!this.minimal) {
c.weightx = 0;
c.gridx++;
 
this.viewButton.setPreferredSize(new Dimension(24, 16));
this.setCanModify(Boolean.getBoolean(CAN_MODIFY));
DefaultGridBagConstraints.lockMinimumSize(this.viewButton);
add(this.viewButton, c);
c.gridx++;
this.listButton.setToolTipText(TM.getInstance().trM("combo.list", "element", this.element.getName()));
DefaultGridBagConstraints.lockMinimumSize(this.listButton);
add(this.listButton, c);
 
// Add button
this.addButton.setPreferredSize(new Dimension(24, 16));
this.addButton.setPreferredSize(new Dimension(iconSize + 8, iconSize));
this.addButton.setIcon(getAddIcon());
IListButton.initButton(this.addButton);
this.addButton.setToolTipText(EditFrame.getCreateMessage(this.element));
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/pen_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/pen_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/plus_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/plus_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/loupe_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/loupe_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/error_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/error_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/request/ListSQLRequest.java
57,8 → 57,6
 
public ListSQLRequest(final SQLRowValues graph, final Where where) {
super(graph, where);
if (!this.getPrimaryTable().isOrdered())
throw new IllegalArgumentException(this.getPrimaryTable() + " is not ordered.");
}
 
protected ListSQLRequest(ListSQLRequest req, final boolean freeze) {
/trunk/OpenConcerto/src/org/openconcerto/sql/request/BaseFillSQLRequest.java
17,7 → 17,9
import org.openconcerto.sql.TM;
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.IFieldPath;
import org.openconcerto.sql.model.OrderComparator;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValues.CreateMode;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
46,6 → 48,7
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
352,7 → 355,38
return this.getDefaultOrder();
}
 
public final boolean isTableOrder() {
return this.getPrimaryTable().isOrdered() && this.getOrder().equals(getTableOrder());
}
 
/**
* Order the passed rows the same as {@link #getFetcher()}.
*
* @param r1 the first row.
* @param r2 the second row.
* @return a negative integer, zero, or a positive integer as the first argument is less than,
* equal to, or greater than the second.
*/
public final int order(final SQLRowValues r1, final SQLRowValues r2) {
if (r1 == r2)
return 0;
// same behaviour as SQLSelect
final Comparator<SQLRowAccessor> comp = OrderComparator.getFallbackToPKInstance();
for (final Path p : getOrder()) {
final SQLRowValues o1 = r1.followPath(p);
final SQLRowValues o2 = r2.followPath(p);
final int res = comp.compare(o1, o2);
if (res != 0)
return res;
}
return 0;
}
 
protected List<Path> getDefaultOrder() {
return getTableOrder();
}
 
protected final List<Path> getTableOrder() {
return Collections.singletonList(Path.get(getPrimaryTable()));
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/element/GlobalMapper.java
43,7 → 43,6
l = new ArrayList<String>(3);
objectsToIds.put(obj, l);
l.add(id);
objectsToIds.put(obj, l);
} else if (!l.contains(obj)) {
l.add(id);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/UISQLComponent.java
203,10 → 203,19
this.setLayout(new GridLayout(1, 1));
this.add(this.tabbedPane);
}
this.currentPanel = new JPanel();
final JPanel newPanel = new JPanel();
// from Guillaume : tabs shouldn't be opaque in Windows L&F
this.currentPanel.setOpaque(false);
this.tabbedPane.addTab(tabTitle, this.currentPanel);
newPanel.setOpaque(false);
this.tabbedPane.addTab(tabTitle, newPanel);
this.setLayouterOn(newPanel, w, d);
}
 
protected final void setLayouterOn(final JPanel cont) {
this.setLayouterOn(cont, this.width, this.def);
}
 
protected final void setLayouterOn(final JPanel cont, int w, int d) {
this.currentPanel = cont;
this.setLayouter(w, d);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java
515,7 → 515,7
 
// must be called in setState() after fields have been set (for isRowable())
private int fetchUndefID() {
int res;
final int res;
final SQLField pk;
synchronized (this) {
pk = isRowable() ? this.getKey() : null;
523,14 → 523,8
if (pk != null) {
final Tuple2<Boolean, Number> currentValue = getUndefID(this.getSchema(), this.getName());
if (!currentValue.get0()) {
try {
// no row
res = this.findMinID(pk);
} catch (Exception e) {
// we ***** don't care
e.printStackTrace();
res = SQLRow.NONEXISTANT_ID;
}
} else {
// a row
final Number id = currentValue.get1();
982,6 → 976,10
@Immutable
static public final class VirtualFields {
 
// must be set first, as they are used by others (e.g. create())
static public final VirtualFields NONE = new VirtualFields(EnumSet.noneOf(VirtualFieldPartition.class));
static public final VirtualFields ALL = new VirtualFields(EnumSet.allOf(VirtualFieldPartition.class));
 
static public final VirtualFields ORDER = new VirtualFields(VirtualFieldPartition.ORDER);
static public final VirtualFields ARCHIVE = new VirtualFields(VirtualFieldPartition.ARCHIVE);
static public final VirtualFields METADATA = new VirtualFields(VirtualFieldPartition.METADATA);
1004,9 → 1002,16
* {@link #PRIMARY_KEY} with {@link #FOREIGN_KEYS}.
*/
static public final VirtualFields KEYS = PRIMARY_KEY.union(FOREIGN_KEYS);
static public final VirtualFields NONE = new VirtualFields(EnumSet.noneOf(VirtualFieldPartition.class));
static public final VirtualFields ALL = new VirtualFields(EnumSet.allOf(VirtualFieldPartition.class));
 
static private VirtualFields create(final EnumSet<VirtualFieldPartition> set) {
if (set.isEmpty())
return NONE;
else if (set.equals(ALL.set))
return ALL;
else
return new VirtualFields(set);
}
 
private final EnumSet<VirtualFieldPartition> set;
 
// use constants above
1021,25 → 1026,45
this.set = set;
}
 
public final boolean contains(VirtualFields other) {
return this == other || this == ALL || this != NONE && this.set.containsAll(other.set);
}
 
public final VirtualFields union(VirtualFields... other) {
// optimizations
if (this == ALL || other.length == 0 || other.length == 1 && this.contains(other[0]))
return this;
if (other.length == 1 && other[0].contains(this))
return other[0];
 
final EnumSet<VirtualFieldPartition> set = this.set.clone();
for (final VirtualFields o : other)
set.addAll(o.set);
return new VirtualFields(set);
return create(set);
}
 
public final VirtualFields intersection(VirtualFields... other) {
// optimizations
if (this == NONE || other.length == 0 || other.length == 1 && other[0].contains(this))
return this;
if (other.length == 1 && this.contains(other[0]))
return other[0];
 
final EnumSet<VirtualFieldPartition> set = this.set.clone();
for (final VirtualFields o : other)
set.retainAll(o.set);
return new VirtualFields(set);
return create(set);
}
 
public final VirtualFields difference(VirtualFields... other) {
// optimizations
if (this == NONE || other.length == 0 || other.length == 1 && Collections.disjoint(this.set, other[0].set))
return this;
 
final EnumSet<VirtualFieldPartition> set = this.set.clone();
for (final VirtualFields o : other)
set.removeAll(o.set);
return new VirtualFields(set);
return create(set);
}
 
public final VirtualFields complement() {
1068,7 → 1093,12
final VirtualFields other = (VirtualFields) obj;
return this.set.equals(other.set);
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " " + this.set;
}
}
 
/**
* A partition of the fields (except that some can be empty). Being a partition allow to use
2177,13 → 2207,17
try {
triggerClass = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new SQLException("Class not found for " + t, e);
// throw new SQLException("Class not found for " + t, e);
e.printStackTrace();
continue;
}
PartialUniqueTrigger n;
try {
n = (PartialUniqueTrigger) triggerClass.newInstance();
} catch (Exception e) {
throw new SQLException("Couldn't instantiate class for " + t, e);
// throw new SQLException("Couldn't instantiate class for " + t, e);
e.printStackTrace();
continue;
}
final String indexName = ChangeTable.getIndexName(t.getName(), thisSystem);
final Index idx = createUniqueIndex(indexName, n.getColumns(), n.getWhere());
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesListFetcher.java
26,6 → 26,7
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.RecursionType;
import org.openconcerto.utils.SetMap;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.cc.LinkedIdentitySet;
246,6 → 247,9
// graftPlace -> {referent path -> fetcher}, unmodifiable
@GuardedBy("this")
private Map<Path, Map<Path, SQLRowValuesListFetcher>> grafts;
// {pathToAdd, existingPath}, unmodifiable
@GuardedBy("this")
private Map<Path, Path> postFetchLinks;
 
/**
* Construct a new instance with the passed graph of SQLRowValues.
349,6 → 353,7
this.frozen = null;
this.freezeRows = false;
this.grafts = Collections.emptyMap();
this.postFetchLinks = Collections.emptyMap();
}
}
 
381,6 → 386,7
e.setValue(Collections.unmodifiableMap(innerMutable));
}
this.grafts = Collections.unmodifiableMap(outerMutable);
this.postFetchLinks = f.postFetchLinks;
}
}
}
629,6 → 635,69
return this.descendantsOrdered;
}
 
public final void addPostFetchLink(final Path toAdd, final Path existingDestination) {
this.addPostFetchLink(toAdd, existingDestination, false);
}
 
/**
* Add a link to be added at the end of fetch(). This is needed when the graph to be fetched
* isn't a tree.
*
* @param toAdd the last step of this parameter will be added at the end of {@link #fetch()},
* e.g. /SOURCE/ --[ID_MOST_SERIOUS_OBS]--> /OBSERVATION/.
* @param existingDestination where the destination rows of <code>toAdd</code> are, e.g.
* /SOURCE/ <--[ID_SOURCE]-- /SOURCE_OBSERVATION/ --[ID_OBSERVATION]--> /OBSERVATION/.
* @param ignoreIfMissing what to do if a passed path isn't in this, <code>true</code> to do
* nothing, <code>false</code> to throw an exception.
* @return <code>true</code> if the link was added.
*/
public synchronized final boolean addPostFetchLink(final Path toAdd, final Path existingDestination, final boolean ignoreIfMissing) {
checkFrozen();
if (toAdd.getLast() != existingDestination.getLast())
throw new IllegalArgumentException("Different destination tables");
if (!toAdd.isSingleField())
throw new IllegalArgumentException("Path to add isn't composed of single fields");
final Step lastStep = toAdd.getStep(-1);
if (lastStep.getDirection() != Direction.FOREIGN)
throw new IllegalArgumentException("Last step isn't foreign : " + lastStep);
if (!getFetchers(toAdd).isEmpty())
throw new IllegalArgumentException("Path to add already fetched");
final Path pathToFK = toAdd.minusLast();
final ListMap<Path, SQLRowValuesListFetcher> fkFetchers = getFetchers(pathToFK);
if (fkFetchers.isEmpty()) {
if (ignoreIfMissing)
return false;
else
throw new IllegalArgumentException("Path to add should only have the last step missing");
}
final String lastFieldName = lastStep.getSingleField().getName();
for (final Entry<Path, List<SQLRowValuesListFetcher>> e : fkFetchers.entrySet()) {
final int pathLength = e.getKey().length();
for (final SQLRowValuesListFetcher fkFetcher : e.getValue()) {
if (!fkFetcher.getGraph().followPath(pathToFK.subPath(pathLength)).contains(lastFieldName)) {
if (ignoreIfMissing)
return false;
else
throw new IllegalArgumentException("Foreign key " + lastFieldName + " isn't fetched");
}
}
}
if (getFetchers(existingDestination).isEmpty()) {
if (ignoreIfMissing)
return false;
else
throw new IllegalArgumentException("Destination won't be fetched : " + existingDestination);
}
final Map<Path, Path> copy = new HashMap<>(this.postFetchLinks);
copy.put(toAdd, existingDestination);
this.postFetchLinks = Collections.unmodifiableMap(copy);
return true;
}
 
public synchronized Map<Path, Path> getPostFetchLinks() {
return this.postFetchLinks;
}
 
public final SQLRowValuesListFetcher graft(final SQLRowValuesListFetcher other) {
return this.graft(other, Path.get(getGraph().getTable()));
}
1239,11 → 1308,13
}
final SQLSelect req;
final Map<Path, Map<Path, SQLRowValuesListFetcher>> grafts;
final Map<Path, Path> postLinks;
final boolean freezeRows;
// the only other internal state used is this.descendantPath which is final immutable
synchronized (this) {
req = this.getReq(w, selTransf);
grafts = this.getGrafts();
postLinks = this.postFetchLinks;
freezeRows = unmodifiableRows == null ? this.areReturnedRowsUnmodifiable() : unmodifiableRows.booleanValue();
}
// getName() would take 5% of ResultSetHandler.handle()
1288,9 → 1359,10
 
final boolean mergeReferents = this.fetchReferents();
final boolean mergeGrafts = grafts.size() > 0;
final boolean addPostLinks = !postLinks.isEmpty();
// if it is possible let the handler do the freeze, avoid another loop and further is
// multi-threaded
final boolean handlerCanFreeze = !mergeReferents && !mergeGrafts;
final boolean handlerCanFreeze = !mergeReferents && !mergeGrafts && !addPostLinks;
 
// if we wanted to use the cache, we'd need to copy the returned list and its items (i.e.
// deepCopy()), since we modify them afterwards. Or perhaps include the code after this line
1328,6 → 1400,58
mainRes.pop();
}
}
if (addPostLinks) {
// group by destinationPath to index only once for all links to add
// SetMap<Tuple2<commonPath, destinationPath>, toAddPath>
final SetMap<Tuple2<Path, Path>, Path> byCommonPath = new SetMap<>();
for (final Entry<Path, Path> e : postLinks.entrySet()) {
final Path toAdd = e.getKey();
final Path existingPath = e.getValue();
final Path commonPath = toAdd.getCommonPath(existingPath);
byCommonPath.add(Tuple2.create(commonPath, existingPath.subPath(commonPath.length())), toAdd.subPath(commonPath.length()));
}
/**
* <pre>
* LOCAL <-- SRC <-- JOIN --> OBSERVATION
* \--ID_OLDEST_OBS--/
* \--ID_MOST_SERIOUS_OBS--/
* </pre>
*/
for (final Entry<Tuple2<Path, Path>, Set<Path>> e : byCommonPath.entrySet()) {
// LOCAL <-- SRC
final Path commonPath = e.getKey().get0();
// SRC <-- JOIN --> OBSERVATION
final Path throughTargetRows = e.getKey().get1();
// SRC -- ID_OLDEST_OBS --> OBSERVATION
// SRC -- ID_MOST_SERIOUS_OBS --> OBSERVATION
final Set<Path> pathsToAdd = e.getValue();
 
for (final SQLRowValues v : merged) {
for (final SQLRowValues commonRow : v.getDistantRows(commonPath)) {
// index target rows
final Map<Number, SQLRowValues> byIDs = new HashMap<>();
for (final SQLRowValues target : commonRow.getDistantRows(throughTargetRows)) {
byIDs.put(target.getIDNumber(), target);
}
// add links
for (final Path toAdd : pathsToAdd) {
final String fkName = toAdd.getStep(-1).getSingleField().getName();
// SRC
final Path throughRowToUpdate = toAdd.minusLast();
for (final SQLRowValues toUpdate : commonRow.getDistantRows(throughRowToUpdate)) {
final Number foreignID = toUpdate.getNonEmptyForeignIDNumber(fkName);
if (foreignID != null) {
final SQLRowValues target = byIDs.get(foreignID);
if (target == null)
throw new IllegalStateException("Missing row for " + foreignID + " at " + throughTargetRows);
toUpdate.put(fkName, target);
}
}
}
}
}
}
}
if (freezeRows && !handlerCanFreeze) {
for (final SQLRowValues r : merged) {
r.getGraph().freeze();
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowAccessor.java
261,6 → 261,10
*/
public abstract Set<String> getFields();
 
public boolean contains(final String fieldName) {
return this.getFields().contains(fieldName);
}
 
public abstract Object getObject(String fieldName);
 
/**
283,8 → 287,14
 
// MAYBE change paramter to enum MissingMode = THROW_EXCEPTION, ADD, RETURN_NULL
public final Object getObject(String fieldName, final boolean mustBePresent) throws IllegalArgumentException {
if (mustBePresent && !this.getFields().contains(fieldName))
throw new IllegalArgumentException("Field " + fieldName + " not present in this : " + this.getFields() + " table " + this.getTable().getName());
if (mustBePresent && !this.contains(fieldName)) {
final String msg;
if (this.getTable().contains(fieldName))
msg = "Field " + fieldName + " not present in this : " + this.getFields() + " but exists in " + this.getTable();
else
msg = "Field " + fieldName + " neither present in this : " + this.getFields() + " nor " + this.getTable();
throw new IllegalArgumentException(msg);
}
return this.getObject(fieldName);
}
 
314,6 → 324,7
* @return the values of the passed fields.
*/
public final Map<String, Object> getValues(final Collection<String> fields, final boolean includeMissingKeys) {
this.initValues();
final Map<String, Object> res = new LinkedHashMap<String, Object>();
final Set<String> thisFields = this.getFields();
for (final String f : fields) {
323,6 → 334,9
return res;
}
 
protected void initValues() {
}
 
/**
* Retourne le champ nommé <code>field</code> de cette ligne. Cette méthode formate la valeur en
* fonction de son type, par exemple une date sera localisée.
465,7 → 479,8
* <code>null</code> :
* <ol>
* <li><code>field</code> is defined and has the value <code>null</code></li>
* <li><code>field</code> is defined and has an SQLRowValues value without an ID</li>
* <li><code>field</code> is defined and has an SQLRowValues value {@link #hasID() without an
* ID} (i.e. field not defined or <code>null</code>)</li>
* </ol>
* In the second case, <code>field</code> is *not* {@link #isForeignEmpty(String) empty}, an ID
* is just missing.
489,14 → 504,19
* {@link #isForeignEmpty(String) empty}, otherwise the foreign ID for the passed field.
* @throws IllegalArgumentException if fieldName is not a foreign field or if the field isn't
* specified.
* @throws IllegalStateException if fieldName is not empty but lacks an ID (i.e. has a
* SQLRowValues without an ID) as by definition a <code>null</code> result means empty.
* @see #getNonEmptyForeign(String)
*/
public final Number getNonEmptyForeignIDNumber(String fieldName) {
if (this.isForeignEmpty(fieldName)) {
return null;
} else {
final Number res = this.getForeignIDNumber(fieldName);
assert res != null;
return res;
final Value<Number> res = this.getForeignIDNumberValue(fieldName);
if (!res.hasValue())
throw new IllegalStateException("Foreign row has no ID");
assert res.getValue() != null;
return res.getValue();
}
}
 
527,7 → 547,7
}
 
private void fetchIfNeeded(String fieldName) {
if (getAccessDBIfNeeded() && (this instanceof SQLRow) && !getFields().contains(fieldName)) {
if (getAccessDBIfNeeded() && (this instanceof SQLRow) && !contains(fieldName)) {
assert false : "Missing " + fieldName + " in " + this;
Log.get().log(Level.WARNING, "Missing " + fieldName + " in " + this, new IllegalStateException());
((SQLRow) this).fetchValues();
540,6 → 560,10
* @param fieldName name of the foreign field.
* @return <code>true</code> if {@link #getForeignIDNumber(String)} is the
* {@link SQLTable#getUndefinedIDNumber()}.
* @throws IllegalArgumentException if fieldName is not a foreign field or if the field isn't
* specified.
* @throws IllegalStateException if <code>fieldName</code> is <code>null</code> but the foreign
* table has an undefined ID.
*/
public final boolean isForeignEmpty(String fieldName) {
final Value<Number> fID = this.getForeignIDNumberValue(fieldName);
550,6 → 574,12
// keep getForeignTable at the 1st line since it does the check
final SQLTable foreignTable = this.getForeignTable(fieldName);
final Number undefID = foreignTable.getUndefinedIDNumber();
if (undefID != null && fID.getValue() == null) {
// since a foreign row with ID=null !hasID() and thus getForeignIDNumberValue() is
// none and this method returns false above
assert this.getObject(fieldName) == null;
throw new IllegalStateException("Null isn't a valid foreign key value when pointing to a table with undefined ID : " + undefID);
}
return NumberUtils.areNumericallyEqual(fID.getValue(), undefID);
}
}
599,17 → 629,6
return this.getTable().hashCode() + this.getID();
}
 
public SQLRowValues getMergedRowValuesFromDatabase() {
SQLRowValues result = this.asRowValues();
if (this.hasID()) {
SQLRow r = result.getTable().getRow(getID());
for (String f : r.getFields()) {
if (!result.getFields().contains(f)) {
result.put(f, r.getObject(f));
// return the all current field values
public abstract String mapToString();
}
}
}
return result;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSchema.java
53,7 → 53,7
public static final String NOAUTO_CREATE_METADATA = "org.openconcerto.sql.noautoCreateMetadata";
 
public static final String FWK_TABLENAME_PREFIX = "FWK_";
static final String METADATA_TABLENAME = FWK_TABLENAME_PREFIX + "SCHEMA_METADATA";
public static final String METADATA_TABLENAME = FWK_TABLENAME_PREFIX + "SCHEMA_METADATA";
private static final String VERSION_MDKEY = "VERSION";
private static final String VERSION_XMLATTR = "schemaVersion";
 
/trunk/OpenConcerto/src/org/openconcerto/sql/model/OrderComparator.java
13,6 → 13,8
package org.openconcerto.sql.model;
 
import org.openconcerto.utils.CompareUtils;
 
import java.util.Comparator;
 
/**
22,10 → 24,28
*/
public class OrderComparator implements Comparator<SQLRowAccessor> {
 
public static final OrderComparator INSTANCE = new OrderComparator();
/**
* Order rows by {@link SQLTable#getOrderField()}.
*/
public static final OrderComparator INSTANCE = new OrderComparator(false);
private static final OrderComparator INSTANCE_FALLBACK_TO_PK = new OrderComparator(true);
 
/**
* Order rows by {@link SQLTable#getOrderField()}, or if the table is not
* {@link SQLTable#isOrdered() ordered} by {@link SQLTable#getKey()}.
*
* @return the comparator.
*/
public static final Comparator<SQLRowAccessor> getFallbackToPKInstance() {
return INSTANCE_FALLBACK_TO_PK;
}
 
private final boolean fallbackToPK;
 
// singleton
private OrderComparator() {
private OrderComparator(boolean fallbackToPK) {
super();
this.fallbackToPK = fallbackToPK;
}
 
@Override
34,9 → 54,21
// MAYBE NULLS FIRST/LAST
if (r1 == r2)
return 0;
if (!r1.getTable().equals(r2.getTable()))
final SQLTable t = r1.getTable();
if (!t.equals(r2.getTable()))
throw new IllegalArgumentException(r1 + " and " + r2 + " are not of the same table");
if (t.isOrdered()) {
return r1.getOrder().compareTo(r2.getOrder());
} else if (this.fallbackToPK) {
if (!t.isRowable())
throw new IllegalArgumentException(t + " neither ordered nor rowable");
else if (r1.hasID() && r2.hasID())
return CompareUtils.compareInt(r1.getID(), r2.getID());
else
throw new IllegalArgumentException("Missing ID");
} else {
throw new IllegalArgumentException(t + " not ordered");
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesCluster.java
123,6 → 123,10
return this.getHead().getTable().getDBSystemRoot();
}
 
public final int getLinksCount() {
return this.links.size();
}
 
/**
* All the rowValues in this cluster.
*
325,6 → 329,43
}
 
public final Map<SQLRowValues, SQLRowValues> deepCopy(final boolean freeze) {
return this.copy(null, false, freeze);
}
 
/**
* Copy a subset of this graph. For each link to copy, if the destination was copied then the
* new row will point to it, otherwise the new row will point to the original row. For example,
* if
*
* <pre>
* start is CONTAINER <-- *ITEM [F1, F2]* --> PRIVATE
* and graph is ITEM [F2, ID_PRIVATE]
* then after this method :
* CONTAINER <-- ITEM [F1, F2] --> PRIVATE
* \-- ITEM [F2] --> PRIVATE
* </pre>
*
* @param start where to start copying.
* @param graph which rows and which fields to copy, not <code>null</code>.
* @return the new rows, indexed by the original rows in this instance.
*/
public final Map<SQLRowValues, SQLRowValues> copy(final SQLRowValues start, final SQLRowValues graph) {
return this.copy(computeToRetain(start, graph, true), true, false);
}
 
/**
* Copy rows of this graph.
*
* @param subset which rows and which fields to copy, <code>null</code> to copy all rows.
* @param allowSameGraph used when copied rows point to rows which weren't copied,
* <code>true</code> to point to the original rows (and thus linking the new rows into
* the existing graph), <code>false</code> to flatten the link (like
* {@link ForeignCopyMode#COPY_ID_OR_RM}).
* @param freeze <code>true</code> if the copied rows should be frozen.
* @return the new rows, indexed by the original rows in this instance.
*/
private final Map<SQLRowValues, SQLRowValues> copy(final SetMap<SQLRowValues, String> subset, final boolean allowSameGraph, final boolean freeze) {
assert !allowSameGraph || !freeze;
// copy all rowValues of this graph
final Map<SQLRowValues, SQLRowValues> noLinkCopy = new IdentityHashMap<SQLRowValues, SQLRowValues>();
// don't copy foreigns, but we want to preserve the order of all fields. This works because
332,6 → 373,7
final ForeignCopyMode copyMode = ForeignCopyMode.COPY_NULL;
for (final SQLRowValues n : this.getItems()) {
final SQLRowValues copy;
if (subset == null || subset.containsKey(n)) {
// might as well use the minimum memory if the values won't change
if (freeze) {
copy = new SQLRowValues(n.getTable(), n.size(), n.getForeignsSize(), n.getReferents().size());
338,18 → 380,43
copy.setAll(n.getAllValues(copyMode));
} else {
copy = new SQLRowValues(n, copyMode);
if (subset != null) {
copy.retainAll(subset.get(n));
}
}
noLinkCopy.put(n, copy);
}
}
 
// and link them together in order
for (final Link l : this.links) {
final List<Link> iterableLinks = subset == null ? this.links : new ArrayList<Link>(this.links);
for (final Link l : iterableLinks) {
if (l.getField() != null) {
noLinkCopy.get(l.getSrc()).put(l.getField().getName(), noLinkCopy.get(l.getDest()));
final SQLRowValues sourceCopy = noLinkCopy.get(l.getSrc());
if (subset == null || (sourceCopy != null && sourceCopy.contains(l.getField().getName()))) {
assert l.getDest() != null;
final SQLRowValues destCopy = noLinkCopy.get(l.getDest());
final Object dest;
if (destCopy != null)
dest = destCopy;
else if (allowSameGraph)
dest = l.getDest();
else if (l.getDest().hasID())
dest = l.getDest().getIDNumber();
else
dest = null;
if (dest != null) {
sourceCopy.put(l.getField().getName(), dest);
} else {
assert noLinkCopy.containsKey(l.getSrc());
// ForeignCopyMode.COPY_ID_OR_RM like pruneWithoutCopy() (avoids
// leaving nulls)
sourceCopy.remove(l.getField().getName());
}
}
} else {
assert subset != null || noLinkCopy.containsKey(l.getSrc());
}
}
 
final SQLRowValues res = noLinkCopy.values().iterator().next();
// only force graph creation if needed
356,6 → 423,7
if (freeze)
res.getGraph().freeze();
assert res.isFrozen() == freeze;
assert allowSameGraph || res.getGraph() != this;
 
return noLinkCopy;
}
896,10 → 964,12
return pruneMap(start, graph, keepUnionOfFields).get(start);
}
 
// private since result isn't trimmed, the values are still all there, not all in the pruned
// graph
private final Map<SQLRowValues, SQLRowValues> pruneMap(final SQLRowValues start, final SQLRowValues graph, final boolean keepUnionOfFields) {
public final Map<SQLRowValues, SQLRowValues> pruneMap(final SQLRowValues start, final SQLRowValues graph, final boolean keepUnionOfFields) {
this.containsCheck(start);
return this.copy(computeToRetain(start, graph, keepUnionOfFields), false, false);
}
 
static SetMap<SQLRowValues, String> computeToRetain(final SQLRowValues start, final SQLRowValues graph, final boolean keepUnionOfFields) {
if (!start.getTable().equals(graph.getTable()))
throw new IllegalArgumentException(start + " is not from the same table as " + graph);
// there's no way to tell apart 2 referents
906,9 → 976,6
if (!graph.getGraph().hasOneRowPerPath())
throw new IllegalArgumentException("More than one row for " + graph.printGraph());
 
final Map<SQLRowValues, SQLRowValues> map = start.getGraph().deepCopy(false);
final SQLRowValues res = map.get(start);
 
final SetMap<SQLRowValues, String> toRetain = new SetMap<SQLRowValues, String>(new IdentityHashMap<SQLRowValues, Set<String>>(), Mode.NULL_FORBIDDEN);
// BREADTH_FIRST to stop as soon as this no longer have rows in the graph
// CycleAllowed since we need to go through every path (e.g. what is a cycle in graph might
921,7 → 988,7
public Object transformChecked(State<Object> input) {
final SQLRowValues r = input.getCurrent();
// since we allowed cycles in graph, allow it here
final Collection<SQLRowValues> rows = res.followPath(input.getPath(), CreateMode.CREATE_NONE, false, true);
final Collection<SQLRowValues> rows = start.followPath(input.getPath(), CreateMode.CREATE_NONE, false, true);
// since we're using BREADTH_FIRST, the next path will be longer so no need to
// continue if there's already no row
if (rows.isEmpty())
935,7 → 1002,18
return null;
}
}, walkOptions);
return toRetain;
}
 
public final SQLRowValues pruneWithoutCopy(final SQLRowValues start, final SQLRowValues graph) {
return this.pruneWithoutCopy(start, graph, true);
}
 
public final SQLRowValues pruneWithoutCopy(final SQLRowValues start, final SQLRowValues graph, final boolean keepUnionOfFields) {
this.containsCheck(start);
final SetMap<SQLRowValues, String> toRetain = computeToRetain(start, graph, keepUnionOfFields);
assert toRetain.containsKey(start);
 
// remove extra fields and flatten if necessary
for (final Entry<SQLRowValues, Set<String>> e : toRetain.entrySet()) {
final SQLRowValues r = e.getKey();
952,7 → 1030,7
}
}
// now, remove referents that aren't in the graph
for (final SQLRowValues r : new ArrayList<SQLRowValues>(res.getGraph().getItems())) {
for (final SQLRowValues r : new ArrayList<SQLRowValues>(start.getGraph().getItems())) {
if (!toRetain.containsKey(r)) {
// only remove links at the border and even then, only remove links to the result :
// avoid creating a myriad of graphs
966,44 → 1044,53
r.removeAll(toFlatten);
}
}
assert res.getGraph().getItems().equals(toRetain.keySet());
 
return map;
assert start.getGraph().getItems().equals(toRetain.keySet());
// NOTE this instance no longer the graph of start if referents were removed
return start;
}
 
// TODO handle referents (and decide how to handle multiple paths to the same node)
final void grow(final SQLRowValues start, final SQLRowValues toGrow, final boolean checkFields) {
final void grow(final SQLRowValues start, final SQLRowValues toGrow, final boolean checkFields, final boolean growUndefined) {
this.containsCheck(start);
if (!start.getTable().equals(toGrow.getTable()))
throw new IllegalArgumentException(start + " is not from the same table as " + toGrow);
this.walk(start, null, new ITransformer<State<Object>, Object>() {
this.walk(start, toGrow, new ITransformer<State<SQLRowValues>, SQLRowValues>() {
@Override
public Object transformChecked(State<Object> input) {
public SQLRowValues transformChecked(State<SQLRowValues> input) {
final SQLRowValues existing = toGrow.followPath(input.getPath());
// don't add undefined row if there's none or if don't want
if (existing == null && input.getAcc().isForeignEmpty(input.getFrom().getName()) && (input.getPath().getLast().getUndefinedIDNumber() == null || !growUndefined))
throw new StopRecurseException().setCompletely(false);
if (existing == null || (checkFields && !existing.getFields().containsAll(input.getCurrent().getFields()))) {
final SQLRowValues leaf = toGrow.assurePath(input.getPath());
if (leaf.hasID()) {
final SQLRowValuesListFetcher fetcher = new SQLRowValuesListFetcher(input.getCurrent());
// don't exclude undef otherwise cannot grow eg
// LOCAL.ID_FAMILLE_2 = 1
if (growUndefined) {
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(SQLSelect input) {
// don't exclude undef otherwise cannot grow eg
// LOCAL.ID_FAMILLE_2 = 1
input.setExcludeUndefined(false);
return input;
}
});
}
final SQLRowValues fetched = fetcher.fetchOne(leaf.getIDNumber());
if (fetched == null)
throw new IllegalArgumentException("no row for " + fetcher);
leaf.load(fetched, null);
} else
// we already loaded all further rows
throw new StopRecurseException().setCompletely(false);
} else {
throw new IllegalArgumentException("cannot expand, missing ID in " + leaf + " at " + input.getPath());
}
return null;
} else {
return existing;
}
}, RecursionType.BREADTH_FIRST);
}
}, RecursionType.BREADTH_FIRST, Direction.FOREIGN);
}
 
public final String contains(final SQLRowValues start, SQLRowValues graph) {
return this.contains(start, graph, true);
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBackgroundTableCacheItem.java
17,25 → 17,33
import java.util.Collections;
import java.util.List;
 
public class SQLBackgroundTableCacheItem implements SQLTableModifiedListener {
public class SQLBackgroundTableCacheItem {
 
private SQLTable table;
private int timeout;
private List<SQLRow> rows = new ArrayList<SQLRow>();
private long lastReload;// time in millis
private boolean enableReloadIfTableModified = true;
 
public SQLBackgroundTableCacheItem(final SQLTable t, final int second) {
this.table = t;
this.timeout = second;
this.table.addTableModifiedListener(new SQLTableModifiedListener() {
 
}
 
@Override
public void tableModified(SQLTableEvent evt) {
this.lastReload = 0;
if (enableReloadIfTableModified) {
lastReload = 0;
}
reloadFromDbIfNeeded();
}
});
}
 
public void setEnableReloadIfTableModified(boolean enableReloadIfTableModified) {
this.enableReloadIfTableModified = enableReloadIfTableModified;
}
 
@SuppressWarnings("unchecked")
public synchronized void reloadFromDbIfNeeded() {
final long delta = System.currentTimeMillis() - this.lastReload;
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRequestLog.java
14,6 → 14,7
package org.openconcerto.sql.model;
 
import org.openconcerto.sql.Log;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.utils.ExceptionUtils;
 
import java.awt.BorderLayout;
237,7 → 238,8
JFrame f = new JFrame("SQL monitoring");
final SQLRequestLogModel model = new SQLRequestLogModel();
final JTable table = new JTable(model);
final TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(table.getModel());
table.setRowHeight(FontUtils.getPreferredRowHeight(table));
final TableRowSorter<TableModel> sorter = new TableRowSorter<>(table.getModel());
table.setRowSorter(sorter);
 
table.getTableHeader().setReorderingAllowed(false);
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRow.java
280,9 → 280,14
return this.fetched;
}
 
private Map<String, Object> getValues() {
@Override
protected void initValues() {
if (!this.isFilled())
this.fetchValues();
}
 
private Map<String, Object> getValues() {
this.initValues();
return this.values;
}
 
326,6 → 331,12
return this.fetched ? Collections.unmodifiableSet(this.getValues().keySet()) : Collections.<String> emptySet();
}
 
// avoid Collections.unmodifiableSet() allocation
@Override
public boolean contains(String fieldName) {
return this.fetched ? this.getValues().containsKey(fieldName) : false;
}
 
private String getQuery() {
return "SELECT * FROM " + this.getTable().getSQLName().quote() + " WHERE " + this.getWhere().getClause();
}
994,6 → 1005,12
return this.getTable().getName() + "[" + this.ID + "]";
}
 
@Override
public String mapToString() {
final String result = this.fullToString(false) + " : ";
return result + (this.values != null ? this.values : (this.isFilled() ? "not in DB" : "not filled"));
}
 
/**
* Renvoie tous les champs de cette ligne, clef comprises. En général on ne veut pas les valeurs
* des clefs, voir getAllValues().
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValues.java
330,6 → 330,10
return this.getGraph().deepCopy(this, false);
}
 
public final SQLRowValues copy(final SQLRowValues graph) {
return this.getGraph().copy(this, graph).get(this);
}
 
/**
* Get a frozen version of this. If not already {@link #isFrozen() frozen}, copy this rowValues
* and all others connected to it and {@link SQLRowValuesCluster#freeze()} the copy. I.e. if the
433,10 → 437,24
}
 
public final SQLRowValues prune(SQLRowValues graph) {
return this.getGraph().prune(this, graph);
return this.prune(graph, true);
}
 
/**
* Prune this graph.
*
* @param graph the rows and fields to keep.
* @param copy <code>true</code> if a pruned copy should be returned, <code>false</code> to
* modify this instance in-place.
* @return a graph no bigger than the passed parameter.
* @see SQLRowValuesCluster#prune(SQLRowValues, SQLRowValues, boolean)
* @see SQLRowValuesCluster#pruneWithoutCopy(SQLRowValues, SQLRowValues, boolean)
*/
public final SQLRowValues prune(SQLRowValues graph, final boolean copy) {
return copy ? this.getGraph().prune(this, graph) : this.getGraph().pruneWithoutCopy(this, graph);
}
 
/**
* Fetch if necessary and store in this the foreign row.
*
* @param fk a foreign key, eg "ID_FAMILLE_2".
469,7 → 487,11
* @throws IllegalArgumentException if this couldn't be grown.
*/
public final SQLRowValues grow(SQLRowValues graph, final boolean checkFields) {
graph.getGraph().grow(graph, this, checkFields);
return this.grow(graph, checkFields, false);
}
 
public final SQLRowValues grow(SQLRowValues graph, final boolean checkFields, final boolean growUndefined) {
graph.getGraph().grow(graph, this, checkFields, growUndefined);
return this;
}
 
768,7 → 790,13
return Collections.unmodifiableSet(this.values.keySet());
}
 
// avoid Collections.unmodifiableSet() allocation
@Override
public boolean contains(String fieldName) {
return this.values.containsKey(fieldName);
}
 
@Override
public final SQLRow asRow() {
if (!this.hasID())
throw new IllegalStateException(this + " has no ID");
1823,7 → 1851,7
} else {
// check that the foreign key is complete
for (final String ff : foreignLink.getCols()) {
if (!this.getFields().contains(ff))
if (!this.contains(ff))
return new Object[] { ff, null };
}
foreignLinks.keySet().removeAll(foreignLink.getCols());
1998,6 → 2026,11
*/
@Override
public String toString() {
return mapToString();
}
 
@Override
public String mapToString() {
String result = this.getClass().getSimpleName() + " on " + this.getTable() + " : {";
result += CollectionUtils.join(this.values.entrySet(), ", ", new ITransformer<Entry<String, ?>, String>() {
public String transformChecked(final Entry<String, ?> e) {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/graph/Path.java
465,4 → 465,15
return this.getLast() == other.getLast();
return thisL >= otherL && this.subPath(thisL - otherL, thisL).equals(other);
}
 
public final Path getCommonPath(final Path other) {
if (other.getFirst() != this.getFirst())
throw new IllegalArgumentException("Not the same starting point");
final int equalsCount = CollectionUtils.equalsFromStart(this.steps, other.steps);
// avoid allocation
if (equalsCount == other.length())
return other;
else
return this.subPath(0, equalsCount);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/users/User.java
28,7 → 28,7
this.name = r.getString("NOM").trim();
this.firstName = r.getString("PRENOM").trim();
this.nickName = r.getString("SURNOM").trim();
if (r.getFields().contains("DISABLED")) {
if (r.contains("DISABLED")) {
this.active = !r.getBoolean("DISABLED");
} else {
this.active = null;
/trunk/OpenConcerto/src/org/openconcerto/sql/users/UserCommonSQLElement.java
93,7 → 93,7
this.familyNameFirst = false;
}
 
public UserCommonSQLElement(DBRoot root, final boolean familyNameFirst) {
public UserCommonSQLElement(final DBRoot root, final boolean familyNameFirst) {
super(root.findTable("USER_COMMON"));
this.familyNameFirst = familyNameFirst;
}
119,7 → 119,7
}
 
@Override
protected synchronized void _initTableSource(SQLTableModelSource res) {
protected synchronized void _initTableSource(final SQLTableModelSource res) {
super._initTableSource(res);
// current user in bold
for (final SQLTableModelColumn col : res.getColumns()) {
126,7 → 126,7
if (col.getValueClass().equals(String.class)) {
col.setRenderer(new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
final JLabel res = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
final boolean isCurrentUser = ITableModel.getLine(table.getModel(), row).getRow().getID() == UserManager.getUserID();
final int targetStyle = isCurrentUser ? Font.BOLD : Font.PLAIN;
154,7 → 154,7
}
 
@Override
protected void _initComboRequest(ComboSQLRequest req) {
protected void _initComboRequest(final ComboSQLRequest req) {
super._initComboRequest(req);
req.setFieldSeparator(" ");
}
189,7 → 189,7
this.accessSocieteElem = t == null ? null : getDirectory().getElement(t);
}
 
protected UserSQLComponent(SQLElement element) {
protected UserSQLComponent(final SQLElement element) {
super(element);
}
 
333,7 → 333,7
}
if (getTable().contains("OUT")) {
c.gridx++;
JCheckBox boxOut = new JCheckBox(getLabelFor("OUT"));
final JCheckBox boxOut = new JCheckBox(getLabelFor("OUT"));
c.gridwidth = 1;
c.weightx = 1;
c.gridwidth = GridBagConstraints.REMAINDER;
342,7 → 342,7
} else {
if (getTable().contains("DISABLED")) {
c.gridx++;
JCheckBox boxDisabled = new JCheckBox(getLabelFor("DISABLED"));
final JCheckBox boxDisabled = new JCheckBox(getLabelFor("DISABLED"));
c.gridwidth = 1;
c.weightx = 1;
c.gridwidth = GridBagConstraints.REMAINDER;
353,11 → 353,11
c.gridy++;
if (getTable().contains("TEL")) {
c.gridx = 0;
JLabel labelTel = new JLabel(getLabelFor("TEL"));
final JLabel labelTel = new JLabel(getLabelFor("TEL"));
c.gridwidth = 1;
c.weightx = 0;
this.add(labelTel, c);
JTextField fieldTel = new JTextField(20);
final JTextField fieldTel = new JTextField(20);
c.gridx++;
c.weightx = 1;
this.add(fieldTel, c);
365,7 → 365,7
}
if (getTable().contains("CALENDAR_USER")) {
c.gridx = 2;
JCheckBox boxCalUser = new JCheckBox(getLabelFor("CALENDAR_USER"));
final JCheckBox boxCalUser = new JCheckBox(getLabelFor("CALENDAR_USER"));
c.weightx = 1;
c.gridwidth = GridBagConstraints.REMAINDER;
this.add(boxCalUser, c);
372,12 → 372,12
this.addView(boxCalUser, "CALENDAR_USER");
}
 
boolean gestionHoraire = false;
final boolean gestionHoraire = false;
if (Configuration.getInstance().getAppName().startsWith("OpenConcerto") && gestionHoraire) {
 
c.gridwidth = 1;
JPanel panelHoraires = new JPanel(new GridBagLayout());
GridBagConstraints cH = new DefaultGridBagConstraints();
final JPanel panelHoraires = new JPanel(new GridBagLayout());
final GridBagConstraints cH = new DefaultGridBagConstraints();
 
createHalfDay(panelHoraires, cH, "Matin :", "MATIN", 8, 12);
createHalfDay(panelHoraires, cH, "Après midi :", "MIDI", 13, 17);
398,8 → 398,8
 
this.add(new JLabelBold("Accés aux sociétés"), c);
c.gridy++;
noCompanyLimitCheckBox = new JCheckBox("ne pas limiter l'accès à certaines sociétés");
this.add(noCompanyLimitCheckBox, c);
this.noCompanyLimitCheckBox = new JCheckBox("ne pas limiter l'accès à certaines sociétés");
this.add(this.noCompanyLimitCheckBox, c);
 
c.gridy++;
c.weighty = 1;
411,22 → 411,22
this.table = new QuickAssignPanel(companyElement, "ID", model);
this.add(this.table, c);
 
noCompanyLimitCheckBox.addItemListener(new ItemListener() {
this.noCompanyLimitCheckBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
table.setEnabled(e.getStateChange() == ItemEvent.DESELECTED);
public void itemStateChanged(final ItemEvent e) {
UserSQLComponent.this.table.setEnabled(e.getStateChange() == ItemEvent.DESELECTED);
}
});
getView("ADMIN").addValueListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
public void propertyChange(final PropertyChangeEvent evt) {
final boolean selected = evt.getNewValue() == Boolean.TRUE;
noCompanyLimitCheckBox.setEnabled(!selected);
UserSQLComponent.this.noCompanyLimitCheckBox.setEnabled(!selected);
if (selected)
noCompanyLimitCheckBox.setSelected(true);
UserSQLComponent.this.noCompanyLimitCheckBox.setSelected(true);
}
});
noCompanyLimitCheckBox.setSelected(true);
this.noCompanyLimitCheckBox.setSelected(true);
}
 
this.addRequiredSQLObject(textLogin, "LOGIN");
443,7 → 443,7
 
this.getPassField().getDocument().addDocumentListener(new SimpleDocumentListener() {
@Override
public void update(DocumentEvent e) {
public void update(final DocumentEvent e) {
updateEncrypted();
fireValidChange();
}
450,7 → 450,7
});
this.getPassFieldConfirm().getDocument().addDocumentListener(new SimpleDocumentListener() {
@Override
public void update(DocumentEvent e) {
public void update(final DocumentEvent e) {
fireValidChange();
}
});
463,7 → 463,7
 
// après midi arrivée 13:30
// __________ départ 17:53
private void createHalfDay(JPanel panelHoraires, GridBagConstraints cH, String label, String field, int startHour, int endHour) {
private void createHalfDay(final JPanel panelHoraires, final GridBagConstraints cH, final String label, final String field, final int startHour, final int endHour) {
panelHoraires.add(new JLabel(label), cH);
cH.gridx++;
createTime(panelHoraires, cH, "arrivée", field + "_A", startHour);
475,7 → 475,7
}
 
// départ 17:53
private void createTime(JPanel panelHoraires, GridBagConstraints cH, String label, String field, int hour) {
private void createTime(final JPanel panelHoraires, final GridBagConstraints cH, final String label, final String field, final int hour) {
panelHoraires.add(new JLabel(label), cH);
cH.gridx++;
 
487,9 → 487,9
}
 
// 17 h or 53 min
private ISpinner createSpinner(JPanel panelHoraires, GridBagConstraints cH, final boolean hour, int value) {
ISpinnerIntegerModel modelHourMA = new ISpinnerIntegerModel(0, hour ? 23 : 59, value);
ISpinner spinHourMA = new ISpinner(modelHourMA);
private ISpinner createSpinner(final JPanel panelHoraires, final GridBagConstraints cH, final boolean hour, final int value) {
final ISpinnerIntegerModel modelHourMA = new ISpinnerIntegerModel(0, hour ? 23 : 59, value);
final ISpinner spinHourMA = new ISpinner(modelHourMA);
panelHoraires.add(spinHourMA.getComp(), cH);
cH.gridx++;
panelHoraires.add(new JLabel(hour ? "h" : "min"), cH);
520,8 → 520,8
// so that this.encryptedPass (which will be updated by updateEncrypted() and thus
// have a bogus value) will be changed to its database value and thus the user can
// update any field without changing the password.
if (table != null) {
table.getModel().clearRows();
if (this.table != null) {
this.table.getModel().clearRows();
}
if (row != null) {
final String bogusPass = "bogusPass!";
530,23 → 530,23
// Allowed companies
if (this.accessSocieteElem != null) {
final SQLTable tableCompanyAccess = this.accessSocieteElem.getTable();
SQLRowValues graph = new SQLRowValues(tableCompanyAccess);
final SQLRowValues graph = new SQLRowValues(tableCompanyAccess);
graph.put("ID", null);
graph.putRowValues("ID_SOCIETE_COMMON").put("NOM", null);
SQLRowValuesListFetcher f = new SQLRowValuesListFetcher(graph);
final SQLRowValuesListFetcher f = new SQLRowValuesListFetcher(graph);
f.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(SQLSelect input) {
public SQLSelect transformChecked(final SQLSelect input) {
input.setWhere(new Where(tableCompanyAccess.getField("ID_USER_COMMON"), "=", row.getID()));
return input;
}
});
List<SQLRowValues> companies = f.fetch();
final List<SQLRowValues> companies = f.fetch();
 
for (SQLRowValues r : companies) {
table.getModel().addRow(r.getForeign("ID_SOCIETE_COMMON").asRowValues());
for (final SQLRowValues r : companies) {
this.table.getModel().addRow(r.getForeign("ID_SOCIETE_COMMON").asRowValues());
}
noCompanyLimitCheckBox.setSelected(companies.isEmpty());
this.noCompanyLimitCheckBox.setSelected(companies.isEmpty());
}
}
super.select(row);
561,17 → 561,17
return id;
}
 
private void insertCompanyAccessForUser(int id) {
private void insertCompanyAccessForUser(final int id) {
final SQLTable tableCompanyAccess = this.getDirectory().getElement("ACCES_SOCIETE").getTable();
int stop = table.getModel().getRowCount();
final int stop = this.table.getModel().getRowCount();
for (int i = 0; i < stop; i++) {
SQLRowValues rCompany = table.getModel().getRowValuesAt(i);
SQLRowValues rAccess = new SQLRowValues(tableCompanyAccess);
final SQLRowValues rCompany = this.table.getModel().getRowValuesAt(i);
final SQLRowValues rAccess = new SQLRowValues(tableCompanyAccess);
rAccess.put("ID_USER_COMMON", id);
rAccess.put("ID_SOCIETE_COMMON", rCompany.getID());
try {
rAccess.commit();
} catch (SQLException e) {
} catch (final SQLException e) {
ExceptionHandler.handle("Unable to store company access", e);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/changer/convert/MergeRows.java
107,7 → 107,7
}
 
protected boolean isEqualValue(final SQLRowAccessor r1, final SQLRowAccessor r2, final String f, final boolean nonEmpty) {
if (!r1.getFields().contains(f) || !r2.getFields().contains(f))
if (!r1.contains(f) || !r2.contains(f))
throw new IllegalStateException("Missing " + f);
final Object normalized1 = normalize(f, r1.getObject(f));
final Object normalized2 = normalize(f, r2.getObject(f));
/trunk/OpenConcerto/src/org/openconcerto/sql/view/EditFrame.java
14,6 → 14,7
package org.openconcerto.sql.view;
 
import static org.openconcerto.sql.TM.getTM;
 
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
197,8 → 198,8
}
 
/**
* Redimensionne la frame pour qu'elle soit de taille maximum sans déborder de l'écran. <img
* src="doc-files/resizeFrame.png"/>
* Redimensionne la frame pour qu'elle soit de taille maximum sans déborder de l'écran.
* <img src="doc-files/resizeFrame.png"/>
*/
protected void viewResized() {
if (!this.frameResize) {
274,4 → 275,9
public boolean isDocTransversable() {
return true;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " " + this.getTitle() + " : " + super.toString();
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/save.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/view/IListPanel.java
31,7 → 31,10
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
import org.openconcerto.sql.view.search.SearchListComponent;
import org.openconcerto.ui.ContinuousButtonModel;
import org.openconcerto.ui.FrameUtil;
38,6 → 41,7
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.ui.component.JRadioButtons.JStringRadioButtons;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Tuple2.List2;
57,9 → 61,6
import java.awt.event.ActionListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
73,6 → 74,7
import java.util.Set;
import java.util.prefs.Preferences;
 
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
119,6 → 121,36
return new File(structFile, c.getSimpleName() + File.separator + IListFrame.getConfigFileName(code));
}
 
public static enum FrameMode {
NO_FRAME, READ_ONLY_FRAME, READ_WRITE_FRAME;
}
 
public static final String TWO_X_SUFFIX = "_2x";
private static final String FLECHE_HAUT_PNG = "fleche_haut.png";
private static final String FLECHE_BAS_PNG = "fleche_bas.png";
private static final Icon UP_ARROW = getIcon(FLECHE_HAUT_PNG, false);
private static final Icon UP_ARROW_2X = getIcon(FLECHE_HAUT_PNG, true);
private static final Icon DOWN_ARROW = getIcon(FLECHE_BAS_PNG, false);
private static final Icon DOWN_ARROW_2X = getIcon(FLECHE_BAS_PNG, true);
 
static final String getResourceName(final String rsrcName, final boolean twoX) {
if (!twoX)
return rsrcName;
final String extension = FileUtils.getExtension(rsrcName, true);
if (extension == null)
return rsrcName + TWO_X_SUFFIX;
else
return FileUtils.removeSuffix(rsrcName, extension) + TWO_X_SUFFIX + extension;
}
 
static final Icon getIcon(final String fileName, final boolean twoX) {
return getIcon(IListPanel.class, fileName, twoX);
}
 
public static final Icon getIcon(final Class<?> clazz, final String fileName, final boolean twoX) {
return new ImageIcon(clazz.getResource(getResourceName(fileName, twoX)));
}
 
private final IListe liste;
 
protected final SQLElement element;
135,9 → 167,6
private JButton buttonPlus;
private JButton buttonMoins;
protected final JPanel searchPanel = new JPanel(new GridBagLayout());
private static final Icon UP_ARROW = new ImageIcon(IListPanel.class.getResource("fleche_haut.png"));
private static final Icon DOWN_ARROW = new ImageIcon(IListPanel.class.getResource("fleche_bas.png"));
 
private static final JButton createBtn(Icon i) {
final JButton res = new JButton(i);
res.setMargin(new Insets(1, 1, 1, 1));
149,9 → 178,11
return res;
}
 
private final RowAction displayRowAction;
protected EditFrame createFrame;
private boolean selectRowOnAdd = true;
private boolean showReadOnlyFrameOnDoubleClick = true;
// NO_FRAME since at creation the action isn't added to our IListe
private FrameMode showFrameOnDoubleClick = FrameMode.NO_FRAME;
private boolean deaf = Boolean.getBoolean("org.openconcerto.sql.listPanel.deafEditPanel");
 
protected SearchListComponent searchComponent;
209,6 → 240,32
}
});
 
this.displayRowAction = new PredicateRowAction(new AbstractAction(TM.tr("display")) {
 
private EditFrame listeningFrame = null;
 
private final EditFrame createFrame(final boolean listening) {
final EditFrame res = new EditFrame(getElement(), IListPanel.this.showFrameOnDoubleClick == FrameMode.READ_ONLY_FRAME ? EditPanel.READONLY : EditPanel.MODIFICATION);
if (listening)
getListe().addIListener(res);
res.selectionId(getListe().getSelectedId());
return res;
}
 
@Override
public void actionPerformed(ActionEvent e) {
final EditFrame frame;
if ((e.getModifiers() & ActionEvent.ALT_MASK) != 0) {
if (this.listeningFrame == null)
this.listeningFrame = createFrame(true);
frame = this.listeningFrame;
} else {
frame = createFrame(false);
}
FrameUtil.show(frame);
}
}, false).setPredicate(IListeEvent.getSingleSelectionPredicate());
 
this.init();
}
 
235,34 → 292,16
IListPanel.this.searchComponent.reset((ITableModel) evt.getNewValue());
}
});
this.liste.getJTable().addMouseListener(new MouseAdapter() {
// don't need to display in a separate frame, if it's already displayed in this panel
final FrameMode m;
if (this.modifyIsImmediate())
m = FrameMode.NO_FRAME;
else if (Boolean.getBoolean("org.openconcerto.sql.listPanel.rwOnDoubleClick"))
m = FrameMode.READ_WRITE_FRAME;
else
m = FrameMode.READ_ONLY_FRAME;
this.setShowFrameOnDoubleClickMode(m);
 
private EditFrame listeningFrame = null;
 
private final EditFrame createFrame(final boolean listening) {
Boolean rw = Boolean.getBoolean("org.openconcerto.sql.listPanel.rwOnDoubleClick");
final EditFrame res = new EditFrame(getElement(), !rw ? EditPanel.READONLY : EditPanel.MODIFICATION);
if (listening)
getListe().addIListener(res);
res.selectionId(getListe().getSelectedId());
return res;
}
 
@Override
public void mouseClicked(MouseEvent e) {
if (IListPanel.this.showReadOnlyFrameOnDoubleClick && e.getClickCount() == 2) {
final EditFrame frame;
if ((e.getModifiersEx() & InputEvent.ALT_DOWN_MASK) != 0) {
if (this.listeningFrame == null)
this.listeningFrame = createFrame(true);
frame = this.listeningFrame;
} else {
frame = createFrame(false);
}
FrameUtil.show(frame);
}
}
});
// selectID() alone won't init us if NONEXISTANT_ID is already the selected id
this.btnMngr.updateBtns();
this.getListe().selectID(SQLRow.NONEXISTANT_ID);
303,15 → 342,19
}
 
protected void createUI() {
// int sca
final boolean twoX = this.getFont().getSize() > 16;
final int buttonSize = twoX ? 36 : 20;
 
this.setOpaque(false);
this.buttonActualiser = new JButton(new ImageIcon(IListPanel.class.getResource("reload.png")));
this.buttonActualiser = new JButton(getIcon("reload.png", twoX));
this.buttonActualiser.setBorderPainted(false);
this.buttonActualiser.setFocusPainted(false);
this.buttonActualiser.setOpaque(false);
this.buttonActualiser.setContentAreaFilled(false);
this.buttonActualiser.setMinimumSize(new Dimension(20, 20));
this.buttonActualiser.setPreferredSize(new Dimension(20, 20));
this.buttonActualiser.setMaximumSize(new Dimension(20, 20));
this.buttonActualiser.setMinimumSize(new Dimension(buttonSize, buttonSize));
this.buttonActualiser.setPreferredSize(new Dimension(buttonSize, buttonSize));
this.buttonActualiser.setMaximumSize(new Dimension(buttonSize, buttonSize));
this.searchComponent = new SearchListComponent(this.liste.getModel());
this.searchComponent.setFormats(this.liste.getSearchFormats());
 
329,17 → 372,18
this.btnMngr.addBtn(this.buttonClone, "noRightToClone", TableAllRights.ADD_ROW_TABLE, true, false);
this.btnMngr.setOKToolTip(this.buttonClone, TM.tr("listPanel.cloneToolTip"));
 
this.saveBtn = new JButton(new ImageIcon(IListPanel.class.getResource("save.png")));
this.saveBtn = new JButton(getIcon("save.png", twoX));
this.saveBtn.setFocusPainted(false);
this.saveBtn.setOpaque(false);
this.saveBtn.setContentAreaFilled(false);
this.saveBtn.setBorderPainted(false);
this.saveBtn.setMinimumSize(new Dimension(20, 20));
this.saveBtn.setPreferredSize(new Dimension(20, 20));
this.saveBtn.setMaximumSize(new Dimension(20, 20));
this.buttonMoins = createBtn(UP_ARROW);
this.buttonPlus = createBtn(DOWN_ARROW);
this.saveBtn.setMinimumSize(new Dimension(buttonSize, buttonSize));
this.saveBtn.setPreferredSize(new Dimension(buttonSize, buttonSize));
this.saveBtn.setMaximumSize(new Dimension(buttonSize, buttonSize));
 
this.buttonMoins = createBtn(twoX ? UP_ARROW_2X : UP_ARROW);
this.buttonPlus = createBtn(twoX ? DOWN_ARROW_2X : DOWN_ARROW);
 
// needSelection = false since we handle it with the transformer
this.btnMngr.addBtn(this.buttonMoins, "noRightToReorder", TableAllRights.MODIFY_ROW_TABLE, false);
this.btnMngr.addBtn(this.buttonPlus, "noRightToReorder", TableAllRights.MODIFY_ROW_TABLE, false);
346,7 → 390,7
final ITransformer<JButton, String> transf = new ITransformer<JButton, String>() {
@Override
public String transformChecked(JButton input) {
final boolean ok = getListe().hasSelection() && !getListe().isSorted();
final boolean ok = getListe().hasSelection() && !getListe().isSorted() && getListe().getSource().getReq().isTableOrder();
// keep them enabled when armed otherwise they will be disabled when used
// since they refresh the list which in turn does a clearSelection()
return input.getModel().isArmed() || ok ? null : TM.tr("listPanel.noSelectionOrSort");
792,10 → 836,21
this.getListe().getJTable().setDragEnabled(b);
}
 
@Deprecated
public void setShowReadOnlyFrameOnDoubleClick(boolean showReadOnlyFrameOnDoubleClick) {
this.showReadOnlyFrameOnDoubleClick = showReadOnlyFrameOnDoubleClick;
this.setShowFrameOnDoubleClickMode(showReadOnlyFrameOnDoubleClick ? FrameMode.READ_ONLY_FRAME : FrameMode.NO_FRAME);
}
 
public void setShowFrameOnDoubleClickMode(FrameMode m) {
if (this.showFrameOnDoubleClick != m) {
this.showFrameOnDoubleClick = m;
if (this.showFrameOnDoubleClick != FrameMode.NO_FRAME)
this.liste.setDefaultRowAction(this.displayRowAction);
else
this.liste.removeIListeAction(this.displayRowAction);
}
}
 
public void setAddVisible(boolean b) {
this.buttonAjouter.setVisible(b);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/reload.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/view/IListButton.java
11,12 → 11,6
* When distributing the software, include this License Header Notice in each file.
*/
/*
* Created on 17 janv. 2005
*
* TODO To change the template for this generated file go to Window - Preferences - Java - Code
* Style - Code Templates
*/
package org.openconcerto.sql.view;
 
import java.awt.Dimension;
24,17 → 18,10
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
 
/**
* @author ilm
*
* TODO To change the template for this generated type comment go to Window - Preferences -
* Java - Code Style - Code Templates
*/
public class IListButton extends JButton {
private static ImageIcon icon = null;
public final class IListButton extends JButton {
private static Icon icon = null;
 
/**
*
79,10 → 66,11
 
private final void init() {
if (icon == null) {
icon = new ImageIcon(getClass().getResource("liste.png"));
icon = IListPanel.getIcon("liste.png", getFont().getSize() > 16);
}
setIcon(icon);
setPreferredSize(new Dimension(24, 16));
setMinimumSize(new Dimension(icon.getIconWidth() + 8, icon.getIconHeight()));
setPreferredSize(new Dimension(icon.getIconWidth() + 8, icon.getIconHeight()));
initButton(this);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/fleche_haut_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/view/fleche_haut_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/view/fleche_bas_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/view/fleche_bas_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/ListSQLLine.java
22,6 → 22,7
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.view.list.search.SearchQueue;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.NumberUtils;
 
import java.util.ArrayList;
import java.util.Collection;
127,6 → 128,30
return this.src.compare(this, o);
}
 
static final int compareLikeRequest(final ListSQLLine l1, final ListSQLLine l2) {
if (l1 == l2)
return 0;
if (l1.getState() != l2.getState())
throw new IllegalArgumentException("Different states");
 
final Number order1, order2;
final SQLTableModelLinesSource src = l1.getSrc();
// avoid comparing in the middle of a reordering
synchronized (src.getModel().getUpdateQ().getFullList()) {
order1 = l1.getOrder();
order2 = l2.getOrder();
}
if (order1 != null) {
if (order2 == null)
throw new IllegalStateException("Order mismatch :\n" + order1 + " for " + l1 + " not coherent with\n" + order2 + " for " + l2);
return NumberUtils.compare(order1, order2);
} else {
if (order2 != null)
throw new IllegalStateException("Order mismatch :\n" + order1 + " for " + l1 + " not coherent with\n" + order2 + " for " + l2);
return l1.getState().getReq().order(l1.getRow(), l2.getRow());
}
}
 
public int getID() {
return this.id;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTableModelLinesSource.java
24,6 → 24,7
import java.beans.PropertyChangeListener;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Future;
 
31,6 → 32,7
public abstract class SQLTableModelLinesSource {
 
private final ITableModel model;
private final PropertyChangeListener reqListener;
private final List<PropertyChangeListener> listeners;
private IPredicate<SQLRowValues> filter;
 
41,9 → 43,20
 
protected SQLTableModelLinesSource(final ITableModel model) {
this.model = model;
this.reqListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
fireChanged(evt);
}
};
}
 
void live() {
this.getParent().getReq().addWhereListener(this.reqListener);
}
 
void die() {
this.getParent().getReq().rmWhereListener(this.reqListener);
}
 
public final ITableModel getModel() {
67,8 → 80,26
*/
public abstract Value<ListSQLLine> get(final int id);
 
public abstract int compare(ListSQLLine l1, ListSQLLine l2);
/**
* Implementations should only use state of the parameters, so that this method can be
* thread-safe (it is called both by the {@link UpdateQueue} and by the EDT in
* {@link ITableModel}). This implementation order lines like the source {@link ListSQLRequest
* request}.
*
* @param l1 the first line.
* @param l2 the second line.
* @return a negative integer, zero, or a positive integer as this object is less than, equal
* to, or greater than the specified object.
* @see Comparator#compare(Object, Object)
*/
public int compare(ListSQLLine l1, ListSQLLine l2) {
return ListSQLLine.compareLikeRequest(l1, l2);
}
 
public boolean isCellEditable(ListSQLLine line, int colIndex, SQLTableModelColumn col) {
return true;
}
 
public abstract Future<?> moveBy(final List<? extends SQLRowAccessor> rows, final int inc);
 
// take IDs :
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTableModelLinesSourceOffline.java
24,15 → 24,14
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.SetMap;
import org.openconcerto.utils.Value;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.ITransformerExn;
 
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
45,7 → 44,6
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicReference;
 
import net.jcip.annotations.NotThreadSafe;
 
59,7 → 57,7
 
// row container with equals() using reference equality
@NotThreadSafe
static private final class Row {
static public final class Row {
private final Integer id;
private SQLRowValues vals;
 
77,7 → 75,7
return this.vals;
}
 
public final void setRow(SQLRowValues newVals) {
final void setRow(SQLRowValues newVals) {
if (!newVals.isFrozen())
throw new IllegalArgumentException("Not frozen : " + newVals);
this.vals = newVals;
138,10 → 136,15
return this.parent;
}
 
private synchronized boolean checkUpdateThread() {
private boolean isUpdateThread() {
return this.getModel().getUpdateQ().currentlyInQueue();
}
 
private void checkUpdateThread() {
if (!this.isUpdateThread())
throw new IllegalStateException("Not in the update thread");
}
 
private final Row getRow(Integer id) {
return this.getRow(id, false);
}
157,6 → 160,16
return res;
}
 
public final Row getRowNow(Integer id, final boolean required) {
checkUpdateThread();
return this.getRow(id, required);
}
 
public final List<Row> getRowsNow() {
checkUpdateThread();
return Collections.unmodifiableList(this.lines);
}
 
protected final int getSize() {
return this.lines.size();
}
181,7 → 194,7
}
 
private final boolean setDBOrder(final boolean dbOrder) {
assert checkUpdateThread();
assert isUpdateThread();
if (this.dbOrder != dbOrder) {
this.dbOrder = dbOrder;
return true;
206,38 → 219,6
return res;
}
 
/**
* Compare 2 lines. Only use state of the parameters, so this method is thread-safe.
*
* @param l1 the first line.
* @param l2 the second line.
* @return a negative integer, zero, or a positive integer as this object is less than, equal
* to, or greater than the specified object.
* @see Comparator#compare(Object, Object)
*/
@Override
public int compare(ListSQLLine l1, ListSQLLine l2) {
if (l1 == l2)
return 0;
 
final Number order1, order2;
final SQLTableModelLinesSource src = l1.getSrc();
// avoid comparing in the middle of a reordering
synchronized (src.getModel().getUpdateQ().getFullList()) {
order1 = l1.getOrder();
order2 = l2.getOrder();
}
if (order1 != null) {
if (order2 == null)
throw new IllegalStateException("Order mismatch :\n" + order1 + " for " + l1 + " not coherent with\n" + order2 + " for " + l2);
return NumberUtils.compare(order1, order2);
} else {
if (order2 != null)
throw new IllegalStateException("Order mismatch :\n" + order1 + " for " + l1 + " not coherent with\n" + order2 + " for " + l2);
return OrderComparator.INSTANCE.compare(l1.getRow(), l2.getRow());
}
}
 
protected final List<SQLRowValues> fetch() {
return this.getUpdateQueueReq().getValues();
}
251,7 → 232,7
*/
@Override
public List<ListSQLLine> getAll() {
assert checkUpdateThread();
assert isUpdateThread();
final List<SQLRowValues> dbRows = this.fetch();
 
if (this.lines.isEmpty()) {
312,32 → 293,57
*/
@Override
public Value<ListSQLLine> get(final int id) {
assert checkUpdateThread();
assert isUpdateThread();
return updateRow(id, this.getUpdateQueueReq().getValues(id));
}
 
// *** Modify virtual rows ***
 
private final <T> Future<T> execInUpdateQ(final OfflineCallable<T> call) {
return this.getModel().getUpdateQ().execute(new FutureTask<T>(call));
}
 
public final Future<Number> add(final SQLRowValues vals) {
// since SQLRowValues isn't thread-safe, use AtomicReference to safely pass it to another
// thread
final AtomicReference<SQLRowValues> copy = new AtomicReference<SQLRowValues>(vals.deepCopy());
return this.getModel().getUpdateQ().execute(new FutureTask<Number>(new OfflineCallable<Number>() {
// copy to avoid back-door and allow grow()
final SQLRowValues copy = vals.deepCopy();
return this.execInUpdateQ(new OfflineCallable<Number>() {
@Override
public Number call() throws Exception {
return _add(copy.get(), true, true).getID();
return addNow(copy, true);
}
}));
});
}
 
/**
* Add a new row. This method can only be called from the update thread, e.g. from
* {@link #useRow(Number, ITransformerExn)}.
*
* @param vals the values, its {@link SQLRowValues#getID() ID} will be ignored.
* @return the ID for the new row.
* @see #add(SQLRowValues)
*/
public final Integer addNow(final SQLRowValues vals) {
return addNow(vals, false);
}
 
private final Integer addNow(final SQLRowValues vals, final boolean safe) {
if (!safe)
checkUpdateThread();
final SQLRowValues copy = safe ? vals : vals.deepCopy();
// otherwise could replace an existing row (use replaceRow() for that)
// existing DB rows can only be added by fetch()
copy.clearPrimaryKeys();
return this._add(copy, true, true).getID();
}
 
protected Row _add(final SQLRowValues vals, final boolean grow, final boolean fireAdd) {
assert checkUpdateThread();
assert isUpdateThread();
// make sure every needed path is there
if (grow)
vals.grow(getUpdateQueueReq().getGraphToFetch(), false);
// ATTN only works because vals was just fetched or just copied
vals.getGraph().freeze();
final boolean fromDB = vals.hasID();
final boolean fromDB = vals.hasID() && vals.getID() >= SQLRow.MIN_VALID_ID;
final List<Integer> order;
final Row r;
r = new Row(fromDB ? vals.getID() : this.freeID--, vals);
366,16 → 372,21
}
 
public final Future<SQLRowValues> remove(final Number id) {
return this.getModel().getUpdateQ().execute(new FutureTask<SQLRowValues>(new OfflineCallable<SQLRowValues>() {
return this.execInUpdateQ(new OfflineCallable<SQLRowValues>() {
@Override
public SQLRowValues call() throws Exception {
final Row r = getRow(id.intValue());
return r == null ? null : rm(r).vals;
return rm(r);
}
}));
});
}
 
private Row rm(final Row r) {
public final SQLRowValues removeNow(final Row r) {
this.checkUpdateThread();
return rm(r);
}
 
private SQLRowValues rm(final Row r) {
if (r != null) {
this._rm(r);
// add to a list of id to archive if it's in the DB
382,12 → 393,14
if (r.vals.hasID())
this.deleted.add(r.vals.getIDNumber());
this.getModel().getUpdateQ().replaceLine(r.getID().intValue(), null);
return r.vals;
} else {
return null;
}
return r;
}
 
private void _rm(final Row l) {
assert checkUpdateThread();
assert isUpdateThread();
if (l != null) {
this.lines.remove(l);
this.id2line.remove(l.id);
400,13 → 413,10
checkCanModif(path);
if (!vals.isFrozen())
throw new IllegalArgumentException("Not frozen");
// since SQLRowValues isn't thread-safe, use AtomicReference to safely pass it to another
// thread
final AtomicReference<SQLRowValues> copy = new AtomicReference<SQLRowValues>(vals);
this.getModel().getUpdateQ().put(new OfflineRunnable() {
this.execInUpdateQ(new OfflineRunnable() {
@Override
public void run() {
getModel().getUpdateQ().updateLine(l, path, copy.get().getID(), copy.get());
getModel().getUpdateQ().updateLine(l, path, vals.getID(), vals);
recordOriginal(l);
}
});
447,22 → 457,26
}, false);
}
 
public Future<?> updateRow(final Number id, final IClosure<SQLRowValues> valsClosure) {
public Future<SQLRowValues> updateRow(final Number id, final IClosure<SQLRowValues> valsClosure) {
return this.updateRow(id, valsClosure, true);
}
 
private Future<?> updateRow(final Number id, final IClosure<SQLRowValues> valsClosure, final boolean mdCanChange) {
return this.getModel().getUpdateQ().put(new OfflineRunnable() {
private Future<SQLRowValues> updateRow(final Number id, final IClosure<SQLRowValues> valsClosure, final boolean mdCanChange) {
return this.execInUpdateQ(new OfflineCallable<SQLRowValues>() {
@Override
public void run() {
_updateRow(id, valsClosure, mdCanChange);
public SQLRowValues call() throws Exception {
return _updateRow(getRow(id.intValue(), true), valsClosure, mdCanChange).vals;
}
});
}
 
protected Row _updateRow(final Number id, final IClosure<SQLRowValues> valsClosure, final boolean mdCanChange) {
assert checkUpdateThread();
final Row r = getRow(id.intValue(), true);
public final SQLRowValues updateRowNow(final Row r, final IClosure<SQLRowValues> valsClosure) {
checkUpdateThread();
return _updateRow(r, valsClosure, true).vals;
}
 
protected Row _updateRow(final Row r, final IClosure<SQLRowValues> valsClosure, final boolean mdCanChange) {
assert isUpdateThread();
final SQLRowValues newVals = r.getRow().deepCopy();
valsClosure.executeChecked(newVals);
// make sure PK and metadata don't change
500,6 → 514,32
r.setRow(newVals);
}
 
public final <T> Future<T> useRow(final Number id, final ITransformerExn<SQLRowValues, T, ?> valsTransf) {
return this.execInUpdateQ(new OfflineCallable<T>() {
@Override
public T call() throws Exception {
final SQLRowValues vals = getRow(id.intValue(), true).vals;
assert vals.isFrozen();
return valsTransf.transformChecked(vals);
}
});
}
 
/**
* Execute the passed transformer in the update queue, allow to call any method ending in "Now".
*
* @param rowsTransf what to do.
* @return a future with the value returned by <code>rowsTransf</code>.
*/
public final <T> Future<T> useRows(final ITransformerExn<SQLTableModelLinesSourceOffline, T, ?> rowsTransf) {
return this.execInUpdateQ(new OfflineCallable<T>() {
@Override
public T call() throws Exception {
return rowsTransf.transformChecked(SQLTableModelLinesSourceOffline.this);
}
});
}
 
// *** Order ***
 
@Override
510,7 → 550,7
// since SQLRowValues isn't thread-safe, use Concurrent Collection to safely pass it to
// another thread
final List<SQLRowAccessor> copy = new CopyOnWriteArrayList<SQLRowAccessor>(list);
return this.getModel().getUpdateQ().put(new OfflineRunnable() {
return this.execInUpdateQ(new OfflineRunnable() {
@Override
public void run() {
_moveBy(copy, inc);
519,7 → 559,7
}
 
protected void _moveBy(final List<? extends SQLRowAccessor> list, final int inc) {
assert checkUpdateThread();
assert isUpdateThread();
final int count = this.lines.size();
final boolean after = inc > 0;
 
556,7 → 596,7
 
@Override
public Future<?> moveTo(final List<? extends Number> ids, final int index) {
return this.getModel().getUpdateQ().put(new OfflineRunnable() {
return this.execInUpdateQ(new OfflineRunnable() {
@Override
public void run() {
_moveTo(ids, index);
565,7 → 605,7
}
 
protected void _moveTo(final List<?> ids, final int index) {
assert checkUpdateThread();
assert isUpdateThread();
final int count = this.lines.size();
 
final List<Integer> order;
607,6 → 647,21
 
// *** Roll back or Commit ***
 
public final Future<Boolean> hasModifications() {
return this.execInUpdateQ(new OfflineCallable<Boolean>() {
@Override
public Boolean call() throws Exception {
return hasModificationsNow();
}
});
}
 
public final boolean hasModificationsNow() {
checkUpdateThread();
// ATTN this.dbOrder doesn't check just for order but also for added rows
return !this.dbVals.isEmpty() || !this.deleted.isEmpty() || !this.dbOrder;
}
 
/**
* Lose any changes and refetch from the database.
*
613,7 → 668,7
* @return the future.
*/
public final Future<?> reset() {
return this.getModel().getUpdateQ().put(new OfflineRunnable() {
return this.execInUpdateQ(new OfflineRunnable() {
@Override
public void run() {
_reset();
622,7 → 677,7
}
 
protected void _reset() {
assert checkUpdateThread();
assert isUpdateThread();
 
this.lines.clear();
this.id2line.clear();
641,17 → 696,22
* @return the future.
*/
public final Future<?> commit() {
return this.getModel().getUpdateQ().execute(new FutureTask<Object>(new OfflineCallable<Object>() {
return this.execInUpdateQ(new OfflineCallable<Object>() {
@Override
public Object call() throws Exception {
_commit();
return null;
}
}));
});
}
 
public final void commitNow() throws SQLException {
checkUpdateThread();
this._commit();
}
 
protected final void _commit() throws SQLException {
assert checkUpdateThread();
assert isUpdateThread();
 
// don't listen to every commit and then to re-order, just updateAll() at the end
this.getModel().getUpdateQ().rmTableListener();
700,6 → 760,7
}
this.dbVals.clear();
 
if (getParent().getPrimaryTable().isOrdered()) {
final List<SQLRow> wantedOrder = new ArrayList<SQLRow>(newRows.values());
final List<SQLRow> dbOrder = new ArrayList<SQLRow>(newRows.values());
Collections.sort(dbOrder, OrderComparator.INSTANCE);
708,3 → 769,4
}
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListeAction.java
230,6 → 230,7
}
 
final JMenuItem getRootMenuItem(final Action defaultAction) {
// Cannot compare actions since menu items are not required to have an action
String actionCommand = (String) defaultAction.getValue(Action.ACTION_COMMAND_KEY);
if (actionCommand == null)
actionCommand = (String) defaultAction.getValue(Action.NAME);
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTable.java
474,4 → 474,9
}
this.sqlName = sqlName;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " of " + this.model.getSQLElement() + " : " + super.toString();
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTextComboTableCellEditor.java
132,7 → 132,7
this.comboBox.addModelListener("wantedID", new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent evt) {
SQLTextComboTableCellEditor.this.val = SQLTextComboTableCellEditor.this.comboBox.getWantedID();
SQLTextComboTableCellEditor.this.val = comboBox.getWantedID();
}
});
// Filtre sur une valeur specifique
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowAction.java
173,7 → 173,7
 
@Override
public Action getDefaultAction(IListeEvent evt) {
return null;
return this.enabledFor(evt) ? this.getAction() : null;
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTableModelLinesSourceOnline.java
17,14 → 17,10
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.utils.SleepingQueue.LethalFutureTask;
import org.openconcerto.utils.SleepingQueue.RunningState;
import org.openconcerto.utils.Value;
 
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
41,19 → 37,11
public class SQLTableModelLinesSourceOnline extends SQLTableModelLinesSource {
 
private final SQLTableModelSourceOnline parent;
private final PropertyChangeListener listener;
private MoveQueue moveQ;
 
public SQLTableModelLinesSourceOnline(SQLTableModelSourceOnline parent, final ITableModel model) {
super(model);
this.parent = parent;
this.listener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
fireChanged(evt);
}
};
this.getParent().getReq().addWhereListener(this.listener);
this.moveQ = null;
}
 
68,8 → 56,6
 
@Override
protected void die() {
this.getParent().getReq().rmWhereListener(this.listener);
 
if (this.moveQ != null) {
final RunningState threadState = this.moveQ.getRunningState();
if (threadState == RunningState.RUNNING) {
105,16 → 91,7
return Value.getSome(createLine(this.getUpdateQueueReq().getValues(id)));
}
 
private BigDecimal getOrder(SQLRowAccessor r) {
return (BigDecimal) r.getObject(r.getTable().getOrderField().getName());
}
 
@Override
public int compare(ListSQLLine l1, ListSQLLine l2) {
return getOrder(l1.getRow()).compareTo(getOrder(l2.getRow()));
}
 
@Override
public Future<?> moveBy(List<? extends SQLRowAccessor> rows, int inc) {
return this.getMoveQ().move(rows, inc);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/ITableModel.java
104,11 → 104,19
ITableModel.defaultCellsEditable = defaultEditable;
}
 
public static final boolean isDefaultCellsEditable() {
return ITableModel.defaultCellsEditable;
}
 
public static void setDefaultOrderEditable(boolean defaultEditable) {
assert SwingUtilities.isEventDispatchThread();
ITableModel.defaultOrderEditable = defaultEditable;
}
 
public static final boolean isDefaultOrderEditable() {
return ITableModel.defaultOrderEditable;
}
 
/**
* Return the line of a JTable at the passed index, handling {@link TableSorter}.
*
171,8 → 179,8
this.updating = false;
this.filledOnce = false;
 
this.setCellsEditable(defaultCellsEditable);
this.setOrderEditable(defaultOrderEditable);
this.setCellsEditable(isDefaultCellsEditable());
this.setOrderEditable(isDefaultOrderEditable());
this.debug = false;
 
// don't use CopyUtils.copy() since this prevent the use of anonymous inner class
445,13 → 453,12
this.setOrderEditable(b);
}
 
public final boolean isEditable() {
return this.areCellsEditable() || this.isOrderEditable();
}
 
public final void setCellsEditable(boolean b) {
if (this.cellsEditable != b) {
this.cellsEditable = b;
this.supp.firePropertyChange("cellsEditable", !this.cellsEditable, this.cellsEditable);
}
}
 
public final boolean areCellsEditable() {
return this.cellsEditable;
458,8 → 465,11
}
 
public final void setOrderEditable(boolean b) {
if (this.orderEditable != b) {
this.orderEditable = b;
this.supp.firePropertyChange("orderEditable", !this.orderEditable, this.orderEditable);
}
}
 
public final boolean isOrderEditable() {
return this.orderEditable;
471,11 → 481,14
return false;
final SQLTableModelColumn col = this.getReq().getColumn(columnIndex);
// hasRight is expensive so put it last
return col.isEditable() && !isReadOnly(rowIndex) && hasRight(col);
return col.isEditable() && !isReadOnly(rowIndex, columnIndex, col) && hasRight(col);
}
 
private boolean isReadOnly(int rowIndex) {
final SQLRowValues r = getRow(rowIndex).getRow();
private boolean isReadOnly(final int rowIndex, final int columnIndex, final SQLTableModelColumn col) {
final ListSQLLine line = getRow(rowIndex);
if (!line.getSrc().isCellEditable(line, columnIndex, col))
return true;
final SQLRowValues r = line.getRow();
return r.getTable().contains(SQLComponent.READ_ONLY_FIELD) && SQLComponent.isReadOnly(r);
}
 
578,7 → 591,7
// *** move
 
protected final boolean canOrder() {
return this.isOrderEditable() && TableAllRights.hasRight(UserRightsManager.getCurrentUserRights(), TableAllRights.MODIFY_ROW_TABLE, getTable());
return this.isOrderEditable() && this.getReq().getReq().isTableOrder() && TableAllRights.hasRight(UserRightsManager.getCurrentUserRights(), TableAllRights.MODIFY_ROW_TABLE, getTable());
}
 
private final void handleCannotOrder(final boolean ignoreForbidden) {
874,6 → 887,7
throw new IllegalStateException("dead tableModel: " + this);
if (state == RunningState.NEW) {
print("starting");
this.getLinesSource().live();
this.updateQ.start();
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java
310,6 → 310,9
 
private int retainCount = 0;
 
private boolean cellModificationAllowed = ITableModel.isDefaultCellsEditable();
private boolean orderModificationAllowed = ITableModel.isDefaultOrderEditable();
 
public IListe(final SQLTableModelSource req) {
this(req, null);
}
445,7 → 448,7
// Better look
this.jTable.setShowHorizontalLines(false);
this.jTable.setGridColor(new Color(230, 230, 230));
this.jTable.setRowHeight(this.jTable.getRowHeight() + 4);
this.jTable.setRowHeight(FontUtils.getPreferredRowHeight(this.jTable));
 
this.popup = new JPopupMenu();
TablePopupMouseListener.add(this.jTable, new ITransformer<MouseEvent, JPopupMenu>() {
548,11 → 551,12
// donc on ne peut faire aucune action pendant les maj
 
this.btnPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
this.addModelListener(new PropertyChangeListener() {
this.addListenerOnModel(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// let the header buttons know that the rows have changed
if ("updating".equals(evt.getPropertyName()) && Boolean.FALSE.equals(evt.getNewValue()))
final boolean doneUpdating = "updating".equals(evt.getPropertyName()) && Boolean.FALSE.equals(evt.getNewValue());
if (doneUpdating || "cellsEditable".equals(evt.getPropertyName()))
updateButtons();
}
});
668,13 → 672,19
for (final IListeAction a : this.rowActions.keySet()) {
final PopupBuilder popupContent = a.getPopupContent(evt);
if (defaultAction != null && a == this.defaultRowAction) {
// Cannot compare actions since menu items are not required to have an action
// If popup actions are ["Dial 03", "Dial 06"] then getDefaultAction() cannot always
// return the same instance "if land line is default then Dial 03 else Dial 06"
// otherwise we can't find its matching menu item in the popup
/**
* If popup actions are ["Dial 03", "Dial 06"] then getDefaultAction() must not
* always return the same instance "if land line is default then Dial 03 else Dial
* 06" otherwise we can't find its matching menu item in the popup. IOW the check
* should be done in getDefaultAction(), which should then return one of the popup
* actions.
* <p>
* Also, the IListeAction can just choose not to return the default action in its
* menu.
*/
final JMenuItem defaultMI = popupContent.getRootMenuItem(defaultAction);
if (defaultMI == null)
Log.get().warning("Default action not found at the root level of popup for " + this);
Log.get().info("Default action not found at the root level of popup for " + this);
else
defaultMI.setFont(defaultMI.getFont().deriveFont(Font.BOLD));
}
884,7 → 894,7
// TODO speed up like IListPanel buttons
// works because "JTable.autoStartsEdit" is false
// otherwise mets un + a la fin de la cellule courante
if (this.getSource().getPrimaryTable().isOrdered()) {
if (this.getSource().getReq().isTableOrder()) {
this.jTable.addKeyListener(new KeyAdapter() {
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == '+') {
1130,12 → 1140,14
 
// protect our internal values
private <R> R getRow(int index, final Class<R> clazz) {
final SQLRowValues internalRow = this.getLine(index).getRow();
final SQLRowAccessor toCast;
final ListSQLLine line = this.getLine(index);
final Object toCast;
if (clazz == SQLRowValues.class) {
toCast = internalRow.toImmutable();
toCast = line.getRow().toImmutable();
} else if (clazz == SQLRow.class) {
toCast = internalRow.asRow();
toCast = line.getRow().asRow();
} else if (clazz == ListSQLLine.class) {
toCast = line;
} else {
throw new IllegalArgumentException("Not implemented : " + clazz);
}
1175,7 → 1187,11
return iterateSelectedRows(SQLRowValues.class);
}
 
private final <R extends SQLRowAccessor> List<R> iterateSelectedRows(final Class<R> clazz) {
public final List<ListSQLLine> getSelectedLines() {
return iterateSelectedRows(ListSQLLine.class);
}
 
private final <R> List<R> iterateSelectedRows(final Class<R> clazz) {
final ListSelectionModel selectionModel = this.getJTable().getSelectionModel();
if (selectionModel.isSelectionEmpty())
return Collections.emptyList();
1340,10 → 1356,6
this.getModel().setSleeping(!this.isShowing());
}
 
public void setSQLEditable(boolean b) {
this.getModel().setEditable(b);
}
 
/**
* The {@link ITableModel} of this list.
*
1372,6 → 1384,7
}
this.sorter.setTableModel(t);
if (t != null) {
updateModelEditable();
// no need to listen to source columns since our ITableModel does, then it
// fireTableStructureChanged() and our JTable createDefaultColumnsFromModel() so
// columnAdded() and thus updateCols() are called. Note: we might want to listen to
1498,6 → 1511,38
return this.jTable;
}
 
private void updateModelEditable() {
final ITableModel m = this.getModel();
if (m != null) {
m.setCellsEditable(this.isCellModificationAllowed() && !getSource().getElem().isPrivate());
m.setOrderEditable(this.isOrderModificationAllowed() && (!getSource().getElem().isPrivate()));
}
}
 
public void setModificationAllowed(boolean b) {
this.setCellModificationAllowed(b);
this.setOrderModificationAllowed(b);
}
 
public void setCellModificationAllowed(boolean b) {
this.cellModificationAllowed = b;
updateModelEditable();
}
 
public boolean isCellModificationAllowed() {
return this.cellModificationAllowed;
}
 
public void setOrderModificationAllowed(boolean b) {
this.orderModificationAllowed = b;
updateModelEditable();
}
 
public boolean isOrderModificationAllowed() {
return this.orderModificationAllowed;
}
 
@Override
public void grabFocus() {
this.jTable.grabFocus();
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/liste_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/view/liste_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/view/save_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/view/save_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/view/reload_2x.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/sql/view/reload_2x.png
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/sql/PropsConfiguration.java
788,6 → 788,10
}
}
 
public final Set<String> getPropertyNames() {
return this.props.stringPropertyNames();
}
 
/**
* For each property starting with {@link #LOG}, set the level of the specified logger to the
* property's value. Eg if there's "log.level.=FINE", the root logger will be set to log FINE
/trunk/OpenConcerto/src/product.properties
1,5 → 1,5
NAME=OpenConcerto
VERSION=1.5.3
VERSION=1.5.4
ORGANIZATION_NAME=OpenConcerto
ORGANIZATION_ID=org.openconcerto