Skip to content

Commit 053e4db

Browse files
committed
refactor: merge TransactionStopService into TransactionService
1 parent a391dd5 commit 053e4db

File tree

3 files changed

+127
-167
lines changed

3 files changed

+127
-167
lines changed

src/main/java/de/rwth/idsg/steve/service/TransactionService.java

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,31 @@
1818
*/
1919
package de.rwth.idsg.steve.service;
2020

21+
import com.google.common.collect.Ordering;
22+
import de.rwth.idsg.steve.repository.OcppServerRepository;
2123
import de.rwth.idsg.steve.repository.TransactionRepository;
2224
import de.rwth.idsg.steve.repository.dto.Transaction;
2325
import de.rwth.idsg.steve.repository.dto.TransactionDetails;
26+
import de.rwth.idsg.steve.repository.dto.UpdateTransactionParams;
27+
import de.rwth.idsg.steve.utils.TransactionStopServiceHelper;
2428
import de.rwth.idsg.steve.web.dto.TransactionQueryForm;
29+
import jooq.steve.db.enums.TransactionStopEventActor;
30+
import jooq.steve.db.tables.records.TransactionStartRecord;
31+
import lombok.Builder;
2532
import lombok.RequiredArgsConstructor;
2633
import lombok.extern.slf4j.Slf4j;
34+
import ocpp.cs._2012._06.UnitOfMeasure;
35+
import org.jetbrains.annotations.Nullable;
36+
import org.joda.time.DateTime;
2737
import org.springframework.stereotype.Service;
2838

2939
import java.io.Writer;
40+
import java.util.Comparator;
3041
import java.util.List;
3142

43+
import static de.rwth.idsg.steve.utils.TransactionStopServiceHelper.floatingStringToIntString;
44+
import static de.rwth.idsg.steve.utils.TransactionStopServiceHelper.kWhStringToWhString;
45+
3246
/**
3347
* @author Sevket Goekay <[email protected]>
3448
* @since 02.10.2025
@@ -39,6 +53,7 @@
3953
public class TransactionService {
4054

4155
private final TransactionRepository transactionRepository;
56+
private final OcppServerRepository ocppServerRepository;
4257

4358
public List<Transaction> getTransactions(TransactionQueryForm form) {
4459
return transactionRepository.getTransactions(form);
@@ -81,4 +96,115 @@ public Transaction getActiveTransaction(String chargeBoxId, Integer connectorId)
8196
throw new IllegalStateException("There are multiple active transactions with the same charge box id and connector id");
8297
}
8398
}
99+
100+
public void stop(List<Integer> transactionPkList) {
101+
transactionPkList.stream()
102+
.sorted(Ordering.natural())
103+
.forEach(this::stop);
104+
}
105+
106+
public void stop(Integer transactionPk) {
107+
TransactionDetails thisTxDetails = transactionRepository.getDetails(transactionPk);
108+
Transaction thisTx = thisTxDetails.getTransaction();
109+
110+
// early exit, if transaction is already stopped
111+
if (thisTx.getStopValue() != null && thisTx.getStopTimestamp() != null) {
112+
return;
113+
}
114+
115+
TerminationValues values = findNeededValues(thisTxDetails);
116+
117+
ocppServerRepository.updateTransaction(UpdateTransactionParams.builder()
118+
.transactionId(thisTx.getId())
119+
.chargeBoxId(thisTx.getChargeBoxId())
120+
.stopMeterValue(values.stopValue)
121+
.stopTimestamp(values.stopTimestamp)
122+
.eventActor(TransactionStopEventActor.manual)
123+
.eventTimestamp(DateTime.now())
124+
.build());
125+
}
126+
127+
private static TerminationValues findNeededValues(TransactionDetails thisTxDetails) {
128+
Transaction thisTx = thisTxDetails.getTransaction();
129+
TransactionStartRecord nextTx = thisTxDetails.getNextTransactionStart();
130+
List<TransactionDetails.MeterValues> intermediateValues = thisTxDetails.getValues();
131+
132+
// -------------------------------------------------------------------------
133+
// 1. intermediate meter values have priority (most accurate data)
134+
// -------------------------------------------------------------------------
135+
136+
TransactionDetails.MeterValues last = findLastMeterValue(intermediateValues);
137+
if (last != null) {
138+
return TerminationValues.builder()
139+
.stopValue(floatingStringToIntString(last.getValue()))
140+
.stopTimestamp(last.getValueTimestamp())
141+
.build();
142+
}
143+
144+
// -------------------------------------------------------------------------
145+
// 2. a latest energy meter value does not exist, use data of next tx
146+
// -------------------------------------------------------------------------
147+
148+
if (nextTx != null) {
149+
// some charging stations do not reset the meter value counter after each transaction and
150+
// continue counting. in such cases, use the value of subsequent transaction's start value
151+
if (Integer.parseInt(nextTx.getStartValue()) > Integer.parseInt(thisTx.getStartValue())) {
152+
return TerminationValues.builder()
153+
.stopValue(nextTx.getStartValue())
154+
.stopTimestamp(nextTx.getStartTimestamp())
155+
.build();
156+
} else {
157+
// this mix of strategies might be really confusing
158+
return TerminationValues.builder()
159+
.stopValue(thisTx.getStartValue())
160+
.stopTimestamp(nextTx.getStartTimestamp())
161+
.build();
162+
}
163+
}
164+
165+
// -------------------------------------------------------------------------
166+
// 3. neither meter values nor next tx exist, use start values
167+
// -------------------------------------------------------------------------
168+
169+
return TerminationValues.builder()
170+
.stopValue(thisTx.getStartValue())
171+
.stopTimestamp(thisTx.getStartTimestamp())
172+
.build();
173+
}
174+
175+
@Nullable
176+
private static TransactionDetails.MeterValues findLastMeterValue(List<TransactionDetails.MeterValues> values) {
177+
TransactionDetails.MeterValues v =
178+
values.stream()
179+
.filter(TransactionStopServiceHelper::isEnergyValue)
180+
.max(Comparator.comparing(TransactionDetails.MeterValues::getValueTimestamp))
181+
.orElse(null);
182+
183+
// if the list of values is empty, we fall to this case, as well.
184+
if (v == null) {
185+
return null;
186+
}
187+
188+
// convert kWh to Wh
189+
if (UnitOfMeasure.K_WH.value().equals(v.getUnit())) {
190+
return TransactionDetails.MeterValues.builder()
191+
.value(kWhStringToWhString(v.getValue()))
192+
.valueTimestamp(v.getValueTimestamp())
193+
.readingContext(v.getReadingContext())
194+
.format(v.getFormat())
195+
.measurand(v.getMeasurand())
196+
.location(v.getLocation())
197+
.unit(v.getUnit())
198+
.phase(v.getPhase())
199+
.build();
200+
} else {
201+
return v;
202+
}
203+
}
204+
205+
@Builder
206+
private static class TerminationValues {
207+
private final String stopValue;
208+
private final DateTime stopTimestamp;
209+
}
84210
}

src/main/java/de/rwth/idsg/steve/service/TransactionStopService.java

Lines changed: 0 additions & 164 deletions
This file was deleted.

src/main/java/de/rwth/idsg/steve/web/controller/TransactionsReservationsController.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import de.rwth.idsg.steve.repository.ReservationStatus;
2424
import de.rwth.idsg.steve.service.OcppTagService;
2525
import de.rwth.idsg.steve.service.TransactionService;
26-
import de.rwth.idsg.steve.service.TransactionStopService;
2726
import de.rwth.idsg.steve.web.dto.ReservationQueryForm;
2827
import de.rwth.idsg.steve.web.dto.TransactionQueryForm;
2928
import lombok.RequiredArgsConstructor;
@@ -55,7 +54,6 @@ public class TransactionsReservationsController {
5554
private final ReservationRepository reservationRepository;
5655
private final ChargePointRepository chargePointRepository;
5756
private final OcppTagService ocppTagService;
58-
private final TransactionStopService transactionStopService;
5957

6058
private static final String PARAMS = "params";
6159

@@ -86,7 +84,7 @@ public String getTransactions(Model model) {
8684

8785
@RequestMapping(value = TRANSACTION_STOP_PATH, method = RequestMethod.POST)
8886
public String stopTransaction(@PathVariable("transactionPk") int transactionPk) {
89-
transactionStopService.stop(transactionPk);
87+
transactionService.stop(transactionPk);
9088
return "redirect:/manager/transactions";
9189
}
9290

0 commit comments

Comments
 (0)