diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ce7f5634..dbb817177 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Changes: - Improve Stocard importer +- Fix importing Catima export with multiline note ## v2.2.0 (2021-08-02) diff --git a/app/src/main/java/protect/card_locker/importexport/CatimaImporter.java b/app/src/main/java/protect/card_locker/importexport/CatimaImporter.java index f5df36e70..5b5a71f1e 100644 --- a/app/src/main/java/protect/card_locker/importexport/CatimaImporter.java +++ b/app/src/main/java/protect/card_locker/importexport/CatimaImporter.java @@ -21,6 +21,7 @@ import java.io.InputStreamReader; import java.io.StringReader; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Currency; import java.util.Date; import java.util.List; @@ -142,18 +143,36 @@ public class CatimaImporter implements Importer String tmp = input.readLine(); if (tmp == null || tmp.isEmpty()) { + boolean sectionParsed = false; + switch (part) { case 0: // This is the version info, ignore + sectionParsed = true; break; case 1: - parseV2Groups(db, database, stringPart); + try { + parseV2Groups(db, database, stringPart); + sectionParsed = true; + } catch (FormatException e) { + // We may have a multiline field, try again + } break; case 2: - parseV2Cards(context, db, database, stringPart); + try { + parseV2Cards(context, db, database, stringPart); + sectionParsed = true; + } catch (FormatException e) { + // We may have a multiline field, try again + } break; case 3: - parseV2CardGroups(db, database, stringPart); + try { + parseV2CardGroups(db, database, stringPart); + sectionParsed = true; + } catch (FormatException e) { + // We may have a multiline field, try again + } break; default: throw new FormatException("Issue parsing CSV data, too many parts for v2 parsing"); @@ -163,8 +182,12 @@ public class CatimaImporter implements Importer break; } - part += 1; - stringPart = ""; + if (sectionParsed) { + part += 1; + stringPart = ""; + } else { + stringPart += tmp + "\n"; + } } else { stringPart += tmp + "\n"; } @@ -183,9 +206,11 @@ public class CatimaImporter implements Importer // Parse groups final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader()); + List records = new ArrayList<>(); + try { for (CSVRecord record : groupParser) { - importGroup(database, db, record); + records.add(record); if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -196,6 +221,10 @@ public class CatimaImporter implements Importer } finally { groupParser.close(); } + + for (CSVRecord record : records) { + importGroup(database, db, record); + } } public void parseV2Cards(Context context, DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException @@ -203,9 +232,11 @@ public class CatimaImporter implements Importer // Parse cards final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader()); + List records = new ArrayList<>(); + try { for (CSVRecord record : cardParser) { - importLoyaltyCard(context, database, db, record); + records.add(record); if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -216,6 +247,10 @@ public class CatimaImporter implements Importer } finally { cardParser.close(); } + + for (CSVRecord record : records) { + importLoyaltyCard(context, database, db, record); + } } public void parseV2CardGroups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException @@ -223,9 +258,11 @@ public class CatimaImporter implements Importer // Parse card group mappings final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader()); + List records = new ArrayList<>(); + try { for (CSVRecord record : cardGroupParser) { - importCardGroupMapping(database, db, record); + records.add(record); if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -236,6 +273,10 @@ public class CatimaImporter implements Importer } finally { cardGroupParser.close(); } + + for (CSVRecord record : records) { + importCardGroupMapping(database, db, record); + } } /** diff --git a/app/src/test/java/protect/card_locker/ImportExportTest.java b/app/src/test/java/protect/card_locker/ImportExportTest.java index 87c700dfd..87a2becf7 100644 --- a/app/src/test/java/protect/card_locker/ImportExportTest.java +++ b/app/src/test/java/protect/card_locker/ImportExportTest.java @@ -980,7 +980,9 @@ public class ImportExportTest "1,Card 1,Note 1,1618053234,100,USD,1234,5432,1,QR_CODE,0,\r\n" + "8,Clothes Store,Note about store,,0,,a,,-5317,,0,\n" + "2,Department Store,,1618041729,0,,A,,-9977996,,0,\n" + - "3,Grocery Store,,,150,,dhd,,-9977996,,0,\n" + + "3,Grocery Store,\"Multiline note about grocery store\n" + + "\n" + + "with blank line\",,150,,dhd,,-9977996,,0,\n" + "4,Pharmacy,,,0,,dhshsvshs,,-10902850,,1,\n" + "5,Restaurant,Note about restaurant here,,0,,98765432,23456,-10902850,CODE_128,0,\n" + "6,Shoe Store,,,12.50,EUR,a,-5317,,AZTEC,0,\n" + @@ -1065,7 +1067,7 @@ public class ImportExportTest LoyaltyCard card3 = db.getLoyaltyCard(3); assertEquals("Grocery Store", card3.store); - assertEquals("", card3.note); + assertEquals("Multiline note about grocery store\n\nwith blank line", card3.note); assertEquals(null, card3.expiry); assertEquals(new BigDecimal("150"), card3.balance); assertEquals(null, card3.balanceType);