/*******************************************************************************
* Copyright (c) 2006-2010, 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
*
*******************************************************************************/
package ch.elexis.core.ui.views;
import java.text.ParseException;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DropTargetEvent;
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.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.statushandlers.StatusManager;
import ch.elexis.admin.AccessControlDefaults;
import ch.elexis.core.constants.Preferences;
import ch.elexis.core.constants.StringConstants;
import ch.elexis.core.data.activator.CoreHub;
import ch.elexis.core.data.events.ElexisEvent;
import ch.elexis.core.data.events.ElexisEventDispatcher;
import ch.elexis.core.data.events.ElexisEventListener;
import ch.elexis.core.data.interfaces.IDiagnose;
import ch.elexis.core.data.interfaces.IVerrechenbar;
import ch.elexis.core.data.status.ElexisStatus;
import ch.elexis.core.model.prescription.EntryType;
import ch.elexis.core.ui.Hub;
import ch.elexis.core.ui.UiDesk;
import ch.elexis.core.ui.actions.CodeSelectorHandler;
import ch.elexis.core.ui.events.ElexisUiEventListenerImpl;
import ch.elexis.core.ui.icons.Images;
import ch.elexis.core.ui.locks.AcquireLockUi;
import ch.elexis.core.ui.locks.IUnlockable;
import ch.elexis.core.ui.locks.LockDeniedNoActionLockHandler;
import ch.elexis.core.ui.util.PersistentObjectDropTarget;
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.Leistungsblock;
import ch.elexis.data.PersistentObject;
import ch.elexis.data.Prescription;
import ch.elexis.data.Verrechnet;
import ch.rgw.tools.Money;
import ch.rgw.tools.Result;
import ch.rgw.tools.StringTool;
public class VerrechnungsDisplay extends Composite implements IUnlockable {
Table tVerr;
TableViewer viewer;
MenuManager contextMenuManager;
private String defaultRGB;
private IWorkbenchPage page;
private final Hyperlink hVer;
private final PersistentObjectDropTarget dropTarget;
private IAction applyMedicationAction, chPriceAction, chCountAction, chTextAction, removeAction,
removeAllAction;
private static final String APPLY_MEDICATION = Messages.VerrechnungsDisplay_applyMedication;
private static final String CHPRICE = Messages.VerrechnungsDisplay_changePrice;
private static final String CHCOUNT = Messages.VerrechnungsDisplay_changeNumber;
private static final String REMOVE = Messages.VerrechnungsDisplay_removeElements;
private static final String CHTEXT = Messages.VerrechnungsDisplay_changeText;
private static final String REMOVEALL = Messages.VerrechnungsDisplay_removeAll;
private final ElexisEventListener eeli_update = new ElexisUiEventListenerImpl(
Konsultation.class, ElexisEvent.EVENT_UPDATE) {
@Override
public void runInUi(ElexisEvent ev){
Konsultation actKons =
(Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class);
setLeistungen(actKons);
}
};
public VerrechnungsDisplay(final IWorkbenchPage p, Composite parent, int style){
super(parent, style);
setLayout(new GridLayout());
this.page = p;
defaultRGB = UiDesk.createColor(new RGB(255, 255, 255));
hVer =
UiDesk.getToolkit().createHyperlink(this, Messages.VerrechnungsDisplay_billing,
SWT.NONE); //$NON-NLS-1$
hVer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
hVer.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e){
try {
if (StringTool.isNothing(LeistungenView.ID)) {
SWTHelper.alert(Messages.VerrechnungsDisplay_error, "LeistungenView.ID"); //$NON-NLS-1$ //$NON-NLS-2$
}
page.showView(LeistungenView.ID);
CodeSelectorHandler.getInstance().setCodeSelectorTarget(dropTarget);
} catch (Exception ex) {
ElexisStatus status =
new ElexisStatus(ElexisStatus.ERROR, Hub.PLUGIN_ID, ElexisStatus.CODE_NONE,
Messages.VerrechnungsDisplay_errorStartingCodeWindow + ex.getMessage(),
ex, ElexisStatus.LOG_ERRORS);
StatusManager.getManager().handle(status, StatusManager.SHOW);
}
}
});
makeActions();
tVerr = UiDesk.getToolkit().createTable(this, SWT.MULTI);
tVerr.setLayoutData(new GridData(GridData.FILL_BOTH));
tVerr.setMenu(createVerrMenu());
// dummy table viewer needed for SelectionsProvider for Menu
viewer = new TableViewer(tVerr);
// add selection event to table which provides selection to ElexisEventDispatcher
tVerr.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e){
TableItem[] selection = tVerr.getSelection();
Verrechnet verrechnet = (Verrechnet) selection[0].getData();
ElexisEventDispatcher.fireSelectionEvent(verrechnet);
applyMedicationAction.setEnabled(false);
IVerrechenbar verrechenbar = verrechnet.getVerrechenbar();
if (verrechenbar != null && (verrechenbar instanceof Artikel)) {
applyMedicationAction.setEnabled(true);
}
}
});
tVerr.addKeyListener(new KeyListener() {
@Override
public void keyReleased(KeyEvent e){}
@Override
public void keyPressed(KeyEvent e){
if (e.keyCode == SWT.DEL) {
if (tVerr.getSelectionIndices().length >= 1 && removeAction != null) {
removeAction.run();
}
}
}
});
dropTarget =
new PersistentObjectDropTarget(Messages.VerrechnungsDisplay_doBill, tVerr,
new DropReceiver()); //$NON-NLS-1$
// refresh the table if a update to a Verrechnet occurs
ElexisEventDispatcher.getInstance().addListeners(
new ElexisUiEventListenerImpl(Verrechnet.class, ElexisEvent.EVENT_UPDATE) {
@Override
public void runInUi(ElexisEvent ev){
Konsultation actKons =
(Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class);
setLeistungen(actKons);
}
});
ElexisEventDispatcher.getInstance().addListeners(eeli_update);
}
public void clear(){
tVerr.removeAll();
hVer.setText(Messages.VerrechnungsDisplay_billed + ")");
}
public void addPersistentObject(PersistentObject o){
Konsultation actKons = (Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class);
if (actKons != null) {
if (o instanceof Prescription) {
Prescription presc = (Prescription) o;
o = presc.getArtikel();
}
if (o instanceof IVerrechenbar) {
if (CoreHub.acl.request(AccessControlDefaults.LSTG_VERRECHNEN) == false) {
SWTHelper.alert(Messages.VerrechnungsDisplay_missingRightsCaption, //$NON-NLS-1$
Messages.VerrechnungsDisplay_missingRightsBody); //$NON-NLS-1$
} else {
Result<IVerrechenbar> result = actKons.addLeistung((IVerrechenbar) o);
if (!result.isOK()) {
SWTHelper.alert(Messages.VerrechnungsDisplay_imvalidBilling,
result.toString()); //$NON-NLS-1$
}
setLeistungen(actKons);
}
} else if (o instanceof IDiagnose) {
actKons.addDiagnose((IDiagnose) o);
}
}
}
private final class DropReceiver implements PersistentObjectDropTarget.IReceiver {
public void dropped(PersistentObject o, DropTargetEvent ev){
addPersistentObject(o);
}
public boolean accept(PersistentObject o){
if (ElexisEventDispatcher.getSelectedPatient() != null) {
if (o instanceof Artikel) {
return !((Artikel) o).isProduct();
}
if (o instanceof IVerrechenbar) {
return true;
}
if (o instanceof Leistungsblock) {
return true;
}
if (o instanceof Prescription) {
Prescription p = ((Prescription) o);
return (p.getArtikel() != null && !p.getArtikel().isProduct());
}
}
return false;
}
}
public void setLeistungen(Konsultation b){
List<Verrechnet> lgl = Collections.emptyList();
if (b != null) {
lgl = b.getLeistungen();
}
tVerr.setRedraw(false);
tVerr.removeAll();
StringBuilder sdg = new StringBuilder();
Money sum = new Money(0);
for (Verrechnet lst : lgl) {
sdg.setLength(0);
int z = lst.getZahl();
Money preis = lst.getNettoPreis().multiply(z);
sum.addMoney(preis);
sdg.append(z).append(" ").append(lst.getCode()).append(" ").append(lst.getText()) //$NON-NLS-1$ //$NON-NLS-2$
.append(" (").append(preis.getAmountAsString()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
TableItem ti = new TableItem(tVerr, SWT.WRAP);
ti.setText(sdg.toString());
ti.setData(lst);
IVerrechenbar vr = lst.getVerrechenbar();
if (vr instanceof Artikel) {
Artikel a = (Artikel) vr;
int abgabeEinheit = a.getAbgabeEinheit();
if (abgabeEinheit > 0 && abgabeEinheit < a.getPackungsGroesse()) {
ti.setImage(Images.IMG_BLOCKS_SMALL.getImage());
}
}
// set table item color
IVerrechenbar verrBar = lst.getVerrechenbar();
if (verrBar != null) {
Color color = UiDesk.getColorFromRGB(defaultRGB);
String codeName = verrBar.getCodeSystemName();
if (codeName != null) {
String rgbColor =
CoreHub.globalCfg.get(Preferences.LEISTUNGSCODES_COLOR + codeName,
defaultRGB);
color = UiDesk.getColorFromRGB(rgbColor);
}
ti.setBackground(color);
}
}
tVerr.setRedraw(true);
sdg.setLength(0);
sdg.append(Messages.VerrechnungsDisplay_billed).append(sum.getAmountAsString()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
hVer.setText(sdg.toString());
}
private Menu createVerrMenu(){
contextMenuManager = new MenuManager();
contextMenuManager.setRemoveAllWhenShown(true);
contextMenuManager.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager){
int[] selIndices = tVerr.getSelectionIndices();
if (selIndices.length > 1) {
manager.add(removeAction);
} else {
int sel = tVerr.getSelectionIndex();
if (sel != -1) {
TableItem ti = tVerr.getItem(sel);
Verrechnet v = (Verrechnet) ti.getData();
manager.add(applyMedicationAction);
manager.add(chPriceAction);
manager.add(chCountAction);
IVerrechenbar vbar = v.getVerrechenbar();
List<IAction> itemActions = (List<IAction>) (List<?>) vbar.getActions(v);
if ((itemActions != null) && (itemActions.size() > 0)) {
manager.add(new Separator());
for (IAction a : itemActions) {
if (a != null) {
manager.add(a);
}
}
}
manager.add(new Separator());
manager.add(chTextAction);
manager.add(removeAction);
manager.add(new Separator());
manager.add(removeAllAction);
}
}
}
});
return contextMenuManager.createContextMenu(tVerr);
}
private void makeActions(){
// #3278
applyMedicationAction = new Action(APPLY_MEDICATION) {
@Override
public void run(){
Verrechnet v = loadSelectedVerrechnet();
AcquireLockUi.aquireAndRun(v, new LockDeniedNoActionLockHandler() {
@Override
public void lockAcquired(){
v.setDetail(Verrechnet.VATSCALE, Double.toString(0.0));
int packungsGroesse = ((Artikel) v.getVerrechenbar()).getPackungsGroesse();
String proposal = (packungsGroesse > 0) ? "1/" + packungsGroesse : "1";
changeQuantityDialog(proposal, v);
Object prescriptionId = v.getDetail(Verrechnet.FLD_EXT_PRESC_ID);
if (prescriptionId instanceof String) {
Prescription prescription = Prescription.load((String) prescriptionId);
if (prescription.getEntryType() == EntryType.SELF_DISPENSED) {
prescription.setApplied(true);
}
}
}
});
}
@Override
public ImageDescriptor getImageDescriptor(){
return Images.IMG_SYRINGE.getImageDescriptor();
}
};
removeAction = new Action(REMOVE) {
@Override
public void run(){
int[] sel = tVerr.getSelectionIndices();
for (int i : sel) {
TableItem ti = tVerr.getItem(i);
Verrechnet v = (Verrechnet) ti.getData();
AcquireLockUi.aquireAndRun(v, new LockDeniedNoActionLockHandler() {
@Override
public void lockAcquired(){
Result<Verrechnet> result = ((Konsultation) ElexisEventDispatcher
.getSelected(Konsultation.class)).removeLeistung(v);
if (!result.isOK()) {
SWTHelper.alert(
Messages.VerrechnungsDisplay_PositionCanootBeRemoved, result //$NON-NLS-1$
.toString());
}
}
});
}
setLeistungen((Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class));
}
};
removeAllAction = new Action(REMOVEALL) {
@Override
public void run(){
TableItem[] items = tVerr.getItems();
for (TableItem ti : items) {
Verrechnet v = (Verrechnet) ti.getData();
if (!v.getKons().isEditable(true)) {
return;
}
AcquireLockUi.aquireAndRun(v, new LockDeniedNoActionLockHandler() {
@Override
public void lockAcquired(){
Result<Verrechnet> result = ((Konsultation) ElexisEventDispatcher
.getSelected(Konsultation.class)).removeLeistung(v);
if (!result.isOK()) {
SWTHelper.alert(
Messages.VerrechnungsDisplay_PositionCanootBeRemoved, result //$NON-NLS-1$
.toString());
}
}
});
}
setLeistungen((Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class));
}
};
chPriceAction = new Action(CHPRICE) {
@Override
public void run(){
int sel = tVerr.getSelectionIndex();
TableItem ti = tVerr.getItem(sel);
Verrechnet v = (Verrechnet) ti.getData();
if(!v.getKons().isEditable(true)) {
return;
}
AcquireLockUi.aquireAndRun(v, new LockDeniedNoActionLockHandler() {
@Override
public void lockAcquired(){
Money oldPrice = v.getBruttoPreis();
String p = oldPrice.getAmountAsString();
InputDialog dlg = new InputDialog(UiDesk.getTopShell(),
Messages.VerrechnungsDisplay_changePriceForService, //$NON-NLS-1$
Messages.VerrechnungsDisplay_enterNewPrice, p, //$NON-NLS-1$
null);
if (dlg.open() == Dialog.OK) {
try {
String val = dlg.getValue().trim();
Money newPrice = new Money(oldPrice);
if (val.endsWith("%") && val.length() > 1) { //$NON-NLS-1$
val = val.substring(0, val.length() - 1);
double percent = Double.parseDouble(val);
double factor = 1.0 + (percent / 100.0);
v.setSecondaryScaleFactor(factor);
} else {
newPrice = new Money(val);
v.setTP(newPrice.getCents());
v.setSecondaryScaleFactor(1);
}
// v.setPreis(newPrice);
setLeistungen(
(Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class));
} catch (ParseException ex) {
SWTHelper.showError(Messages.VerrechnungsDisplay_badAmountCaption, //$NON-NLS-1$
Messages.VerrechnungsDisplay_badAmountBody); //$NON-NLS-1$
}
}
}
});
}
};
chCountAction = new Action(CHCOUNT) {
@Override
public void run(){
int sel = tVerr.getSelectionIndex();
TableItem ti = tVerr.getItem(sel);
Verrechnet v = (Verrechnet) ti.getData();
if(!v.getKons().isEditable(true)) {
return;
}
String p = Integer.toString(v.getZahl());
AcquireLockUi.aquireAndRun(v, new LockDeniedNoActionLockHandler() {
@Override
public void lockAcquired(){
changeQuantityDialog(p, v);
}
});
}
};
chTextAction = new Action(CHTEXT) {
@Override
public void run(){
int sel = tVerr.getSelectionIndex();
TableItem ti = tVerr.getItem(sel);
Verrechnet v = (Verrechnet) ti.getData();
if(!v.getKons().isEditable(true)) {
return;
}
AcquireLockUi.aquireAndRun(v, new LockDeniedNoActionLockHandler() {
@Override
public void lockAcquired(){
String oldText = v.getText();
InputDialog dlg = new InputDialog(UiDesk.getTopShell(),
Messages.VerrechnungsDisplay_changeTextCaption, //$NON-NLS-1$
Messages.VerrechnungsDisplay_changeTextBody, //$NON-NLS-1$
oldText, null);
if (dlg.open() == Dialog.OK) {
String input = dlg.getValue();
if (input.matches("[0-9\\.,]+")) { //$NON-NLS-1$
if (!SWTHelper.askYesNo(
Messages.VerrechnungsDisplay_confirmChangeTextCaption, //$NON-NLS-1$
Messages.VerrechnungsDisplay_confirmChangeTextBody)) { //$NON-NLS-1$
return;
}
}
v.setText(input);
setLeistungen((Konsultation) ElexisEventDispatcher
.getSelected(Konsultation.class));
}
}
});
}
};
}
private Verrechnet loadSelectedVerrechnet(){
int sel = tVerr.getSelectionIndex();
TableItem ti = tVerr.getItem(sel);
return (Verrechnet) ti.getData();
}
private void changeQuantityDialog(String p, Verrechnet v){
InputDialog dlg =
new InputDialog(UiDesk.getTopShell(), Messages.VerrechnungsDisplay_changeNumberCaption, //$NON-NLS-1$
Messages.VerrechnungsDisplay_changeNumberBody, //$NON-NLS-1$
p, null);
if (dlg.open() == Dialog.OK) {
try {
String val = dlg.getValue();
if (!StringTool.isNothing(val)) {
int changeAnzahl;
double secondaryScaleFactor = 1.0;
String text = v.getVerrechenbar().getText();
if (val.indexOf(StringConstants.SLASH) > 0) {
changeAnzahl = 1;
String[] frac = val.split(StringConstants.SLASH);
secondaryScaleFactor =
Double.parseDouble(frac[0]) / Double.parseDouble(frac[1]);
text = v.getText() + " (" + val //$NON-NLS-1$
+ Messages.VerrechnungsDisplay_Orininalpackungen;
} else if (val.indexOf('.') > 0) {
changeAnzahl = 1;
secondaryScaleFactor = Double.parseDouble(val);
text = v.getText() + " (" + Double.toString(secondaryScaleFactor) + ")";
} else {
changeAnzahl = Integer.parseInt(dlg.getValue());
}
IStatus ret = v.changeAnzahlValidated(changeAnzahl);
if (ret.isOK()) {
v.setSecondaryScaleFactor(secondaryScaleFactor);
v.setText(text);
} else {
SWTHelper.showError(Messages.VerrechnungsDisplay_error, ret.getMessage());
}
}
setLeistungen((Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class));
} catch (NumberFormatException ne) {
SWTHelper.showError(Messages.VerrechnungsDisplay_invalidEntryCaption, //$NON-NLS-1$
Messages.VerrechnungsDisplay_invalidEntryBody); //$NON-NLS-1$
}
}
}
@Override
public void setUnlocked(boolean unlocked) {
setEnabled(unlocked);
redraw();
}
}