- intermediate commit

This commit is contained in:
Jan 2025-10-13 14:00:28 +02:00
parent 79dea999ad
commit 3141e62b08
33 changed files with 153 additions and 316 deletions

View file

@ -116,7 +116,7 @@ const executeRequest = async (requestingStore, request) => {
trace: null
}
logger.error(error);
logger.error(error, e);
const errorStore = useErrorStore();
void errorStore.addError(error, {store: requestingStore, request: request});
@ -172,4 +172,4 @@ const executeRequest = async (requestingStore, request) => {
}
export default performRequest;
export {performUpload, performDownload};
export {performUpload, performDownload, getCsrfToken};

View file

@ -185,7 +185,7 @@ export default {
}
:deep(.leaflet-control-attribution) {
font-size: 10px;
font-size: 0.8rem;
background: rgba(255, 255, 255, 0.8);
}
</style>

View file

@ -16,7 +16,7 @@
<div class="input-field">{{ coordinatesDMS }}</div>
</div>
<div class="supplier-map">
<open-street-map-embed :coordinates="supplierCoordinates" zoom="15" width="600px" height="300px" custom-filter="grayscale(0.8) sepia(0.5) hue-rotate(180deg) saturate(0.5) brightness(1.0)"></open-street-map-embed>
<open-street-map-embed :coordinates="supplierCoordinates" :zoom="15" width="100%" height="300px" custom-filter="grayscale(0.8) sepia(0.5) hue-rotate(180deg) saturate(0.5) brightness(1.0)"></open-street-map-embed>
</div>
<div class="footer">
<modal :state="selectSupplierModalState" @close="closeEditModal">
@ -177,12 +177,9 @@ export default {
}
.container {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
gap: 3.6rem;
flex: 1 1 auto;
display: grid;
grid-template-columns: 1fr 1fr;
}
.supplier-container {

View file

@ -91,88 +91,48 @@ export const useAssistantStore = defineStore('assistant', {
console.log(`${url} with query ${query}`);
const headers = new Headers();
headers.append('search', encodeURIComponent(query));
try {
const resp = await performRequest(this, 'GET', `${config.backendUrl}/calculation/search/?search=${encodeURIComponent(query)}`, null, true);
const data = resp.data;
const request = {url: url, params: {method: 'GET'}};
const newSuppliers = [];
const response = await fetch(url, {
method: 'GET',
headers: headers
}).catch(e => {
this.error = {code: 'Network error.', message: "Please check your internet connection.", trace: null}
this.loading = false;
console.error(this.error);
const errorStore = useErrorStore();
void errorStore.addError(this.error, {store: this, request: request});
throw e;
});
const data = await response.json().catch(e => {
this.error = {
code: 'Malformed response',
message: "Malformed server response. Please contact support.",
trace: null
for (const supplier of data.supplier) {
const newSupplier = {
id: `s${supplier.id}`,
origId: supplier.id,
isUserSupplier: false,
name: supplier.name,
address: supplier.address,
iso: supplier.country['iso_code']
};
newSuppliers.push(newSupplier);
}
for (const supplier of data.user_supplier) {
const newSupplier = {
id: `u${supplier.id}`,
origId: supplier.id,
isUserSupplier: true,
name: supplier.name,
address: supplier.address,
iso: supplier.country['iso_code']
};
newSuppliers.push(newSupplier);
}
this.loading = false;
this.materials = data.materials;
this.suppliers = newSuppliers;
console.error(this.error);
const errorStore = useErrorStore();
void errorStore.addError(this.error, {store: this, request: request});
throw e;
});
if (!response.ok) {
this.error = {
code: data.error.code,
title: data.error.title,
message: data.error.message,
trace: data.error.trace
};
this.loading = false;
console.error(this.error);
const errorStore = useErrorStore();
void errorStore.addError(this.error, {store: this, request: request});
return;
}
const newSuppliers = [];
for (const supplier of data.supplier) {
const newSupplier = {
id: `s${supplier.id}`,
origId: supplier.id,
isUserSupplier: false,
name: supplier.name,
address: supplier.address,
iso: supplier.country['iso_code']
};
newSuppliers.push(newSupplier);
}
for (const supplier of data.user_supplier) {
const newSupplier = {
id: `u${supplier.id}`,
origId: supplier.id,
isUserSupplier: true,
name: supplier.name,
address: supplier.address,
iso: supplier.country['iso_code']
};
newSuppliers.push(newSupplier);
} catch (e) {
}
this.loading = false;
this.materials = data.materials;
this.suppliers = newSuppliers;
}

View file

@ -1,6 +1,7 @@
import {defineStore, getActivePinia} from 'pinia'
import {config} from '@/config'
import {toRaw} from "vue";
import {getCsrfToken} from "@/backend.js";
export const useErrorStore = defineStore('error', {
state() {
@ -46,8 +47,10 @@ export const useErrorStore = defineStore('error', {
const params = {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
'Content-Type': 'application/json',
'X-XSRF-TOKEN': getCsrfToken()
},
body: JSON.stringify(toRaw(this.sendCache))
};

View file

@ -56,6 +56,8 @@ public class DevUserEmulationFilter extends OncePerRequestFilter {
setEmulatedUser(user);
System.out.println("DevUserEmulationFilter - Set user: " + user.getEmail());
}
} else {
System.out.println("DevUserEmulationFilter - " + request.getRequestURI() + " - No emulated user set");
}
filterChain.doFilter(request, response);

View file

@ -22,7 +22,6 @@ import de.avatic.lcc.service.calculation.PremiseCreationService;
import de.avatic.lcc.service.calculation.PremiseSearchStringAnalyzerService;
import de.avatic.lcc.util.exception.badrequest.InvalidArgumentException;
import de.avatic.lcc.util.exception.base.BadRequestException;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import org.slf4j.Logger;
@ -35,7 +34,6 @@ import org.springframework.web.bind.annotation.*;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -82,18 +80,14 @@ public class PremiseController {
@GetMapping({"/search", "/search/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<PremiseSearchResultDTO> findMaterialsAndSuppliers(@RequestHeader String search) {
public ResponseEntity<PremiseSearchResultDTO> findMaterialsAndSuppliers(@RequestParam String search) {
try {
// Decode the header value
String decodedValue = URLDecoder.decode(search, StandardCharsets.UTF_8);
return ResponseEntity.ok(premiseSearchStringAnalyzerService.findMaterialAndSuppliers(decodedValue));
} catch (Exception e) {
throw new BadRequestException("Bad string encoding", "Unable to decode request",e);
throw new BadRequestException("Bad string encoding", "Unable to decode request", e);
}
}
@PostMapping({"/create", "/create/"})

View file

@ -1,44 +0,0 @@
package de.avatic.lcc.model.azuremaps;
import java.util.ArrayList;
import java.util.List;
public class BatchGeocodingResult {
private final List<GeocodingResult> results;
private final int successfulRequests;
private final int totalRequests;
public BatchGeocodingResult(List<GeocodingResult> results, int successfulRequests, int totalRequests) {
this.results = results;
this.successfulRequests = successfulRequests;
this.totalRequests = totalRequests;
}
public List<GeocodingResult> getResults() {
return results;
}
public int getSuccessfulRequests() {
return successfulRequests;
}
public int getTotalRequests() {
return totalRequests;
}
public int getFailedRequests() {
return totalRequests - successfulRequests;
}
public boolean isFullySuccessful() {
return successfulRequests == totalRequests;
}
public GeocodingResult getResult(int index) {
if (index >= 0 && index < results.size()) {
return results.get(index);
}
return null;
}
}

View file

@ -1,29 +0,0 @@
package de.avatic.lcc.model.azuremaps;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class BatchResponseItem {
@JsonProperty("statusCode")
private Integer statusCode;
@JsonProperty("response")
private GeocodingResponse response;
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public GeocodingResponse getResponse() {
return response;
}
public void setResponse(GeocodingResponse response) {
this.response = response;
}
}

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding;
import de.avatic.lcc.model.nodes.Location;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding.batch;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding.batch;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@ -12,7 +12,7 @@ public class BatchGeocodingResponse {
private Summary summary;
@JsonProperty("batchItems")
private List<BatchResponseItem> batchItems;
private List<GeocodingBatchResponseItem> batchItems;
public Summary getSummary() {
return summary;
@ -22,11 +22,11 @@ public class BatchGeocodingResponse {
this.summary = summary;
}
public List<BatchResponseItem> getBatchItems() {
public List<GeocodingBatchResponseItem> getBatchItems() {
return batchItems;
}
public void setBatchItems(List<BatchResponseItem> batchItems) {
public void setBatchItems(List<GeocodingBatchResponseItem> batchItems) {
this.batchItems = batchItems;
}

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding.batch;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -0,0 +1,33 @@
package de.avatic.lcc.model.azuremaps.geocoding.batch;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.avatic.lcc.model.azuremaps.geocoding.Feature;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class GeocodingBatchResponseItem {
@JsonProperty("type")
private String type;
@JsonProperty("features")
private List<Feature> features;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Feature> getFeatures() {
return features;
}
public void setFeatures(List<Feature> features) {
this.features = features;
}
}

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.geocoding.batch;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.route;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.route;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.route;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.route;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.route;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

View file

@ -1,4 +1,4 @@
package de.avatic.lcc.model.azuremaps;
package de.avatic.lcc.model.azuremaps.route;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

View file

@ -1,8 +1,11 @@
package de.avatic.lcc.service.api;
import de.avatic.lcc.excelmodel.ExcelNode;
import de.avatic.lcc.model.azuremaps.*;
import de.avatic.lcc.model.azuremaps.geocoding.batch.BatchGeocodingRequest;
import de.avatic.lcc.model.azuremaps.geocoding.batch.BatchGeocodingResponse;
import de.avatic.lcc.model.azuremaps.geocoding.batch.BatchItem;
import de.avatic.lcc.model.bulk.BulkInstruction;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
@ -11,10 +14,11 @@ import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.math.BigDecimal;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Optional;
@Service
public class BatchGeoApiService {
@ -32,60 +36,60 @@ public class BatchGeoApiService {
this.subscriptionKey = subscriptionKey;
}
/**
* Geocode multiple addresses in a single batch request
* @param addresses List of address strings to geocode
* @return BatchGeocodingResult containing all results
*/
public BatchGeocodingResult geocodeBatch(List<BulkInstruction<ExcelNode>> nodes) {
public void geocodeBatch(List<BulkInstruction<ExcelNode>> nodes) {
if (nodes == null || nodes.isEmpty()) {
logger.warn("Address list is null or empty");
return new BatchGeocodingResult(new ArrayList<>(), 0, 0);
return;
}
ArrayList<BulkInstruction<ExcelNode>> noGeo = new ArrayList<>();
int totalSuccessful = 0;
for(var node : nodes) {
if(node.getEntity().getGeoLat() == null || node.getEntity().getGeoLng() == null) {
for (var node : nodes) {
if (node.getEntity().getGeoLat() == null || node.getEntity().getGeoLng() == null) {
noGeo.add(node);
}
}
// Split into chunks if exceeds max batch size
if (noGeo.size() > MAX_BATCH_SIZE) {
return geocodeLargeBatch(noGeo);
for (int currentBatch = 0; currentBatch < noGeo.size(); currentBatch += MAX_BATCH_SIZE) {
int end = Math.min(currentBatch + MAX_BATCH_SIZE, noGeo.size());
var chunk = noGeo.subList(currentBatch, end);
var chunkResult = executeBatchRequest(chunk.stream()
.map(BulkInstruction::getEntity).map(this::getGeoCodeString).map(BatchItem::new)
.toList());
if (chunkResult.isPresent()) {
totalSuccessful += chunkResult.get().getSummary().getSuccessfulRequests();
for (int itemIdx = 0; itemIdx < chunk.size(); itemIdx++) {
var result = chunkResult.get().getBatchItems().get(itemIdx);
var node = chunk.get(itemIdx).getEntity();
if (!result.getFeatures().isEmpty() && result.getFeatures().getFirst().getProperties().getConfidence().equalsIgnoreCase("high")) {
var geometry = result.getFeatures().getFirst().getGeometry();
node.setGeoLng(BigDecimal.valueOf(geometry.getCoordinates().get(0)));
node.setGeoLat(BigDecimal.valueOf(geometry.getCoordinates().get(1)));
} else {
logger.warn("Geocoding failed for address {}", node.getAddress());
throw new ExcelValidationError("Unable to geocode " + node.getName() + ". Please check your address or enter geo position yourself.");
}
}
}
}
List<BatchItem> batchItems = noGeo.stream()
.map(BulkInstruction::getEntity).map(ExcelNode::getAddress).map(BatchItem::new)
.collect(Collectors.toList());
return executeBatchRequest(batchItems);
}
/**
* Geocode multiple addresses with detailed address components
* @param batchItems List of BatchItem with detailed address information
* @return BatchGeocodingResult containing all results
*/
public BatchGeocodingResult geocodeBatchDetailed(List<BatchItem> batchItems) {
if (batchItems == null || batchItems.isEmpty()) {
logger.warn("Batch items list is null or empty");
return new BatchGeocodingResult(new ArrayList<>(), 0, 0);
}
// Split into chunks if exceeds max batch size
if (batchItems.size() > MAX_BATCH_SIZE) {
return geocodeLargeBatchDetailed(batchItems);
}
return executeBatchRequest(batchItems);
private String getGeoCodeString(ExcelNode excelNode) {
return excelNode.getAddress() + ", " + excelNode.getCountryId();
}
private BatchGeocodingResult executeBatchRequest(List<BatchItem> batchItems) {
private Optional<BatchGeocodingResponse> executeBatchRequest(List<BatchItem> batchItems) {
try {
URI uri = UriComponentsBuilder.fromUriString(AZURE_MAPS_BATCH_GEOCODING_URL)
.queryParam("api-version", "2023-06-01")
.queryParam("api-version", "2025-01-01")
.queryParam("subscription-key", subscriptionKey)
.build()
.toUri();
@ -106,21 +110,7 @@ public class BatchGeoApiService {
BatchGeocodingResponse.class
);
BatchGeocodingResponse response = responseEntity.getBody();
if (response != null) {
List<GeocodingResult> results = processResponse(response);
int successful = response.getSummary() != null ?
response.getSummary().getSuccessfulRequests() : 0;
int total = response.getSummary() != null ?
response.getSummary().getTotalRequests() : batchItems.size();
logger.info("Batch geocoding completed: {}/{} successful", successful, total);
return new BatchGeocodingResult(results, successful, total);
}
logger.warn("Received null response from batch geocoding");
return new BatchGeocodingResult(new ArrayList<>(), 0, batchItems.size());
return Optional.ofNullable(responseEntity.getBody());
} catch (Exception e) {
logger.error("Failed to execute batch geocoding request", e);
@ -128,73 +118,4 @@ public class BatchGeoApiService {
}
}
private List<GeocodingResult> processResponse(BatchGeocodingResponse response) {
List<GeocodingResult> results = new ArrayList<>();
if (response.getBatchItems() != null) {
for (BatchResponseItem item : response.getBatchItems()) {
if (item.getStatusCode() == 200 &&
item.getResponse() != null &&
item.getResponse().getFeatures() != null &&
!item.getResponse().getFeatures().isEmpty()) {
Feature feature = item.getResponse().getFeatures().get(0);
results.add(new GeocodingResult(feature));
} else {
// Add null for failed requests to maintain index alignment
results.add(null);
logger.debug("Failed to geocode item at index {}: status code {}",
results.size() - 1, item.getStatusCode());
}
}
}
return results;
}
/**
* Handle batches larger than MAX_BATCH_SIZE by splitting into multiple requests
*/
private BatchGeocodingResult geocodeLargeBatch(List<BulkInstruction<ExcelNode>> addresses) {
logger.info("Processing large batch of {} addresses in chunks of {}",
addresses.size(), MAX_BATCH_SIZE);
List<GeocodingResult> allResults = new ArrayList<>();
int totalSuccessful = 0;
int totalRequests = addresses.size();
//
// for (int i = 0; i < addresses.size(); i += MAX_BATCH_SIZE) {
// int end = Math.min(i + MAX_BATCH_SIZE, addresses.size());
// List<String> chunk = addresses.subList(i, end);
//
// BatchGeocodingResult chunkResult = geocodeBatch(chunk);
// allResults.addAll(chunkResult.getResults());
// totalSuccessful += chunkResult.getSuccessfulRequests();
// }
return new BatchGeocodingResult(allResults, totalSuccessful, totalRequests);
}
/**
* Handle detailed batches larger than MAX_BATCH_SIZE
*/
private BatchGeocodingResult geocodeLargeBatchDetailed(List<BatchItem> batchItems) {
logger.info("Processing large detailed batch of {} items in chunks of {}",
batchItems.size(), MAX_BATCH_SIZE);
List<GeocodingResult> allResults = new ArrayList<>();
int totalSuccessful = 0;
int totalRequests = batchItems.size();
for (int i = 0; i < batchItems.size(); i += MAX_BATCH_SIZE) {
int end = Math.min(i + MAX_BATCH_SIZE, batchItems.size());
List<BatchItem> chunk = batchItems.subList(i, end);
BatchGeocodingResult chunkResult = geocodeBatchDetailed(chunk);
allResults.addAll(chunkResult.getResults());
totalSuccessful += chunkResult.getSuccessfulRequests();
}
return new BatchGeocodingResult(allResults, totalSuccessful, totalRequests);
}
}

View file

@ -1,6 +1,6 @@
package de.avatic.lcc.service.api;
import de.avatic.lcc.model.azuremaps.RouteDirectionsResponse;
import de.avatic.lcc.model.azuremaps.route.RouteDirectionsResponse;
import de.avatic.lcc.model.nodes.Distance;
import de.avatic.lcc.model.nodes.DistanceMatrixState;
import de.avatic.lcc.model.nodes.Node;

View file

@ -1,8 +1,8 @@
package de.avatic.lcc.service.api;
import de.avatic.lcc.model.azuremaps.GeocodingResponse;
import de.avatic.lcc.model.azuremaps.GeocodingResult;
import de.avatic.lcc.model.azuremaps.Feature;
import de.avatic.lcc.model.azuremaps.geocoding.GeocodingResponse;
import de.avatic.lcc.model.azuremaps.geocoding.GeocodingResult;
import de.avatic.lcc.model.azuremaps.geocoding.Feature;
import de.avatic.lcc.model.nodes.Location;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -36,7 +36,7 @@ public class GeoApiService {
try {
URI uri = UriComponentsBuilder.fromUriString(AZURE_MAPS_GEOCODING_URL)
.queryParam("api-version", "2023-06-01")
.queryParam("api-version", "2025-01-01")
.queryParam("query", address)
.queryParam("subscription-key", subscriptionKey)
.build()

View file

@ -91,7 +91,7 @@ public class BulkImportService {
break;
case NODE:
var nodeInstructions = nodeExcelMapper.extractSheet(sheet);
// batchGeoApiService.geocodeBatch(nodeInstructions);
batchGeoApiService.geocodeBatch(nodeInstructions);
nodeInstructions.forEach(nodeBulkImportService::processNodeInstructions);
break;
default: