Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[transform.vat] Initial contribution #14529

Merged
merged 1 commit into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@
/bundles/org.openhab.transform.regex/ @openhab/add-ons-maintainers
/bundles/org.openhab.transform.rollershutterposition/ @jsjames
/bundles/org.openhab.transform.scale/ @clinique
/bundles/org.openhab.transform.vat/ @jlaur
/bundles/org.openhab.transform.xpath/ @openhab/add-ons-maintainers
/bundles/org.openhab.transform.xslt/ @openhab/add-ons-maintainers
/bundles/org.openhab.voice.googlestt/ @GiviMAD
Expand Down
5 changes: 5 additions & 0 deletions bom/openhab-addons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2001,6 +2001,11 @@
<artifactId>org.openhab.transform.scale</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.transform.vat</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.transform.xpath</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions bundles/org.openhab.transform.vat/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.

* Project home: https://www.openhab.org

== Declared Project Licenses

This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.

== Source Code

https://github.com/openhab/openhab-addons
41 changes: 41 additions & 0 deletions bundles/org.openhab.transform.vat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# VAT Transformation Service

The VAT Transformation Service adds VAT (Value-Added Tax) to a given input amount.
The input string must be either an ISO 3166 alpha-2 country code or a percentage, i.e. numerical format.

## Examples

### Display

```java
Number CurrentSpotPrice "Current Spot Price incl. VAT [VAT(12.5):%s]" <price>
```

### In a Rule

Add Danish VAT to price:

```java
var Number price = 499
logInfo("Price", "Price incl. VAT: " + transform("VAT", "DK", price.toString))
```

## Usage as a Profile

The functionality of this `TransformationService` can also be used in a `Profile` on an `ItemChannelLink`.
This is the most powerful usage since VAT will be added without providing any explicit country code, percentage or configuration.
To use this, an `.items` file can be configured as follows:

```java
Number CurrentSpotPrice "Current Spot Price" <price> { channel="<channelUID>" [profile="transform:VAT"] }
```

To override VAT percentage for configured system country:

```java
Number CurrentSpotPrice "Current Spot Price" <price> { channel="<channelUID>" [profile="transform:VAT", percentage="12.5"] }
```

If VAT is not known for the configured country or the provided percentage is invalid, the default is 0%, so the input value will be put into the transformation without any changes.

Please note: This profile is a one-way transformation, i.e. only values from a device towards the item are changed, the other direction is left untouched.
17 changes: 17 additions & 0 deletions bundles/org.openhab.transform.vat/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>4.0.0-SNAPSHOT</version>
</parent>

<artifactId>org.openhab.transform.vat</artifactId>

<name>openHAB Add-ons :: Bundles :: Transformation Service :: Value-Added Tax</name>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.transform.vat-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>

<feature name="openhab-transformation-vat" description="Value-Added Tax Transformation" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="75">mvn:org.openhab.addons.bundles/org.openhab.transform.vat/${project.version}</bundle>
</feature>
</features>
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.transform.vat.internal;

import java.util.Map;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.profiles.ProfileTypeUID;
import org.openhab.core.transform.TransformationService;

/**
* The {@link VATTransformationConstants} class defines constants
* used across the whole profile.
*
* @author Jacob Laursen - Initial contribution
*/
@NonNullByDefault
public class VATTransformationConstants {

public static final ProfileTypeUID PROFILE_TYPE_UID = new ProfileTypeUID(
TransformationService.TRANSFORM_PROFILE_SCOPE, "VAT");

public static final Map<String, String> RATES = Map.ofEntries(
// European Union countries
Map.entry("AT", "20"), // Austria
Map.entry("BE", "21"), // Belgium
Map.entry("BG", "20"), // Bulgaria
Map.entry("HR", "25"), // Croatia
Map.entry("CY", "19"), // Cyprus
Map.entry("CZ", "21"), // Czech Republic
Map.entry("DK", "25"), // Denmark
Map.entry("EE", "20"), // Estonia
Map.entry("FI", "24"), // Finland
Map.entry("FR", "20"), // France
Map.entry("DE", "19"), // Germany
Map.entry("GR", "24"), // Greece
Map.entry("HU", "27"), // Hungary
Map.entry("IE", "23"), // Ireland
Map.entry("IT", "22"), // Italy
Map.entry("LV", "21"), // Latvia
Map.entry("LT", "21"), // Lithuania
Map.entry("LU", "17"), // Luxembourg
Map.entry("MT", "18"), // Malta
Map.entry("NL", "21"), // Netherlands
Map.entry("PL", "23"), // Poland
Map.entry("PT", "23"), // Portugal
Map.entry("RO", "19"), // Romania
Map.entry("SK", "20"), // Slovakia
Map.entry("SI", "22"), // Slovenia
Map.entry("ES", "21"), // Spain
Map.entry("SE", "25"), // Sweden

// Non-European Union countries
Map.entry("AL", "20"), // Albania
Map.entry("DZ", "19"), // Algeria
Map.entry("AD", "4.5"), // Andorra
Map.entry("AO", "14"), // Angola
Map.entry("AG", "15"), // Antigua and Barbuda
Map.entry("AR", "21"), // Argentina
Map.entry("AM", "20"), // Armenia
Map.entry("AU", "10"), // Australia
Map.entry("AZ", "18"), // Azerbaijan
Map.entry("BS", "12"), // Bahamas
Map.entry("BH", "10"), // Bahrain
Map.entry("BD", "15"), // Bangladesh
Map.entry("BB", "17.5"), // Barbados
Map.entry("BY", "20"), // Belarus
Map.entry("BZ", "12.5"), // Belize
Map.entry("BJ", "18"), // Benin
Map.entry("BO", "13"), // Bolivia
Map.entry("BA", "17"), // Bosnia and Herzegovina
Map.entry("BW", "12"), // Botswana
Map.entry("BR", "20"), // Brazil
Map.entry("BF", "18"), // Burkina Faso
Map.entry("BI", "18"), // Burundi
Map.entry("KH", "10"), // Cambodia
Map.entry("CM", "19.25"), // Cameroon
Map.entry("CA", "5"), // Canada
Map.entry("CV", "15"), // Cape Verde
Map.entry("CF", "19"), // Central African Republic
Map.entry("TD", "18"), // Chad
Map.entry("CL", "19"), // Chile
Map.entry("CN", "13"), // China
Map.entry("CO", "19"), // Colombia
Map.entry("CR", "13"), // Costa Rica
Map.entry("CD", "16"), // Democratic Republic of the Congo
Map.entry("DM", "15"), // Dominica
Map.entry("DO", "18"), // Dominican Republic
Map.entry("EC", "12"), // Ecuador
Map.entry("EG", "14"), // Egypt
Map.entry("SV", "13"), // El Salvador
Map.entry("GQ", "15"), // Equatorial Guinea
Map.entry("ET", "15"), // Ethiopia
Map.entry("FO", "25"), // Faroe Islands
Map.entry("FJ", "15"), // Fiji
Map.entry("GA", "18"), // Gabon
Map.entry("GM", "15"), // Gambia
Map.entry("GE", "18"), // Georgia
Map.entry("GH", "15"), // Ghana
Map.entry("GD", "15"), // Grenada
Map.entry("GT", "12"), // Guatemala
Map.entry("GN", "18"), // Guinea
Map.entry("GW", "15"), // Guinea-Bissau
Map.entry("GY", "16"), // Guyana
Map.entry("HT", "10"), // Haiti
Map.entry("HN", "15"), // Honduras
Map.entry("IS", "24"), // Iceland
Map.entry("IN", "5.5"), // India
Map.entry("ID", "11"), // Indonesia
Map.entry("IR", "9"), // Iran
Map.entry("IM", "20"), // Isle of Man
Map.entry("IL", "17"), // Israel
Map.entry("CI", "18"), // Ivory Coast
Map.entry("JM", "12.5"), // Jamaica
Map.entry("JP", "10"), // Japan
Map.entry("JE", "5"), // Jersey
Map.entry("JO", "16"), // Jordan
Map.entry("KZ", "12"), // Kazakhstan
Map.entry("KE", "16"), // Kenya
Map.entry("KG", "20"), // Kyrgyzstan
Map.entry("LA", "10"), // Laos
Map.entry("LB", "11"), // Lebanon
Map.entry("LS", "14"), // Lesotho
Map.entry("LI", "7.7"), // Liechtenstein
Map.entry("MG", "20"), // Madagascar
Map.entry("MW", "16.5"), // Malawi
Map.entry("MY", "6"), // Malaysia
Map.entry("MV", "6"), // Maldives
Map.entry("ML", "18"), // Mali
Map.entry("MR", "14"), // Mauritania
Map.entry("MU", "15"), // Mauritius
Map.entry("MX", "16"), // Mexico
Map.entry("MD", "20"), // Moldova
Map.entry("MC", "19.6"), // Monaco
Map.entry("MN", "10"), // Mongolia
Map.entry("ME", "21"), // Montenegro
Map.entry("MA", "20"), // Morocco
Map.entry("MZ", "17"), // Mozambique
Map.entry("NA", "15"), // Namibia
Map.entry("NP", "13"), // Nepal
Map.entry("NZ", "15"), // New Zealand
Map.entry("NI", "15"), // Nicaragua
Map.entry("NE", "19"), // Niger
Map.entry("NG", "7.5"), // Nigeria
Map.entry("NU", "5"), // Niue
Map.entry("MK", "18"), // North Macedonia
Map.entry("NO", "25"), // Norway
Map.entry("PK", "17"), // Pakistan
Map.entry("PW", "10"), // Palau
Map.entry("PS", "16"), // Palestine
Map.entry("PA", "7"), // Panama
Map.entry("PG", "10"), // Papua New Guinea
Map.entry("PY", "10"), // Paraguay
Map.entry("PE", "18"), // Peru
Map.entry("PH", "12"), // Philippines
Map.entry("CG", "16"), // Republic of Congo
Map.entry("RU", "20"), // Russia
Map.entry("RW", "18"), // Rwanda
Map.entry("KN", "17"), // Saint Kitts and Nevis
Map.entry("VC", "15"), // Saint Vincent and the Grenadines
Map.entry("WS", "15"), // Samoa
Map.entry("SA", "15"), // Saudi Arabia
Map.entry("SN", "18"), // Senegal
Map.entry("RS", "20"), // Serbia
Map.entry("SC", "15"), // Seychelles
Map.entry("SL", "15"), // Sierra Leone
Map.entry("SG", "8"), // Singapore
Map.entry("ZA", "15"), // South Africa
Map.entry("KR", "10"), // South Korea
Map.entry("LK", "12"), // Sri Lanka
Map.entry("SD", "17"), // Sudan
Map.entry("CH", "7.7"), // Switzerland
Map.entry("TW", "5"), // Taiwan
Map.entry("TJ", "20"), // Tajikistan
Map.entry("TZ", "18"), // Tanzania
Map.entry("TH", "10"), // Thailand
Map.entry("TG", "18"), // Togo
Map.entry("TO", "15"), // Tonga
Map.entry("TT", "12.5"), // Trinidad and Tobago
Map.entry("TN", "18"), // Tunisia
Map.entry("TR", "18"), // Turkey
Map.entry("TM", "15"), // Turkmenistan
Map.entry("UG", "18"), // Uganda
Map.entry("UA", "20"), // Ukraine
Map.entry("AE", "5"), // United Arab Emirates
Map.entry("GB", "20"), // United Kingdom
Map.entry("UY", ""), // Uruguay
Map.entry("UZ", "12"), // Uzbekistan
Map.entry("VU", "13"), // Vanuatu
Map.entry("VN", "10"), // Vietnam
Map.entry("VE", "12"), // Venezuela
Map.entry("ZM", "16"), // Zambia
Map.entry("ZW", "15") // Zimbabwe
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.transform.vat.internal;

import static org.openhab.transform.vat.internal.VATTransformationConstants.*;

import java.math.BigDecimal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.transform.TransformationException;
import org.openhab.core.transform.TransformationService;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This {@link TransformationService} adds VAT to the input according to configured country.
*
* @author Jacob Laursen - Initial contribution
*/
@NonNullByDefault
@Component(service = { TransformationService.class }, property = { "openhab.transform=VAT" })
public class VATTransformationService implements TransformationService {

private final Logger logger = LoggerFactory.getLogger(VATTransformationService.class);

@Override
public @Nullable String transform(String valueString, String sourceString) throws TransformationException {
QuantityType<?> source;
try {
source = new QuantityType<>(sourceString);
} catch (IllegalArgumentException e) {
logger.warn("Input value '{}' could not be converted to a valid number", sourceString);
throw new TransformationException("VAT Transformation can only be used with numeric inputs", e);
}
BigDecimal value;
try {
value = new BigDecimal(valueString);
} catch (NumberFormatException e) {
String rate = RATES.get(valueString);
if (rate == null) {
logger.warn("Input value '{}' could not be converted to a valid number or country code", valueString);
throw new TransformationException("VAT Transformation can only be used with numeric inputs", e);
}
value = new BigDecimal(rate);
}

return addVAT(source, value).toString();
}

private QuantityType<?> addVAT(QuantityType<?> source, BigDecimal percentage) {
return source.multiply(percentage.divide(new BigDecimal("100")).add(BigDecimal.ONE));
}
}
Loading