Merge branch 'main' of git.avatic.de:avatic/lcc_tool
This commit is contained in:
commit
dc29a38230
11 changed files with 67 additions and 218 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="container-rate-container">
|
||||
|
||||
<staged-rates ref="stagedRatesRef"></staged-rates>
|
||||
<staged-rates ref="stagedRatesRef" @rates-update="reloadTable"></staged-rates>
|
||||
|
||||
<div class="container-rate-header">
|
||||
|
||||
|
|
@ -79,7 +79,8 @@ export default {
|
|||
},
|
||||
components: {
|
||||
StagedRates,
|
||||
RadioOption, TableView, DataTable, AutosuggestSearchbar, ModalDialog, Tooltip, IconButton, Dropdown},
|
||||
RadioOption, TableView, DataTable, AutosuggestSearchbar, ModalDialog, Tooltip, IconButton, Dropdown
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useValidityPeriodStore, useMatrixRateStore, useContainerRateStore),
|
||||
loadingPeriods() {
|
||||
|
|
@ -207,7 +208,17 @@ export default {
|
|||
this.modalDialogDeleteState = true;
|
||||
}
|
||||
},
|
||||
async reloadTable() {
|
||||
await this.validityPeriodStore.loadPeriods();
|
||||
await this.matrixRateStore.setQuery();
|
||||
await this.containerRateStore.setQuery();
|
||||
this.pagination = this.rateType === 'container' ? this.containerRateStore.getPagination : this.matrixRateStore.getPagination;
|
||||
},
|
||||
deleteModalClick() {
|
||||
this.modalDialogDeleteState = false;
|
||||
|
||||
if (action === 'accept')
|
||||
this.validPeriodStore.invalidate();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import {useStagedRatesStore} from "@/store/stagedRates.js";
|
|||
export default {
|
||||
name: "StagedRates",
|
||||
components: {ModalDialog, IconButton},
|
||||
emits: ['ratesUpdate'],
|
||||
data() {
|
||||
return {
|
||||
modalDialogStagedChangesState: false,
|
||||
|
|
@ -76,7 +77,7 @@ export default {
|
|||
this.modalDialogStagedChangesState = false;
|
||||
if (action === 'accept') {
|
||||
await this.stagedRatesStore.applyChanges();
|
||||
this.$emit('rates-update');
|
||||
this.$emit('ratesUpdate');
|
||||
}
|
||||
},
|
||||
checkChanges() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="destination-edit-modal-container">
|
||||
<h3 class="sub-header">Edit Destination</h3>
|
||||
<h3 class="sub-header">Edit destination</h3>
|
||||
<div class="destination-edit-container">
|
||||
<tab-container :tabs="tabsConfig" class="tab-container">
|
||||
</tab-container >
|
||||
|
|
|
|||
|
|
@ -7,25 +7,25 @@
|
|||
</div>
|
||||
<div>
|
||||
<checkbox :checked="inputFieldsActive" @checkbox-changed="activateInputFields">I want to enter handling and
|
||||
repackaging costs.
|
||||
repackaging costs manually.
|
||||
</checkbox>
|
||||
</div>
|
||||
<div class="destination-edit-handling-cost-container" v-show="inputFieldsActive">
|
||||
<div class="destination-edit-column-caption">Repackaging cost [EUR]</div>
|
||||
<div class="destination-edit-column-caption">Repackaging cost [EUR/HU]</div>
|
||||
<div class="destination-edit-column-data">
|
||||
<div class="text-container">
|
||||
<input :value="repackaging" @blur="validate('repackaging', $event)" class="input-field"
|
||||
autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="destination-edit-column-caption">Handling cost [EUR]</div>
|
||||
<div class="destination-edit-column-caption">Handling cost [EUR/HU]</div>
|
||||
<div class="destination-edit-column-data">
|
||||
<div class="text-container">
|
||||
<input :value="handling" @blur="validate('handling', $event)" class="input-field"
|
||||
autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="destination-edit-column-caption">Disposal cost [EUR]</div>
|
||||
<div class="destination-edit-column-caption">Disposal cost [EUR/HU]</div>
|
||||
<div class="destination-edit-column-data">
|
||||
<div class="text-container">
|
||||
<input :value="disposal" @blur="validate('disposal', $event)" class="input-field"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import {defineStore} from 'pinia'
|
|||
import {config} from '@/config'
|
||||
import {useErrorStore} from "@/store/error.js";
|
||||
import { useStageStore } from './stage.js'
|
||||
import performRequest from "@/backend.js";
|
||||
|
||||
export const usePropertySetsStore = defineStore('propertySets', {
|
||||
state() {
|
||||
|
|
@ -47,7 +48,7 @@ export const usePropertySetsStore = defineStore('propertySets', {
|
|||
async invalidate() {
|
||||
|
||||
const url = `${config.backendUrl}/properties/periods/${this.getSelectedPeriod}/`;
|
||||
this.periods = await this.performRequest('DELETE', url, null, false);
|
||||
this.periods = await performRequest(this,'DELETE', url, null, false);
|
||||
|
||||
await this.reload();
|
||||
|
||||
|
|
@ -55,103 +56,9 @@ export const usePropertySetsStore = defineStore('propertySets', {
|
|||
async loadPeriods() {
|
||||
this.loading = true;
|
||||
const url = `${config.backendUrl}/properties/periods`;
|
||||
this.periods = await this.performRequest('GET', url, null, );
|
||||
this.periods = await performRequest(this, 'GET', url, null);
|
||||
this.selectedPeriod = this.getCurrentPeriodId;
|
||||
this.loading = false;
|
||||
},
|
||||
async performRequest(method, url, body, expectResponse = true) {
|
||||
|
||||
const params = {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
if ((body ?? null) !== null) {
|
||||
params.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
const request = {url: url, params: params};
|
||||
console.log("Request:", request);
|
||||
|
||||
const response = await fetch(url, params
|
||||
).catch(e => {
|
||||
const error = {
|
||||
code: 'Network error.',
|
||||
message: "Please check your internet connection.",
|
||||
trace: null
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
|
||||
throw e;
|
||||
});
|
||||
|
||||
let data = null;
|
||||
if (expectResponse) {
|
||||
data = await response.json().catch(e => {
|
||||
const error = {
|
||||
code: 'Malformed response',
|
||||
message: "Malformed server response. Please contact support.",
|
||||
trace: null
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
throw e;
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = {
|
||||
code: data.error.code,
|
||||
title: data.error.title,
|
||||
message: data.error.message,
|
||||
trace: data.error.trace
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
throw new Error('Internal backend error');
|
||||
}
|
||||
} else {
|
||||
if (!response.ok) {
|
||||
|
||||
const data = await response.json().catch(e => {
|
||||
const error = {
|
||||
code: "Return code error " + response.status,
|
||||
message: "Server returned wrong response code",
|
||||
trace: null
|
||||
}
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
throw new Error('Internal backend error');
|
||||
|
||||
});
|
||||
|
||||
const error = {
|
||||
code: data.error.code,
|
||||
title: data.error.title,
|
||||
message: data.error.message,
|
||||
trace: data.error.trace
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
throw new Error('Internal backend error');
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Response:", data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -2,6 +2,7 @@ import {defineStore} from 'pinia'
|
|||
import {config} from '@/config'
|
||||
import {useErrorStore} from "@/store/error.js";
|
||||
import { useStageStore } from './stage.js'
|
||||
import performRequest from "@/backend.js";
|
||||
|
||||
export const useValidityPeriodStore = defineStore('validityPeriod', {
|
||||
state() {
|
||||
|
|
@ -42,7 +43,7 @@ export const useValidityPeriodStore = defineStore('validityPeriod', {
|
|||
async invalidate() {
|
||||
|
||||
const url = `${config.backendUrl}/rates/periods/${this.getSelectedPeriod}/`;
|
||||
this.periods = await this.performRequest('DELETE', url, null, false);
|
||||
this.periods = await performRequest(this,'DELETE', url, null, false);
|
||||
|
||||
await this.reload();
|
||||
|
||||
|
|
@ -50,103 +51,9 @@ export const useValidityPeriodStore = defineStore('validityPeriod', {
|
|||
async loadPeriods() {
|
||||
this.loading = true;
|
||||
const url = `${config.backendUrl}/rates/periods`;
|
||||
this.periods = await this.performRequest('GET', url, null, );
|
||||
this.periods = await performRequest(this,'GET', url, null);
|
||||
this.selectedPeriod = this.getCurrentPeriodId;
|
||||
this.loading = false;
|
||||
},
|
||||
async performRequest(method, url, body, expectResponse = true) {
|
||||
|
||||
const params = {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
if ((body ?? null) !== null) {
|
||||
params.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
const request = {url: url, params: params};
|
||||
console.log("Request:", request);
|
||||
|
||||
const response = await fetch(url, params
|
||||
).catch(e => {
|
||||
const error = {
|
||||
code: 'Network error.',
|
||||
message: "Please check your internet connection.",
|
||||
trace: null
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
|
||||
throw e;
|
||||
});
|
||||
|
||||
let data = null;
|
||||
if (expectResponse) {
|
||||
data = await response.json().catch(e => {
|
||||
const error = {
|
||||
code: 'Malformed response',
|
||||
message: "Malformed server response. Please contact support.",
|
||||
trace: null
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
throw e;
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = {
|
||||
code: data.error.code,
|
||||
title: data.error.title,
|
||||
message: data.error.message,
|
||||
trace: data.error.trace
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
throw new Error('Internal backend error');
|
||||
}
|
||||
} else {
|
||||
if (!response.ok) {
|
||||
|
||||
const data = await response.json().catch(e => {
|
||||
const error = {
|
||||
code: "Return code error " + response.status,
|
||||
message: "Server returned wrong response code",
|
||||
trace: null
|
||||
}
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
throw new Error('Internal backend error');
|
||||
|
||||
});
|
||||
|
||||
const error = {
|
||||
code: data.error.code,
|
||||
title: data.error.title,
|
||||
message: data.error.message,
|
||||
trace: data.error.trace
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
const errorStore = useErrorStore();
|
||||
void errorStore.addError(error, {store: this, request: request});
|
||||
throw new Error('Internal backend error');
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Response:", data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -62,10 +62,10 @@ public class CalculationJobRepository {
|
|||
}
|
||||
|
||||
@Transactional
|
||||
public Optional<CalculationJob> getCalculationJob(Integer periodId, Integer nodeId, Integer materialId) {
|
||||
public Optional<CalculationJob> getCalculationJobWithJobStateValid(Integer periodId, Integer nodeId, Integer materialId) {
|
||||
|
||||
/* there should only be one job per period id, node id and material id combination */
|
||||
String query = "SELECT * FROM calculation_job AS cj INNER JOIN premise AS p ON cj.premise_id = p.id WHERE validity_period_id = ? AND p.supplier_node_id = ? AND material_id = ? LIMIT 1";
|
||||
String query = "SELECT * FROM calculation_job AS cj INNER JOIN premise AS p ON cj.premise_id = p.id WHERE job_state = 'VALID' AND validity_period_id = ? AND p.supplier_node_id = ? AND material_id = ? LIMIT 1";
|
||||
|
||||
var job = jdbcTemplate.query(query, new CalculationJobMapper(), periodId, nodeId, materialId);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import de.avatic.lcc.repositories.NodeRepository;
|
|||
import de.avatic.lcc.repositories.rates.ContainerRateRepository;
|
||||
import de.avatic.lcc.service.bulk.helper.ConstraintGenerator;
|
||||
import de.avatic.lcc.service.bulk.helper.HeaderGenerator;
|
||||
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
|
@ -88,13 +89,35 @@ public class ContainerRateExcelMapper {
|
|||
return true;
|
||||
}
|
||||
|
||||
private String toExcelLetter(int columnIdx) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
columnIdx++; // Convert from 0-based to 1-based for the algorithm
|
||||
while (columnIdx > 0) {
|
||||
columnIdx--; // Adjust for 1-based indexing
|
||||
result.insert(0, (char) ('A' + columnIdx % 26));
|
||||
columnIdx /= 26;
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private ContainerRate mapToEntity(Row row) {
|
||||
ContainerRate entity = new ContainerRate();
|
||||
|
||||
validateConstraints(row);
|
||||
|
||||
entity.setFromNodeId(nodeRepository.getByExternalMappingId(row.getCell(ContainerRateHeader.FROM_NODE.ordinal()).getStringCellValue()).orElseThrow().getId());
|
||||
entity.setToNodeId(nodeRepository.getByExternalMappingId(row.getCell(ContainerRateHeader.TO_NODE.ordinal()).getStringCellValue()).orElseThrow().getId());
|
||||
var fromNode = nodeRepository.getByExternalMappingId(row.getCell(ContainerRateHeader.FROM_NODE.ordinal()).getStringCellValue());
|
||||
var toNode = nodeRepository.getByExternalMappingId(row.getCell(ContainerRateHeader.TO_NODE.ordinal()).getStringCellValue());
|
||||
|
||||
if(fromNode.isEmpty() || fromNode.get().getDeprecated()) {
|
||||
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter( ContainerRateHeader.FROM_NODE.ordinal()) + ": Node with mapping id " + row.getCell(ContainerRateHeader.FROM_NODE.ordinal()).getStringCellValue() + " not found.");
|
||||
}
|
||||
|
||||
if(toNode.isEmpty() || toNode.get().getDeprecated()) {
|
||||
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter( ContainerRateHeader.TO_NODE.ordinal()) + ": Node with mapping id " + row.getCell(ContainerRateHeader.TO_NODE.ordinal()).getStringCellValue() + " not found.");
|
||||
}
|
||||
|
||||
entity.setFromNodeId(fromNode.orElseThrow().getId());
|
||||
entity.setToNodeId(toNode.orElseThrow().getId());
|
||||
entity.setType(TransportType.valueOf(row.getCell(ContainerRateHeader.CONTAINER_RATE_TYPE.ordinal()).getStringCellValue()));
|
||||
entity.setLeadTime(Double.valueOf(row.getCell(ContainerRateHeader.LEAD_TIME.ordinal()).getNumericCellValue()).intValue());
|
||||
entity.setType(TransportType.valueOf(row.getCell(ContainerRateHeader.CONTAINER_RATE_TYPE.ordinal()).getStringCellValue()));
|
||||
|
|
|
|||
|
|
@ -118,16 +118,16 @@ public class PreCalculationCheckService {
|
|||
throw new PremiseValidationError("In destination " + node.getName() + ": destination geo location not set. Please contact your administrator.");
|
||||
}
|
||||
|
||||
if (destination.getDisposalCost() != null && destination.getDisposalCost().compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new PremiseValidationError("In destination " + node.getName() + ": disposal costs entered as zero.");
|
||||
if (destination.getDisposalCost() != null && destination.getDisposalCost().compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new PremiseValidationError("In destination " + node.getName() + ": disposal costs are not set or entered value is less than zero.");
|
||||
}
|
||||
|
||||
if (destination.getHandlingCost() != null && destination.getHandlingCost().compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new PremiseValidationError("In destination " + node.getName() + ": handling costs entered as zero.");
|
||||
if (destination.getHandlingCost() != null && destination.getHandlingCost().compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new PremiseValidationError("In destination " + node.getName() + ": handling costs are not set or entered value is less than zero.");
|
||||
}
|
||||
|
||||
if (destination.getRepackingCost() != null && destination.getRepackingCost().compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new PremiseValidationError("In destination " + node.getName() + ": repackaging costs enstered as zero.");
|
||||
if (destination.getRepackingCost() != null && destination.getRepackingCost().compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new PremiseValidationError("In destination " + node.getName() + ": repackaging costs are not set or entered value is less than zero.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -158,11 +158,11 @@ public class PreCalculationCheckService {
|
|||
private void packagingCheck(Premise premise) {
|
||||
|
||||
if (premise.getHuMixable() == null) {
|
||||
throw new PremiseValidationError("Mixable not set. Please contact administrator");
|
||||
throw new PremiseValidationError("Mixable not set. Please contact administrator.");
|
||||
}
|
||||
|
||||
if (premise.getHuStackable() == null) {
|
||||
throw new PremiseValidationError("Stackable not set. Please contact administrator");
|
||||
throw new PremiseValidationError("Stackable not set. Please contact administrator.");
|
||||
}
|
||||
|
||||
if (premise.getHuStackable() == false && premise.getHuMixable() == true) {
|
||||
|
|
@ -190,11 +190,11 @@ public class PreCalculationCheckService {
|
|||
}
|
||||
|
||||
if (premise.getHuDisplayedWeightUnit() == null) {
|
||||
throw new PremiseValidationError("Packaging weight unit not set. Please contact administrator");
|
||||
throw new PremiseValidationError("Packaging weight unit not set. Please contact administrator.");
|
||||
}
|
||||
|
||||
if (premise.getHuDisplayedDimensionUnit() == null) {
|
||||
throw new PremiseValidationError("Packaging dimension unit not set. Please contact administrator");
|
||||
throw new PremiseValidationError("Packaging dimension unit not set. Please contact administrator.");
|
||||
}
|
||||
|
||||
var hu = dimensionTransformer.toDimensionEntity(premise).withTolerance(DIMENSION_TOLERANCE);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class ReportingService {
|
|||
|
||||
var periodId = period.get().getId();
|
||||
|
||||
var jobs = nodeIds.stream().map(nodeId -> calculationJobRepository.getCalculationJob(periodId, nodeId,materialId)).filter(Optional::isPresent).map(Optional::get).toList();
|
||||
var jobs = nodeIds.stream().map(nodeId -> calculationJobRepository.getCalculationJobWithJobStateValid(periodId, nodeId,materialId)).filter(Optional::isPresent).map(Optional::get).toList();
|
||||
return jobs.stream().map(reportTransformer::toReportDTO).toList();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -573,7 +573,7 @@ CREATE TABLE IF NOT EXISTS calculation_job_route_section
|
|||
FOREIGN KEY (calculation_job_destination_id) REFERENCES calculation_job_destination (id),
|
||||
INDEX idx_premise_route_section_id (premise_route_section_id),
|
||||
INDEX idx_calculation_job_destination_id (calculation_job_destination_id),
|
||||
CONSTRAINT chk_stacked CHECK (is_unmixed_price IS FALSE OR is_stacked IS TRUE) -- only unmixed transports can be unstacked
|
||||
CONSTRAINT chk_stacked CHECK (is_unmixed_price IS TRUE OR is_stacked IS TRUE) -- only unmixed transports can be unstacked
|
||||
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue