Skip to content

Commit

Permalink
[25926] add optional lookup of missing vat rates for tarmed 45 export
Browse files Browse the repository at this point in the history
  • Loading branch information
huthomas committed Dec 18, 2023
1 parent fc8b431 commit 74dd288
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ch.elexis.base.ch.arzttarife.xml.exporter;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;

Expand All @@ -16,8 +17,8 @@ public class ServicesFinancialInfo {

private VatRateSum vatRateSum;

public static ServicesFinancialInfo of(ServicesType services) {
ServicesFinancialInfo ret = new ServicesFinancialInfo();
public static ServicesFinancialInfo of(ServicesType services, LocalDate localDate) {
ServicesFinancialInfo ret = new ServicesFinancialInfo(localDate);

for (Object obj : services.getServiceExOrService()) {
if (obj instanceof ServiceExType) {
Expand All @@ -38,9 +39,9 @@ public static ServicesFinancialInfo of(ServicesType services) {
return ret;
}

public ServicesFinancialInfo() {
public ServicesFinancialInfo(LocalDate localDate) {
tariffSum = new HashMap<>();
vatRateSum = new VatRateSum();
vatRateSum = new VatRateSum(localDate);
obligationSum = 0.0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ protected String getModus(ICoverage coverage) {
protected Object getBalance(IInvoice invoice) {
Tiers tiersType = CoverageServiceHolder.get().getTiersType(invoice.getCoverage());

ServicesFinancialInfo financialInfo = ServicesFinancialInfo.of(getServices(invoice));
ServicesFinancialInfo financialInfo = ServicesFinancialInfo.of(getServices(invoice), invoice.getDateFrom());

if (tiersType == Tiers.GARANT) {
BalanceTGType balanceTGType = new BalanceTGType();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,73 @@
package ch.elexis.base.ch.arzttarife.xml.exporter;

import java.time.LocalDate;
import java.util.HashMap;

import ch.rgw.tools.Money;

public class VatRateSum {

private HashMap<Double, VatRateElement> rates;
private double sumvat = 0.0;

private LocalDate invoiceStartDate;

public VatRateSum(LocalDate localDate) {
rates = new HashMap<Double, VatRateElement>();
invoiceStartDate = localDate;
}

public void add(double scale, double amount) {
VatRateElement element = rates.get(Double.valueOf(scale));
if (element == null) {
element = new VatRateElement(scale);
rates.put(Double.valueOf(scale), element);
}
element.add(amount);
sumvat += ((amount / (100.0 + scale)) * scale);
}

public Money getSumVat() {
return new Money(sumvat);
}

public HashMap<Double, VatRateElement> getRates() {
// add missing rates to show correct values on bill
if (VatUtil.isVatAvailable()) {
if (isNormalRateMissing()) {
String normalRate = VatUtil.getNormalRateFromConfig(invoiceStartDate);
if(normalRate != null) {
try {
Double scale = Double.valueOf(normalRate);
rates.put(scale, new VatRateElement(scale));
} catch (Exception e) {
// ignore
}
}
}
if (isReducedRateMissing()) {
String reducedRate = VatUtil.getReducedRateFromConfig(invoiceStartDate);
if (reducedRate != null) {
try {
Double scale = Double.valueOf(reducedRate);
rates.put(scale, new VatRateElement(scale));
} catch (Exception e) {
// ignore
}
}
}
}
return rates;
}

private boolean isReducedRateMissing() {
return rates.keySet().stream().filter(vatRate -> VatUtil.guessVatCode(vatRate) == 2).findAny().isEmpty();
}

private boolean isNormalRateMissing() {
return rates.keySet().stream().filter(vatRate -> VatUtil.guessVatCode(vatRate) == 1).findAny().isEmpty();
}

public static class VatRateElement implements Comparable<VatRateElement> {
private double scale;
private double sumamount;
Expand Down Expand Up @@ -44,25 +106,4 @@ public Money getVat() {
return new Money(sumvat);
}
}

private HashMap<Double, VatRateElement> rates = new HashMap<Double, VatRateElement>();
private double sumvat = 0.0;

public void add(double scale, double amount) {
VatRateElement element = rates.get(Double.valueOf(scale));
if (element == null) {
element = new VatRateElement(scale);
rates.put(new Double(scale), element);
}
element.add(amount);
sumvat += ((amount / (100.0 + scale)) * scale);
}

public Money getSumVat() {
return new Money(sumvat);
}

public HashMap<Double, VatRateElement> getRates() {
return rates;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package ch.elexis.base.ch.arzttarife.xml.exporter;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import ch.elexis.core.services.IConfigService;
import ch.elexis.core.services.holder.ConfigServiceHolder;
import ch.rgw.tools.TimeTool;

/**
* Provides access to the configured vat values. Vat values are implemented in
* at.medevit.medelexis.vat_ch. No direct dependency is possible as
* at.medevit.medelexis.vat_ch is locate in a closed source repository.
*
*/
public class VatUtil {

public static final String VAT_VALUE_WITH_DATE = "at.medevit.medelexis.vat_ch/ValueWithDate";

public static boolean isVatAvailable() {
return !readDateableConfigValue(ConfigServiceHolder.get()).isEmpty();
}

/**
* Get the normal vat rate at the date. Value is set by
* at.medevit.medelexis.vat_ch.util.VatUtil.
*
* @param perfConstant
* @param date
* @return
*/
public static String getNormalRateFromConfig(LocalDate date) {
if (date != null) {
return getCurrentValueFromConfig(date, 1);
}
return null;
}

/**
* Get the reduced vat rate at the date. Value is set by
* at.medevit.medelexis.vat_ch.util.VatUtil.
*
* @param perfConstant
* @param date
* @return
*/
public static String getReducedRateFromConfig(LocalDate date) {
if (date != null) {
return getCurrentValueFromConfig(date, 2);
}
return null;
}

/**
* Returns the first matching value with is after date x.
*
* @param configValue
* @param date
* @param intValIdx
* @return
*/
private static String getCurrentValueFromConfig(LocalDate date, int intValIdx) {
List<String> values = readDateableConfigValue(ConfigServiceHolder.get());

values.sort((l, r) -> {
String[] lsplits = l.split("::");
String[] rsplits = r.split("::");
if (!lsplits[0].isEmpty() && !rsplits[0].isEmpty()) {
LocalDate lDate = new TimeTool(lsplits[0]).toLocalDate();
LocalDate rDate = new TimeTool(rsplits[0]).toLocalDate();
return rDate.compareTo(lDate);
} else if (!lsplits[0].isEmpty() || !rsplits[0].isEmpty()) {
if (!lsplits[0].isEmpty()) {
return -1;
} else {
return 1;
}
}
return 0;
});

for (String s : values) {
String[] splits = s.split("::");
if (splits.length == 3) {
String dateAsString = splits[0];
if (!dateAsString.isEmpty()) {
LocalDate configDate = new TimeTool(dateAsString).toLocalDate();
boolean isAfter = date.isAfter(configDate) || date.equals(configDate);
if (isAfter) {
return splits[intValIdx];
}
} else {
// no date specified - for legacy propose
return splits[intValIdx];
}
}
}

return null;
}

private static List<String> readDateableConfigValue(IConfigService configService) {
List<String> configValues = new ArrayList<>();
String rawValue = configService.get(VAT_VALUE_WITH_DATE, null);
if (StringUtils.isBlank(rawValue)) {
return configValues;
}
String[] configValue = rawValue.split(",");

if (configValue != null) {
configValues.addAll(Arrays.asList(configValue));
for (String s : configValue) {
if (s.startsWith("::")) {
break;
}
}
}
return configValues;
}

public static int guessVatCode(Double vatRate) {
if (vatRate != null) {
// make a guess for the correct code
if (vatRate == 0)
return 0;
else if (vatRate < 7)
return 2;
else
return 1;
}
return 0;
}
}

0 comments on commit 74dd288

Please sign in to comment.