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(final BilanzRowRepository bilanzRowRepository, final ShopRepository shopRepository, final PaymentRepository paymentRepository, final CategoryRepository categoryRepository, final 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(final String worksheetName, final Path spreadsheet) throws IOException {
53 BilanzOdsReader reader = new BilanzOdsReader(worksheetName, spreadsheet);
54 return reader.extractData();
55 }
56
57 @Async
58 @Transactional
59 public void flushDataIntoDatabase(final BilanzRowParserResult data) {
60 long start = System.nanoTime();
61 log.info("Starting to flush data into database...");
62
63 for (BilanzRow row : data.rows()) {
64 BilanzRowEntity entity = new BilanzRowEntity();
65 entity.setDate(row.getDate());
66 entity.setAmount(row.getAmount());
67 entity.setDescription(replaceIfEmpty(row.getDescription()));
68 entity.setShop(getOrCreateShop(row.getShop()));
69 entity.setPayment(getOrCreatePayment(row.getPayment()));
70 entity.setCategory(getOrCreateCategory(row.getCategory()));
71 entity.setSource(getOrCreateSource(row.getSource()));
72 bilanzRowRepository.save(entity);
73 }
74
75 log.info("Successfully flushed data into database in {} ms.", (System.nanoTime() - start) / 1_000_000);
76 }
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 @Transactional
100 <T> T getOrCreate(final String rawName, final Function<String, Optional<T>> finder, final Function<String, T> creator) {
101 String name = replaceIfEmpty(rawName);
102
103 return finder.apply(name).orElseGet(() -> {
104 try {
105 return creator.apply(name);
106 } catch (DataIntegrityViolationException e) {
107
108 return finder.apply(name).orElseThrow();
109 }
110 });
111 }
112
113 @Transactional
114 ShopEntity getOrCreateShop(final String name) {
115 return getOrCreate(name, shopRepository::findByName, n -> {
116 ShopEntity e = new ShopEntity();
117 e.setName(n);
118 return shopRepository.save(e);
119 });
120 }
121
122 @Transactional
123 PaymentEntity getOrCreatePayment(final String name) {
124 return getOrCreate(name, paymentRepository::findByName, n -> {
125 PaymentEntity e = new PaymentEntity();
126 e.setName(n);
127 return paymentRepository.save(e);
128 });
129 }
130
131 @Transactional
132 CategoryEntity getOrCreateCategory(final String name) {
133 return getOrCreate(name, categoryRepository::findByName, n -> {
134 CategoryEntity e = new CategoryEntity();
135 e.setName(n);
136 return categoryRepository.save(e);
137 });
138 }
139
140 @Transactional
141 SourceEntity getOrCreateSource(final String name) {
142 return getOrCreate(name, sourceRepository::findByName, n -> {
143 SourceEntity e = new SourceEntity();
144 e.setName(n);
145 return sourceRepository.save(e);
146 });
147 }
148
149 String replaceIfEmpty(final String value) {
150 return value == null || value.isBlank() ? "<empty>" : value.trim();
151 }
152
153 }