/*******************************************************************************
* Copyright (c) 2005-2016, G. Weirich and Elexis
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* G. Weirich - initial implementation
* MEDEVIT - major refactorings due to multi-stock implementation
*******************************************************************************/
package ch.elexis.data;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.IProgressMonitor;
import ch.elexis.core.data.activator.CoreHub;
import ch.elexis.core.data.util.IRunnableWithProgress;
import ch.elexis.core.model.IStockEntry;
import ch.elexis.core.model.article.IArticle;
import ch.rgw.tools.Money;
import ch.rgw.tools.StringTool;
import ch.rgw.tools.TimeTool;
public class Artikel extends VerrechenbarAdapter implements IArticle {
public static final String TABLENAME = "ARTIKEL";
public static final String FLD_EAN = "EAN";
public static final String FLD_CODECLASS = "Codeclass";
public static final String FLD_KLASSE = "Klasse";
public static final String XID_PHARMACODE = "www.xid.ch/id/pharmacode/ch";
public static final String FLD_SUB_ID = "SubID";
public static final String ARTIKEL = "Artikel";
public static final String FLD_PHARMACODE = "Pharmacode";
public static final String FLD_EXTID = "ExtID";
public static final String VERKAUFSEINHEIT = "Verkaufseinheit";
public static final String VERPACKUNGSEINHEIT = "Verpackungseinheit";
public static final String FLD_VK_PREIS = "VK_Preis";
public static final String FLD_EK_PREIS = "EK_Preis";
public static final String EIGENNAME = "Eigenname";
public static final String FLD_TYP = "Typ";
public static final String FLD_NAME = "Name";
public static final String FLD_ATC_CODE = "ATC_code";
/** Deprecated - will be removed in 3.3 (https://redmine.medelexis.ch/issues/5204) **/
@Deprecated
public static final String LIEFERANT_ID = "LieferantID";
@Deprecated
public static final String ISTBESTAND = "Istbestand";
@Deprecated
public static final String ANBRUCH = "Anbruch";
@Deprecated
public static final String MINBESTAND = "Minbestand";
@Deprecated
public static final String MAXBESTAND = "Maxbestand";
/** END **/
public static final Pattern NAME_VE_PATTERN = Pattern.compile(".+ ([0-9]+) Stk.*");
static {
addMapping(TABLENAME, LIEFERANT_ID, FLD_NAME, MAXBESTAND, MINBESTAND, ISTBESTAND,
FLD_EK_PREIS, FLD_VK_PREIS, FLD_TYP, FLD_EXTINFO, FLD_EAN, FLD_SUB_ID,
EIGENNAME + "=Name_intern", FLD_CODECLASS, FLD_KLASSE, FLD_ATC_CODE, FLD_EXTID);
Xid.localRegisterXIDDomainIfNotExists(XID_PHARMACODE, FLD_PHARMACODE,
Xid.ASSIGNMENT_REGIONAL);
}
@Override
protected String getTableName(){
return TABLENAME;
}
/**
* @param qbe
* @param clazz
* @deprecated to be removed in 3.3
* @see https://redmine.medelexis.ch/issues/5204
*/
public static void transferAllStockInformationToNew32StockModel(Query<? extends Artikel> qbe,
Class<? extends Artikel> clazz){
if (!CoreHub.globalCfg.get(clazz.getSimpleName() + "StocksMigratedTo32", false)) {
IRunnableWithProgress irwp = new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException{
log.debug("Migrating stock information");
qbe.startGroup();
qbe.add(MINBESTAND, Query.NOT_EQUAL, null);
qbe.or();
qbe.add(ISTBESTAND, Query.NOT_EQUAL, null);
qbe.add(MAXBESTAND, Query.NOT_EQUAL, null);
qbe.add(LIEFERANT_ID, Query.NOT_EQUAL, null);
qbe.endGroup();
List<? extends Artikel> stockArticles = qbe.execute();
monitor.beginTask(
"Migrating " + clazz.getSimpleName() + " to new stock format.",
stockArticles.size());
Stock stdStock = Stock.load(Stock.DEFAULT_STOCK_ID);
for (Artikel art : stockArticles) {
if (art.isProduct()) {
log.warn("Article is product with stock [{}].", art.getId());
continue;
}
log.debug("Migrating stock information for [{}]", art.getLabel());
IStockEntry se = CoreHub.getStockService().storeArticleInStock(stdStock,
art.storeToString());
String[] fields = new String[] {
MINBESTAND, ISTBESTAND, MAXBESTAND, LIEFERANT_ID
};
String[] values = art.get(false, fields);
String anbruch = art.getExt(ANBRUCH);
if (anbruch != null && anbruch.length() > 0) {
int anbruchValue = 0;
try {
anbruchValue = Integer.valueOf(anbruch);
} catch (NumberFormatException nfe) {
log.warn(
"Error converting fraction value [{}] for id [{}], setting 0.",
anbruch, art.getId(), nfe);
}
se.setFractionUnits(anbruchValue);
art.setExt(ANBRUCH, null);
}
for (int i = 0; i < values.length; i++) {
if (values[i] != null && values[i].length() > 0) {
if (i == 0) {
se.setMinimumStock(Integer.valueOf(values[i].trim()));
} else if (i == 1) {
se.setCurrentStock(Integer.valueOf(values[i].trim()));
} else if (i == 2) {
se.setMaximumStock(Integer.valueOf(values[i].trim()));
} else if (i == 3) {
se.setProvider(values[i]);
}
}
}
for (String field : fields) {
art.set(field, null);
}
monitor.worked(1);
}
CoreHub.globalCfg.set(clazz.getSimpleName() + "StocksMigratedTo32", true);
CoreHub.globalCfg.flush();
monitor.done();
}
};
PersistentObject.cod.showProgress(irwp);
}
}
public String getXidDomain(){
return XID_PHARMACODE;
}
/**
* This implementation of PersistentObject#load is special in that it tries to load the actual
* appropriate subclass
*/
public static Artikel load(final String id){
if (id == null) {
return null;
}
Artikel ret = new Artikel(id);
if (!ret.exists()) {
return ret;
}
String clazz = ret.get(FLD_KLASSE);
if (!StringTool.isNothing(clazz)) {
try {
ret = (Artikel) CoreHub.poFactory.createFromString(clazz + "::" + id);
} catch (Exception ex) {
log.error("Fehlerhafter Leistungscode " + clazz + "::" + id);
}
}
return ret;
}
/**
* Einen neuen Artikel mit vorgegebenen Parametern erstellen
*
* @param Name
* @param Typ
*/
public Artikel(final String Name, final String Typ){
create(null);
set(new String[] {
FLD_NAME, FLD_TYP
}, new String[] {
Name, Typ
});
}
public Artikel(final String Name, final String Typ, final String subid){
create(null);
set(new String[] {
FLD_NAME, FLD_TYP, FLD_SUB_ID
}, Name, Typ, subid);
}
@Override
public String getLabel(){
if (!exists()) {
return "(" + getName() + ")";
}
return getInternalName();
}
public String[] getDisplayedFields(){
return new String[] {
FLD_TYP, FLD_NAME
};
}
/**
* Den internen Namen setzen. Dieser ist vom Anwender frei wählbar und erscheint in der
* Artikelauswahl und auf der Rechnung.
*
* @param nick
* Der "Spitzname"
*/
public void setInternalName(final String nick){
set(EIGENNAME, nick);
}
/**
* Den internen Namen holen
*
* @return
*/
public String getInternalName(){
String ret = get(EIGENNAME);
if (StringTool.isNothing(ret)) {
ret = getName();
}
return ret;
}
/**
* Den offiziellen namen holen
*
* @return
*/
public String getName(){
return checkNull(get(FLD_NAME));
}
/**
* Den "echten" Namen setzen. Dies ist der offizielle Name des Artikels, wie er beispielsweise
* in Katalogen aufgeführt ist. Dieser sollte normalerweise nicht geändert werden.
*
* @param name
* der neue "echte" Name
*/
public void setName(final String name){
set(FLD_NAME, name);
}
/**
* Basis-Einkaufspreis in Rappen pro Einheit
*
* @return
*/
public Money getEKPreis(){
try {
return new Money(checkZero(get(FLD_EK_PREIS)));
} catch (Throwable ex) {
log.error("Fehler beim Einlesen von EK für " + getLabel());
}
return new Money();
}
/**
* Basis-Verkaufspreis in Rappen pro Einheit
*
* @return
*/
public Money getVKPreis(){
try {
return new Money(checkZero(get(FLD_VK_PREIS)));
} catch (Throwable ex) {
log.error("Fehler beim Einlesen von VK für " + getLabel());
}
return new Money();
}
/**
* Einkaufspreis setzen. Das sollte normalerweise nur der Importer tun
*
* @param preis
*/
public void setEKPreis(final Money preis){
set(FLD_EK_PREIS, preis.getCentsAsString());
}
/**
* Den Verkaufspreis setzen. Das sollte bei gesetztlich festgelegten Artikeln nur der Importer
* tun.
*
* @param preis
*/
public void setVKPreis(final Money preis){
set(FLD_VK_PREIS, preis.getCentsAsString());
}
/**
* Versuche, die Verpakcungseinheit herauszufinden. Entweder haben wir sie im Artikeldetail
* angegeben, dann ist es trivial, oder vielleicht steht im Namen etwas wie xx Stk.
*
* @return einen educated guess oder 0 (unknown)
*/
public int guessVE(){
int ret = getVerpackungsEinheit();
if (ret == 0) {
String name = getName();
Matcher matcher = NAME_VE_PATTERN.matcher(name);
if (matcher.matches()) {
String num = matcher.group(1);
try {
return Integer.parseInt(num);
} catch (Exception ex) {
}
}
}
return ret;
}
public String getEAN(){
return get(FLD_EAN);
}
@Override
public String getGTIN(){
return getEAN();
}
public void setEAN(String ean){
set(FLD_EAN, ean);
}
public String getATC_code(){
String ATC_code = get(FLD_ATC_CODE);
return ATC_code;
}
public void setATC_code(String ATC_code){
set(FLD_ATC_CODE, ATC_code);
}
public void setPharmaCode(String pharmacode){
Map<Object, Object> ext = getMap(FLD_EXTINFO);
ext.put(FLD_PHARMACODE, pharmacode);
setMap(FLD_EXTINFO, ext);
}
public String getPharmaCode(){
return checkNull(getExt(FLD_PHARMACODE));
}
public int getVerpackungsEinheit(){
return checkZero((String) getExtInfoStoredObjectByKey(VERPACKUNGSEINHEIT));
}
@Override
public int getPackageUnit(){
return getVerpackungsEinheit();
}
public void setVerpackungsEinheit(int ve){
setExt(VERPACKUNGSEINHEIT, Integer.toString(ve));
}
public int getVerkaufseinheit(){
return checkZero(getExt(VERKAUFSEINHEIT));
}
@Override
public int getSellingUnit(){
return getVerkaufseinheit();
}
public void setVerkaufseinheit(int number){
setExt(VERKAUFSEINHEIT, Integer.toString(number));
}
/**
* @return the package size, zero if not defined
*/
public int getPackungsGroesse(){
return checkZero(getExt(VERPACKUNGSEINHEIT));
}
public void setPackungsGroesse(int packageSize){
setExtInfoStoredObjectByKey(VERPACKUNGSEINHEIT, Integer.toString(packageSize));
}
public String getPackungsGroesseDesc(){
return Integer.toString(getPackungsGroesse());
}
public int getAbgabeEinheit(){
return checkZero(getExt(VERKAUFSEINHEIT));
}
@SuppressWarnings("unchecked")
public void setExt(final String name, final String value){
Map h = getMap(FLD_EXTINFO);
if (value == null) {
h.remove(name);
} else {
h.put(name, value);
}
setMap(FLD_EXTINFO, h);
}
@SuppressWarnings("unchecked")
public String getExt(final String name){
Map h = getMap(FLD_EXTINFO);
return checkNull((String) h.get(name));
}
protected Artikel(final String id){
super(id);
}
protected Artikel(){}
/************************ Verrechenbar ************************/
@Override
public String getCode(){
return getId();
}
@Override
public String getText(){
return getInternalName();
}
@Override
public String getCodeSystemName(){
return ARTIKEL;
}
@Override
public boolean isProduct(){
return false;
}
@SuppressWarnings("unchecked")
public int getPreis(final TimeTool dat, final Fall fall){
double vkt = checkZeroDouble(get(FLD_VK_PREIS));
Map ext = getMap(FLD_EXTINFO);
double vpe = checkZeroDouble((String) ext.get(VERPACKUNGSEINHEIT));
double vke = checkZeroDouble((String) ext.get(VERKAUFSEINHEIT));
if ((vpe > 0.0) && (vke > 0.0) && (vpe != vke)) {
return (int) Math.round(vke * (vkt / vpe));
} else {
return (int) Math.round(vkt);
}
}
@SuppressWarnings("unchecked")
@Override
public Money getKosten(final TimeTool dat){
double vkt = checkZeroDouble(get(FLD_EK_PREIS));
Map ext = getMap(FLD_EXTINFO);
double vpe = checkZeroDouble((String) ext.get(VERPACKUNGSEINHEIT));
double vke = checkZeroDouble((String) ext.get(VERKAUFSEINHEIT));
if (vpe != vke) {
return new Money((int) Math.round(vke * (vkt / vpe)));
} else {
return new Money((int) Math.round(vkt));
}
}
public int getTP(final TimeTool date, final Fall fall){
return getPreis(date, fall);
}
public double getFactor(final TimeTool date, final Fall fall){
return 1.0;
}
@Override
protected String[] getExportFields(){
return new String[] {
FLD_EAN, FLD_SUB_ID, FLD_KLASSE, FLD_NAME, FLD_EK_PREIS, FLD_VK_PREIS, FLD_TYP,
FLD_CODECLASS, FLD_ATC_CODE, FLD_EXTINFO
};
}
@Override
protected String getExportUIDValue(){
String pharmacode = getExt(FLD_PHARMACODE);
String ean = get(FLD_EAN);
return ean + "_" + pharmacode;
}
@Override
public List<Object> getActions(Object kontext){
// TODO Auto-generated method stub
return null;
}
}