/*******************************************************************************
* Copyright (c) 2007-2015, D. Lutz 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:
* D. Lutz - initial API and implementation
* Gerry Weirich - adapted for 2.1
* Niklaus Giger - small improvements, split into 20 classes
*
* Sponsors:
* Dr. Peter Schönbucher, Luzern
******************************************************************************/
package org.iatrix.widgets;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.iatrix.Iatrix;
import org.iatrix.data.Problem;
import org.iatrix.views.JournalView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.elexis.admin.AccessControlDefaults;
import ch.elexis.core.data.activator.CoreHub;
import ch.elexis.core.data.interfaces.IVerrechenbar;
import ch.elexis.core.ui.UiDesk;
import ch.elexis.core.ui.actions.CodeSelectorHandler;
import ch.elexis.core.ui.actions.ICodeSelectorTarget;
import ch.elexis.core.ui.util.SWTHelper;
import ch.elexis.core.ui.views.codesystems.LeistungenView;
import ch.elexis.data.Artikel;
import ch.elexis.data.Konsultation;
import ch.elexis.data.PersistentObject;
import ch.elexis.data.PersistentObjectFactory;
import ch.elexis.data.Query;
import ch.elexis.data.Verrechnet;
import ch.rgw.tools.ExHandler;
import ch.rgw.tools.Money;
import ch.rgw.tools.Result;
import ch.rgw.tools.StringTool;
public class KonsVerrechnung implements IJournalArea {
private Konsultation actKons = null;
private FormToolkit tk;
private static Logger log = LoggerFactory.getLogger(KonsVerrechnung.class);
public IAction delVerrechnetAction;
public IAction changeVerrechnetPreisAction;
public IAction changeVerrechnetZahlAction;
private TableViewer verrechnungViewer;
private Color verrechnungViewerColor; // original color of verrechnungViewer
private Hyperlink hVerrechnung;
private Text tVerrechnungKuerzel;
private ICodeSelectorTarget konsultationVerrechnungCodeSelectorTarget;
private Color highlightColor;
public KonsVerrechnung(Composite verrechnungComposite, Form form, String partName,
Composite assignmentComposite){
tk = UiDesk.getToolkit();
// highlighting colors for ICodeSelectorTarget
highlightColor = form.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
verrechnungComposite.setLayout(new GridLayout(1, true));
Composite verrechnungHeader = tk.createComposite(verrechnungComposite);
verrechnungHeader.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false));
verrechnungHeader.setLayout(new GridLayout(2, false));
hVerrechnung = tk.createHyperlink(verrechnungHeader, "Verrechnung", SWT.NONE);
hVerrechnung.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false));
hVerrechnung.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e){
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.showView(LeistungenView.ID);
CodeSelectorHandler.getInstance()
.setCodeSelectorTarget(konsultationVerrechnungCodeSelectorTarget);
} catch (Exception ex) {
ExHandler.handle(ex);
log.error("Fehler beim Starten des Leistungscodes " + ex.getMessage());
}
}
});
hVerrechnung.setEnabled(false);
tVerrechnungKuerzel = tk.createText(verrechnungHeader, "", SWT.BORDER);
GridData gd;
gd = new GridData(SWT.END);
gd.widthHint = 50;
tVerrechnungKuerzel.setLayoutData(gd);
tVerrechnungKuerzel.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e){
String mnemonic = tVerrechnungKuerzel.getText();
if (!StringTool.isNothing(mnemonic)) {
// TODO evaluate return value, visualize errors
addLeistungByMnemonic(mnemonic, false, false);
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e){
widgetSelected(e);
}
});
tVerrechnungKuerzel.setEnabled(false);
Table verrechnungTable = tk.createTable(verrechnungComposite, SWT.MULTI);
verrechnungViewer = new TableViewer(verrechnungTable);
verrechnungViewer.getControl().setLayoutData(SWTHelper.getFillGridData(1, true, 1, true));
// used by hightlightVerrechnung()
verrechnungHeader.setBackground(verrechnungHeader.getBackground());
verrechnungTable.setBackground(verrechnungHeader.getBackground());
verrechnungViewerColor = verrechnungTable.getBackground();
hVerrechnung.setBackground(verrechnungHeader.getBackground());
verrechnungViewer.setContentProvider(new IStructuredContentProvider() {
@Override
public Object[] getElements(Object inputElement){
if (actKons != null) {
List<Verrechnet> lgl = actKons.getLeistungen();
return lgl.toArray();
}
return new Object[0];
}
@Override
public void dispose(){
// nothing to do
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput){
// nothing to do
}
});
verrechnungViewer.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element){
if (!(element instanceof Verrechnet)) {
return "";
}
Verrechnet verrechnet = (Verrechnet) element;
StringBuilder sb = new StringBuilder();
int z = verrechnet.getZahl();
// TODO: Ersetzen durch errechnet.getStandardPreis() ??
Money preis = new Money(verrechnet.getEffPreis()).multiply(z);
// double preis = (z * verrechnet.getEffPreisInRappen()) / 100.0;
sb.append(z).append(" ").append(verrechnet.getCode()).append(" ")
.append(verrechnet.getText()).append(" (").append(preis.getAmountAsString())
.append(")");
return sb.toString();
}
});
verrechnungViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event){
boolean enableDel = false;
boolean enableChange = false;
IStructuredSelection sel = (IStructuredSelection) event.getSelection();
if (sel != null) {
if (sel.size() >= 1) {
enableDel = true;
}
if (sel.size() == 1) {
enableChange = true;
}
}
delVerrechnetAction.setEnabled(enableDel);
changeVerrechnetZahlAction.setEnabled(enableChange);
changeVerrechnetPreisAction.setEnabled(enableChange);
}
});
verrechnungViewer.setInput(this);
makeActions();
/* Implementation Drag&Drop */
final TextTransfer textTransfer = TextTransfer.getInstance();
Transfer[] types = new Transfer[] {
textTransfer
};
verrechnungViewer.getControl().addKeyListener(new KeyListener() {
@Override
public void keyReleased(KeyEvent e){
if (e.keyCode == SWT.DEL) {
int j = verrechnungViewer.getTable().getSelectionIndex();
deleleSelectedItem();
// Allow pressing delete several times in a row
if (j >= 1) { // Correct by one, as we removed one item
verrechnungViewer.getTable().setFocus();
verrechnungViewer.getTable().select(j-1);
}
}
}
@Override
public void keyPressed(KeyEvent e){}
});
// assignmentComposite
DropTarget dtarget = new DropTarget(assignmentComposite, DND.DROP_COPY);
dtarget.setTransfer(types);
dtarget.addDropListener(new DropTargetListener() {
@Override
public void dragEnter(DropTargetEvent event){
/* Wir machen nur Copy-Operationen */
event.detail = DND.DROP_COPY;
}
/* Mausbewegungen mit gedrückter Taste sind uns egal */
@Override
public void dragLeave(DropTargetEvent event){
/* leer */
}
@Override
public void dragOperationChanged(DropTargetEvent event){
/* leer */
}
@Override
public void dragOver(DropTargetEvent event){
/* leer */
}
/* Erst das Loslassen interessiert uns wieder */
@Override
public void drop(DropTargetEvent event){
String drp = (String) event.data;
String[] dl = drp.split(",");
for (String obj : dl) {
PersistentObject dropped = CoreHub.poFactory.createFromString(obj);
if (dropped instanceof Problem) {
Problem problem = (Problem) dropped;
problem.addToKonsultation(actKons);
// TODO: updateProblemAssignmentViewer();
// TODO: setDiagnosenText(actKons);
}
}
}
@Override
public void dropAccept(DropTargetEvent event){
/* leer */
}
});
// verrechnungComposite
dtarget = new DropTarget(verrechnungComposite, DND.DROP_COPY);
dtarget.setTransfer(types);
dtarget.addDropListener(new DropTargetListener() {
@Override
public void dragEnter(DropTargetEvent event){
/* Wir machen nur Copy-Operationen */
event.detail = DND.DROP_COPY;
}
/* Mausbewegungen mit gedrückter Taste sind uns egal */
@Override
public void dragLeave(DropTargetEvent event){
/* leer */
}
@Override
public void dragOperationChanged(DropTargetEvent event){
/* leer */
}
@Override
public void dragOver(DropTargetEvent event){
/* leer */
}
/* Erst das Loslassen interessiert uns wieder */
@Override
public void drop(DropTargetEvent event){
String drp = (String) event.data;
String[] dl = drp.split(",");
for (String obj : dl) {
PersistentObject dropped = CoreHub.poFactory.createFromString(obj);
if (dropped instanceof IVerrechenbar) {
if (CoreHub.acl.request(AccessControlDefaults.LSTG_VERRECHNEN) == false) {
SWTHelper.alert("Fehlende Rechte",
"Sie haben nicht die Berechtigung, Leistungen zu verrechnen");
} else {
Result<IVerrechenbar> result =
actKons.addLeistung((IVerrechenbar) dropped);
if (!result.isOK()) {
SWTHelper.alert("Diese Verrechnung it ungültig", result.toString());
}
verrechnungViewer.refresh();
updateVerrechnungSum();
}
}
}
}
@Override
public void dropAccept(DropTargetEvent event){
/* leer */
}
});
// ICodeSelectorTarget for Verrechnung in consultation area
konsultationVerrechnungCodeSelectorTarget = new ICodeSelectorTarget() {
@Override
public String getName(){
return partName;
}
@Override
public void codeSelected(PersistentObject po){
if (po instanceof IVerrechenbar) {
if (CoreHub.acl.request(AccessControlDefaults.LSTG_VERRECHNEN) == false) {
SWTHelper.alert("Fehlende Rechte",
"Sie haben nicht die Berechtigung, Leistungen zu verrechnen");
} else {
IVerrechenbar verrechenbar = (IVerrechenbar) po;
if (actKons != null) {
Result<IVerrechenbar> result = actKons.addLeistung(verrechenbar);
if (!result.isOK()) {
SWTHelper.alert("Diese Verrechnung ist ungültig",
result.toString());
} else {
if (CoreHub.userCfg.get(Iatrix.CFG_CODE_SELECTION_AUTOCLOSE,
Iatrix.CFG_CODE_SELECTION_AUTOCLOSE_DEFAULT)) {
// re-activate this view
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().showView(JournalView.ID);
} catch (Exception ex) {
ExHandler.handle(ex);
log.error("Fehler beim Öffnen von JournalView: "
+ ex.getMessage());
}
}
}
verrechnungViewer.refresh();
updateVerrechnungSum();
}
}
}
}
@Override
public void registered(boolean registered){
highlightVerrechnung(registered);
}
};
}
public void updateVerrechnungSum(){
StringBuilder sb = new StringBuilder();
sb.append("Verrechnung");
if (actKons != null) {
List<Verrechnet> leistungen = actKons.getLeistungen();
Money sum = new Money(0);
for (Verrechnet leistung : leistungen) {
int z = leistung.getZahl();
// TODO: Ersetzen durch errechnet.getStandardPreis() ??
Money preis = leistung.getEffPreis().multiply(z);
sum.addMoney(preis);
}
sb.append(" (");
sb.append(sum.getAmountAsString());
sb.append(")");
}
hVerrechnung.setText(sb.toString());
}
/**
* Leistung anhand des Kuerzels hinzufuegen
*/
private boolean addLeistungByMnemonic(String mnemonic, boolean approximation, boolean multi){
boolean success = false;
if (actKons != null && !StringTool.isNothing(mnemonic)) {
Query<Artikel> query = new Query<>(Artikel.class);
if (approximation) {
query.add("Eigenname", "LIKE", mnemonic + "%");
} else {
query.add("Eigenname", "=", mnemonic);
}
List<Artikel> artikels = query.execute();
if (artikels != null && !artikels.isEmpty()) {
List<Artikel> selection = new ArrayList<>();
if (multi) {
selection.addAll(artikels);
} else {
selection.add(artikels.get(0));
}
List<Result<IVerrechenbar>> results = new ArrayList<>();
PersistentObjectFactory factory = new PersistentObjectFactory();
for (Artikel artikel : artikels) {
String typ = artikel.get("Typ");
String id = artikel.getId();
// work-around for articles without class information (plugin
// elexis-artikel-schweiz)
if (typ.equals("Medikament") || typ.equals("Medical") || typ.equals("MiGeL")) {
typ = "ch.elexis.artikel_ch.data." + typ;
}
PersistentObject po = factory.createFromString(typ + "::" + id);
if (po instanceof IVerrechenbar) {
Result<IVerrechenbar> result = actKons.addLeistung((IVerrechenbar) po);
if (!result.isOK()) {
results.add(result);
}
}
}
verrechnungViewer.refresh();
updateVerrechnungSum();
if (results.isEmpty()) {
success = true;
} else {
StringBuffer sb = new StringBuffer();
boolean first = true;
for (Result<IVerrechenbar> result : results) {
if (first) {
first = false;
} else {
sb.append("; ");
}
sb.append(result.toString());
SWTHelper.alert("Diese Verrechnung ist ungültig", sb.toString());
}
}
}
}
return success;
}
public void updateKonsultation(boolean updateText){
if (actKons != null) {
hVerrechnung.setEnabled(true);
tVerrechnungKuerzel.setEnabled(true);
log.debug("Konsultation: " + actKons.getId());
} else {
hVerrechnung.setEnabled(false);
tVerrechnungKuerzel.setEnabled(false);
log.debug("Konsultation: null");
}
}
private void highlightVerrechnung(boolean highlight){
Table table = verrechnungViewer.getTable();
if (highlight) {
// set highlighting color
table.setBackground(highlightColor);
} else {
// set default color
table.setBackground(verrechnungViewerColor);
}
}
/*
* Return the index of the selected item. -1 if it could not be found
*/
private void deleleSelectedItem(){
IStructuredSelection sel = (IStructuredSelection) verrechnungViewer.getSelection();
if (sel != null) {
for (Object obj : sel.toArray()) {
if (obj instanceof Verrechnet) {
Verrechnet verrechnet = (Verrechnet) obj;
Result<Verrechnet> result = actKons.removeLeistung(verrechnet);
if (!result.isOK()) {
SWTHelper.alert("Leistungsposition kann nicht entfernt werden",
result.toString());
}
verrechnungViewer.refresh();
updateVerrechnungSum();
}
}
}
}
private void makeActions(){
delVerrechnetAction = new Action("Leistungsposition entfernen") {
@Override
public void run(){
deleleSelectedItem();
}
};
changeVerrechnetPreisAction = new Action("Preis ändern") {
@Override
public void run(){
Object sel =
((IStructuredSelection) verrechnungViewer.getSelection()).getFirstElement();
if (sel != null) {
Verrechnet verrechnet = (Verrechnet) sel;
if(!verrechnet.getKons().isEditable(true)) {
return;
}
// String p=Rechnung.geldFormat.format(verrechnet.getEffPreisInRappen()/100.0);
// TODO: Ersetzen durch errechnet.getStandardPreis() ??
String p = verrechnet.getEffPreis().getAmountAsString();
InputDialog dlg = new InputDialog(
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
"Preis für Leistung ändern",
"Geben Sie bitte den neuen Preis für die Leistung ein (x.xx)", p, null);
if (dlg.open() == Dialog.OK) {
Money newPrice;
try {
newPrice = new Money(dlg.getValue());
// TODO: Durch was kann man setPreis ersetzen?
verrechnet.setPreis(newPrice);
verrechnungViewer.refresh();
updateVerrechnungSum();
} catch (ParseException e) {
ExHandler.handle(e);
SWTHelper.showError("Falsche Eingabe",
"Konnte Angabe nicht interpretieren");
}
}
}
}
};
changeVerrechnetZahlAction = new Action("Zahl ändern") {
@Override
public void run(){
Object sel =
((IStructuredSelection) verrechnungViewer.getSelection()).getFirstElement();
if (sel != null) {
Verrechnet verrechnet = (Verrechnet) sel;
String p = Integer.toString(verrechnet.getZahl());
InputDialog dlg = new InputDialog(
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
"Zahl der Leistung ändern",
"Geben Sie bitte die neue Anwendungszahl für die Leistung bzw. den Artikel ein",
p, null);
if (dlg.open() == Dialog.OK) {
int vorher = verrechnet.getZahl();
int neu = Integer.parseInt(dlg.getValue());
verrechnet.setZahl(neu);
IVerrechenbar verrechenbar = verrechnet.getVerrechenbar();
if (verrechenbar instanceof Artikel) {
Artikel art = (Artikel) verrechenbar;
CoreHub.getStockService().performSingleReturn(art, 1);
CoreHub.getStockService().performSingleDisposal(art, 1);
}
verrechnungViewer.refresh();
updateVerrechnungSum();
}
}
}
};
}
@Override
public void setKons(Konsultation newKons, KonsActions op){
if (KonsActions.ACTIVATE_KONS == op) {
actKons = newKons;
updateKonsultation(false);
verrechnungViewer.refresh();
updateVerrechnungSum();
}
}
@Override
public void visible(boolean mode){
// nothing todo
}
@Override
public void activation(boolean mode){
// nothing todo
}
public TableViewer getVerrechnungViewer(){
return verrechnungViewer;
}
}