From 8c0f55bd7a14d8b617d105e35d6d7ed983c2af36 Mon Sep 17 00:00:00 2001
From: Robert Goldmann <deadlocker@gmx.de>
Date: Sat, 22 May 2021 11:58:33 +0200
Subject: [PATCH] #598 - DatabaseParser_v5 now imports json into backup models
 and offers convert method

---
 .../budgetmaster/database/DatabaseParser.java |   5 +-
 .../database/DatabaseParser_v5.java           | 277 +++++++++++++++---
 .../resources/languages/base_de.properties    |   2 +-
 .../unit/database/DatabaseParserTest.java     |  94 ++++++
 .../unit/database/DatabaseParser_v5Test.java  | 127 +++++++-
 5 files changed, 450 insertions(+), 55 deletions(-)
 create mode 100644 src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParserTest.java

diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java
index fa3d60976..5664f313a 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java
@@ -4,6 +4,7 @@ import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import de.deadlocker8.budgetmaster.database.legacy.LegacyParser;
 import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.database.model.v5.BackupDatabase_v5;
 import de.thecodelabs.utils.util.Localization;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,9 +60,9 @@ public class DatabaseParser
 
 			if(version == 5)
 			{
-				final Database database = new DatabaseParser_v5(jsonString).parseDatabaseFromJSON();
+				final BackupDatabase_v5 database = new DatabaseParser_v5(jsonString).parseDatabaseFromJSON();
 				LOGGER.debug(MessageFormat.format("Parsed database with {0} transactions, {1} categories, {2} accounts, {3} templates and {4} charts", database.getTransactions().size(), database.getCategories().size(), database.getAccounts().size(), database.getTemplates().size(), database.getCharts().size()));
-				return database;
+				return database.convert();
 			}
 
 			throw new IllegalArgumentException(Localization.getString("error.database.import.unknown.version"));
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v5.java b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v5.java
index 39278f140..502f9637b 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v5.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v5.java
@@ -1,12 +1,17 @@
 package de.deadlocker8.budgetmaster.database;
 
 import com.google.gson.*;
-import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.accounts.AccountState;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
-import de.deadlocker8.budgetmaster.charts.Chart;
-import de.deadlocker8.budgetmaster.images.Image;
-import de.deadlocker8.budgetmaster.templates.Template;
+import de.deadlocker8.budgetmaster.database.model.v5.*;
+import de.deadlocker8.budgetmaster.repeating.RepeatingOption;
+import de.deadlocker8.budgetmaster.repeating.endoption.*;
+import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifier;
+import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierType;
+import de.deadlocker8.budgetmaster.tags.Tag;
+import de.thecodelabs.utils.util.Localization;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -14,42 +19,37 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 
-public class DatabaseParser_v5 extends DatabaseParser_v4
+public class DatabaseParser_v5
 {
 	final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
 	private final String jsonString;
 
-	protected List<Chart> charts;
-	protected List<Image> images;
+	private BackupDatabase_v5 database;
 
 	public DatabaseParser_v5(String json)
 	{
-		super(json);
 		this.jsonString = json;
+		this.database = new BackupDatabase_v5();
 	}
 
-	@Override
-	public Database parseDatabaseFromJSON() throws IllegalArgumentException
+	public BackupDatabase_v5 parseDatabaseFromJSON() throws IllegalArgumentException
 	{
-		final JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
-
-		this.images = parseImages(root);
-		super.accounts = parseAccounts(root);
-
-		super.categories = super.parseCategories(root);
-		super.transactions = super.parseTransactions(root);
+		database = new BackupDatabase_v5();
 
-		super.templates = parseTemplates(root);
-
-		this.charts = parseCharts(root);
-
-		return new Database(categories, accounts, transactions, templates, charts, images);
+		final JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
+		database.setImages(parseImages(root));
+		database.setAccounts(parseAccounts(root));
+		database.setCategories(parseCategories(root));
+		database.setTransactions(parseTransactions(root));
+		database.setTemplates(parseTemplates(root));
+		database.setCharts(parseCharts(root));
+
+		return database;
 	}
 
-	@Override
-	protected List<Account> parseAccounts(JsonObject root)
+	private List<BackupAccount_v5> parseAccounts(JsonObject root)
 	{
-		List<Account> parsedAccounts = new ArrayList<>();
+		List<BackupAccount_v5> parsedAccounts = new ArrayList<>();
 		JsonArray accounts = root.get("accounts").getAsJsonArray();
 		for(JsonElement currentAccount : accounts)
 		{
@@ -64,53 +64,148 @@ public class DatabaseParser_v5 extends DatabaseParser_v4
 				accountState = AccountState.valueOf(accountObject.get("accountState").getAsString());
 			}
 
-			Image icon = null;
+			BackupImage_v5 icon = null;
 			if(accountObject.has("icon"))
 			{
 				final Integer iconID = accountObject.get("icon").getAsJsonObject().get("ID").getAsInt();
-				icon = this.images.stream().filter(image -> image.getID().equals(iconID)).findFirst().orElseThrow();
+				icon = database.getImages().stream().filter(image -> image.getID().equals(iconID)).findFirst().orElseThrow();
 			}
 
-			Account parsedAccount = new Account(name, accountType, icon);
-			parsedAccount.setID(ID);
-			parsedAccount.setAccountState(accountState);
-
-			parsedAccounts.add(parsedAccount);
+			parsedAccounts.add(new BackupAccount_v5(ID, name, accountState, accountType, icon));
 		}
 
 		return parsedAccounts;
 	}
 
-	protected List<Chart> parseCharts(JsonObject root)
+	private List<BackupCategory_v5> parseCategories(JsonObject root)
+	{
+		List<BackupCategory_v5> parsedCategories = new ArrayList<>();
+		JsonArray jsonCategories = root.get("categories").getAsJsonArray();
+		for(JsonElement currentCategory : jsonCategories)
+		{
+			BackupCategory_v5 parsedCategory = new Gson().fromJson(currentCategory, BackupCategory_v5.class);
+			parsedCategories.add(parsedCategory);
+		}
+
+		return parsedCategories;
+	}
+
+	private List<BackupTransaction_v5> parseTransactions(JsonObject root)
 	{
-		List<Chart> parsedCharts = new ArrayList<>();
+		List<BackupTransaction_v5> parsedTransactions = new ArrayList<>();
+		JsonArray transactionsToImport = root.get("transactions").getAsJsonArray();
+		for(JsonElement currentTransaction : transactionsToImport)
+		{
+			final JsonObject transactionObject = currentTransaction.getAsJsonObject();
+
+			int amount = transactionObject.get("amount").getAsInt();
+			String name = transactionObject.get("name").getAsString();
+			String description = transactionObject.get("description").getAsString();
+
+			BackupTransaction_v5 transaction = new BackupTransaction_v5();
+			transaction.setAmount(amount);
+			transaction.setName(name);
+			transaction.setDescription(description);
+			transaction.setTags(parseTags(transactionObject));
+
+			int categoryID = transactionObject.get("category").getAsJsonObject().get("ID").getAsInt();
+			transaction.setCategory(getCategoryByID(categoryID));
+
+			int accountID = transactionObject.get("account").getAsJsonObject().get("ID").getAsInt();
+			transaction.setAccount(getAccountByID(accountID));
+
+			JsonElement transferAccount = transactionObject.get("transferAccount");
+			if(transferAccount != null)
+			{
+				int transferAccountID = transferAccount.getAsJsonObject().get("ID").getAsInt();
+				transaction.setTransferAccount(getAccountByID(transferAccountID));
+			}
+
+			String date = transactionObject.get("date").getAsString();
+			DateTime parsedDate = DateTime.parse(date, DateTimeFormat.forPattern("yyyy-MM-dd"));
+			transaction.setDate(parsedDate);
+
+			transaction.setRepeatingOption(parseRepeatingOption(transactionObject, parsedDate));
+
+			handleIsExpenditureForTransactions(transactionObject, transaction);
+
+			parsedTransactions.add(transaction);
+		}
+
+		return parsedTransactions;
+	}
+
+	private RepeatingOption parseRepeatingOption(JsonObject transaction, DateTime startDate)
+	{
+		if(!transaction.has("repeatingOption"))
+		{
+			return null;
+		}
+
+		JsonObject option = transaction.get("repeatingOption").getAsJsonObject();
+
+		JsonObject repeatingModifier = option.get("modifier").getAsJsonObject();
+		String repeatingModifierType = repeatingModifier.get("localizationKey").getAsString();
+
+		RepeatingModifierType type = RepeatingModifierType.getByLocalization(Localization.getString(repeatingModifierType));
+		RepeatingModifier modifier = RepeatingModifier.fromModifierType(type, repeatingModifier.get("quantity").getAsInt());
+
+		JsonObject repeatingEnd = option.get("endOption").getAsJsonObject();
+		String repeatingEndType = repeatingEnd.get("localizationKey").getAsString();
+
+		RepeatingEnd endOption = null;
+		RepeatingEndType endType = RepeatingEndType.getByLocalization(Localization.getString(repeatingEndType));
+		switch(endType)
+		{
+			case NEVER:
+				endOption = new RepeatingEndNever();
+				break;
+			case AFTER_X_TIMES:
+				endOption = new RepeatingEndAfterXTimes(repeatingEnd.get("times").getAsInt());
+				break;
+			case DATE:
+				DateTime endDate = DateTime.parse(repeatingEnd.get("endDate").getAsString(), DateTimeFormat.forPattern("yyyy-MM-dd"));
+				endOption = new RepeatingEndDate(endDate);
+				break;
+		}
+
+		RepeatingOption repeatingOption = new RepeatingOption();
+		repeatingOption.setStartDate(startDate);
+		repeatingOption.setEndOption(endOption);
+		repeatingOption.setModifier(modifier);
+
+		return repeatingOption;
+	}
+
+	private List<BackupChart_v5> parseCharts(JsonObject root)
+	{
+		List<BackupChart_v5> parsedCharts = new ArrayList<>();
 
 		JsonArray chartsToImport = root.get("charts").getAsJsonArray();
 		for(JsonElement currentChart : chartsToImport)
 		{
-			parsedCharts.add(new Gson().fromJson(currentChart, Chart.class));
+			parsedCharts.add(new Gson().fromJson(currentChart, BackupChart_v5.class));
 		}
 
 		return parsedCharts;
 	}
 
-	protected List<Image> parseImages(JsonObject root)
+	private List<BackupImage_v5> parseImages(JsonObject root)
 	{
-		List<Image> parsedImages = new ArrayList<>();
+		List<BackupImage_v5> parsedImages = new ArrayList<>();
 
 		JsonArray imagesToImport = root.get("images").getAsJsonArray();
 		for(JsonElement currentImage : imagesToImport)
 		{
-			parsedImages.add(new Gson().fromJson(currentImage, Image.class));
+			parsedImages.add(new Gson().fromJson(currentImage, BackupImage_v5.class));
 		}
 
 		return parsedImages;
 	}
 
-	@Override
-	protected List<Template> parseTemplates(JsonObject root)
+	private List<BackupTemplate_v5> parseTemplates(JsonObject root)
 	{
-		final List<Template> parsedTemplates = new ArrayList<>();
+		final List<BackupTemplate_v5> parsedTemplates = new ArrayList<>();
 		final JsonArray templatesToImport = root.get("templates").getAsJsonArray();
 		for(JsonElement currentTemplate : templatesToImport)
 		{
@@ -118,9 +213,9 @@ public class DatabaseParser_v5 extends DatabaseParser_v4
 
 			final String templateName = templateObject.get("templateName").getAsString();
 
-			final Template template = new Template();
+			final BackupTemplate_v5 template = new BackupTemplate_v5();
 			template.setTemplateName(templateName);
-			template.setTags(super.parseTags(templateObject));
+			template.setTags(parseTags(templateObject));
 
 			final JsonElement element = templateObject.get("amount");
 			if(element != null)
@@ -143,17 +238,17 @@ public class DatabaseParser_v5 extends DatabaseParser_v4
 			if(templateObject.has("icon"))
 			{
 				final Integer iconID = templateObject.get("icon").getAsJsonObject().get("ID").getAsInt();
-				template.setIcon(this.images.stream().filter(image -> image.getID().equals(iconID)).findFirst().orElseThrow());
+				template.setIcon(database.getImages().stream().filter(image -> image.getID().equals(iconID)).findFirst().orElseThrow());
 			}
 
 			final Optional<Integer> categoryOptional = parseIDOfElementIfExists(templateObject, "category");
-			categoryOptional.ifPresent(integer -> template.setCategory(super.getCategoryByID(integer)));
+			categoryOptional.ifPresent(integer -> template.setCategory(getCategoryByID(integer)));
 
 			final Optional<Integer> accountOptional = parseIDOfElementIfExists(templateObject, "account");
-			accountOptional.ifPresent(integer -> template.setAccount(super.getAccountByID(integer)));
+			accountOptional.ifPresent(integer -> template.setAccount(getAccountByID(integer)));
 
 			final Optional<Integer> transferAccountOptional = parseIDOfElementIfExists(templateObject, "transferAccount");
-			transferAccountOptional.ifPresent(integer -> template.setTransferAccount(super.getAccountByID(integer)));
+			transferAccountOptional.ifPresent(integer -> template.setTransferAccount(getAccountByID(integer)));
 
 			handleIsExpenditure(templateObject, template);
 
@@ -162,4 +257,92 @@ public class DatabaseParser_v5 extends DatabaseParser_v4
 
 		return parsedTemplates;
 	}
+
+	private void handleIsExpenditure(JsonObject jsonObject, BackupTemplate_v5 template)
+	{
+		final JsonElement isExpenditure = jsonObject.get("isExpenditure");
+		if(isExpenditure == null)
+		{
+			if(template.getAmount() == null)
+			{
+				template.setExpenditure(true);
+			}
+			else
+			{
+				template.setExpenditure(template.getAmount() <= 0);
+			}
+		}
+		else
+		{
+			template.setExpenditure(isExpenditure.getAsBoolean());
+		}
+	}
+
+	private void handleIsExpenditureForTransactions(JsonObject jsonObject, BackupTransaction_v5 transaction)
+	{
+		final JsonElement isExpenditure = jsonObject.get("isExpenditure");
+		if(isExpenditure == null)
+		{
+			if(transaction.getAmount() == null)
+			{
+				transaction.setExpenditure(true);
+			}
+			else
+			{
+				transaction.setExpenditure(transaction.getAmount() <= 0);
+			}
+		}
+		else
+		{
+			transaction.setExpenditure(isExpenditure.getAsBoolean());
+		}
+	}
+
+	private Optional<Integer> parseIDOfElementIfExists(JsonObject jsonObject, String elementName)
+	{
+		final JsonElement element = jsonObject.get(elementName);
+		if(element != null)
+		{
+			return Optional.of(element.getAsJsonObject().get("ID").getAsInt());
+		}
+		return Optional.empty();
+	}
+
+	private List<Tag> parseTags(JsonObject transaction)
+	{
+		List<Tag> parsedTags = new ArrayList<>();
+		JsonArray tags = transaction.get("tags").getAsJsonArray();
+		for(JsonElement currentTag : tags)
+		{
+			parsedTags.add(new Gson().fromJson(currentTag, Tag.class));
+		}
+
+		return parsedTags;
+	}
+
+	private BackupCategory_v5 getCategoryByID(int ID)
+	{
+		for(BackupCategory_v5 category : database.getCategories())
+		{
+			if(category.getID() == ID)
+			{
+				return category;
+			}
+		}
+
+		return null;
+	}
+
+	private BackupAccount_v5 getAccountByID(int ID)
+	{
+		for(BackupAccount_v5 account : database.getAccounts())
+		{
+			if(account.getID() == ID)
+			{
+				return account;
+			}
+		}
+
+		return null;
+	}
 }
\ No newline at end of file
diff --git a/src/main/resources/languages/base_de.properties b/src/main/resources/languages/base_de.properties
index ef5b9bfeb..62bb26e9e 100644
--- a/src/main/resources/languages/base_de.properties
+++ b/src/main/resources/languages/base_de.properties
@@ -18,7 +18,7 @@ errorpages.500=Ein interner Serverfehler ist aufgetreten.
 error.title.database.import=Importfehler
 error.text.database.import=Beim Importieren der Datei ist ein Fehler aufgetreten.<br>Details:<br>{0}
 error.database.import.invalid.json=Die hochgeladene JSON Datei ist ungültig.
-error.database.import.unknown.version=Die hochgeladene JSON Datei enthält keine gültige Definition einerBudgetMaster Datenbank.
+error.database.import.unknown.version=Die hochgeladene JSON Datei enthält keine gültige Definition einer BudgetMaster Datenbank.
 
 # TITLE
 title.incomes=Einnahmen
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParserTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParserTest.java
new file mode 100644
index 000000000..44382ce70
--- /dev/null
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParserTest.java
@@ -0,0 +1,94 @@
+package de.deadlocker8.budgetmaster.unit.database;
+
+import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.categories.CategoryType;
+import de.deadlocker8.budgetmaster.database.Database;
+import de.deadlocker8.budgetmaster.database.DatabaseParser;
+import de.thecodelabs.utils.util.Localization;
+import de.thecodelabs.utils.util.Localization.LocalizationDelegate;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+public class DatabaseParserTest
+{
+	@Before
+	public void before()
+	{
+		Localization.setDelegate(new LocalizationDelegate()
+		{
+			@Override
+			public Locale getLocale()
+			{
+				return Locale.ENGLISH;
+			}
+
+			@Override
+			public String getBaseResource()
+			{
+				return "languages/base";
+			}
+		});
+		Localization.load();
+	}
+
+	@Test
+	public void test_v5() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v5Test.json").toURI())));
+		final Category categoryNone = new Category("NONE", "#FFFFFF", CategoryType.NONE);
+		categoryNone.setID(1);
+
+		DatabaseParser importer = new DatabaseParser(json, categoryNone);
+		final Database database = importer.parseDatabaseFromJSON();
+		assertThat(database.getTransactions())
+				.hasSize(6);
+	}
+
+	@Test
+	public void test_v4() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v4Test.json").toURI())));
+		final Category categoryNone = new Category("NONE", "#FFFFFF", CategoryType.NONE);
+		categoryNone.setID(1);
+
+		DatabaseParser importer = new DatabaseParser(json, categoryNone);
+		final Database database = importer.parseDatabaseFromJSON();
+		assertThat(database.getTransactions())
+				.hasSize(6);
+	}
+
+	@Test
+	public void test_v3() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v3Test.json").toURI())));
+		final Category categoryNone = new Category("NONE", "#FFFFFF", CategoryType.NONE);
+		categoryNone.setID(1);
+
+		DatabaseParser importer = new DatabaseParser(json, categoryNone);
+		final Database database = importer.parseDatabaseFromJSON();
+		assertThat(database.getTransactions())
+				.hasSize(6);
+	}
+
+	@Test
+	public void test_v2() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("LegacyParserTest.json").toURI())));
+		final Category categoryNone = new Category("NONE", "#FFFFFF", CategoryType.NONE);
+		categoryNone.setID(1);
+
+		DatabaseParser importer = new DatabaseParser(json, categoryNone);
+		final Database database = importer.parseDatabaseFromJSON();
+		assertThat(database.getTransactions())
+				.hasSize(4);
+	}
+}
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java
index 17bcb1a09..491c5fac6 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java
@@ -7,12 +7,20 @@ import de.deadlocker8.budgetmaster.categories.CategoryType;
 import de.deadlocker8.budgetmaster.charts.Chart;
 import de.deadlocker8.budgetmaster.charts.ChartType;
 import de.deadlocker8.budgetmaster.database.Database;
+import de.deadlocker8.budgetmaster.database.DatabaseParser_v4;
 import de.deadlocker8.budgetmaster.database.DatabaseParser_v5;
 import de.deadlocker8.budgetmaster.images.Image;
 import de.deadlocker8.budgetmaster.images.ImageFileExtension;
+import de.deadlocker8.budgetmaster.repeating.RepeatingOption;
+import de.deadlocker8.budgetmaster.repeating.endoption.RepeatingEndAfterXTimes;
+import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierDays;
+import de.deadlocker8.budgetmaster.tags.Tag;
 import de.deadlocker8.budgetmaster.templates.Template;
+import de.deadlocker8.budgetmaster.transactions.Transaction;
 import de.thecodelabs.utils.util.Localization;
 import de.thecodelabs.utils.util.Localization.LocalizationDelegate;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -21,6 +29,7 @@ import java.net.URISyntaxException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
@@ -57,7 +66,7 @@ public class DatabaseParser_v5Test
 		{
 			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v5Test.json").toURI())));
 			DatabaseParser_v5 importer = new DatabaseParser_v5(json);
-			Database database = importer.parseDatabaseFromJSON();
+			Database database = importer.parseDatabaseFromJSON().convert();
 
 			final Chart chart = new Chart("The best chart", "/* This list will be dynamically filled with all the transactions between\r\n* the start and and date you select on the \"Show Chart\" page\r\n* and filtered according to your specified filter.\r\n* An example entry for this list and tutorial about how to create custom charts ca be found in the BudgetMaster wiki:\r\n* https://github.com/deadlocker8/BudgetMaster/wiki/How-to-create-custom-charts\r\n*/\r\nvar transactionData \u003d [];\r\n\r\n// Prepare your chart settings here (mandatory)\r\nvar plotlyData \u003d [{\r\n    x: [],\r\n    y: [],\r\n    type: \u0027bar\u0027\r\n}];\r\n\r\n// Add your Plotly layout settings here (optional)\r\nvar plotlyLayout \u003d {};\r\n\r\n// Add your Plotly configuration settings here (optional)\r\nvar plotlyConfig \u003d {\r\n    showSendToCloud: false,\r\n    displaylogo: false,\r\n    showLink: false,\r\n    responsive: true\r\n};\r\n\r\n// Don\u0027t touch this line\r\nPlotly.newPlot(\"containerID\", plotlyData, plotlyLayout, plotlyConfig);\r\n", ChartType.CUSTOM, 7);
 			chart.setID(9);
@@ -78,7 +87,7 @@ public class DatabaseParser_v5Test
 		{
 			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v5Test.json").toURI())));
 			DatabaseParser_v5 importer = new DatabaseParser_v5(json);
-			Database database = importer.parseDatabaseFromJSON();
+			Database database = importer.parseDatabaseFromJSON().convert();
 
 			final Category category = new Category("0815", "#ffcc00", CategoryType.CUSTOM, "fas fa-icons");
 			category.setID(3);
@@ -99,7 +108,7 @@ public class DatabaseParser_v5Test
 		{
 			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v5Test.json").toURI())));
 			DatabaseParser_v5 importer = new DatabaseParser_v5(json);
-			Database database = importer.parseDatabaseFromJSON();
+			Database database = importer.parseDatabaseFromJSON().convert();
 
 			final Image accountImage = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
 			accountImage.setID(1);
@@ -125,7 +134,7 @@ public class DatabaseParser_v5Test
 		{
 			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v5Test.json").toURI())));
 			DatabaseParser_v5 importer = new DatabaseParser_v5(json);
-			Database database = importer.parseDatabaseFromJSON();
+			Database database = importer.parseDatabaseFromJSON().convert();
 
 			final Image image = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
 			image.setID(1);
@@ -149,7 +158,7 @@ public class DatabaseParser_v5Test
 		{
 			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v5Test.json").toURI())));
 			DatabaseParser_v5 importer = new DatabaseParser_v5(json);
-			Database database = importer.parseDatabaseFromJSON();
+			Database database = importer.parseDatabaseFromJSON().convert();
 
 			final Image templateImage = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
 			templateImage.setID(1);
@@ -170,4 +179,112 @@ public class DatabaseParser_v5Test
 			e.printStackTrace();
 		}
 	}
+
+	@Test
+	public void test_Transactions()
+	{
+		try
+		{
+			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v5Test.json").toURI())));
+			DatabaseParser_v5 importer = new DatabaseParser_v5(json);
+			Database database = importer.parseDatabaseFromJSON().convert();
+
+			Account account1 = new Account("Default", AccountType.CUSTOM);
+			account1.setID(2);
+
+			Image image = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
+			image.setID(1);
+
+			Account account2 = new Account("Second Account", AccountType.CUSTOM);
+			account2.setIcon(image);
+			account2.setID(3);
+
+			Category categoryNone = new Category("Keine Kategorie", "#FFFFFF", CategoryType.NONE);
+			categoryNone.setID(1);
+
+			Category category3 = new Category("0815", "#ffcc00", CategoryType.CUSTOM);
+			category3.setIcon("fas fa-icons");
+			category3.setID(3);
+
+			Transaction normalTransaction_1 = new Transaction();
+			normalTransaction_1.setAmount(35000);
+			normalTransaction_1.setDate(DateTime.parse("2018-03-13", DateTimeFormat.forPattern("yyyy-MM-dd")));
+			normalTransaction_1.setCategory(categoryNone);
+			normalTransaction_1.setName("Income");
+			normalTransaction_1.setDescription("Lorem Ipsum");
+			normalTransaction_1.setTags(new ArrayList<>());
+			normalTransaction_1.setAccount(account1);
+			normalTransaction_1.setIsExpenditure(false);
+
+			Transaction normalTransaction_2 = new Transaction();
+			normalTransaction_2.setAmount(-2000);
+			normalTransaction_2.setDate(DateTime.parse("2018-06-15", DateTimeFormat.forPattern("yyyy-MM-dd")));
+			normalTransaction_2.setName("Simple");
+			normalTransaction_2.setDescription("");
+			normalTransaction_2.setAccount(account2);
+			normalTransaction_2.setCategory(category3);
+			normalTransaction_2.setIsExpenditure(true);
+
+			List<Tag> tags = new ArrayList<>();
+			Tag tag = new Tag("0815");
+			tag.setID(1);
+			tags.add(tag);
+			normalTransaction_2.setTags(tags);
+
+			Transaction repeatingTransaction_1 = new Transaction();
+			repeatingTransaction_1.setAmount(-12300);
+			DateTime repeatingTransactionDate_1 = DateTime.parse("2018-03-13", DateTimeFormat.forPattern("yyyy-MM-dd"));
+			repeatingTransaction_1.setDate(repeatingTransactionDate_1);
+			repeatingTransaction_1.setCategory(categoryNone);
+			repeatingTransaction_1.setName("Test");
+			repeatingTransaction_1.setDescription("");
+			repeatingTransaction_1.setAccount(account1);
+			RepeatingOption repeatingOption_1 = new RepeatingOption();
+			repeatingOption_1.setModifier(new RepeatingModifierDays(10));
+			repeatingOption_1.setStartDate(repeatingTransactionDate_1);
+			repeatingOption_1.setEndOption(new RepeatingEndAfterXTimes(2));
+			repeatingTransaction_1.setRepeatingOption(repeatingOption_1);
+			repeatingTransaction_1.setTags(new ArrayList<>());
+			repeatingTransaction_1.setIsExpenditure(true);
+
+			Transaction repeatingTransaction_2 = new Transaction();
+			repeatingTransaction_2.setAmount(-12300);
+			DateTime repeatingTransactionDate_2 = DateTime.parse("2018-03-23", DateTimeFormat.forPattern("yyyy-MM-dd"));
+			repeatingTransaction_2.setDate(repeatingTransactionDate_2);
+			repeatingTransaction_2.setCategory(categoryNone);
+			repeatingTransaction_2.setName("Test");
+			repeatingTransaction_2.setDescription("");
+			repeatingTransaction_2.setAccount(account1);
+			RepeatingOption repeatingOption_2 = new RepeatingOption();
+			repeatingOption_2.setModifier(new RepeatingModifierDays(10));
+			repeatingOption_2.setStartDate(repeatingTransactionDate_2);
+			repeatingOption_2.setEndOption(new RepeatingEndAfterXTimes(2));
+			repeatingTransaction_2.setRepeatingOption(repeatingOption_2);
+			repeatingTransaction_2.setTags(new ArrayList<>());
+			repeatingTransaction_2.setIsExpenditure(true);
+
+			Transaction transferTransaction = new Transaction();
+			transferTransaction.setAmount(-250);
+			transferTransaction.setDate(DateTime.parse("2018-06-15", DateTimeFormat.forPattern("yyyy-MM-dd")));
+			transferTransaction.setName("Transfer");
+			transferTransaction.setDescription("");
+			transferTransaction.setAccount(account2);
+			transferTransaction.setTransferAccount(account1);
+			transferTransaction.setCategory(category3);
+			transferTransaction.setTags(new ArrayList<>());
+			transferTransaction.setIsExpenditure(true);
+
+			assertThat(database.getTransactions()).hasSize(6)
+					.contains(normalTransaction_1,
+							normalTransaction_2,
+							repeatingTransaction_1,
+							repeatingTransaction_2,
+							transferTransaction);
+
+		}
+		catch(IOException | URISyntaxException e)
+		{
+			e.printStackTrace();
+		}
+	}
 }
\ No newline at end of file
-- 
GitLab