1 package de.aikiit.bilanzanalyser.upload;
2
3 import de.aikiit.bilanzanalyser.entity.BilanzRow;
4 import de.aikiit.bilanzanalyser.entity.database.BilanzRowEntity;
5 import de.aikiit.bilanzanalyser.entity.database.CategoryEntity;
6 import de.aikiit.bilanzanalyser.entity.database.PaymentEntity;
7 import de.aikiit.bilanzanalyser.entity.database.ShopEntity;
8 import de.aikiit.bilanzanalyser.entity.database.SourceEntity;
9 import de.aikiit.bilanzanalyser.entity.database.repository.BilanzRowRepository;
10 import de.aikiit.bilanzanalyser.entity.database.repository.CategoryRepository;
11 import de.aikiit.bilanzanalyser.entity.database.repository.PaymentRepository;
12 import de.aikiit.bilanzanalyser.entity.database.repository.ShopRepository;
13 import de.aikiit.bilanzanalyser.entity.database.repository.SourceRepository;
14 import de.aikiit.bilanzanalyser.reader.BilanzOdsReader;
15 import de.aikiit.bilanzanalyser.reader.BilanzRowParserResult;
16 import jakarta.transaction.Transactional;
17 import lombok.extern.log4j.Log4j2;
18 import org.springframework.dao.DataIntegrityViolationException;
19 import org.springframework.scheduling.annotation.Async;
20 import org.springframework.stereotype.Service;
21
22 import java.io.IOException;
23 import java.nio.file.Path;
24 import java.util.Optional;
25 import java.util.function.Function;
26
27 @Service
28 @Log4j2
29 public class UploadAnalysisService {
30 private final BilanzRowRepository bilanzRowRepository;
31 private final ShopRepository shopRepository;
32 private final PaymentRepository paymentRepository;
33 private final CategoryRepository categoryRepository;
34 private final SourceRepository sourceRepository;
35
36 public UploadAnalysisService(BilanzRowRepository bilanzRowRepository, ShopRepository shopRepository, PaymentRepository paymentRepository, CategoryRepository categoryRepository, SourceRepository sourceRepository) {
37 this.bilanzRowRepository = bilanzRowRepository;
38 this.shopRepository = shopRepository;
39 this.paymentRepository = paymentRepository;
40 this.categoryRepository = categoryRepository;
41 this.sourceRepository = sourceRepository;
42 }
43
44
45
46
47
48
49
50
51
52 BilanzRowParserResult processFile(String worksheetName, Path spreadsheet) throws IOException {
53 BilanzOdsReader reader = new BilanzOdsReader(worksheetName, spreadsheet);
54 return reader.extractData();
55 }
56
57 @Async
58 public void flushDataIntoDatabase(BilanzRowParserResult data) {
59 long start = System.nanoTime();
60 log.info("Starting to flush data into database...");
61
62 for (BilanzRow row : data.rows()) {
63 BilanzRowEntity entity = new BilanzRowEntity();
64 entity.setDate(row.getDate());
65 entity.setAmount(row.getAmount());
66 entity.setDescription(replaceIfEmpty(row.getDescription()));
67 entity.setShop(getOrCreateShop(row.getShop()));
68 entity.setPayment(getOrCreatePayment(row.getPayment()));
69 entity.setCategory(getOrCreateCategory(row.getCategory()));
70 entity.setSource(getOrCreateSource(row.getSource()));
71 bilanzRowRepository.save(entity);
72 }
73
74 log.info("Successfully flushed data into database in {} ms.", (System.nanoTime() - start) / 1_000_000);
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 @Transactional
99 <T> T getOrCreate(String rawName, Function<String, Optional<T>> finder, Function<String, T> creator) {
100 String name = replaceIfEmpty(rawName);
101
102 return finder.apply(name).orElseGet(() -> {
103 try {
104 return creator.apply(name);
105 } catch (DataIntegrityViolationException e) {
106
107 return finder.apply(name).orElseThrow();
108 }
109 });
110 }
111
112 @Transactional
113 ShopEntity getOrCreateShop(String name) {
114 return getOrCreate(name, shopRepository::findByName, n -> {
115 ShopEntity e = new ShopEntity();
116 e.setName(n);
117 return shopRepository.save(e);
118 });
119 }
120
121 @Transactional
122 PaymentEntity getOrCreatePayment(String name) {
123 return getOrCreate(name, paymentRepository::findByName, n -> {
124 PaymentEntity e = new PaymentEntity();
125 e.setName(n);
126 return paymentRepository.save(e);
127 });
128 }
129
130 @Transactional
131 CategoryEntity getOrCreateCategory(String name) {
132 return getOrCreate(name, categoryRepository::findByName, n -> {
133 CategoryEntity e = new CategoryEntity();
134 e.setName(n);
135 return categoryRepository.save(e);
136 });
137 }
138
139 @Transactional
140 SourceEntity getOrCreateSource(String name) {
141 return getOrCreate(name, sourceRepository::findByName, n -> {
142 SourceEntity e = new SourceEntity();
143 e.setName(n);
144 return sourceRepository.save(e);
145 });
146 }
147
148 String replaceIfEmpty(String value) {
149 return value == null || value.isBlank() ? "<empty>" : value.trim();
150 }
151
152 }