package ch.elexis.data; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.elexis.core.types.LabItemTyp; import ch.rgw.tools.JdbcLink; import ch.rgw.tools.VersionInfo; public class LabMapping extends PersistentObject { private static Logger logger = LoggerFactory.getLogger(LabMapping.class); public static final String TABLENAME = "at_medevit_elexis_labmap"; //$NON-NLS-1$ public static final String VERSION = "1.0.0"; //$NON-NLS-1$ public static final String VERSIONID = "VERSION"; //$NON-NLS-1$ public static final String FLD_ORIGINID = "originid"; //$NON-NLS-1$ public static final String FLD_ITEMNAME = "itemname"; //$NON-NLS-1$ public static final String FLD_LABITEMID = "labitemid"; //$NON-NLS-1$ public static final String FLD_CHARGE = "charge"; //$NON-NLS-1$ private static StringBuilder notImported = new StringBuilder(); private static int importerLabItemsCreated = 0; // @formatter:off static final String create = "CREATE TABLE " + TABLENAME + " (" + //$NON-NLS-1$ //$NON-NLS-2$ "ID VARCHAR(25) primary key, " + //$NON-NLS-1$ "lastupdate BIGINT," + //$NON-NLS-1$ "deleted CHAR(1) default '0'," + //$NON-NLS-1$ "itemname VARCHAR(255)," + //$NON-NLS-1$ "originid VARCHAR(128)," + //$NON-NLS-1$ "labitemid VARCHAR(128)," + //$NON-NLS-1$ "charge CHAR(1)" + //$NON-NLS-1$ ");" + //$NON-NLS-1$ "CREATE INDEX loincmap1 ON " + TABLENAME + " (" + FLD_ORIGINID + ");" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ "CREATE INDEX loincmap2 ON " + TABLENAME + " (" + FLD_ITEMNAME + ");" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ "INSERT INTO " + TABLENAME + " (ID," + FLD_LABITEMID + ") VALUES (" + JdbcLink.wrap(VERSIONID) + "," + JdbcLink.wrap(VERSION) + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ // @formatter:on static { addMapping(TABLENAME, FLD_ITEMNAME, FLD_ORIGINID, FLD_LABITEMID, FLD_CHARGE); if (!tableExists(TABLENAME)) { createOrModifyTable(create); } else { LabMapping version = load(VERSIONID); VersionInfo vi = new VersionInfo(version.get(FLD_LABITEMID)); if (vi.isOlder(VERSION)) { // we should update eg. with createOrModifyTable(update.sql); // And then set the new version version.set(FLD_LABITEMID, VERSION); } } } public LabMapping(){ // TODO Auto-generated constructor stub } public LabMapping(String id){ super(id); } public static LabMapping load(final String id){ return new LabMapping(id); } public LabMapping(String contactId, String itemName, String labItemId, boolean charge){ LabMapping existing = getByContactAndItemName(contactId, itemName); if (existing != null) { throw new IllegalArgumentException( String .format( "Mapping for origin id [%s] - [%s] already exists can not create multiple instances.", //$NON-NLS-1$ contactId, itemName)); } create(null); set(FLD_ORIGINID, contactId); set(FLD_ITEMNAME, itemName); set(FLD_LABITEMID, labItemId); setCharge(charge); } public void setCharge(boolean charge){ set(FLD_CHARGE, charge ? "1" : "0"); //$NON-NLS-1$ //$NON-NLS-2$ } public boolean isCharge(){ String chargeStr = checkNull(get(FLD_CHARGE)); if (chargeStr.isEmpty()) { return false; } else { return chargeStr.equals("1"); //$NON-NLS-1$ } } public LabItem getLabItem(){ String labItemId = checkNull(get(FLD_LABITEMID)); if (labItemId.isEmpty()) { return null; } else { LabItem ret = LabItem.load(labItemId); if (ret.exists()) { return ret; } else { logger.error(String.format("LabItem [%s] does not exist.", get(FLD_LABITEMID))); //$NON-NLS-1$ return ret; } } } public Kontakt getOrigin(){ String originId = checkNull(get(FLD_ORIGINID)); if (originId.isEmpty()) { return null; } else { Kontakt ret = Kontakt.load(originId); if (ret.exists()) { return ret; } else { logger.error(String.format("Kontakt [%s] does not exist.", get(FLD_ORIGINID))); //$NON-NLS-1$ return ret; } } } public String getItemName(){ return checkNull(get(FLD_ITEMNAME)); } public void setItemName(String itemName){ set(FLD_ITEMNAME, itemName); } @Override public String getLabel(){ LabItem item = LabItem.load(get(FLD_LABITEMID)); if (item.exists()) { return String.format("%s - %s -> %s", get(FLD_ORIGINID), get(FLD_ITEMNAME), //$NON-NLS-1$ item.getLabel()); } else { return String.format("%s - %s -> item [%s] does not exist.", get(FLD_ORIGINID), //$NON-NLS-1$ get(FLD_ITEMNAME), get(FLD_LABITEMID)); } } @Override protected String getTableName(){ return TABLENAME; } /** * Test if the mapping is valid. Checking {@link LabItem}, item name and origin. * * @return */ public boolean isMappingValid(){ LabItem item = getLabItem(); if (item == null || !item.exists()) { return false; } String itemName = getItemName(); if (itemName == null || itemName.isEmpty()) { return false; } Kontakt origin = getOrigin(); if (origin == null || !origin.exists()) { return false; } return true; } public static LabMapping getByContactAndItemName(String contactId, String itemName){ Query<LabMapping> qbe = new Query<LabMapping>(LabMapping.class); qbe.add("ID", Query.NOT_EQUAL, VERSIONID); //$NON-NLS-1$ qbe.add(FLD_ORIGINID, Query.EQUALS, contactId); qbe.add(FLD_ITEMNAME, Query.EQUALS, itemName); List<LabMapping> res = qbe.execute(); if (res.isEmpty()) { return null; } else { if (res.size() > 1) { throw new IllegalArgumentException(String.format( "Found more then 1 mapping for origin id [%s] - [%s]", contactId, itemName)); //$NON-NLS-1$ } return res.get(0); } } public static LabMapping getByContactAndItemId(String contactId, String itemId){ Query<LabMapping> qbe = new Query<LabMapping>(LabMapping.class); qbe.add("ID", Query.NOT_EQUAL, VERSIONID); //$NON-NLS-1$ qbe.add(FLD_ORIGINID, Query.EQUALS, contactId); qbe.add(FLD_LABITEMID, Query.EQUALS, itemId); List<LabMapping> res = qbe.execute(); if (res.isEmpty()) { return null; } else { if (res.size() > 1) { logger.warn(String.format("Found [%s] mappings for origin id [%s] and item id [%s]", res.size(), contactId, itemId)); logger.info( String.format("Using mapping with item name [%s]", res.get(0).getItemName())); } return res.get(0); } } public static List<LabMapping> getByLabItemId(String labItemId){ Query<LabMapping> qbe = new Query<LabMapping>(LabMapping.class); qbe.add("ID", Query.NOT_EQUAL, VERSIONID); //$NON-NLS-1$ qbe.add(FLD_LABITEMID, Query.EQUALS, labItemId); return qbe.execute(); } /** * Create or update the mapping table. The CSV format is as follows <br\> * * <pre> * CONTACT_NAME;CONTACT_ITEMNAME;LOINCCODE;LABITEM_NAME;LABITEM_SHORTNAME;LABITEM_REFM; * LABITEM_REFF;LABITEM_UNIT;LABITEM_TYP;LABITEM_GROUP;LABITEM_BILLINGCODE * </pre> * * Possible values for LABITEM_TYP -> numeric,absolute,text <br\> * * @param csv * @throws IOException */ public static void importMappingFromCsv(InputStream csv) throws IOException{ BufferedReader reader = new BufferedReader(new InputStreamReader(csv)); notImported.setLength(0); importerLabItemsCreated = 0; String line; while ((line = reader.readLine()) != null) { String[] parts = line.split(";", -1); //$NON-NLS-1$ if (parts.length < 10) { String reason = String.format(Messages.LabMapping_reasonLineNotValid, line, parts.length); logger.warn(reason); notImported.append(line); notImported.append(" -> "); //$NON-NLS-1$ notImported.append(reason); notImported.append("\n"); //$NON-NLS-1$ continue; } else if (parts[0].equalsIgnoreCase("CONTACT_NAME")) { //$NON-NLS-1$ // skip description line continue; } Labor labor = null; List<Labor> origins = lookupLabor(parts[0]); if (origins.isEmpty()) { logger.warn(String.format("Could not find labor with name [%s]", parts[0])); //$NON-NLS-1$ labor = createLabor(parts[0]); } else if (origins.size() > 1) { String reason = String.format(Messages.LabMapping_reasonMoreContacts, parts[0]); logger.warn(reason); notImported.append(line); notImported.append(" -> "); //$NON-NLS-1$ notImported.append(reason); notImported.append("\n"); //$NON-NLS-1$ continue; } else { labor = origins.get(0); } String laborItemName = parts[1]; String labItemLoinc = parts[2]; String labItemName = parts[3]; String labItemShort = parts[4]; String labItemRefM = parts[5]; String labItemRefF = parts[6]; String labItemUnit = parts[7]; String labItemTyp = parts[8]; String labItemGroup = parts[9]; String labItemBillingCode = ""; if (parts.length > 10) { labItemBillingCode = parts[10]; } if (laborItemName == null || laborItemName.isEmpty() || labItemName == null || labItemName.isEmpty() || labItemShort == null || labItemShort.isEmpty()) { String reason = Messages.LabMapping_reasonDefinitionNotValid; logger.warn(reason); notImported.append(line); notImported.append(" -> "); //$NON-NLS-1$ notImported.append(reason); notImported.append("\n"); //$NON-NLS-1$ continue; } LabItem labItem = null; List<LabItem> items = lookupLabItem(labItemLoinc, labor.getId(), labItemShort, labItemRefM, labItemRefF, labItemUnit); if (items.isEmpty()) { logger.warn(String.format( "Could not find labor item with loinc [%s] and shortname [%s]", labItemLoinc, //$NON-NLS-1$ labItemShort)); labItem = createLabItem(labor.getId(), labItemName, labItemShort, labItemRefM, labItemRefF, labItemUnit, labItemTyp, labItemGroup, labItemLoinc, labItemBillingCode); } else if (origins.size() > 1) { String reason = String.format(Messages.LabMapping_reasonMoreLabItems, labItemLoinc, labItemShort); logger.warn(reason); notImported.append(line); notImported.append(" -> "); //$NON-NLS-1$ notImported.append(reason); notImported.append("\n"); //$NON-NLS-1$ continue; } else { labItem = items.get(0); } LabMapping existing = LabMapping.getByContactAndItemName(labor.getId(), laborItemName); if (existing != null) { logger.info(String.format("Merging mapping [%s] - [%s] -> [%s] - [%s]", //$NON-NLS-1$ labor.getKuerzel(), laborItemName, labItemLoinc, labItemShort)); mergeMapping(labor, laborItemName, labItem); } else { logger.info(String.format("Creating mapping [%s] - [%s] -> [%s] - [%s]", //$NON-NLS-1$ labor.getKuerzel(), laborItemName, labItemLoinc, labItemShort)); createMapping(labor, parts[1], labItem); } } if (notImported.length() > 0) { throw new IOException(notImported.toString()); } } private static LabItem createLabItem(String laborId, String labItemName, String labItemShort, String labItemRefM, String labItemRefF, String labItemUnit, String labItemTyp, String labItemGroup, String labItemLoinc, String labItemBillingCode){ logger.warn(String.format( "Creating new labor item with name [%s] and shortname [%s] loinc [%s]", labItemName, //$NON-NLS-1$ labItemShort, labItemLoinc)); LabItem item = new LabItem(labItemShort, labItemName, Labor.load(laborId), labItemRefM, labItemRefF, labItemUnit, getLabItemTyp(labItemTyp), labItemGroup, Integer.toString(importerLabItemsCreated++)); if (labItemLoinc != null && !labItemLoinc.isEmpty()) { item.setLoincCode(labItemLoinc); } if (labItemBillingCode != null && !labItemBillingCode.isEmpty()) { item.setBillingCode(labItemBillingCode); } return item; } private static LabItemTyp getLabItemTyp(String labItemTyp){ if (labItemTyp.equalsIgnoreCase("numeric")) { //$NON-NLS-1$ return LabItemTyp.NUMERIC; } else if (labItemTyp.equalsIgnoreCase("absolute")) { //$NON-NLS-1$ return LabItemTyp.ABSOLUTE; } else if (labItemTyp.equalsIgnoreCase("text")) { //$NON-NLS-1$ return LabItemTyp.TEXT; } return LabItemTyp.NUMERIC; } private static Labor createLabor(String labName){ logger.warn("Creating new labor with name [" + labName + "]"); //$NON-NLS-1$ //$NON-NLS-2$ return new Labor(labName, "Labor " + labName); //$NON-NLS-1$ } private static List<Labor> lookupLabor(String labName){ Query<Labor> qbe = new Query<Labor>(Labor.class); qbe.add(Kontakt.FLD_NAME1, Query.LIKE, "%" + labName + "%"); //$NON-NLS-1$ //$NON-NLS-2$ List<Labor> list = qbe.execute(); return list; } private static List<LabItem> lookupLabItem(String loinc, String laborId, String shortDesc, String refM, String refW, String unit){ // lookup using loinc first ... List<LabItem> labItems = null; if (loinc != null && !loinc.isEmpty()) { Query<LabItem> qli = new Query<LabItem>(LabItem.class); qli.add(LabItem.LOINCCODE, "=", loinc.trim()); //$NON-NLS-1$ labItems = qli.execute(); if (labItems.size() == 1) { return labItems; } } return lookupLabItem(laborId, shortDesc, refM, refW, unit); } private static List<LabItem> lookupLabItem(String laborId, String shortDesc, String refM, String refW, String unit){ // dont use laborId of LabItem ... it is in the mappings now List<LabItem> items = LabItem.getLabItems(null, shortDesc, refM, refW, unit); if (!items.isEmpty()) { ArrayList<LabItem> ret = new ArrayList<LabItem>(); for (LabItem labItem : items) { List<LabMapping> mappings = getByLabItemId(labItem.getId()); for (LabMapping labMapping : mappings) { if (labMapping.get(LabMapping.FLD_ORIGINID).equals(laborId)) { ret.add(labItem); } } } return ret; } return items; } private static void createMapping(Kontakt origin, String itemName, LabItem item){ new LabMapping(origin.getId(), itemName, item.getId(), false); } private static void mergeMapping(Kontakt origin, String itemName, LabItem item){ LabMapping mapping = getByContactAndItemName(origin.getId(), itemName); mapping.set(LabMapping.FLD_LABITEMID, item.getId()); } }