Dépôt officiel du code source de l'ERP OpenConcerto
Rev 144 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* 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.model;
import org.openconcerto.erp.core.sales.pos.POSConfiguration;
import org.openconcerto.erp.core.sales.pos.model.RegisterState.Status;
import org.openconcerto.erp.utils.TM;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.utils.CollectionUtils;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import net.jcip.annotations.Immutable;
/**
* Encapsulate all the data about a register in the DB at a point in time.
*
* @author sylvain
*/
@Immutable
public final class DBState {
private static final Status getStatus(final SQLRowAccessor entry) {
final Status res = Status.valueOf(entry.getString("EVT"));
if (res != Status.OPEN && res != Status.CLOSED)
throw new IllegalStateException("Invalid status : " + res);
return res;
}
// used not for requests but for tables and paths
private final RegisterDB registerDB;
private final SQLRowValues registerVals;
private final SQLRowValues lastReceiptVals;
private final RegisterState registerState;
// first is the latest
private final List<SQLRowValues> lastEntries;
protected DBState(final RegisterDB registerDB, final SQLRowValues registerR) {
super();
this.registerDB = registerDB;
this.registerVals = registerR.toImmutable();
if (this.getPosID() != registerDB.getPosID())
throw new IllegalArgumentException("Not same register");
this.lastReceiptVals = CollectionUtils.getSole(this.registerVals.getReferentRows(this.registerDB.getReceiptElement().getTable().getField("ID_CAISSE")));
this.lastEntries = Collections.unmodifiableList(new ArrayList<>(this.registerVals.getReferentRows(this.registerDB.getLogElement().getTable().getField("ID_CAISSE"))));
final SQLRowAccessor lastEntry = getLastEntry();
if (lastEntry == null) {
this.registerState = new RegisterState(Status.CLOSED, null);
} else {
if (lastEntry.getForeignID("ID_CAISSE") != this.getPosID())
throw new IllegalStateException("Incoherent register IDs");
final Status status = getStatus(lastEntry);
this.registerState = new RegisterState(status, lastEntry.getDate("DATE").getTime());
}
}
public final int getPosID() {
return this.registerVals.getID();
}
public final RegisterState getRegisterState() {
return this.registerState;
}
public SQLRowValues getRegisterRow() {
return this.registerVals;
}
public final SQLRowValues getLastClosure() {
return this.registerVals.followPath(this.registerDB.getRegisterToLastClosureEntry().minusLast());
}
public final SQLRowValues getLastClosureEntry() {
return this.registerVals.followPath(this.registerDB.getRegisterToLastClosureEntry());
}
public final SQLRowValues getLastOpeningEntry() {
final List<SQLRowValues> entries = this.getLastEntries();
if (entries.isEmpty()) {
// never opened
assert !this.getRegisterState().hasDate();
return null;
} else if (getStatus(entries.get(0)).equals(Status.OPEN)) {
return entries.get(0);
} else if (entries.size() > 1 && getStatus(entries.get(1)).equals(Status.OPEN)) {
return entries.get(1);
} else {
throw new IllegalStateException("Two consecutive non-open entries : " + entries);
}
}
public final SQLRowValues getLastEntry() {
return CollectionUtils.getFirst(this.getLastEntries());
}
public final List<SQLRowValues> getLastEntries() {
return this.lastEntries;
}
public final SQLRowValues getLastReceiptRow() {
return this.lastReceiptVals;
}
public final ReceiptCode getLastReceiptCode() throws ParseException {
final SQLRowValues lastReceiptRow = this.getLastReceiptRow();
return lastReceiptRow == null ? null : new ReceiptCode(lastReceiptRow.getString("NUMERO"));
}
public final SQLRowValues fillHostValues(final SQLRowValues logVals) {
logVals.put("HOST_NAME", PropsConfiguration.getHostname());
logVals.put("HOST_USER", System.getProperty("user.name"));
return logVals;
}
// initial values for entries created before this version
private static final Map<String, ?> NULL_VALUES = CollectionUtils.createMap("HOST_NAME", null, "HOST_USER", null);
/**
* Check if the register installation has moved and ask the user about it if it did. This can be
* called from outside the EDT.
*
* @return <code>true</code> if the user wants to quit.
* @throws InterruptedException if this thread was interrupted while waiting on the EDT.
* @throws ExecutionException if there was an error while asking the user.
*/
public final boolean checkIfMoved() throws InterruptedException, ExecutionException {
final SQLRowValues lastEntry = this.getLastEntry();
if (lastEntry == null) {
return false;
}
final Map<String, Object> currentValues = fillHostValues(new SQLRowValues(lastEntry.getTable())).getAbsolutelyAll();
final Map<String, Object> dbValues = lastEntry.getValues(currentValues.keySet());
if (dbValues.equals(currentValues) || NULL_VALUES.equals(dbValues)) {
return false;
} else {
final String message = TM.tr("register.moved", getPosID());
final String[] options = new String[] { TM.tr("register.moved.ignore"), TM.tr("register.moved.quit") };
final FutureTask<Boolean> askUserCallable = new FutureTask<>(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// quit by default
final int ans = JOptionPane.showOptionDialog(null, message, TM.tr("register.moved.title"), JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
// CLOSED_OPTION also means quit, only clicking "ignore" means don't quit
return ans != 0;
}
});
SwingThreadUtils.invoke(askUserCallable);
final boolean quit = askUserCallable.get();
if (!quit)
POSConfiguration.getLogger().log(Level.WARNING, "User choose to ignore changed host,\nDB values : {0}\ncurrent values : {1}", new Object[] { dbValues, currentValues });
return quit;
}
}
@Override
public String toString() {
return this.getClass().getSimpleName() + " for register " + this.getPosID() + " in state " + this.getRegisterState();
}
}