Remove RoutingService2 and implement premise creation logic
Deleted the unused `RoutingService2` class to simplify the codebase. Added the logic for creating and duplicating premises in `PremiseCreationService`, including filtering and handling combinations of material and supplier IDs.
This commit is contained in:
parent
a468e3d187
commit
fd6e4ea435
20 changed files with 1406 additions and 1375 deletions
|
|
@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/calculation")
|
@RequestMapping("/api/calculation")
|
||||||
|
|
@ -70,7 +71,7 @@ public class CalculationController {
|
||||||
// triggers a calculation
|
// triggers a calculation
|
||||||
@PutMapping("/done")
|
@PutMapping("/done")
|
||||||
public ResponseEntity<Integer> completePremises(@RequestBody List<Integer> premiseIds) {
|
public ResponseEntity<Integer> completePremises(@RequestBody List<Integer> premiseIds) {
|
||||||
return ResponseEntity.ok(premisesServices.startCalculation(premiseIds));
|
return ResponseEntity.ok(premisesServices.startCalculation(premiseIds)); //TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/packaging")
|
@PutMapping("/packaging")
|
||||||
|
|
@ -89,7 +90,7 @@ public class CalculationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/destination")
|
@PostMapping("/destination")
|
||||||
public ResponseEntity<HashMap<Integer, DestinationDTO>> createDestination(@RequestBody DestinationCreateDTO destinationCreateDTO) {
|
public ResponseEntity<Map<Integer, DestinationDTO>> createDestination(@RequestBody DestinationCreateDTO destinationCreateDTO) {
|
||||||
return ResponseEntity.ok(destinationService.createDestination(destinationCreateDTO));
|
return ResponseEntity.ok(destinationService.createDestination(destinationCreateDTO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ public class SetDataDTO {
|
||||||
@JsonProperty("update_master_data")
|
@JsonProperty("update_master_data")
|
||||||
boolean updateMasterData;
|
boolean updateMasterData;
|
||||||
|
|
||||||
@JsonProperty("supplier_node_id", required = false)
|
@JsonProperty(defaultValue = "supplier_node_id", required = false)
|
||||||
Integer supplierNodeId;
|
Integer supplierNodeId;
|
||||||
|
|
||||||
@JsonProperty("is_user_supplier_node")
|
@JsonProperty("is_user_supplier_node")
|
||||||
|
|
|
||||||
|
|
@ -7,20 +7,22 @@ public class RouteInformation {
|
||||||
|
|
||||||
private Route route;
|
private Route route;
|
||||||
|
|
||||||
private List<RouteSection> sections;
|
private List<RouteSectionInformation> sections;
|
||||||
|
|
||||||
private List<RouteNode> nodes;
|
|
||||||
|
|
||||||
|
public Route getRoute() {
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
public void setRoute(Route route) {
|
public void setRoute(Route route) {
|
||||||
this.route = route;
|
this.route = route;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRouteNodes(List<RouteNode> nodes) {
|
public List<RouteSectionInformation> getSections() {
|
||||||
this.nodes = nodes;
|
return sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRouteSections(List<RouteSection> sections) {
|
public void setSections(List<RouteSectionInformation> sections) {
|
||||||
this.sections = sections;
|
this.sections = sections;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package de.avatic.lcc.model.premises.route;
|
||||||
|
|
||||||
|
public class RouteSectionInformation {
|
||||||
|
|
||||||
|
private RouteNode fromNode;
|
||||||
|
private RouteNode toNode;
|
||||||
|
private RouteSection section;
|
||||||
|
|
||||||
|
public RouteSectionInformation(RouteSection routeSection, RouteNode fromNode, RouteNode toNode) {
|
||||||
|
this.section = routeSection;
|
||||||
|
this.fromNode = fromNode;
|
||||||
|
this.toNode = toNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public RouteNode getFromNode() {
|
||||||
|
return fromNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromNode(RouteNode fromNode) {
|
||||||
|
this.fromNode = fromNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteNode getToNode() {
|
||||||
|
return toNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToNode(RouteNode toNode) {
|
||||||
|
this.toNode = toNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteSection getSection() {
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSection(RouteSection section) {
|
||||||
|
this.section = section;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,9 +15,7 @@ import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public class MaterialRepository {
|
public class MaterialRepository {
|
||||||
|
|
@ -29,28 +27,6 @@ public class MaterialRepository {
|
||||||
this.jdbcTemplate = jdbcTemplate;
|
this.jdbcTemplate = jdbcTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Material> listAllMaterials() {
|
|
||||||
String query = "SELECT * FROM material ORDER BY normalized_part_number";
|
|
||||||
return jdbcTemplate.query(query, new MaterialMapper());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class MaterialMapper implements RowMapper<Material> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Material mapRow(ResultSet rs, int rowNum) throws SQLException {
|
|
||||||
Material data = new Material();
|
|
||||||
data.setId(rs.getInt("id"));
|
|
||||||
data.setName(rs.getString("name"));
|
|
||||||
data.setPartNumber(rs.getString("part_number"));
|
|
||||||
data.setNormalizedPartNumber(rs.getString("normalized_part_number"));
|
|
||||||
data.setHsCode(rs.getString("hs_code"));
|
|
||||||
data.setDeprecated(rs.getBoolean("is_deprecated"));
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static String buildCountQuery(String filter, boolean excludeDeprecated) {
|
private static String buildCountQuery(String filter, boolean excludeDeprecated) {
|
||||||
StringBuilder queryBuilder = new StringBuilder("""
|
StringBuilder queryBuilder = new StringBuilder("""
|
||||||
SELECT count(*)
|
SELECT count(*)
|
||||||
|
|
@ -66,7 +42,6 @@ public class MaterialRepository {
|
||||||
return queryBuilder.toString();
|
return queryBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static String buildQuery(String filter, boolean excludeDeprecated) {
|
private static String buildQuery(String filter, boolean excludeDeprecated) {
|
||||||
StringBuilder queryBuilder = new StringBuilder("""
|
StringBuilder queryBuilder = new StringBuilder("""
|
||||||
SELECT id, name, part_number, normalized_part_number, hs_code, is_deprecated
|
SELECT id, name, part_number, normalized_part_number, hs_code, is_deprecated
|
||||||
|
|
@ -82,8 +57,25 @@ public class MaterialRepository {
|
||||||
return queryBuilder.toString();
|
return queryBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Material> listAllMaterials() {
|
||||||
|
String query = "SELECT * FROM material ORDER BY normalized_part_number";
|
||||||
|
return jdbcTemplate.query(query, new MaterialMapper());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Material> getByPartNumbers(Collection<String> partNumbers) {
|
||||||
|
// Handle null or empty case
|
||||||
|
if (partNumbers == null || partNumbers.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String placeholders = String.join(",", Collections.nCopies(partNumbers.size(), "?"));
|
||||||
|
String query = "SELECT * FROM material WHERE part_number IN (" + placeholders + ")";
|
||||||
|
|
||||||
|
return jdbcTemplate.query(query, new MaterialMapper(), partNumbers.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public Optional<Integer> setDeprecatedById(Integer id) {
|
public Optional<Integer> setDeprecatedById(Integer id) {
|
||||||
String query = "UPDATE material SET is_deprecated = TRUE WHERE id = ?";
|
String query = "UPDATE material SET is_deprecated = TRUE WHERE id = ?";
|
||||||
return Optional.ofNullable(jdbcTemplate.update(query, id) == 0 ? null : id);
|
return Optional.ofNullable(jdbcTemplate.update(query, id) == 0 ? null : id);
|
||||||
}
|
}
|
||||||
|
|
@ -149,4 +141,19 @@ public class MaterialRepository {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class MaterialMapper implements RowMapper<Material> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||||
|
Material data = new Material();
|
||||||
|
data.setId(rs.getInt("id"));
|
||||||
|
data.setName(rs.getString("name"));
|
||||||
|
data.setPartNumber(rs.getString("part_number"));
|
||||||
|
data.setNormalizedPartNumber(rs.getString("normalized_part_number"));
|
||||||
|
data.setHsCode(rs.getString("hs_code"));
|
||||||
|
data.setDeprecated(rs.getBoolean("is_deprecated"));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package de.avatic.lcc.repositories;
|
package de.avatic.lcc.repositories;
|
||||||
|
|
||||||
|
import de.avatic.lcc.dto.generic.NodeDTO;
|
||||||
import de.avatic.lcc.dto.generic.NodeType;
|
import de.avatic.lcc.dto.generic.NodeType;
|
||||||
import de.avatic.lcc.model.nodes.Node;
|
import de.avatic.lcc.model.nodes.Node;
|
||||||
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
|
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
|
||||||
|
|
@ -32,9 +33,21 @@ public class NodeRepository {
|
||||||
FROM node
|
FROM node
|
||||||
WHERE node.id = ?""";
|
WHERE node.id = ?""";
|
||||||
|
|
||||||
var chain = jdbcTemplate.queryForObject(query, new NodeMapper(), id);
|
var node = jdbcTemplate.queryForObject(query, new NodeMapper(), id);
|
||||||
|
|
||||||
return Optional.ofNullable(chain);
|
return Optional.ofNullable(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Node> getByIds(List<Integer> nodeIds) {
|
||||||
|
|
||||||
|
String placeholders = String.join(",", Collections.nCopies(nodeIds.size(), "?"));
|
||||||
|
String query = """
|
||||||
|
SELECT node.id AS id, node.name AS name, node.address as address, node.is_source as is_source,
|
||||||
|
node.is_destination as is_destination, node.is_intermediate as is_intermediate, node.country_id as country_id, node.predecessor_required as predecessor_required
|
||||||
|
FROM node
|
||||||
|
WHERE node.id IN (?)""";
|
||||||
|
|
||||||
|
return jdbcTemplate.query(query, new NodeMapper(), nodeIds.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Map<Integer, Integer>> getPredecessorsOf(Integer id) {
|
private List<Map<Integer, Integer>> getPredecessorsOf(Integer id) {
|
||||||
|
|
@ -281,6 +294,7 @@ public class NodeRepository {
|
||||||
return jdbcTemplate.query(query, new NodeMapper(), countryId);
|
return jdbcTemplate.query(query, new NodeMapper(), countryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class NodeMapper implements RowMapper<Node> {
|
private class NodeMapper implements RowMapper<Node> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,14 @@ package de.avatic.lcc.repositories.premise;
|
||||||
import de.avatic.lcc.model.premises.route.Destination;
|
import de.avatic.lcc.model.premises.route.Destination;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||||
|
import org.springframework.jdbc.support.KeyHolder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
@ -70,6 +73,38 @@ public class DestinationRepository {
|
||||||
return Optional.of(userId.getFirst());
|
return Optional.of(userId.getFirst());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Destination> getByPremiseIdsAndNodeId(List<Integer> premiseId, Integer nodeId, Integer userId) {
|
||||||
|
String placeholder = String.join(",", Collections.nCopies(premiseId.size(), "?"));
|
||||||
|
String query = "SELECT * FROM premise_destination JOIN premise ON premise_destination.premise_id = premise.id WHERE premise_id IN ("+placeholder+") AND premise_destination.destination_node_id AND premise.user_id = ?";
|
||||||
|
|
||||||
|
return jdbcTemplate.query(query, new DestinationMapper(), premiseId, nodeId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer insert(Destination destination) {
|
||||||
|
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||||
|
|
||||||
|
String query = "INSERT INTO premise_destination (annual_amount, premise_id, destination_node_id, rate_d2d, is_d2d, repacking_cost, handling_cost, disposal_cost) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
|
||||||
|
jdbcTemplate.update(connection -> {
|
||||||
|
var ps = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
||||||
|
ps.setBigDecimal(1, destination.getAnnualAmount());
|
||||||
|
ps.setInt(2, destination.getPremiseId());
|
||||||
|
ps.setInt(3, destination.getDestinationNodeId());
|
||||||
|
ps.setBigDecimal(4, destination.getRateD2d());
|
||||||
|
ps.setBoolean(5, destination.getD2d());
|
||||||
|
ps.setBigDecimal(6, destination.getRepackingCost());
|
||||||
|
ps.setBigDecimal(7, destination.getHandlingCost());
|
||||||
|
ps.setBigDecimal(8, destination.getDisposalCost());
|
||||||
|
return ps;
|
||||||
|
}, keyHolder);
|
||||||
|
|
||||||
|
return keyHolder.getKey() != null ? keyHolder.getKey().intValue() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void duplicate(Integer fromId, Integer toId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class DestinationMapper implements RowMapper<Destination> {
|
private static class DestinationMapper implements RowMapper<Destination> {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,17 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||||
|
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||||
|
import org.springframework.jdbc.support.KeyHolder;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -34,6 +39,7 @@ public class PremiseRepository {
|
||||||
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
|
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public SearchQueryResult<PremiseListEntry> listPremises(String filter, SearchQueryPagination pagination,
|
public SearchQueryResult<PremiseListEntry> listPremises(String filter, SearchQueryPagination pagination,
|
||||||
Integer userId, Boolean deleted, Boolean archived, Boolean done) {
|
Integer userId, Boolean deleted, Boolean archived, Boolean done) {
|
||||||
|
|
||||||
|
|
@ -111,6 +117,7 @@ public class PremiseRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
public List<Premise> getPremisesById(List<Integer> premiseIds) {
|
public List<Premise> getPremisesById(List<Integer> premiseIds) {
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -132,6 +139,7 @@ public class PremiseRepository {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public Optional<Premise> getPremiseById(Integer id) {
|
public Optional<Premise> getPremiseById(Integer id) {
|
||||||
|
|
||||||
String query = """
|
String query = """
|
||||||
|
|
@ -189,6 +197,7 @@ public class PremiseRepository {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void updateMaterial(List<Integer> premiseIds, Integer userId, String hsCode, BigDecimal tariffRate) {
|
public void updateMaterial(List<Integer> premiseIds, Integer userId, String hsCode, BigDecimal tariffRate) {
|
||||||
|
|
||||||
String placeholders = String.join(",", Collections.nCopies(premiseIds.size(), "?"));
|
String placeholders = String.join(",", Collections.nCopies(premiseIds.size(), "?"));
|
||||||
|
|
@ -214,6 +223,7 @@ public class PremiseRepository {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void updatePrice(List<Integer> premiseIds, int userId, BigDecimal price, Boolean includeFcaFee, BigDecimal overseaShare) {
|
public void updatePrice(List<Integer> premiseIds, int userId, BigDecimal price, Boolean includeFcaFee, BigDecimal overseaShare) {
|
||||||
String placeholders = String.join(",", Collections.nCopies(premiseIds.size(), "?"));
|
String placeholders = String.join(",", Collections.nCopies(premiseIds.size(), "?"));
|
||||||
|
|
||||||
|
|
@ -255,6 +265,7 @@ public class PremiseRepository {
|
||||||
* @return A list of premises in the DRAFT state with the same material and supplier combination (excluding the specified premise).
|
* @return A list of premises in the DRAFT state with the same material and supplier combination (excluding the specified premise).
|
||||||
* @throws IllegalArgumentException If any of the provided parameters are null.
|
* @throws IllegalArgumentException If any of the provided parameters are null.
|
||||||
*/
|
*/
|
||||||
|
@Transactional(readOnly = true)
|
||||||
public List<Premise> getCollidingPremisesOnChange(Integer userId, Integer premiseId, Integer materialId, Integer supplierId) {
|
public List<Premise> getCollidingPremisesOnChange(Integer userId, Integer premiseId, Integer materialId, Integer supplierId) {
|
||||||
|
|
||||||
if( premiseId == null || materialId == null || supplierId == null )
|
if( premiseId == null || materialId == null || supplierId == null )
|
||||||
|
|
@ -270,6 +281,7 @@ public class PremiseRepository {
|
||||||
return jdbcTemplate.query(sql, new PremiseMapper(), materialId, supplierId, premiseId, userId);
|
return jdbcTemplate.query(sql, new PremiseMapper(), materialId, supplierId, premiseId, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void deletePremisesById(List<Integer> premiseIds) {
|
public void deletePremisesById(List<Integer> premiseIds) {
|
||||||
if(premiseIds == null || premiseIds.isEmpty()) return;
|
if(premiseIds == null || premiseIds.isEmpty()) return;
|
||||||
|
|
||||||
|
|
@ -281,12 +293,14 @@ public class PremiseRepository {
|
||||||
jdbcTemplate.update(query, premiseIds.toArray());
|
jdbcTemplate.update(query, premiseIds.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void updateTariffRate(Integer premiseId, Number tariffRate) {
|
public void updateTariffRate(Integer premiseId, Number tariffRate) {
|
||||||
String sql = "UPDATE premise SET tariff_rate = ? WHERE id = ?";
|
String sql = "UPDATE premise SET tariff_rate = ? WHERE id = ?";
|
||||||
|
|
||||||
jdbcTemplate.update(sql, tariffRate, premiseId);
|
jdbcTemplate.update(sql, tariffRate, premiseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void setSupplierId(List<Integer> premiseId, Integer supplierId, boolean userSupplierNode) {
|
public void setSupplierId(List<Integer> premiseId, Integer supplierId, boolean userSupplierNode) {
|
||||||
String placeholders = String.join(",", Collections.nCopies(premiseId.size(), "?"));
|
String placeholders = String.join(",", Collections.nCopies(premiseId.size(), "?"));
|
||||||
String sql = "UPDATE premise SET supplier_node_id = ?, user_supplier_node_id = ? WHERE id IN ("+placeholders+")";
|
String sql = "UPDATE premise SET supplier_node_id = ?, user_supplier_node_id = ? WHERE id IN ("+placeholders+")";
|
||||||
|
|
@ -298,6 +312,124 @@ public class PremiseRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void setMaterialId(List<Integer> premiseId, Integer materialId) {
|
||||||
|
String placeholders = String.join(",", Collections.nCopies(premiseId.size(), "?"));
|
||||||
|
String sql = "UPDATE premise SET material_id = ? WHERE id IN ("+placeholders+")";
|
||||||
|
|
||||||
|
jdbcTemplate.update(sql, materialId, premiseId.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public List<Premise> getPremisesByMaterialIdsAndSupplierIds(List<Integer> materialIds, List<Integer> supplierIds, List<Integer> userSupplierIds, Integer userId, boolean draftsOnly) {
|
||||||
|
|
||||||
|
if ((materialIds == null || materialIds.isEmpty()) &&
|
||||||
|
(supplierIds == null || supplierIds.isEmpty()) &&
|
||||||
|
(userSupplierIds == null || userSupplierIds.isEmpty())) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder query = new StringBuilder("""
|
||||||
|
SELECT * FROM premise
|
||||||
|
WHERE 1=1
|
||||||
|
""");
|
||||||
|
|
||||||
|
if(draftsOnly)
|
||||||
|
query.append(" AND user_id = ? AND state = ?");
|
||||||
|
|
||||||
|
// Append conditions for IDs
|
||||||
|
if (materialIds != null && !materialIds.isEmpty()) {
|
||||||
|
String materialPlaceholders = String.join(",", Collections.nCopies(materialIds.size(), "?"));
|
||||||
|
query.append(" AND material_id IN (").append(materialPlaceholders).append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supplierIds != null && !supplierIds.isEmpty()) {
|
||||||
|
String supplierPlaceholders = String.join(",", Collections.nCopies(supplierIds.size(), "?"));
|
||||||
|
query.append(" AND supplier_node_id IN (").append(supplierPlaceholders).append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userSupplierIds != null && !userSupplierIds.isEmpty()) {
|
||||||
|
String userSupplierPlaceholders = String.join(",", Collections.nCopies(userSupplierIds.size(), "?"));
|
||||||
|
query.append(" AND user_supplier_node_id IN (").append(userSupplierPlaceholders).append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine parameters for prepared statement
|
||||||
|
var params = new ArrayList<>();
|
||||||
|
|
||||||
|
if(draftsOnly) {
|
||||||
|
params.add(userId);
|
||||||
|
params.add(PremiseState.DRAFT.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (materialIds != null && !materialIds.isEmpty()) params.addAll(materialIds);
|
||||||
|
if (supplierIds != null && !supplierIds.isEmpty()) params.addAll(supplierIds);
|
||||||
|
if (userSupplierIds != null && !userSupplierIds.isEmpty()) params.addAll(userSupplierIds);
|
||||||
|
|
||||||
|
return jdbcTemplate.query(query.toString(), new PremiseMapper(), params.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Integer insert(Integer materialId, Integer supplierId, Integer userSupplierId, Integer userId) {
|
||||||
|
|
||||||
|
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||||
|
|
||||||
|
jdbcTemplate.update(connection -> {
|
||||||
|
PreparedStatement ps = connection.prepareStatement(
|
||||||
|
"INSERT INTO premise (material_id, supplier_node_id, user_supplier_node_id, user_id, state, createdAt, updatedAt)" +
|
||||||
|
" VALUES (?, ?, ?, ?, 'DRAFT', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)",
|
||||||
|
Statement.RETURN_GENERATED_KEYS);
|
||||||
|
|
||||||
|
ps.setInt(1, materialId);
|
||||||
|
ps.setObject(2, supplierId);
|
||||||
|
ps.setObject(3, userSupplierId);
|
||||||
|
ps.setInt(4, userId);
|
||||||
|
|
||||||
|
return ps;
|
||||||
|
}, keyHolder);
|
||||||
|
|
||||||
|
return keyHolder.getKey() != null ? keyHolder.getKey().intValue() : null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public List<Integer> findAssociatedSuppliers(List<Integer> materialIds) {
|
||||||
|
if (materialIds == null || materialIds.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String placeholders = String.join(",", Collections.nCopies(materialIds.size(), "?"));
|
||||||
|
String query = """
|
||||||
|
SELECT DISTINCT supplier_node_id
|
||||||
|
FROM premise
|
||||||
|
WHERE material_id IN (""" + placeholders + ")";
|
||||||
|
|
||||||
|
return jdbcTemplate.query(
|
||||||
|
query,
|
||||||
|
(rs, rowNum) -> rs.getInt("supplier_node_id"),
|
||||||
|
materialIds.toArray()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public List<Integer> findAssociatedUserSuppliers(List<Integer> materialIds) {
|
||||||
|
|
||||||
|
if (materialIds == null || materialIds.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String placeholders = String.join(",", Collections.nCopies(materialIds.size(), "?"));
|
||||||
|
String query = """
|
||||||
|
SELECT DISTINCT user_supplier_node_id
|
||||||
|
FROM premise
|
||||||
|
WHERE material_id IN (""" + placeholders + ")";
|
||||||
|
|
||||||
|
return jdbcTemplate.query(
|
||||||
|
query,
|
||||||
|
(rs, rowNum) -> rs.getInt("user_supplier_node_id"),
|
||||||
|
materialIds.toArray()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates SQL query building logic
|
* Encapsulates SQL query building logic
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,14 @@ package de.avatic.lcc.repositories.premise;
|
||||||
import de.avatic.lcc.model.premises.route.RouteNode;
|
import de.avatic.lcc.model.premises.route.RouteNode;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||||
|
import org.springframework.jdbc.support.KeyHolder;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -43,6 +47,29 @@ public class RouteNodeRepository {
|
||||||
jdbcTemplate.update(sql, ids.toArray(new Object[0]));
|
jdbcTemplate.update(sql, ids.toArray(new Object[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer insert(RouteNode node) {
|
||||||
|
String sql = "INSERT INTO premise_route_node (name, address, geo_lat, geo_lng, is_destination, is_intermediate, " +
|
||||||
|
"is_source, node_id, user_node_id, is_outdated) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||||
|
|
||||||
|
jdbcTemplate.update(connection -> {
|
||||||
|
PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
|
||||||
|
ps.setString(1, node.getName());
|
||||||
|
ps.setString(2, node.getAddress());
|
||||||
|
ps.setBigDecimal(3, node.getGeoLat());
|
||||||
|
ps.setBigDecimal(4, node.getGeoLng());
|
||||||
|
ps.setBoolean(5, Boolean.TRUE.equals(node.getDestination()));
|
||||||
|
ps.setBoolean(6, Boolean.TRUE.equals(node.getIntermediate()));
|
||||||
|
ps.setBoolean(7, Boolean.TRUE.equals(node.getSource()));
|
||||||
|
ps.setObject(8, node.getNodeId(), java.sql.Types.INTEGER);
|
||||||
|
ps.setObject(9, node.getUserNodeId(), java.sql.Types.INTEGER);
|
||||||
|
ps.setBoolean(10, Boolean.TRUE.equals(node.getOutdated()));
|
||||||
|
return ps;
|
||||||
|
}, keyHolder);
|
||||||
|
|
||||||
|
return keyHolder.getKey() != null ? keyHolder.getKey().intValue() : null;
|
||||||
|
}
|
||||||
|
|
||||||
private static class RouteNodeMapper implements RowMapper<RouteNode> {
|
private static class RouteNodeMapper implements RowMapper<RouteNode> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,17 @@ package de.avatic.lcc.repositories.premise;
|
||||||
import de.avatic.lcc.model.premises.route.Route;
|
import de.avatic.lcc.model.premises.route.Route;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||||
|
import org.springframework.jdbc.support.KeyHolder;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public class RouteRepository {
|
public class RouteRepository {
|
||||||
|
|
@ -36,6 +41,26 @@ public class RouteRepository {
|
||||||
jdbcTemplate.update(sql, ids.toArray(new Object[0]));
|
jdbcTemplate.update(sql, ids.toArray(new Object[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer insert(Route premiseRoute) {
|
||||||
|
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||||
|
|
||||||
|
jdbcTemplate.update(connection -> {
|
||||||
|
PreparedStatement ps = connection.prepareStatement(
|
||||||
|
"INSERT INTO premise_route (is_cheapest, is_fastest, is_selected, premise_destination_id) " +
|
||||||
|
"VALUES (?, ?, ?, ?)",
|
||||||
|
Statement.RETURN_GENERATED_KEYS);
|
||||||
|
|
||||||
|
ps.setBoolean(1, premiseRoute.getCheapest());
|
||||||
|
ps.setBoolean(2, premiseRoute.getFastest());
|
||||||
|
ps.setBoolean(3, premiseRoute.getSelected());
|
||||||
|
ps.setInt(4, premiseRoute.getDestinationId());
|
||||||
|
|
||||||
|
return ps;
|
||||||
|
}, keyHolder);
|
||||||
|
|
||||||
|
return keyHolder.getKey() != null ? keyHolder.getKey().intValue() : null;
|
||||||
|
}
|
||||||
|
|
||||||
private static class RouteMapper implements RowMapper<Route> {
|
private static class RouteMapper implements RowMapper<Route> {
|
||||||
@Override
|
@Override
|
||||||
public Route mapRow(ResultSet rs, int rowNum) throws SQLException {
|
public Route mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,14 @@ import de.avatic.lcc.dto.generic.RouteType;
|
||||||
import de.avatic.lcc.model.premises.route.RouteSection;
|
import de.avatic.lcc.model.premises.route.RouteSection;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||||
|
import org.springframework.jdbc.support.KeyHolder;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -38,6 +42,28 @@ public class RouteSectionRepository {
|
||||||
jdbcTemplate.update(sql, ids.toArray(new Object[0]));
|
jdbcTemplate.update(sql, ids.toArray(new Object[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer insert(RouteSection premiseRouteSection) {
|
||||||
|
String sql = "INSERT INTO premise_route_section (premise_route_id, from_route_node_id, to_route_node_id, list_position, transport_type, is_pre_run, is_main_run, is_post_run, is_outdated) " +
|
||||||
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||||
|
|
||||||
|
jdbcTemplate.update(connection -> {
|
||||||
|
PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
|
||||||
|
ps.setInt(1, premiseRouteSection.getRouteId());
|
||||||
|
ps.setInt(2, premiseRouteSection.getFromRouteNodeId());
|
||||||
|
ps.setInt(3, premiseRouteSection.getToRouteNodeId());
|
||||||
|
ps.setInt(4, premiseRouteSection.getListPosition());
|
||||||
|
ps.setString(5, premiseRouteSection.getTransportType().name());
|
||||||
|
ps.setBoolean(6, premiseRouteSection.getPreRun());
|
||||||
|
ps.setBoolean(7, premiseRouteSection.getMainRun());
|
||||||
|
ps.setBoolean(8, premiseRouteSection.getPostRun());
|
||||||
|
ps.setBoolean(9, premiseRouteSection.getOutdated());
|
||||||
|
return ps;
|
||||||
|
}, keyHolder);
|
||||||
|
|
||||||
|
return keyHolder.getKey() != null ? keyHolder.getKey().intValue() : null;
|
||||||
|
}
|
||||||
|
|
||||||
private static class RouteSectionMapper implements RowMapper<RouteSection> {
|
private static class RouteSectionMapper implements RowMapper<RouteSection> {
|
||||||
@Override
|
@Override
|
||||||
public RouteSection mapRow(ResultSet rs, int rowNum) throws SQLException {
|
public RouteSection mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,20 @@ package de.avatic.lcc.service.access;
|
||||||
import de.avatic.lcc.dto.calculation.edit.destination.DestinationCreateDTO;
|
import de.avatic.lcc.dto.calculation.edit.destination.DestinationCreateDTO;
|
||||||
import de.avatic.lcc.dto.calculation.DestinationDTO;
|
import de.avatic.lcc.dto.calculation.DestinationDTO;
|
||||||
import de.avatic.lcc.dto.calculation.edit.destination.DestinationUpdateDTO;
|
import de.avatic.lcc.dto.calculation.edit.destination.DestinationUpdateDTO;
|
||||||
import de.avatic.lcc.model.premises.route.Route;
|
import de.avatic.lcc.model.nodes.Node;
|
||||||
import de.avatic.lcc.model.premises.route.RouteSection;
|
import de.avatic.lcc.model.premises.route.*;
|
||||||
import de.avatic.lcc.repositories.premise.DestinationRepository;
|
import de.avatic.lcc.repositories.NodeRepository;
|
||||||
import de.avatic.lcc.repositories.premise.RouteNodeRepository;
|
import de.avatic.lcc.repositories.premise.*;
|
||||||
import de.avatic.lcc.repositories.premise.RouteRepository;
|
import de.avatic.lcc.repositories.users.UserNodeRepository;
|
||||||
import de.avatic.lcc.repositories.premise.RouteSectionRepository;
|
import de.avatic.lcc.service.calculation.RoutingService;
|
||||||
import de.avatic.lcc.service.transformer.premise.DestinationTransformer;
|
import de.avatic.lcc.service.transformer.premise.DestinationTransformer;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.math.BigDecimal;
|
||||||
import java.util.HashMap;
|
import java.sql.Array;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Optional;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
|
@ -28,25 +28,62 @@ public class DestinationService {
|
||||||
private final RouteRepository routeRepository;
|
private final RouteRepository routeRepository;
|
||||||
private final RouteSectionRepository routeSectionRepository;
|
private final RouteSectionRepository routeSectionRepository;
|
||||||
private final RouteNodeRepository routeNodeRepository;
|
private final RouteNodeRepository routeNodeRepository;
|
||||||
|
private final RoutingService routingService;;
|
||||||
|
private final NodeRepository nodeRepository;
|
||||||
|
private final PremiseRepository premiseRepository;
|
||||||
|
private final UserNodeRepository userNodeRepository;
|
||||||
|
|
||||||
public DestinationService(DestinationRepository destinationRepository, DestinationTransformer destinationTransformer, RouteRepository routeRepository, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository) {
|
public DestinationService(DestinationRepository destinationRepository, DestinationTransformer destinationTransformer, RouteRepository routeRepository, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository, RoutingService routingService, NodeRepository nodeRepository, PremiseRepository premiseRepository, UserNodeRepository userNodeRepository) {
|
||||||
this.destinationRepository = destinationRepository;
|
this.destinationRepository = destinationRepository;
|
||||||
this.destinationTransformer = destinationTransformer;
|
this.destinationTransformer = destinationTransformer;
|
||||||
this.routeRepository = routeRepository;
|
this.routeRepository = routeRepository;
|
||||||
this.routeSectionRepository = routeSectionRepository;
|
this.routeSectionRepository = routeSectionRepository;
|
||||||
this.routeNodeRepository = routeNodeRepository;
|
this.routeNodeRepository = routeNodeRepository;
|
||||||
|
this.routingService = routingService;
|
||||||
|
this.nodeRepository = nodeRepository;
|
||||||
|
this.premiseRepository = premiseRepository;
|
||||||
|
this.userNodeRepository = userNodeRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashMap<Integer, DestinationDTO> createDestination(DestinationCreateDTO destinationCreateDTO) {
|
@Transactional
|
||||||
|
public Map<Integer, DestinationDTO> createDestination(DestinationCreateDTO dto) {
|
||||||
|
|
||||||
// do some checks
|
Integer userId = 1; //TODO get user id.
|
||||||
// - no duplicates
|
|
||||||
|
|
||||||
// do routing.
|
var existingDestinations = destinationRepository.getByPremiseIdsAndNodeId(dto.getPremiseId(), dto.getDestinationNodeId(), userId);
|
||||||
|
|
||||||
// create database entries.
|
var premisesIdsToProcess = new ArrayList<Integer>();
|
||||||
|
for(var premiseId : dto.getPremiseId()) {
|
||||||
|
if(existingDestinations.stream().map(Destination::getPremiseId).noneMatch(id -> id.equals(premiseId))) {
|
||||||
|
premisesIdsToProcess.add(premiseId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var premisesToProcess = premiseRepository.getPremisesById(premisesIdsToProcess);
|
||||||
|
Node destinationNode = nodeRepository.getById(dto.getDestinationNodeId()).orElseThrow();
|
||||||
|
|
||||||
|
|
||||||
|
var destinations = new ArrayList<Destination>();
|
||||||
|
|
||||||
|
for(var premise : premisesToProcess) {
|
||||||
|
var destination = new Destination();
|
||||||
|
destination.setDestinationNodeId(dto.getDestinationNodeId());
|
||||||
|
destination.setPremiseId(premise.getId());
|
||||||
|
destination.setAnnualAmount(BigDecimal.ZERO);
|
||||||
|
destination.setD2d(false);
|
||||||
|
destination.setDisposalCost(null);
|
||||||
|
destination.setHandlingCost(null);
|
||||||
|
destination.setRepackingCost(null);
|
||||||
|
destination.setRateD2d(BigDecimal.ZERO);
|
||||||
|
destination.setId(destinationRepository.insert(destination));
|
||||||
|
|
||||||
|
Node source = premise.getSupplierNodeId() == null ? userNodeRepository.getById(premise.getUserSupplierNodeId()).orElseThrow() : nodeRepository.getById(premise.getSupplierNodeId()).orElseThrow();
|
||||||
|
findRouteAndSave(destination.getId(), destinationNode, source, premise.getSupplierNodeId() == null);
|
||||||
|
destinations.add(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
return destinations.stream().collect(Collectors.toMap(Destination::getPremiseId, destinationTransformer::toDestinationDTO));
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DestinationDTO getDestination(Integer id) {
|
public DestinationDTO getDestination(Integer id) {
|
||||||
|
|
@ -63,6 +100,44 @@ public class DestinationService {
|
||||||
destinationRepository.update(id, userId, destinationUpdateDTO.getRepackingCost(), destinationUpdateDTO.getDisposalCost(), destinationUpdateDTO.getHandlingCost());
|
destinationRepository.update(id, userId, destinationUpdateDTO.getRepackingCost(), destinationUpdateDTO.getDisposalCost(), destinationUpdateDTO.getHandlingCost());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void findRouteAndSave(Integer destinationId, Node destination, Node supplier, boolean isUserSupplierNode) {
|
||||||
|
|
||||||
|
var routeObjs = routingService.findRoutes(destination, supplier, isUserSupplierNode);
|
||||||
|
|
||||||
|
for (var routeObj : routeObjs) {
|
||||||
|
boolean first = true;
|
||||||
|
Integer fromNodeId = null;
|
||||||
|
|
||||||
|
var premiseRoute = routeObj.getRoute();
|
||||||
|
premiseRoute.setDestinationId(destinationId);
|
||||||
|
int routeId = routeRepository.insert(premiseRoute);
|
||||||
|
|
||||||
|
|
||||||
|
for (RouteSectionInformation section : routeObj.getSections()) {
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
fromNodeId = routeNodeRepository.insert(section.getFromNode());
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var toNode = section.getToNode();
|
||||||
|
Integer toNodeId = routeNodeRepository.insert(toNode);
|
||||||
|
|
||||||
|
var premiseRouteSection = section.getSection();
|
||||||
|
|
||||||
|
premiseRouteSection.setRouteId(routeId);
|
||||||
|
premiseRouteSection.setFromRouteNodeId(fromNodeId);
|
||||||
|
premiseRouteSection.setToRouteNodeId(toNodeId);
|
||||||
|
|
||||||
|
routeSectionRepository.insert(premiseRouteSection);
|
||||||
|
|
||||||
|
fromNodeId = toNodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deleteAllDestinationsByPremiseId(List<Integer> ids, boolean deleteRoutesOnly) {
|
public void deleteAllDestinationsByPremiseId(List<Integer> ids, boolean deleteRoutesOnly) {
|
||||||
ids.forEach(id -> deleteDestinationById(id, deleteRoutesOnly));
|
ids.forEach(id -> deleteDestinationById(id, deleteRoutesOnly));
|
||||||
|
|
@ -96,5 +171,35 @@ public class DestinationService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void duplicate(Integer fromPremiseId, Integer toPremiseId) {
|
||||||
|
|
||||||
|
List<Destination> destinations = destinationRepository.getByPremiseId(fromPremiseId);
|
||||||
|
|
||||||
|
for(Destination destination : destinations) {
|
||||||
|
|
||||||
|
destination.setPremiseId(toPremiseId);
|
||||||
|
Integer destinationId = destinationRepository.insert(destination);
|
||||||
|
|
||||||
|
for(Route route : routeRepository.getByDestinationId(destination.getId())) {
|
||||||
|
route.setDestinationId(destinationId);
|
||||||
|
Integer routeId = routeRepository.insert(route);
|
||||||
|
|
||||||
|
for(RouteSection section : routeSectionRepository.getByRouteId(route.getId())) {
|
||||||
|
section.setRouteId(routeId);
|
||||||
|
|
||||||
|
RouteNode fromNode = routeNodeRepository.getById(section.getFromRouteNodeId()).orElseThrow();
|
||||||
|
RouteNode toNode = routeNodeRepository.getById(section.getToRouteNodeId()).orElseThrow();
|
||||||
|
|
||||||
|
Integer fromNodeId = routeNodeRepository.insert(fromNode);
|
||||||
|
Integer toNodeId = routeNodeRepository.insert(toNode);
|
||||||
|
|
||||||
|
section.setFromRouteNodeId(fromNodeId);
|
||||||
|
section.setToRouteNodeId(toNodeId);
|
||||||
|
|
||||||
|
routeSectionRepository.insert(section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import de.avatic.lcc.dto.calculation.edit.masterData.PackagingUpdateDTO;
|
||||||
import de.avatic.lcc.dto.calculation.edit.masterData.PriceUpdateDTO;
|
import de.avatic.lcc.dto.calculation.edit.masterData.PriceUpdateDTO;
|
||||||
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
|
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
|
||||||
import de.avatic.lcc.repositories.pagination.SearchQueryResult;
|
import de.avatic.lcc.repositories.pagination.SearchQueryResult;
|
||||||
import de.avatic.lcc.repositories.premise.*;
|
import de.avatic.lcc.repositories.premise.PremiseRepository;
|
||||||
import de.avatic.lcc.service.transformer.generic.DimensionTransformer;
|
import de.avatic.lcc.service.transformer.generic.DimensionTransformer;
|
||||||
import de.avatic.lcc.service.transformer.premise.PremiseTransformer;
|
import de.avatic.lcc.service.transformer.premise.PremiseTransformer;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
@ -16,7 +16,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PremisesService {
|
public class PremisesService {
|
||||||
|
|
@ -26,7 +25,7 @@ public class PremisesService {
|
||||||
private final DimensionTransformer dimensionTransformer;
|
private final DimensionTransformer dimensionTransformer;
|
||||||
private final DestinationService destinationService;
|
private final DestinationService destinationService;
|
||||||
|
|
||||||
public PremisesService(PremiseRepository premiseRepository, PremiseTransformer premiseTransformer, DimensionTransformer dimensionTransformer, DestinationService destinationService, DestinationRepository destinationRepository, RouteRepository routeRepository, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository, DestinationService destinationService) {
|
public PremisesService(PremiseRepository premiseRepository, PremiseTransformer premiseTransformer, DimensionTransformer dimensionTransformer, DestinationService destinationService) {
|
||||||
this.premiseRepository = premiseRepository;
|
this.premiseRepository = premiseRepository;
|
||||||
this.premiseTransformer = premiseTransformer;
|
this.premiseTransformer = premiseTransformer;
|
||||||
this.dimensionTransformer = dimensionTransformer;
|
this.dimensionTransformer = dimensionTransformer;
|
||||||
|
|
@ -53,7 +52,7 @@ public class PremisesService {
|
||||||
|
|
||||||
//TODO move to other service
|
//TODO move to other service
|
||||||
public Integer startCalculation(List<Integer> premises) {
|
public Integer startCalculation(List<Integer> premises) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashMap<String, String> updatePackaging(PackagingUpdateDTO packagingDTO) {
|
public HashMap<String, String> updatePackaging(PackagingUpdateDTO packagingDTO) {
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,103 @@ package de.avatic.lcc.service.calculation;
|
||||||
|
|
||||||
import de.avatic.lcc.dto.calculation.edit.PremiseDetailDTO;
|
import de.avatic.lcc.dto.calculation.edit.PremiseDetailDTO;
|
||||||
import de.avatic.lcc.dto.calculation.edit.SetDataDTO;
|
import de.avatic.lcc.dto.calculation.edit.SetDataDTO;
|
||||||
|
import de.avatic.lcc.model.packaging.PackagingDimension;
|
||||||
|
import de.avatic.lcc.model.premises.Premise;
|
||||||
|
import de.avatic.lcc.model.properties.PackagingProperty;
|
||||||
|
import de.avatic.lcc.model.properties.PackagingPropertyMappingId;
|
||||||
|
import de.avatic.lcc.repositories.NodeRepository;
|
||||||
|
import de.avatic.lcc.repositories.packaging.PackagingDimensionRepository;
|
||||||
|
import de.avatic.lcc.repositories.packaging.PackagingPropertiesRepository;
|
||||||
|
import de.avatic.lcc.repositories.packaging.PackagingRepository;
|
||||||
|
import de.avatic.lcc.repositories.premise.PremiseRepository;
|
||||||
|
import de.avatic.lcc.repositories.users.UserNodeRepository;
|
||||||
|
import de.avatic.lcc.service.CustomApiService;
|
||||||
|
import de.avatic.lcc.service.access.PremisesService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ChangeMaterialService {
|
public class ChangeMaterialService {
|
||||||
|
|
||||||
|
private final PremiseRepository premiseRepository;
|
||||||
|
private final PremisesService premisesService;
|
||||||
|
private final CustomApiService customApiService;
|
||||||
|
private final NodeRepository nodeRepository;
|
||||||
|
private final UserNodeRepository userNodeRepository;
|
||||||
|
private final PackagingRepository packagingRepository;
|
||||||
|
private final PackagingDimensionRepository packagingDimensionRepository;
|
||||||
|
private final PackagingPropertiesRepository packagingPropertiesRepository;
|
||||||
|
|
||||||
|
public ChangeMaterialService(PremiseRepository premiseRepository, PremisesService premisesService, CustomApiService customApiService, NodeRepository nodeRepository, UserNodeRepository userNodeRepository, PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, PackagingPropertiesRepository packagingPropertiesRepository) {
|
||||||
|
this.premiseRepository = premiseRepository;
|
||||||
|
this.premisesService = premisesService;
|
||||||
|
this.customApiService = customApiService;
|
||||||
|
this.nodeRepository = nodeRepository;
|
||||||
|
this.userNodeRepository = userNodeRepository;
|
||||||
|
this.packagingRepository = packagingRepository;
|
||||||
|
this.packagingDimensionRepository = packagingDimensionRepository;
|
||||||
|
this.packagingPropertiesRepository = packagingPropertiesRepository;
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public List<PremiseDetailDTO> setMaterial(SetDataDTO setMaterialDTO) {
|
public List<PremiseDetailDTO> setMaterial(SetDataDTO dto) {
|
||||||
//0. check if one of the given premises contains the same supplier id, and abort if any duplicate would emerge
|
Integer userId = 1; /* TODO get user id */
|
||||||
|
|
||||||
//3 if updateMasterDate is set:
|
Integer materialId = dto.getMaterialId();
|
||||||
//3.1 copy packaging data (if exists) of new material to premise
|
List<Integer> premiseIds = dto.getPremiseId();
|
||||||
//3.2 set new tariff rate and hs code (if supplier country changed)
|
|
||||||
|
|
||||||
//4. Deliver Premise Detail
|
if (materialId == null || premiseIds == null || premiseIds.isEmpty())
|
||||||
|
throw new IllegalArgumentException("No supplier supplierNodeId or premises given");
|
||||||
|
|
||||||
|
// get all premises first.
|
||||||
|
List<Premise> allPremises = premiseRepository.getPremisesById(premiseIds);
|
||||||
|
|
||||||
|
// find resulting duplicates, split into "keep" and "to be deleted".
|
||||||
|
Map<Integer, Premise> uniqueMap = new HashMap<>();
|
||||||
|
List<Premise> premisesToBeDeleted = new ArrayList<>();
|
||||||
|
allPremises.forEach(p -> {
|
||||||
|
if (null != uniqueMap.putIfAbsent(p.getMaterialId(), p)) premisesToBeDeleted.add(p);
|
||||||
|
});
|
||||||
|
Collection<Premise> premisesToProcess = uniqueMap.values();
|
||||||
|
|
||||||
|
// check if user owns all premises:
|
||||||
|
if (allPremises.stream().anyMatch(p -> !p.getUserId().equals(userId)))
|
||||||
|
throw new IllegalArgumentException("Not authorized to change suppliers of premises owned by other users");
|
||||||
|
|
||||||
|
// check for any other collisions, and mark as "to be deleted":
|
||||||
|
premisesToBeDeleted.addAll(premisesToProcess.stream().map(p -> premiseRepository.getCollidingPremisesOnChange(userId, p.getId(), materialId, p.getSupplierNodeId())).flatMap(List::stream).toList());
|
||||||
|
|
||||||
|
if(dto.isUpdateMasterData()) {
|
||||||
|
for (var premise : premisesToProcess) {
|
||||||
|
var countryId = dto.isUserSupplierNode() ? userNodeRepository.getById(premise.getUserSupplierNodeId()).orElseThrow().getCountryId() : nodeRepository.getById(premise.getSupplierNodeId()).orElseThrow().getCountryId();
|
||||||
|
var tariffRate = customApiService.getTariffRate(premise.getHsCode(), countryId);
|
||||||
|
premiseRepository.updateTariffRate(premise.getId(), tariffRate);
|
||||||
|
|
||||||
|
if (!dto.isUserSupplierNode()) {
|
||||||
|
var packaging = packagingRepository.getByMaterialIdAndSupplierId(premise.getMaterialId(), dto.getSupplierNodeId());
|
||||||
|
Optional<PackagingDimension> dimension = packagingDimensionRepository.getById(packaging.getFirst().getHuId());
|
||||||
|
|
||||||
|
if (dimension.isPresent()) {
|
||||||
|
boolean stackable = packagingPropertiesRepository.getByPackagingIdAndType(packaging.getFirst().getId(), PackagingPropertyMappingId.STACKABLE.name()).map(PackagingProperty::getValue).map(Boolean::valueOf).orElse(false);
|
||||||
|
boolean mixable = packagingPropertiesRepository.getByPackagingIdAndType(packaging.getFirst().getId(), PackagingPropertyMappingId.MIXABLE.name()).map(PackagingProperty::getValue).map(Boolean::valueOf).orElse(false);
|
||||||
|
premiseRepository.updatePackaging(Collections.singletonList(premise.getId()), userId, dimension.get(), stackable, mixable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// actually update materialId.
|
||||||
|
premiseRepository.setMaterialId(premisesToProcess.stream().map(Premise::getId).toList(), materialId);
|
||||||
|
|
||||||
|
|
||||||
return null;
|
//delete all conflicting premises:
|
||||||
|
premisesService.delete(premisesToBeDeleted.stream().map(Premise::getId).toList());
|
||||||
|
|
||||||
|
|
||||||
|
return premisesService.getPremises(premisesToProcess.stream().map(Premise::getId).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,14 @@ import de.avatic.lcc.model.nodes.Node;
|
||||||
import de.avatic.lcc.model.packaging.PackagingDimension;
|
import de.avatic.lcc.model.packaging.PackagingDimension;
|
||||||
import de.avatic.lcc.model.premises.Premise;
|
import de.avatic.lcc.model.premises.Premise;
|
||||||
import de.avatic.lcc.model.premises.route.Destination;
|
import de.avatic.lcc.model.premises.route.Destination;
|
||||||
|
import de.avatic.lcc.model.premises.route.RouteSectionInformation;
|
||||||
import de.avatic.lcc.model.properties.PackagingProperty;
|
import de.avatic.lcc.model.properties.PackagingProperty;
|
||||||
import de.avatic.lcc.model.properties.PackagingPropertyMappingId;
|
import de.avatic.lcc.model.properties.PackagingPropertyMappingId;
|
||||||
import de.avatic.lcc.repositories.MaterialRepository;
|
|
||||||
import de.avatic.lcc.repositories.NodeRepository;
|
import de.avatic.lcc.repositories.NodeRepository;
|
||||||
import de.avatic.lcc.repositories.packaging.PackagingDimensionRepository;
|
import de.avatic.lcc.repositories.packaging.PackagingDimensionRepository;
|
||||||
import de.avatic.lcc.repositories.packaging.PackagingPropertiesRepository;
|
import de.avatic.lcc.repositories.packaging.PackagingPropertiesRepository;
|
||||||
import de.avatic.lcc.repositories.packaging.PackagingRepository;
|
import de.avatic.lcc.repositories.packaging.PackagingRepository;
|
||||||
import de.avatic.lcc.repositories.premise.DestinationRepository;
|
import de.avatic.lcc.repositories.premise.*;
|
||||||
import de.avatic.lcc.repositories.premise.PremiseRepository;
|
|
||||||
import de.avatic.lcc.repositories.users.UserNodeRepository;
|
import de.avatic.lcc.repositories.users.UserNodeRepository;
|
||||||
import de.avatic.lcc.service.CustomApiService;
|
import de.avatic.lcc.service.CustomApiService;
|
||||||
import de.avatic.lcc.service.access.DestinationService;
|
import de.avatic.lcc.service.access.DestinationService;
|
||||||
|
|
@ -34,13 +33,15 @@ public class ChangeSupplierService {
|
||||||
private final CustomApiService customApiService;
|
private final CustomApiService customApiService;
|
||||||
private final NodeRepository nodeRepository;
|
private final NodeRepository nodeRepository;
|
||||||
private final UserNodeRepository userNodeRepository;
|
private final UserNodeRepository userNodeRepository;
|
||||||
private final MaterialRepository materialRepository;
|
|
||||||
private final PackagingRepository packagingRepository;
|
private final PackagingRepository packagingRepository;
|
||||||
private final PackagingDimensionRepository packagingDimensionRepository;
|
private final PackagingDimensionRepository packagingDimensionRepository;
|
||||||
private final PackagingPropertiesRepository packagingPropertiesRepository;
|
private final PackagingPropertiesRepository packagingPropertiesRepository;
|
||||||
private final DestinationRepository destinationRepository;
|
private final DestinationRepository destinationRepository;
|
||||||
|
private final RouteRepository routeRepository;
|
||||||
|
private final RouteSectionRepository routeSectionRepository;
|
||||||
|
private final RouteNodeRepository routeNodeRepository;
|
||||||
|
|
||||||
public ChangeSupplierService(PremiseRepository premiseRepository, DestinationService destinationService, RoutingService routingService, PremisesService premisesService, CustomApiService customApiService, NodeRepository nodeRepository, UserNodeRepository userNodeRepository, MaterialRepository materialRepository, PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, PackagingPropertiesRepository packagingPropertiesRepository, DestinationRepository destinationRepository) {
|
public ChangeSupplierService(PremiseRepository premiseRepository, DestinationService destinationService, RoutingService routingService, PremisesService premisesService, CustomApiService customApiService, NodeRepository nodeRepository, UserNodeRepository userNodeRepository, PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, PackagingPropertiesRepository packagingPropertiesRepository, DestinationRepository destinationRepository, RouteRepository routeRepository, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository) {
|
||||||
this.premiseRepository = premiseRepository;
|
this.premiseRepository = premiseRepository;
|
||||||
this.destinationService = destinationService;
|
this.destinationService = destinationService;
|
||||||
this.routingService = routingService;
|
this.routingService = routingService;
|
||||||
|
|
@ -48,11 +49,13 @@ public class ChangeSupplierService {
|
||||||
this.customApiService = customApiService;
|
this.customApiService = customApiService;
|
||||||
this.nodeRepository = nodeRepository;
|
this.nodeRepository = nodeRepository;
|
||||||
this.userNodeRepository = userNodeRepository;
|
this.userNodeRepository = userNodeRepository;
|
||||||
this.materialRepository = materialRepository;
|
|
||||||
this.packagingRepository = packagingRepository;
|
this.packagingRepository = packagingRepository;
|
||||||
this.packagingDimensionRepository = packagingDimensionRepository;
|
this.packagingDimensionRepository = packagingDimensionRepository;
|
||||||
this.packagingPropertiesRepository = packagingPropertiesRepository;
|
this.packagingPropertiesRepository = packagingPropertiesRepository;
|
||||||
this.destinationRepository = destinationRepository;
|
this.destinationRepository = destinationRepository;
|
||||||
|
this.routeRepository = routeRepository;
|
||||||
|
this.routeSectionRepository = routeSectionRepository;
|
||||||
|
this.routeNodeRepository = routeNodeRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -92,8 +95,9 @@ public class ChangeSupplierService {
|
||||||
//recalculate routes:
|
//recalculate routes:
|
||||||
for (Premise premise : premisesToProcess) {
|
for (Premise premise : premisesToProcess) {
|
||||||
List<Destination> destination = destinationRepository.getByPremiseId(premise.getId());
|
List<Destination> destination = destinationRepository.getByPremiseId(premise.getId());
|
||||||
for( Destination d : destination ) {
|
for (Destination d : destination) {
|
||||||
routingService.findRoutes(d.getId(), supplierNodeId);
|
Node destinationNode = nodeRepository.getById(d.getDestinationNodeId()).orElseThrow();
|
||||||
|
destinationService.findRouteAndSave(d.getId(), destinationNode, supplier, dto.isUserSupplierNode() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,15 +112,11 @@ public class ChangeSupplierService {
|
||||||
Optional<PackagingDimension> dimension = packagingDimensionRepository.getById(packaging.getFirst().getHuId());
|
Optional<PackagingDimension> dimension = packagingDimensionRepository.getById(packaging.getFirst().getHuId());
|
||||||
|
|
||||||
if (dimension.isPresent()) {
|
if (dimension.isPresent()) {
|
||||||
Optional<PackagingProperty> stackable = packagingPropertiesRepository.getByPackagingIdAndType(packaging.getFirst().getId(), PackagingPropertyMappingId.STACKABLE.name());
|
boolean stackable = packagingPropertiesRepository.getByPackagingIdAndType(packaging.getFirst().getId(), PackagingPropertyMappingId.STACKABLE.name()).map(PackagingProperty::getValue).map(Boolean::valueOf).orElse(false);
|
||||||
Optional<PackagingProperty> mixable = packagingPropertiesRepository.getByPackagingIdAndType(packaging.getFirst().getId(), PackagingPropertyMappingId.MIXABLE.name());
|
boolean mixable = packagingPropertiesRepository.getByPackagingIdAndType(packaging.getFirst().getId(), PackagingPropertyMappingId.MIXABLE.name()).map(PackagingProperty::getValue).map(Boolean::valueOf).orElse(false);
|
||||||
//TODO check optional
|
premiseRepository.updatePackaging(Collections.singletonList(premise.getId()), userId, dimension.get(), stackable, mixable);
|
||||||
premiseRepository.updatePackaging(Collections.singletonList(premise.getId()), userId, dimension.get(), Boolean.valueOf(stackable.get().getValue()), Boolean.valueOf(mixable.get().getValue()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
premisesService.fillPackaging(premisesToProcess.stream().map(Premise::getId).toList());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,4 +132,6 @@ public class ChangeSupplierService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,139 @@
|
||||||
package de.avatic.lcc.service.calculation;
|
package de.avatic.lcc.service.calculation;
|
||||||
|
|
||||||
import de.avatic.lcc.dto.calculation.edit.PremiseDetailDTO;
|
import de.avatic.lcc.dto.calculation.edit.PremiseDetailDTO;
|
||||||
|
import de.avatic.lcc.model.premises.Premise;
|
||||||
|
import de.avatic.lcc.model.premises.PremiseState;
|
||||||
|
import de.avatic.lcc.repositories.premise.DestinationRepository;
|
||||||
|
import de.avatic.lcc.repositories.premise.PremiseRepository;
|
||||||
|
import de.avatic.lcc.repositories.premise.RouteRepository;
|
||||||
|
import de.avatic.lcc.service.access.DestinationService;
|
||||||
|
import de.avatic.lcc.service.transformer.premise.PremiseTransformer;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PremiseCreationService {
|
public class PremiseCreationService {
|
||||||
|
private final PremiseRepository premiseRepository;
|
||||||
|
private final PremiseTransformer premiseTransformer;
|
||||||
|
private final DestinationService destinationService;
|
||||||
|
|
||||||
|
public PremiseCreationService(PremiseRepository premiseRepository, PremiseTransformer premiseTransformer, DestinationService destinationService) {
|
||||||
|
this.premiseRepository = premiseRepository;
|
||||||
|
this.premiseTransformer = premiseTransformer;
|
||||||
|
this.destinationService = destinationService;
|
||||||
|
}
|
||||||
|
|
||||||
public List<PremiseDetailDTO> createPremises(List<Integer> materialIds, List<Integer> supplierIds, List<Integer> userSupplierIds, boolean createEmpty) {
|
public List<PremiseDetailDTO> createPremises(List<Integer> materialIds, List<Integer> supplierIds, List<Integer> userSupplierIds, boolean createEmpty) {
|
||||||
return null;
|
|
||||||
|
Integer userId = 1; //TODO get user id
|
||||||
|
|
||||||
|
List<TemporaryPremise> foundPremises = new ArrayList<>(premiseRepository.getPremisesByMaterialIdsAndSupplierIds(materialIds, supplierIds, userSupplierIds, userId, createEmpty).stream().map(TemporaryPremise::new).toList());
|
||||||
|
|
||||||
|
List<TemporaryPremise> toBeCopied = foundPremises.stream().filter(p -> (!p.getPremise().getState().equals(PremiseState.DRAFT) || !Objects.equals(p.getPremise().getUserId(), userId))).toList();
|
||||||
|
|
||||||
|
List<TemporaryPremise> toBeCreated = materialIds.stream()
|
||||||
|
.flatMap(materialId -> {
|
||||||
|
Stream<TemporaryPremise> supplierCombinations = supplierIds.stream()
|
||||||
|
.map(supplierId -> new TemporaryPremise(materialId, supplierId, null, false));
|
||||||
|
|
||||||
|
Stream<TemporaryPremise> userSupplierCombinations =
|
||||||
|
(userSupplierIds != null && !userSupplierIds.isEmpty()) ?
|
||||||
|
userSupplierIds.stream()
|
||||||
|
.map(userSupplierId -> new TemporaryPremise(materialId, null, userSupplierId, true)) :
|
||||||
|
Stream.empty();
|
||||||
|
|
||||||
|
return Stream.concat(supplierCombinations, userSupplierCombinations);
|
||||||
|
})
|
||||||
|
// filter existing combinations.
|
||||||
|
.filter(p -> foundPremises.stream()
|
||||||
|
.noneMatch(found ->
|
||||||
|
Objects.equals(found.materialId, p.materialId) &&
|
||||||
|
Objects.equals(found.supplierId, p.supplierId) &&
|
||||||
|
Objects.equals(found.userSupplierId, p.userSupplierId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
List<Integer> premiseIds = new ArrayList<>(toBeCreated.stream().map(p -> premiseRepository.insert(p.getMaterialId(), p.getSupplierId(), p.getUserSupplierId(), userId)).toList());
|
||||||
|
|
||||||
|
for( TemporaryPremise p : toBeCopied ) {
|
||||||
|
Integer id = premiseRepository.insert(p.getMaterialId(), p.getSupplierId(), p.getUserSupplierId(), userId);
|
||||||
|
destinationService.duplicate(p.getPremise().getId(), id);
|
||||||
|
premiseIds.add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return premiseRepository.getPremisesById(premiseIds).stream().map(premiseTransformer::toPremiseDetailDTO).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static class TemporaryPremise {
|
||||||
|
private Integer materialId;
|
||||||
|
private Integer supplierId;
|
||||||
|
private Integer userSupplierId;
|
||||||
|
private boolean isUserSupplier;
|
||||||
|
|
||||||
|
private Premise premise;
|
||||||
|
|
||||||
|
public Integer getMaterialId() {
|
||||||
|
return materialId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaterialId(Integer materialId) {
|
||||||
|
this.materialId = materialId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSupplierId() {
|
||||||
|
return supplierId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupplierId(Integer supplierId) {
|
||||||
|
this.supplierId = supplierId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUserSupplierId() {
|
||||||
|
return userSupplierId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserSupplierId(Integer userSupplierId) {
|
||||||
|
this.userSupplierId = userSupplierId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUserSupplier() {
|
||||||
|
return isUserSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserSupplier(boolean userSupplier) {
|
||||||
|
isUserSupplier = userSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPremise(Premise premise) {
|
||||||
|
this.premise = premise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemporaryPremise(Premise premise) {
|
||||||
|
this.premise = premise;
|
||||||
|
this.materialId = premise.getMaterialId();
|
||||||
|
this.supplierId = premise.getSupplierNodeId();
|
||||||
|
this.userSupplierId = premise.getUserSupplierNodeId();
|
||||||
|
this.isUserSupplier = premise.getUserSupplierNodeId() != null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemporaryPremise(Integer materialId, Integer supplierId, Integer userSupplierId, boolean isUserSupplier) {
|
||||||
|
this.materialId = materialId;
|
||||||
|
this.supplierId = supplierId;
|
||||||
|
this.userSupplierId = userSupplierId;
|
||||||
|
this.isUserSupplier = isUserSupplier;
|
||||||
|
this.premise = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Premise getPremise() {
|
||||||
|
return premise;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,101 @@
|
||||||
package de.avatic.lcc.service.calculation;
|
package de.avatic.lcc.service.calculation;
|
||||||
|
|
||||||
import de.avatic.lcc.dto.calculation.create.PremiseSearchResultDTO;
|
import de.avatic.lcc.dto.calculation.create.PremiseSearchResultDTO;
|
||||||
|
import de.avatic.lcc.model.materials.Material;
|
||||||
|
import de.avatic.lcc.repositories.MaterialRepository;
|
||||||
|
import de.avatic.lcc.repositories.NodeRepository;
|
||||||
|
import de.avatic.lcc.repositories.premise.PremiseRepository;
|
||||||
|
import de.avatic.lcc.service.transformer.generic.MaterialTransformer;
|
||||||
|
import de.avatic.lcc.service.transformer.generic.NodeTransformer;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for analyzing search strings and retrieving materials and their associated suppliers.
|
||||||
|
* This service uses repositories and transformers to process and map database entities
|
||||||
|
* to DTOs for the result.
|
||||||
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class PremiseSearchStringAnalyzerService {
|
public class PremiseSearchStringAnalyzerService {
|
||||||
|
|
||||||
|
private static final String PART_NUMBER_REGEX = "([a-zA-Z0-9][a-zA-Z0-9\\-]{4,11})";
|
||||||
|
private static final Pattern PART_NUMBER_PATTERN = Pattern.compile(PART_NUMBER_REGEX);
|
||||||
|
private final MaterialRepository materialRepository;
|
||||||
|
private final NodeRepository nodeRepository;
|
||||||
|
private final PremiseRepository premiseRepository;
|
||||||
|
private final NodeTransformer nodeTransformer;
|
||||||
|
private final MaterialTransformer materialTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the PremiseSearchStringAnalyzerService, initializing the required repositories
|
||||||
|
* and transformers for analyzing search strings and processing materials and suppliers.
|
||||||
|
*
|
||||||
|
* @param materialRepository Repository for accessing material entities from the database.
|
||||||
|
* @param nodeRepository Repository for accessing node entities (suppliers) from the database.
|
||||||
|
* @param premiseRepository Repository for accessing premise-related data, including suppliers associated with materials.
|
||||||
|
* @param nodeTransformer Transformer for mapping database node entities (suppliers) to DTOs.
|
||||||
|
* @param materialTransformer Transformer for mapping database material entities to DTOs.
|
||||||
|
*/
|
||||||
|
public PremiseSearchStringAnalyzerService(MaterialRepository materialRepository, NodeRepository nodeRepository, PremiseRepository premiseRepository, NodeTransformer nodeTransformer, MaterialTransformer materialTransformer) {
|
||||||
|
this.materialRepository = materialRepository;
|
||||||
|
this.nodeRepository = nodeRepository;
|
||||||
|
this.premiseRepository = premiseRepository;
|
||||||
|
this.nodeTransformer = nodeTransformer;
|
||||||
|
this.materialTransformer = materialTransformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes the provided search string to find materials and associated suppliers.
|
||||||
|
* Processes the search string to extract part numbers, retrieves the associated materials,
|
||||||
|
* and identifies the suppliers connected to the materials. These results are returned
|
||||||
|
* in the form of a DTO containing lists of materials and suppliers.
|
||||||
|
*
|
||||||
|
* @param search The search string potentially containing part numbers used to find
|
||||||
|
* materials and their associated suppliers.
|
||||||
|
*
|
||||||
|
* @return A {@code PremiseSearchResultDTO} containing lists of material DTOs, suppliers,
|
||||||
|
* and user-specific suppliers related to the identified materials.
|
||||||
|
*/
|
||||||
public PremiseSearchResultDTO findMaterialAndSuppliers(String search) {
|
public PremiseSearchResultDTO findMaterialAndSuppliers(String search) {
|
||||||
return null;
|
List<Material> material = materialRepository.getByPartNumbers(findPartNumbers(search));
|
||||||
|
List<Integer> materialIds = material.stream().map(Material::getId).toList();
|
||||||
|
|
||||||
|
// find suppliers associated with this material.
|
||||||
|
List<Integer> supplierIds = premiseRepository.findAssociatedSuppliers(materialIds);
|
||||||
|
List<Integer> userSupplierIds = premiseRepository.findAssociatedUserSuppliers(materialIds);
|
||||||
|
|
||||||
|
var dto = new PremiseSearchResultDTO();
|
||||||
|
|
||||||
|
dto.setMaterials(material.stream().map(materialTransformer::toMaterialDTO).toList());
|
||||||
|
dto.setSupplier(nodeRepository.getByIds(supplierIds).stream().map(nodeTransformer::toNodeDTO).toList());
|
||||||
|
dto.setUserSupplier(nodeRepository.getByIds(userSupplierIds).stream().map(nodeTransformer::toNodeDTO).toList());
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts part numbers from the provided search string based on a predefined pattern.
|
||||||
|
*
|
||||||
|
* @param search The input string that potentially contains part numbers to be extracted.
|
||||||
|
* @return A collection of unique part numbers found within the input string.
|
||||||
|
*/
|
||||||
|
public static Collection<String> findPartNumbers(String search) {
|
||||||
|
Set<String> partNumbers = new HashSet<>();
|
||||||
|
Matcher matcher = PART_NUMBER_PATTERN.matcher(search);
|
||||||
|
|
||||||
|
// Find all matches
|
||||||
|
while (matcher.find()) {
|
||||||
|
// Get the match from group 1 (inside the lookahead)
|
||||||
|
String partNumber = matcher.group(1);
|
||||||
|
partNumbers.add(partNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return partNumbers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,796 +0,0 @@
|
||||||
package de.avatic.lcc.service.calculation;
|
|
||||||
|
|
||||||
import de.avatic.lcc.dto.generic.RouteType;
|
|
||||||
import de.avatic.lcc.model.nodes.Node;
|
|
||||||
import de.avatic.lcc.model.premises.route.Route;
|
|
||||||
import de.avatic.lcc.model.premises.route.RouteInformation;
|
|
||||||
import de.avatic.lcc.model.premises.route.RouteNode;
|
|
||||||
import de.avatic.lcc.model.premises.route.RouteSection;
|
|
||||||
import de.avatic.lcc.model.properties.SystemPropertyMappingId;
|
|
||||||
import de.avatic.lcc.model.rates.ContainerRate;
|
|
||||||
import de.avatic.lcc.model.rates.ContainerRateType;
|
|
||||||
import de.avatic.lcc.model.rates.MatrixRate;
|
|
||||||
import de.avatic.lcc.repositories.NodeRepository;
|
|
||||||
import de.avatic.lcc.repositories.properties.PropertyRepository;
|
|
||||||
import de.avatic.lcc.repositories.rates.ContainerRateRepository;
|
|
||||||
import de.avatic.lcc.repositories.rates.MatrixRateRepository;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class RoutingService2 {
|
|
||||||
|
|
||||||
|
|
||||||
private final MatrixRateRepository matrixRateRepository;
|
|
||||||
private final ChainResolver chainResolver;
|
|
||||||
private final NodeRepository nodeRepository;
|
|
||||||
private final ContainerRateRepository containerRateRepository;
|
|
||||||
private final DistanceService distanceService;
|
|
||||||
private final PropertyRepository propertyRepository;
|
|
||||||
|
|
||||||
public RoutingService2(MatrixRateRepository matrixRateRepository, ChainResolver chainResolver, NodeRepository nodeRepository, ContainerRateRepository containerRateRepository, DistanceService distanceService, PropertyRepository propertyRepository) {
|
|
||||||
this.matrixRateRepository = matrixRateRepository;
|
|
||||||
this.chainResolver = chainResolver;
|
|
||||||
this.nodeRepository = nodeRepository;
|
|
||||||
this.containerRateRepository = containerRateRepository;
|
|
||||||
this.distanceService = distanceService;
|
|
||||||
this.propertyRepository = propertyRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<RouteInformation> findRoute(Node destination, Node source, boolean sourceIsUserNode) {
|
|
||||||
List<RouteInformation> routeInformation = new ArrayList<>();
|
|
||||||
TemporaryContainer container = new TemporaryContainer(source, destination);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the source and destination node from database.
|
|
||||||
* Check if there is a matrix rate for the source country.
|
|
||||||
*/
|
|
||||||
matrixRateRepository.getByCountryIds(source.getCountryId(), source.getCountryId()).ifPresent(container::setSourceMatrixRate);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate recursive all chains starting with the destination node.
|
|
||||||
* This means all chains within the last node of a chain are connected to the
|
|
||||||
* existing chain.
|
|
||||||
*
|
|
||||||
* Furthermore, it is evaluated that all nodes within the chain do not have chains
|
|
||||||
* themselves that are in conflict with the chain.
|
|
||||||
*
|
|
||||||
* Then get all countries from the end of the destination chains.
|
|
||||||
*/
|
|
||||||
|
|
||||||
List<List<Node>> destinationChains = chainResolver.buildChains(destination.getId());
|
|
||||||
List<Integer> inboundCountries = destinationChains.stream().filter(chain -> !chain.isEmpty()).map(chain -> chain.getLast().getCountryId()).distinct().toList();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get all outbound nodes for the country of the source node. In this first step this includes:
|
|
||||||
* - all intermediate nodes that have the same country id.
|
|
||||||
* - all nodes that are explicitly mapped as outbound node for this country id.
|
|
||||||
*/
|
|
||||||
List<Node> outboundNodes = nodeRepository.getAllOutboundFor(source.getCountryId());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find main runs based on the outbound nodes and the inbound countries found before.
|
|
||||||
* Find post-runs for the main runs.
|
|
||||||
*
|
|
||||||
* Store all information in the TemporaryContainer object.
|
|
||||||
*/
|
|
||||||
container.setMainRuns(outboundNodes.stream().collect(Collectors.toMap(Node::getId, n -> containerRateRepository.findRoutesByStartNodeIdAndDestinationCountryId(n.getId(), inboundCountries))));
|
|
||||||
container.setPostRuns(container.getMainRuns().stream().collect(Collectors.toMap(ContainerRate::getId, containerRateRepository::getPostRunsFor)));
|
|
||||||
|
|
||||||
|
|
||||||
connectDestinationChainAndMainRun(container, outboundNodes, destinationChains);
|
|
||||||
connectSourceChainAndSource(container);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* At this point all routes with a main run are created.
|
|
||||||
* We find now the best route per main run and throw away the rest.
|
|
||||||
*/
|
|
||||||
findCheapestPerMainRun(container);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now we also create routes without main run (matrix rate)
|
|
||||||
*/
|
|
||||||
connectDestinationChainDirectly(container, destinationChains);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* finally find and mark the fastest and the cheapest route.
|
|
||||||
*/
|
|
||||||
findAndMarkCheapestAndFastest(container);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert to Database model
|
|
||||||
*/
|
|
||||||
for (var route : container.getRoutes()) {
|
|
||||||
RouteInformation routeInformationObj = new RouteInformation();
|
|
||||||
|
|
||||||
routeInformationObj.setRoute(mapRoute(route));
|
|
||||||
routeInformationObj.setRouteSections(mapSections(route.getSections()));
|
|
||||||
routeInformationObj.setRouteNodes(route.getNodes().stream().map(n -> mapNode(n, n.getId().equals(source.getId()) && sourceIsUserNode)).toList());
|
|
||||||
routeInformation.add(routeInformationObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
return routeInformation;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private RouteNode mapNode(Node node, boolean isUserNode) {
|
|
||||||
RouteNode routeNode = new RouteNode();
|
|
||||||
|
|
||||||
routeNode.setName(node.getName());
|
|
||||||
routeNode.setCountryId(node.getCountryId());
|
|
||||||
routeNode.setAddress(node.getAddress());
|
|
||||||
routeNode.setGeoLng(node.getGeoLng());
|
|
||||||
routeNode.setGeoLat(node.getGeoLat());
|
|
||||||
routeNode.setUserNodeId(isUserNode? node.getId() : null);
|
|
||||||
routeNode.setNodeId(isUserNode ? null : node.getId());
|
|
||||||
routeNode.setIntermediate(node.getIntermediate() != null ? node.getIntermediate() : false);
|
|
||||||
routeNode.setDestination(node.getDestination() != null ? node.getIntermediate() : false);
|
|
||||||
routeNode.setSource(node.getSource() != null ? node.getIntermediate() : false);
|
|
||||||
routeNode.setOutdated(node.getDeprecated());
|
|
||||||
|
|
||||||
return routeNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Route mapRoute(TemporaryRouteObject route) {
|
|
||||||
Route routeObj = new Route();
|
|
||||||
|
|
||||||
routeObj.setCheapest(route.isCheapest());
|
|
||||||
routeObj.setFastest(route.isFastest());
|
|
||||||
|
|
||||||
return routeObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<RouteSection> mapSections(List<TemporaryRateObject> sections) {
|
|
||||||
int index = 1;
|
|
||||||
|
|
||||||
List<RouteSection> routeSections = new ArrayList<>();
|
|
||||||
boolean passedMainRun = false;
|
|
||||||
|
|
||||||
for(var section : sections) {
|
|
||||||
var routeSection = mapSection(section);
|
|
||||||
|
|
||||||
if (!section.getType().equals(TemporaryRateObject.TemporaryRateObjectType.MAIN_RUN) && !section.getType().equals(TemporaryRateObject.TemporaryRateObjectType.POST_RUN)) {
|
|
||||||
if (!passedMainRun)
|
|
||||||
routeSection.setPreRun(true);
|
|
||||||
|
|
||||||
if (passedMainRun)
|
|
||||||
routeSection.setPostRun(true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if(section.getType().equals(TemporaryRateObject.TemporaryRateObjectType.MAIN_RUN) || section.getType().equals(TemporaryRateObject.TemporaryRateObjectType.POST_RUN))
|
|
||||||
passedMainRun = true;
|
|
||||||
|
|
||||||
routeSection.setListPosition(index++);
|
|
||||||
routeSections.add(routeSection);
|
|
||||||
}
|
|
||||||
|
|
||||||
return routeSections;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RouteSection mapSection(TemporaryRateObject section) {
|
|
||||||
RouteSection routeSection = new RouteSection();
|
|
||||||
|
|
||||||
routeSection.setTransportType(mapRouteType(section));
|
|
||||||
routeSection.setFromRouteNodeId(section.getFromNode().getId());
|
|
||||||
routeSection.setToRouteNodeId(section.getToNode().getId());
|
|
||||||
routeSection.setMainRun(section.getType().equals(TemporaryRateObject.TemporaryRateObjectType.MAIN_RUN));
|
|
||||||
routeSection.setOutdated(false);
|
|
||||||
|
|
||||||
routeSection.setPostRun(false);
|
|
||||||
routeSection.setPreRun(false);
|
|
||||||
|
|
||||||
return routeSection;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private RouteType mapRouteType(TemporaryRateObject rate) {
|
|
||||||
|
|
||||||
switch(rate.getType()) {
|
|
||||||
case MATRIX, CONTAINER -> {
|
|
||||||
return RouteType.ROAD;
|
|
||||||
}
|
|
||||||
case POST_RUN -> {
|
|
||||||
return RouteType.POST_RUN;
|
|
||||||
}
|
|
||||||
case MAIN_RUN -> {
|
|
||||||
return RouteType.valueOf(rate.getContainerRateTye().name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void findAndMarkCheapestAndFastest(TemporaryContainer container) {
|
|
||||||
var routes = container.getRoutes();
|
|
||||||
|
|
||||||
TemporaryRouteObject cheapest = null;
|
|
||||||
double cheapestCost = Double.MAX_VALUE;
|
|
||||||
|
|
||||||
TemporaryRouteObject fastest = null;
|
|
||||||
double fastestRoute = Double.MAX_VALUE;
|
|
||||||
|
|
||||||
for(var route : routes) {
|
|
||||||
double routeCost = route.getCost();
|
|
||||||
int leadTime = route.getLeadTime();
|
|
||||||
|
|
||||||
if(routeCost < cheapestCost) {
|
|
||||||
cheapestCost = routeCost;
|
|
||||||
cheapest = route;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(leadTime < fastestRoute) {
|
|
||||||
fastestRoute = leadTime;
|
|
||||||
fastest = route;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cheapest != null) {
|
|
||||||
cheapest.setCheapest();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fastest != null) {
|
|
||||||
fastest.setFastest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void findCheapestPerMainRun(TemporaryContainer container) {
|
|
||||||
|
|
||||||
var routesByMainRun = container.getRoutes().stream().collect(Collectors.groupingBy(TemporaryRouteObject::getMainRun));
|
|
||||||
Collection<TemporaryRouteObject> cheapestRoutes = new ArrayList<>();
|
|
||||||
|
|
||||||
for(var mainRun : routesByMainRun.keySet()) {
|
|
||||||
List<TemporaryRouteObject> routes = routesByMainRun.get(mainRun);
|
|
||||||
TemporaryRouteObject cheapest = null;
|
|
||||||
double cheapestCost = Double.MAX_VALUE;
|
|
||||||
|
|
||||||
for(var route : routes) {
|
|
||||||
double routeCost = route.getCost();
|
|
||||||
|
|
||||||
if(routeCost < cheapestCost) {
|
|
||||||
cheapestCost = routeCost;
|
|
||||||
cheapest = route;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cheapest != null) {
|
|
||||||
cheapestRoutes.add(cheapest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
container.overrideRoutes(cheapestRoutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectDestinationChainDirectly(TemporaryContainer container, List<List<Node>> chains) {
|
|
||||||
Collection<TemporaryRateObject> rates = container.getRates();
|
|
||||||
|
|
||||||
for (var chain : chains) {
|
|
||||||
var toNode = chain.isEmpty() ? container.getDestinationNode() : chain.getLast();
|
|
||||||
|
|
||||||
TemporaryRateObject finalSection = new TemporaryRateObject(container.getSourceNode(), toNode, TemporaryRateObject.TemporaryRateObjectType.MATRIX);
|
|
||||||
|
|
||||||
if (rates.contains(finalSection)) {
|
|
||||||
TemporaryRateObject finalMatrixRateObj = finalSection;
|
|
||||||
finalSection = container.getRates().stream().filter(r -> r.equals(finalMatrixRateObj)).findFirst().orElse(null);
|
|
||||||
} else {
|
|
||||||
var matrixRate = matrixRateRepository.getByCountryIds(container.getSourceNode().getCountryId(), toNode.getCountryId()).orElse(null);
|
|
||||||
|
|
||||||
// no matrix rate in database. skip this chain
|
|
||||||
if (matrixRate == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
finalSection.setRate(matrixRate);
|
|
||||||
finalSection.setApproxDistance(distanceService.getDistance(container.getSourceNode(), toNode, true));
|
|
||||||
rates.add(finalSection);
|
|
||||||
}
|
|
||||||
|
|
||||||
// could not create an temporary rate object -> so just skip here ... (should not happen)
|
|
||||||
if (finalSection == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a route.
|
|
||||||
boolean routable = true;
|
|
||||||
TemporaryRouteObject routeObj = new TemporaryRouteObject();
|
|
||||||
|
|
||||||
for (int idx = 1; idx < chain.size(); idx++) {
|
|
||||||
Node startNode = chain.get(idx);
|
|
||||||
Node endNode = chain.get(idx - 1);
|
|
||||||
|
|
||||||
var rate = connectNodes(startNode, endNode, container);
|
|
||||||
|
|
||||||
if (rate != null) {
|
|
||||||
routeObj.addSection(rate);
|
|
||||||
} else {
|
|
||||||
// chain is not routable -> discard
|
|
||||||
routable = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the chain is routable -> add the final rate and save the route.
|
|
||||||
if (routable) {
|
|
||||||
routeObj.addSection(finalSection);
|
|
||||||
container.addRoute(routeObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private TemporaryRateObject connectNearByNodes(Node chainEnd, List<Node> nearByNodes, TemporaryContainer container) {
|
|
||||||
|
|
||||||
|
|
||||||
for (var nearbyNode : nearByNodes) {
|
|
||||||
TemporaryRateObject nearByRate = connectNodes(nearbyNode, chainEnd, container);
|
|
||||||
if (null != nearByRate) {
|
|
||||||
return nearByRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectSourceChainAndSource(TemporaryContainer container) {
|
|
||||||
|
|
||||||
/* get the near-by nodes if no country matrix rate present */
|
|
||||||
List<Node> nearByNodes = (container.hasSourceMatrixRate()) ? null : nodeRepository.getByDistance(container.getSourceNode(), getRegionRadius());
|
|
||||||
|
|
||||||
Collection<TemporaryRouteObject> routes = new ArrayList<>();
|
|
||||||
|
|
||||||
for (var route : container.getRoutes()) {
|
|
||||||
var mainRun = route.getMainRun();
|
|
||||||
var sourceChains = chainResolver.buildChains(mainRun.getFromNode().getId());
|
|
||||||
|
|
||||||
|
|
||||||
for (var chain : sourceChains) {
|
|
||||||
Node source = container.getSourceNode();
|
|
||||||
boolean chainEndIsSource = source.getId().equals(chain.getLast().getId());
|
|
||||||
|
|
||||||
// find final section: check if chain end and source node are identical, then check if chain end can be connected to
|
|
||||||
// source node, if this is not possible use a near-by node
|
|
||||||
TemporaryRateObject finalSection = (chainEndIsSource) ? null : connectNodes(source, chain.getLast(), container);
|
|
||||||
finalSection = ((finalSection == null && !chainEndIsSource && nearByNodes != null) ? connectNearByNodes(chain.getLast(), nearByNodes, container) : finalSection);
|
|
||||||
|
|
||||||
if (finalSection != null || chainEndIsSource) {
|
|
||||||
boolean routable = true;
|
|
||||||
TemporaryRouteObject duplicate = route.clone();
|
|
||||||
|
|
||||||
for (int idx = 1; idx < chain.size() - 1; idx++) {
|
|
||||||
Node startNode = chain.get(idx);
|
|
||||||
Node endNode = chain.get(idx - 1);
|
|
||||||
|
|
||||||
TemporaryRateObject rate = connectNodes(startNode, endNode, container);
|
|
||||||
|
|
||||||
if (rate != null) duplicate.addSection(rate);
|
|
||||||
else {
|
|
||||||
routable = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routable) {
|
|
||||||
if (finalSection != null) {
|
|
||||||
// add final section if necessary,
|
|
||||||
// if last chain node == source node this can be skipped.
|
|
||||||
duplicate.addSection(finalSection);
|
|
||||||
if (!finalSection.getFromNode().getId().equals(source.getId())) duplicate.routeOverNearBy();
|
|
||||||
}
|
|
||||||
routes.add(duplicate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
container.overrideRoutes(routes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Integer getRegionRadius() {
|
|
||||||
var property = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.RADIUS_REGION);
|
|
||||||
return property.map(propertyDTO -> Integer.valueOf(propertyDTO.getCurrentValue())).orElseGet(SystemPropertyMappingId.RADIUS_REGION::getDefaultAsInteger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectDestinationChainAndMainRun(TemporaryContainer container, List<Node> outboundNodes, List<List<Node>> destinationChains) {
|
|
||||||
/*
|
|
||||||
* Try to connect everything together:
|
|
||||||
* - go trough all main runs and adjacent post-runs
|
|
||||||
* - find any compatible chain:
|
|
||||||
* - check if chain is routable
|
|
||||||
* - add post run and main run
|
|
||||||
*/
|
|
||||||
for (var mainRun : container.getMainRuns()) {
|
|
||||||
|
|
||||||
Node mainRunEndNode = nodeRepository.getById(mainRun.getToNodeId()).orElseThrow();
|
|
||||||
Node mainRunStartNode = outboundNodes.stream().filter(n -> n.getId().equals(mainRun.getFromNodeId())).findFirst().orElseThrow();
|
|
||||||
|
|
||||||
TemporaryRateObject mainRunObj = new TemporaryRateObject(mainRunStartNode, mainRunEndNode, TemporaryRateObject.TemporaryRateObjectType.MAIN_RUN, mainRun);
|
|
||||||
|
|
||||||
for (var postRun : container.getPostRuns().get(mainRun.getId())) {
|
|
||||||
|
|
||||||
Node postRunEndNode = nodeRepository.getById(postRun.getToNodeId()).orElseThrow();
|
|
||||||
TemporaryRateObject postRunObj = new TemporaryRateObject(postRunEndNode, mainRunEndNode, TemporaryRateObject.TemporaryRateObjectType.POST_RUN, postRun);
|
|
||||||
|
|
||||||
for (var chain : destinationChains) {
|
|
||||||
ChainQuality quality = getChainQuality(chain, postRun, mainRun);
|
|
||||||
|
|
||||||
/* if connection quality is bad, do not try to route this and continue. */
|
|
||||||
if (quality == ChainQuality.FALLBACK) continue;
|
|
||||||
|
|
||||||
boolean routable = true;
|
|
||||||
TemporaryRouteObject routeObj = new TemporaryRouteObject();
|
|
||||||
|
|
||||||
for (int idx = 1; idx < chain.size() - quality.getSizeOffset(); idx++) {
|
|
||||||
Node startNode = chain.get(idx);
|
|
||||||
Node endNode = chain.get(idx - 1);
|
|
||||||
|
|
||||||
var rate = connectNodes(startNode, endNode, container);
|
|
||||||
|
|
||||||
if (rate != null) {
|
|
||||||
routeObj.addSection(rate);
|
|
||||||
} else {
|
|
||||||
// chain is not routable -> discard
|
|
||||||
routable = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routable) {
|
|
||||||
routeObj.addPostRunSection(postRunObj);
|
|
||||||
routeObj.addMainRunSection(mainRunObj);
|
|
||||||
container.addRoute(routeObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private ChainQuality getChainQuality(List<Node> chain, ContainerRate postRun, ContainerRate mainRun) {
|
|
||||||
if (chain.getLast().getId().equals(postRun.getToNodeId())) {
|
|
||||||
return ChainQuality.MEDIUM;
|
|
||||||
} else if (chain.getLast().getId().equals(postRun.getFromNodeId()) && chain.get(chain.size() - 2).getId().equals(postRun.getToNodeId())) {
|
|
||||||
return ChainQuality.HIGH;
|
|
||||||
} else if (chain.getLast().getCountryId().equals(postRun.getToCountryId())) {
|
|
||||||
return ChainQuality.LOW;
|
|
||||||
}
|
|
||||||
return ChainQuality.FALLBACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TemporaryRateObject connectNodes(Node startNode, Node endNode, TemporaryContainer container) {
|
|
||||||
var containerRateObj = new TemporaryRateObject(startNode, endNode, TemporaryRateObject.TemporaryRateObjectType.CONTAINER);
|
|
||||||
var matrixRateObj = new TemporaryRateObject(startNode, endNode, TemporaryRateObject.TemporaryRateObjectType.MATRIX);
|
|
||||||
|
|
||||||
if (container.getRates().contains(containerRateObj))
|
|
||||||
return container.getRates().stream().filter(r -> r.equals(containerRateObj)).findFirst().orElseThrow();
|
|
||||||
|
|
||||||
if (container.getRates().contains(matrixRateObj))
|
|
||||||
return container.getRates().stream().filter(r -> r.equals(matrixRateObj)).findFirst().orElseThrow();
|
|
||||||
|
|
||||||
Optional<ContainerRate> containerRate = containerRateRepository.findRoute(startNode.getId(), endNode.getId(), ContainerRateType.ROAD);
|
|
||||||
|
|
||||||
if (containerRate.isPresent()) {
|
|
||||||
containerRateObj.setRate(containerRate.get());
|
|
||||||
container.getRates().add(containerRateObj);
|
|
||||||
return containerRateObj;
|
|
||||||
} else {
|
|
||||||
Optional<MatrixRate> matrixRate = matrixRateRepository.getByCountryIds(startNode.getCountryId(), endNode.getCountryId());
|
|
||||||
|
|
||||||
if (matrixRate.isPresent()) {
|
|
||||||
matrixRateObj.setRate(matrixRate.get());
|
|
||||||
matrixRateObj.setApproxDistance(distanceService.getDistance(startNode, endNode, true));
|
|
||||||
container.getRates().add(matrixRateObj);
|
|
||||||
return matrixRateObj;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum ChainQuality {
|
|
||||||
HIGH(1), MEDIUM(0), LOW(0), FALLBACK(0);
|
|
||||||
|
|
||||||
private final int sizeOffset;
|
|
||||||
|
|
||||||
ChainQuality(int sizeOffset) {
|
|
||||||
this.sizeOffset = sizeOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSizeOffset() {
|
|
||||||
return sizeOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TemporaryContainer {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set to lookup route sections. Generated from node pairs.
|
|
||||||
*/
|
|
||||||
private final Set<TemporaryRateObject> rates = new HashSet<>();
|
|
||||||
/*
|
|
||||||
* Routes that are build within the routing service.
|
|
||||||
*/
|
|
||||||
private final Collection<TemporaryRouteObject> routes = new ArrayList<>();
|
|
||||||
/*
|
|
||||||
* Source and destination node
|
|
||||||
*/
|
|
||||||
private final Node source;
|
|
||||||
private final Node destination;
|
|
||||||
/*
|
|
||||||
* mainRuns and postRuns retrieved from database.
|
|
||||||
*/
|
|
||||||
private Map<Integer, List<ContainerRate>> mainRuns;
|
|
||||||
private Map<Integer, List<ContainerRate>> postRuns;
|
|
||||||
private MatrixRate sourceMatrixRate;
|
|
||||||
|
|
||||||
public TemporaryContainer(Node source, Node destination) {
|
|
||||||
this.source = source;
|
|
||||||
this.destination = destination;
|
|
||||||
this.mainRuns = null;
|
|
||||||
this.postRuns = null;
|
|
||||||
this.sourceMatrixRate = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Collection<TemporaryRateObject> getRates() {
|
|
||||||
return rates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ContainerRate> getMainRuns(Integer outboundNodeId) {
|
|
||||||
return mainRuns.get(outboundNodeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ContainerRate> getMainRuns() {
|
|
||||||
return mainRuns.values().stream().flatMap(Collection::stream).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMainRuns(Map<Integer, List<ContainerRate>> mainRuns) {
|
|
||||||
this.mainRuns = mainRuns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Integer, List<ContainerRate>> getPostRuns() {
|
|
||||||
return postRuns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPostRuns(Map<Integer, List<ContainerRate>> postRuns) {
|
|
||||||
this.postRuns = postRuns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRoute(TemporaryRouteObject route) {
|
|
||||||
this.routes.add(route);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<TemporaryRouteObject> getRoutes() {
|
|
||||||
return routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node getSourceNode() {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node getDestinationNode() {
|
|
||||||
return destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSourceMatrixRate(MatrixRate sourceMatrixRate) {
|
|
||||||
this.sourceMatrixRate = sourceMatrixRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasSourceMatrixRate() {
|
|
||||||
return sourceMatrixRate != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void overrideRoutes(Collection<TemporaryRouteObject> routes) {
|
|
||||||
this.routes.clear();
|
|
||||||
this.routes.addAll(routes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TemporaryRouteObject {
|
|
||||||
|
|
||||||
private final List<TemporaryRateObject> sections;
|
|
||||||
|
|
||||||
private TemporaryRateObject mainRun;
|
|
||||||
private TemporaryRateObject postRun;
|
|
||||||
|
|
||||||
private boolean nearBy = false;
|
|
||||||
private boolean isCheapest = false;
|
|
||||||
private boolean isFastest = false;
|
|
||||||
|
|
||||||
public TemporaryRouteObject() {
|
|
||||||
sections = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TemporaryRateObject> getSections() {
|
|
||||||
return sections;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSection(TemporaryRateObject section) {
|
|
||||||
this.sections.add(section);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMainRunSection(TemporaryRateObject mainRun) {
|
|
||||||
addSection(mainRun);
|
|
||||||
this.mainRun = mainRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addPostRunSection(TemporaryRateObject postRun) {
|
|
||||||
addSection(postRun);
|
|
||||||
this.postRun = postRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TemporaryRateObject getMainRun() {
|
|
||||||
return mainRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMainRun(TemporaryRateObject mainRun) {
|
|
||||||
this.mainRun = mainRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TemporaryRateObject getPostRun() {
|
|
||||||
return postRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TemporaryRouteObject clone() {
|
|
||||||
TemporaryRouteObject clone = new TemporaryRouteObject();
|
|
||||||
clone.sections.addAll(sections);
|
|
||||||
clone.mainRun = mainRun;
|
|
||||||
clone.postRun = postRun;
|
|
||||||
clone.nearBy = nearBy;
|
|
||||||
clone.isCheapest = isCheapest;
|
|
||||||
clone.isFastest = isFastest;
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void routeOverNearBy() {
|
|
||||||
this.nearBy = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getCost() {
|
|
||||||
return sections.stream().mapToDouble(TemporaryRateObject::getCost).sum();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCheapest() {
|
|
||||||
this.isCheapest = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFastest() {
|
|
||||||
this.isFastest = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLeadTime() {
|
|
||||||
return sections.stream().mapToInt(TemporaryRateObject::getLeadTime).sum();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Node> getNodes() {
|
|
||||||
List<Node> nodes = new ArrayList<>();
|
|
||||||
|
|
||||||
for(var section : sections.reversed()) {
|
|
||||||
|
|
||||||
if(sections.getFirst().equals(section))
|
|
||||||
nodes.add(section.getFromNode());
|
|
||||||
|
|
||||||
nodes.add(section.getToNode());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isCheapest() {
|
|
||||||
return isCheapest;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isFastest() {
|
|
||||||
return isFastest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class TemporaryRateObject {
|
|
||||||
|
|
||||||
private final Node fromNode;
|
|
||||||
private final Node toNode;
|
|
||||||
private MatrixRate matrixRate;
|
|
||||||
private double approxDistance;
|
|
||||||
private ContainerRate containerRate;
|
|
||||||
|
|
||||||
private TemporaryRateObjectType type;
|
|
||||||
|
|
||||||
|
|
||||||
public TemporaryRateObject(Node fromNode, Node toNode, TemporaryRateObjectType type) {
|
|
||||||
|
|
||||||
this.fromNode = fromNode;
|
|
||||||
this.toNode = toNode;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TemporaryRateObject(Node fromNode, Node toNode, TemporaryRateObjectType type, ContainerRate rate) {
|
|
||||||
this.fromNode = fromNode;
|
|
||||||
this.toNode = toNode;
|
|
||||||
this.type = type;
|
|
||||||
this.containerRate = rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
TemporaryRateObject that = (TemporaryRateObject) o;
|
|
||||||
|
|
||||||
if (this.type.equals(that.type)) {
|
|
||||||
if (this.type.equals(TemporaryRateObjectType.MATRIX)) {
|
|
||||||
return Objects.equals(this.fromNode.getCountryId(), that.fromNode.getCountryId()) && Objects.equals(this.toNode.getCountryId(), that.toNode.getCountryId());
|
|
||||||
} else if (this.type.equals(TemporaryRateObjectType.CONTAINER) || this.type.equals(TemporaryRateObjectType.MAIN_RUN) || this.type.equals(TemporaryRateObjectType.POST_RUN)) {
|
|
||||||
return Objects.equals(this.fromNode.getId(), that.fromNode.getId()) && Objects.equals(this.toNode.getId(), that.toNode.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
if (matrixRate != null) return Objects.hash(matrixRate.getFromCountry(), matrixRate.getToCountry());
|
|
||||||
|
|
||||||
if (containerRate != null) return Objects.hash(containerRate.getFromNodeId(), containerRate.getToNodeId());
|
|
||||||
|
|
||||||
return Objects.hash(null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRate(ContainerRate containerRate) {
|
|
||||||
this.containerRate = containerRate;
|
|
||||||
this.type = TemporaryRateObjectType.CONTAINER;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRate(MatrixRate matrixRate) {
|
|
||||||
this.matrixRate = matrixRate;
|
|
||||||
this.type = TemporaryRateObjectType.MATRIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getApproxDistance() {
|
|
||||||
return approxDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setApproxDistance(double distance) {
|
|
||||||
this.approxDistance = distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node getFromNode() {
|
|
||||||
return fromNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node getToNode() {
|
|
||||||
return toNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getCost() {
|
|
||||||
if(type.equals(TemporaryRateObjectType.MATRIX)) {
|
|
||||||
return matrixRate.getRate().doubleValue() * approxDistance;
|
|
||||||
} else {
|
|
||||||
return containerRate.getRateFeu().doubleValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLeadTime() {
|
|
||||||
if (type.equals(TemporaryRateObjectType.MATRIX)) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
return containerRate.getLeadTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TemporaryRateObjectType getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContainerRateType getContainerRateTye() {
|
|
||||||
return containerRate.getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum TemporaryRateObjectType {
|
|
||||||
MATRIX, CONTAINER, POST_RUN, MAIN_RUN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -373,6 +373,8 @@ CREATE TABLE IF NOT EXISTS premise_destination
|
||||||
premise_id INT NOT NULL,
|
premise_id INT NOT NULL,
|
||||||
annual_amount INT UNSIGNED NOT NULL COMMENT 'annual amount in single pieces',
|
annual_amount INT UNSIGNED NOT NULL COMMENT 'annual amount in single pieces',
|
||||||
destination_node_id INT NOT NULL,
|
destination_node_id INT NOT NULL,
|
||||||
|
is_d2d BOOLEAN DEFAULT FALSE,
|
||||||
|
rate_d2d DECIMAL(15, 2) DEFAULT NULL,
|
||||||
repacking_cost DECIMAL(15, 2) DEFAULT NULL,
|
repacking_cost DECIMAL(15, 2) DEFAULT NULL,
|
||||||
handling_cost DECIMAL(15, 2) DEFAULT NULL,
|
handling_cost DECIMAL(15, 2) DEFAULT NULL,
|
||||||
disposal_cost DECIMAL(15, 2) DEFAULT NULL,
|
disposal_cost DECIMAL(15, 2) DEFAULT NULL,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue