Merge pull request 'feature/reporting - merge reporting current state into dev because it contains bugfixes for issue #78' (#84) from feature/reporting into dev
Reviewed-on: #84
This commit is contained in:
commit
0a128a7cb4
12 changed files with 441 additions and 236 deletions
|
|
@ -133,9 +133,12 @@ export default {
|
||||||
.box-content.collapsed {
|
.box-content.collapsed {
|
||||||
max-height: 0;
|
max-height: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
margin: 0 !important; /* ← !important um alle margins zu überschreiben */
|
||||||
padding-top: 0;
|
padding: 0 !important;
|
||||||
padding-bottom: 0;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -7,42 +7,53 @@
|
||||||
<report-chart
|
<report-chart
|
||||||
title=""
|
title=""
|
||||||
:mek_a="report.costs.mek_a.total"
|
:mek_a="report.costs.mek_a.total"
|
||||||
:logistics_costs="report.risk.mek_b.total-report.costs.mek_a.total"
|
:logistics_costs="report.overview.mek_b.total-report.costs.mek_a.total"
|
||||||
:chance_cost="report.risk.opportunity_scenario.total"
|
:chance_cost="report.overview.opportunity_scenario.total"
|
||||||
:risk_cost="report.risk.risk_scenario.total"
|
:risk_cost="report.overview.risk_scenario.total"
|
||||||
:scale="chartScale"
|
:scale="chartScale"
|
||||||
></report-chart>
|
></report-chart>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- summary -->
|
||||||
<div class="box-gap">
|
<div class="box-gap">
|
||||||
<collapsible-box :is-collapsable="false" variant="border" title="Overview" size="m" :stretch-content="true">
|
<collapsible-box :is-collapsable="false" variant="border" title="Summary" size="m" :stretch-content="true">
|
||||||
<div class="report-content-container--3-col">
|
<div class="report-content-container--3-col">
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div class="report-content-row-highlight">MEK B</div>
|
<div>MEK A</div>
|
||||||
<div class="report-content-data-cell report-content-row-highlight">{{ report.risk.mek_b.total.toFixed(2) }} €</div>
|
<div class="report-content-data-cell">{{ report.overview.mek_a.total.toFixed(2) }} €</div>
|
||||||
<div class="report-content-data-cell"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="report-content-row">
|
|
||||||
<div>Opportunity scenario</div>
|
|
||||||
<div class="report-content-data-cell">{{ report.risk.opportunity_scenario.total.toFixed(2) }} €</div>
|
|
||||||
<div class="report-content-data-cell">{{
|
<div class="report-content-data-cell">{{
|
||||||
`${(report.risk.opportunity_scenario.percentage * 100).toFixed(2)} %`
|
`${(report.overview.mek_a.percentage * 100).toFixed(2)} %`
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Risk scenario</div>
|
<div>Logistics cost</div>
|
||||||
<div class="report-content-data-cell">{{ report.risk.risk_scenario.total.toFixed(2) }} €</div>
|
<div class="report-content-data-cell">{{ report.overview.logistics.total.toFixed(2) }} €</div>
|
||||||
<div class="report-content-data-cell">{{ `${(report.risk.risk_scenario.percentage * 100).toFixed(2)} %`}}</div>
|
<div class="report-content-data-cell">{{
|
||||||
|
`${(report.overview.logistics.percentage * 100).toFixed(2)} %`
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="report-content-row">
|
||||||
|
<div class="report-content-row-highlight">MEK B</div>
|
||||||
|
<div class="report-content-data-cell report-content-row-highlight">{{
|
||||||
|
report.overview.mek_b.total.toFixed(2)
|
||||||
|
}} €
|
||||||
|
</div>
|
||||||
|
<div class="report-content-data-cell report-content-row-highlight">{{
|
||||||
|
`${(report.overview.mek_b.percentage * 100).toFixed(2)} %`
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</collapsible-box>
|
</collapsible-box>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- weighted cost breakdown-->
|
||||||
<div class="box-gap">
|
<div class="box-gap">
|
||||||
<collapsible-box :is-collapsable="false" variant="border" title="Weighted cost breakdown" size="m"
|
<collapsible-box :is-collapsable="false" variant="border" title="Weighted cost breakdown" size="m"
|
||||||
:stretch-content="true">
|
:stretch-content="true">
|
||||||
|
|
@ -142,57 +153,80 @@
|
||||||
<div class="report-content-data-cell">{{ (report.costs.capital.percentage * 100).toFixed(2) }}</div>
|
<div class="report-content-data-cell">{{ (report.costs.capital.percentage * 100).toFixed(2) }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="report-content-row">
|
||||||
|
<div class="report-content-row-highlight">Total</div>
|
||||||
|
<div class="report-content-data-cell report-content-row-highlight">{{
|
||||||
|
report.costs.total.total.toFixed(2)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="report-content-data-cell report-content-row-highlight">
|
||||||
|
{{ (report.costs.total.percentage * 100).toFixed(2) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</collapsible-box>
|
</collapsible-box>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- all time high/low container rate-->
|
||||||
|
<div class="box-gap">
|
||||||
|
<collapsible-box :is-collapsable="true" variant="border" title="All time high/low MEK_B"
|
||||||
|
:initially-collapsed="true"
|
||||||
|
:stretch-content="true" size="m">
|
||||||
|
|
||||||
<div class="box-gap" :key="premise.id" v-for="(premise, idx) in report.premises">
|
<div class="report-content-container--3-col-2">
|
||||||
|
|
||||||
<collapsible-box class="report-content-container" variant="border" :title="premise.destination.name"
|
<div class="report-content-row">
|
||||||
:stretch-content="true" :initially-collapsed="true">
|
<div></div>
|
||||||
<div>
|
<div class="report-content-data-header-cell">total [€]</div>
|
||||||
<report-route :sections="premise.sections" :destination="premise.destination"
|
<div class="report-content-data-header-cell">of MEK_B [%]</div>
|
||||||
:route-section-scale="routeSectionScale[idx]"></report-route>
|
</div>
|
||||||
|
|
||||||
<div class="report-sub-header">General</div>
|
<div class="report-content-row">
|
||||||
|
<div>Opportunity scenario</div>
|
||||||
|
<div class="report-content-data-cell">{{ report.overview.opportunity_scenario.total.toFixed(2) }} €</div>
|
||||||
|
<div class="report-content-data-cell">{{
|
||||||
|
`${(report.overview.opportunity_scenario.percentage * 100).toFixed(2)}`
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="report-content-row">
|
||||||
|
<div>Risk scenario</div>
|
||||||
|
<div class="report-content-data-cell">{{ report.overview.risk_scenario.total.toFixed(2) }} €</div>
|
||||||
|
<div class="report-content-data-cell">
|
||||||
|
{{ `${(report.overview.risk_scenario.percentage * 100).toFixed(2)}` }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</collapsible-box>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- material and handling unit-->
|
||||||
|
<div class="box-gap">
|
||||||
|
<collapsible-box :is-collapsable="false" variant="border" title="Material" size="m"
|
||||||
|
:stretch-content="true">
|
||||||
|
|
||||||
<div class="report-content-container--2-col">
|
<div class="report-content-container--2-col">
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Annual Quantity</div>
|
<div>Part number</div>
|
||||||
<div class="report-content-data-cell">{{ premise.annual_quantity }}</div>
|
<div class="report-content-data-cell"> {{ report.material.part_number }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>HS code</div>
|
<div>HS code</div>
|
||||||
<div class="report-content-data-cell">{{ premise.hs_code }}</div>
|
<div class="report-content-data-cell"> {{ report.premises.hs_code }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Tariff rate</div>
|
<div>Tariff rate</div>
|
||||||
<div class="report-content-data-cell">{{ (premise.tariff_rate * 100).toFixed(2) }}%</div>
|
<div class="report-content-data-cell"> {{ (report.premises.tariff_rate * 100).toFixed(2) }}%</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="report-content-row">
|
|
||||||
<div>Oversea share</div>
|
|
||||||
<div class="report-content-data-cell">{{ (premise.oversea_share * 100).toFixed(2) }}%</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="report-content-row" v-if="(premise.air_freight_share ?? null) !== null">
|
|
||||||
<div>Airfreight share</div>
|
|
||||||
<div class="report-content-data-cell">{{ (premise.air_freight_share * 100).toFixed(2) }}%</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="report-content-row">
|
|
||||||
<div>Transit time [days]</div>
|
|
||||||
<div class="report-content-data-cell">{{ premise.transport_time }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="report-content-row">
|
|
||||||
<div>Safety stock [w-days]</div>
|
|
||||||
<div class="report-content-data-cell">{{ premise.safety_stock }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -202,59 +236,113 @@
|
||||||
<div class="report-content-container--2-col">
|
<div class="report-content-container--2-col">
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Dimensions [{{ premise.dimension_unit }}]</div>
|
<div>Dimensions [{{ report.premises.dimension_unit }}]</div>
|
||||||
<div class="report-content-data-cell">{{ toFixedDimension(premise.length, premise.dimension_unit) }} x
|
<div class="report-content-data-cell">{{
|
||||||
{{ toFixedDimension(premise.width, premise.dimension_unit) }} x
|
toFixedDimension(report.premises.length, report.premises.dimension_unit)
|
||||||
{{ toFixedDimension(premise.height, premise.dimension_unit) }}
|
}} x
|
||||||
|
{{ toFixedDimension(report.premises.width, report.premises.dimension_unit) }} x
|
||||||
|
{{ toFixedDimension(report.premises.height, report.premises.dimension_unit) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Weight [{{ premise.weight_unit }}]</div>
|
<div>Weight [{{ report.premises.weight_unit }}]</div>
|
||||||
<div class="report-content-data-cell">{{ toFixedWeight(premise.weight, premise.weight_unit) }}</div>
|
<div class="report-content-data-cell">{{
|
||||||
|
toFixedWeight(report.premises.weight, report.premises.weight_unit)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Unit count</div>
|
<div>Unit count</div>
|
||||||
<div class="report-content-data-cell">{{ premise.hu_unit_count }}</div>
|
<div class="report-content-data-cell">{{ report.premises.hu_unit_count }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Mixed transport</div>
|
<div>Mixed transport</div>
|
||||||
<div class="report-content-data-cell">{{ premise.mixed ? 'Yes' : 'No' }}</div>
|
<div class="report-content-data-cell">{{ report.premises.mixed ? 'Yes' : 'No' }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</collapsible-box>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- destinations -->
|
||||||
|
<div class="box-gap" :key="destination.id" v-for="(destination, idx) in report.destinations">
|
||||||
|
|
||||||
|
<collapsible-box class="report-content-container" variant="border" :title="destination.destination.name"
|
||||||
|
:stretch-content="true" :initially-collapsed="true">
|
||||||
|
<div>
|
||||||
|
<report-route :sections="destination.sections" :destination="destination.destination"
|
||||||
|
:route-section-scale="routeSectionScale[idx]"></report-route>
|
||||||
|
|
||||||
|
<div class="report-sub-header">General</div>
|
||||||
|
|
||||||
|
<div class="report-content-container--2-col">
|
||||||
|
|
||||||
|
<div class="report-content-row">
|
||||||
|
<div>Annual Quantity</div>
|
||||||
|
<div class="report-content-data-cell">{{ destination.annual_quantity }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="report-content-row">
|
||||||
|
<div>Oversea share</div>
|
||||||
|
<div class="report-content-data-cell">{{ (destination.oversea_share * 100).toFixed(2) }}%</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="report-content-row" v-if="(destination.air_freight_share ?? null) !== null">
|
||||||
|
<div>Airfreight share</div>
|
||||||
|
<div class="report-content-data-cell">{{ (destination.air_freight_share * 100).toFixed(2) }}%</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="report-content-row">
|
||||||
|
<div>Transit time [days]</div>
|
||||||
|
<div class="report-content-data-cell">{{ destination.transport_time }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="report-content-row">
|
||||||
|
<div>Safety stock [w-days]</div>
|
||||||
|
<div class="report-content-data-cell">{{ destination.safety_stock }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="report-sub-header">Container</div>
|
<div class="report-sub-header">Container</div>
|
||||||
|
|
||||||
<div class="report-content-container--2-col">
|
<div class="report-content-container--2-col">
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Stacked layers</div>
|
<div>Stacked layers</div>
|
||||||
<div class="report-content-data-cell">{{ hasMainRun(premise.sections) ? premise.layer : '-' }}</div>
|
<div class="report-content-data-cell">{{
|
||||||
|
hasMainRunOrD2D(destination.sections) ? destination.layer : '-'
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Container unit count</div>
|
<div>Container unit count</div>
|
||||||
<div class="report-content-data-cell">
|
<div class="report-content-data-cell">
|
||||||
{{ hasMainRun(premise.sections) ? (premise.unit_count * premise.hu_unit_count) : '-' }}
|
{{
|
||||||
|
hasMainRunOrD2D(destination.sections) ? (destination.unit_count * report.premises.hu_unit_count) : '-'
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Container type</div>
|
<div>Container type</div>
|
||||||
<div class="report-content-data-cell">
|
<div class="report-content-data-cell">
|
||||||
{{ hasMainRun(premise.sections) ? getContainerTypeName(premise.container_type) : '-' }}
|
{{ hasMainRunOrD2D(destination.sections) ? getContainerTypeName(destination.container_type) : '-' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-content-row">
|
<div class="report-content-row">
|
||||||
<div>Limiting factor</div>
|
<div>Limiting factor</div>
|
||||||
<div class="report-content-data-cell">
|
<div class="report-content-data-cell">
|
||||||
{{ hasMainRun(premise.sections) ? premise.weight_exceeded ? 'Weight' : 'Volume' : '-' }}
|
{{ hasMainRunOrD2D(destination.sections) ? destination.weight_exceeded ? 'Weight' : 'Volume' : '-' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -293,8 +381,8 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
hasMainRun(sections) {
|
hasMainRunOrD2D(sections) {
|
||||||
return sections.some(section => section.transport_type === 'SEA' || section.transport_type === 'RAIL');
|
return sections.some(section => section.transport_type === 'SEA' || section.transport_type === 'RAIL' || section.rate_type === 'D2D');
|
||||||
},
|
},
|
||||||
shorten(text, length) {
|
shorten(text, length) {
|
||||||
if (text !== null && text !== undefined && text.length > length) {
|
if (text !== null && text !== undefined && text.length > length) {
|
||||||
|
|
@ -390,6 +478,14 @@ export default {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.report-content-container--3-col-2 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 5fr 3fr 3fr;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1.6rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.report-content-row {
|
.report-content-row {
|
||||||
display: contents;
|
display: contents;
|
||||||
color: #6B869C;
|
color: #6B869C;
|
||||||
|
|
|
||||||
|
|
@ -75,12 +75,12 @@ export default {
|
||||||
},
|
},
|
||||||
routeSectionScale() {
|
routeSectionScale() {
|
||||||
const reports = this.reportsStore.reports;
|
const reports = this.reportsStore.reports;
|
||||||
const scale = new Array(reports.map(r => r.premises.length).reduce((max, n) => Math.max(n, max), 0)).fill(0);
|
const scale = new Array(reports.map(r => r.destinations.length).reduce((max, n) => Math.max(n, max), 0)).fill(0);
|
||||||
|
|
||||||
for (let i = 0; i < scale.length; i++) {
|
for (let i = 0; i < scale.length; i++) {
|
||||||
for (const report of reports) {
|
for (const report of reports) {
|
||||||
if(report.premises.length > i) {
|
if(report.destinations.length > i) {
|
||||||
scale[i] = Math.max(scale[i], report.premises[i].sections.length);
|
scale[i] = Math.max(scale[i], report.destinations[i].sections.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ export const useReportsStore = defineStore('reports', {
|
||||||
let max = 0;
|
let max = 0;
|
||||||
|
|
||||||
state.reports.forEach(report => {
|
state.reports.forEach(report => {
|
||||||
max = Math.max(report.risk.mek_b.total, max);
|
max = Math.max(report.overview.mek_b.total, max);
|
||||||
max = Math.max(report.risk.risk_scenario.total, max);
|
max = Math.max(report.overview.risk_scenario.total, max);
|
||||||
})
|
})
|
||||||
|
|
||||||
const magnitude = Math.pow(10, Math.floor(Math.log10(max)));
|
const magnitude = Math.pow(10, Math.floor(Math.log10(max)));
|
||||||
|
|
@ -74,14 +74,14 @@ export const useReportsStore = defineStore('reports', {
|
||||||
this.showComparableWarning = false;
|
this.showComparableWarning = false;
|
||||||
for (const [idx, report] of this.reports.entries()) {
|
for (const [idx, report] of this.reports.entries()) {
|
||||||
for (const otherReport of this.reports.slice(idx + 1)) {
|
for (const otherReport of this.reports.slice(idx + 1)) {
|
||||||
if (report.premises.length !== otherReport.premises.length) {
|
if (report.destinations.length !== otherReport.destinations.length) {
|
||||||
this.showComparableWarning = true;
|
this.showComparableWarning = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const premise of report.premises) {
|
for (const premise of report.destinations) {
|
||||||
|
|
||||||
const otherPremise = otherReport.premises.find(otherPremise => otherPremise.destination.external_mapping_id === premise.destination.external_mapping_id);
|
const otherPremise = otherReport.destinations.find(otherPremise => otherPremise.destination.external_mapping_id === premise.destination.external_mapping_id);
|
||||||
|
|
||||||
if((otherPremise ?? null) == null) {
|
if((otherPremise ?? null) == null) {
|
||||||
this.showComparableWarning = true;
|
this.showComparableWarning = true;
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,17 @@ package de.avatic.lcc.controller.report;
|
||||||
|
|
||||||
import de.avatic.lcc.dto.generic.NodeDTO;
|
import de.avatic.lcc.dto.generic.NodeDTO;
|
||||||
import de.avatic.lcc.dto.report.ReportDTO;
|
import de.avatic.lcc.dto.report.ReportDTO;
|
||||||
|
import de.avatic.lcc.dto.report.ReportSearchRequestDTO;
|
||||||
import de.avatic.lcc.service.report.ExcelReportingService;
|
import de.avatic.lcc.service.report.ExcelReportingService;
|
||||||
import de.avatic.lcc.service.report.ReportingService;
|
import de.avatic.lcc.service.report.ReportingService;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
import org.apache.coyote.Response;
|
import org.apache.coyote.Response;
|
||||||
import org.springframework.core.io.InputStreamResource;
|
import org.springframework.core.io.InputStreamResource;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -25,7 +24,6 @@ import java.util.List;
|
||||||
@RequestMapping("/api/reports")
|
@RequestMapping("/api/reports")
|
||||||
public class ReportingController {
|
public class ReportingController {
|
||||||
|
|
||||||
//TODO: rollenbeschränkung
|
|
||||||
|
|
||||||
private final ReportingService reportingService;
|
private final ReportingService reportingService;
|
||||||
private final ExcelReportingService excelReportingService;
|
private final ExcelReportingService excelReportingService;
|
||||||
|
|
@ -42,6 +40,17 @@ public class ReportingController {
|
||||||
this.excelReportingService = excelReportingService;
|
this.excelReportingService = excelReportingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping({"/", ""})
|
||||||
|
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION', 'BASIC')")
|
||||||
|
public ResponseEntity<String> listReports(@RequestBody(required = false) ReportSearchRequestDTO filter,
|
||||||
|
@RequestParam(defaultValue = "20") @Min(1) int limit,
|
||||||
|
@RequestParam(defaultValue = "1") @Min(1) int page) {
|
||||||
|
|
||||||
|
//TODO implement me
|
||||||
|
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,13 @@ public class ReportDTO {
|
||||||
@JsonProperty("costs")
|
@JsonProperty("costs")
|
||||||
public Map<String, ReportEntryDTO> cost;
|
public Map<String, ReportEntryDTO> cost;
|
||||||
|
|
||||||
@JsonProperty("risk")
|
@JsonProperty("overview")
|
||||||
public Map<String, ReportEntryDTO> risk;
|
public Map<String, ReportEntryDTO> overview;
|
||||||
|
|
||||||
@JsonProperty("premises")
|
@JsonProperty("premises")
|
||||||
|
private ReportPremisesDTO premises;
|
||||||
|
|
||||||
|
@JsonProperty("destinations")
|
||||||
public List<ReportDestinationDTO> destinations;
|
public List<ReportDestinationDTO> destinations;
|
||||||
|
|
||||||
public NodeDTO getSupplier() {
|
public NodeDTO getSupplier() {
|
||||||
|
|
@ -49,12 +52,12 @@ public class ReportDTO {
|
||||||
this.cost = cost;
|
this.cost = cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, ReportEntryDTO> getRisk() {
|
public Map<String, ReportEntryDTO> getOverview() {
|
||||||
return risk;
|
return overview;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRisk(Map<String, ReportEntryDTO> risk) {
|
public void setOverview(Map<String, ReportEntryDTO> overview) {
|
||||||
this.risk = risk;
|
this.overview = overview;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ReportDestinationDTO> getDestinations() {
|
public List<ReportDestinationDTO> getDestinations() {
|
||||||
|
|
@ -88,4 +91,14 @@ public class ReportDTO {
|
||||||
public void setEndDate(LocalDateTime endDate) {
|
public void setEndDate(LocalDateTime endDate) {
|
||||||
this.endDate = endDate;
|
this.endDate = endDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ReportPremisesDTO getPremises() {
|
||||||
|
return premises;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPremises(ReportPremisesDTO premises) {
|
||||||
|
this.premises = premises;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,6 @@ public class ReportDestinationDTO {
|
||||||
private List<ReportSectionDTO> sections;
|
private List<ReportSectionDTO> sections;
|
||||||
|
|
||||||
/* general */
|
/* general */
|
||||||
|
|
||||||
@JsonProperty("annual_quantity")
|
|
||||||
private Integer annualQuantity;
|
|
||||||
|
|
||||||
@JsonProperty("hs_code")
|
|
||||||
private String hsCode;
|
|
||||||
|
|
||||||
@JsonProperty("tariff_rate")
|
|
||||||
private Number tariffRate;
|
|
||||||
|
|
||||||
@JsonProperty("oversea_share")
|
@JsonProperty("oversea_share")
|
||||||
private Double overseaShare;
|
private Double overseaShare;
|
||||||
|
|
||||||
|
|
@ -38,29 +28,12 @@ public class ReportDestinationDTO {
|
||||||
@JsonProperty("safety_stock")
|
@JsonProperty("safety_stock")
|
||||||
private Integer safetyStock;
|
private Integer safetyStock;
|
||||||
|
|
||||||
/* packaging */
|
@JsonProperty("annual_quantity")
|
||||||
|
private Integer annualQuantity;
|
||||||
private Double width;
|
|
||||||
|
|
||||||
private Double height;
|
|
||||||
|
|
||||||
private Double length;
|
|
||||||
|
|
||||||
private Double weight;
|
|
||||||
|
|
||||||
@JsonProperty("dimension_unit")
|
|
||||||
private DimensionUnit dimensionUnit;
|
|
||||||
|
|
||||||
@JsonProperty("weight_unit")
|
|
||||||
private WeightUnit weightUnit;
|
|
||||||
|
|
||||||
@JsonProperty("hu_unit_count")
|
|
||||||
private Integer huUnitCount;
|
|
||||||
|
|
||||||
private Integer layer;
|
private Integer layer;
|
||||||
|
|
||||||
/* container */
|
/* container */
|
||||||
|
|
||||||
@JsonProperty("unit_count")
|
@JsonProperty("unit_count")
|
||||||
private Number unitCount;
|
private Number unitCount;
|
||||||
|
|
||||||
|
|
@ -77,7 +50,6 @@ public class ReportDestinationDTO {
|
||||||
|
|
||||||
private Boolean mixed;
|
private Boolean mixed;
|
||||||
|
|
||||||
|
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
@ -110,22 +82,6 @@ public class ReportDestinationDTO {
|
||||||
this.annualQuantity = annualQuantity;
|
this.annualQuantity = annualQuantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHsCode() {
|
|
||||||
return hsCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHsCode(String hsCode) {
|
|
||||||
this.hsCode = hsCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Number getTariffRate() {
|
|
||||||
return tariffRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTariffRate(Number tariffRate) {
|
|
||||||
this.tariffRate = tariffRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getOverseaShare() {
|
public Double getOverseaShare() {
|
||||||
return overseaShare;
|
return overseaShare;
|
||||||
}
|
}
|
||||||
|
|
@ -158,62 +114,6 @@ public class ReportDestinationDTO {
|
||||||
this.safetyStock = safetyStock;
|
this.safetyStock = safetyStock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getWidth() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWidth(Double width) {
|
|
||||||
this.width = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHeight(Double height) {
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getLength() {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLength(Double length) {
|
|
||||||
this.length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getWeight() {
|
|
||||||
return weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWeight(Double weight) {
|
|
||||||
this.weight = weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DimensionUnit getDimensionUnit() {
|
|
||||||
return dimensionUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDimensionUnit(DimensionUnit dimensionUnit) {
|
|
||||||
this.dimensionUnit = dimensionUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WeightUnit getWeightUnit() {
|
|
||||||
return weightUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWeightUnit(WeightUnit weightUnit) {
|
|
||||||
this.weightUnit = weightUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getHuUnitCount() {
|
|
||||||
return huUnitCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHuUnitCount(Integer huUnitCount) {
|
|
||||||
this.huUnitCount = huUnitCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getLayer() {
|
public Integer getLayer() {
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
108
src/main/java/de/avatic/lcc/dto/report/ReportPremisesDTO.java
Normal file
108
src/main/java/de/avatic/lcc/dto/report/ReportPremisesDTO.java
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
package de.avatic.lcc.dto.report;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import de.avatic.lcc.model.db.utils.DimensionUnit;
|
||||||
|
import de.avatic.lcc.model.db.utils.WeightUnit;
|
||||||
|
|
||||||
|
public class ReportPremisesDTO {
|
||||||
|
|
||||||
|
|
||||||
|
@JsonProperty("hs_code")
|
||||||
|
private String hsCode;
|
||||||
|
|
||||||
|
@JsonProperty("tariff_rate")
|
||||||
|
private Number tariffRate;
|
||||||
|
|
||||||
|
|
||||||
|
/* packaging */
|
||||||
|
|
||||||
|
private Double width;
|
||||||
|
|
||||||
|
private Double height;
|
||||||
|
|
||||||
|
private Double length;
|
||||||
|
|
||||||
|
private Double weight;
|
||||||
|
|
||||||
|
@JsonProperty("dimension_unit")
|
||||||
|
private DimensionUnit dimensionUnit;
|
||||||
|
|
||||||
|
@JsonProperty("weight_unit")
|
||||||
|
private WeightUnit weightUnit;
|
||||||
|
|
||||||
|
@JsonProperty("hu_unit_count")
|
||||||
|
private Integer huUnitCount;
|
||||||
|
|
||||||
|
|
||||||
|
public String getHsCode() {
|
||||||
|
return hsCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHsCode(String hsCode) {
|
||||||
|
this.hsCode = hsCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Number getTariffRate() {
|
||||||
|
return tariffRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTariffRate(Number tariffRate) {
|
||||||
|
this.tariffRate = tariffRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(Double width) {
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(Double height) {
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLength(Double length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getWeight() {
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWeight(Double weight) {
|
||||||
|
this.weight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DimensionUnit getDimensionUnit() {
|
||||||
|
return dimensionUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDimensionUnit(DimensionUnit dimensionUnit) {
|
||||||
|
this.dimensionUnit = dimensionUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WeightUnit getWeightUnit() {
|
||||||
|
return weightUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWeightUnit(WeightUnit weightUnit) {
|
||||||
|
this.weightUnit = weightUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getHuUnitCount() {
|
||||||
|
return huUnitCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHuUnitCount(Integer huUnitCount) {
|
||||||
|
this.huUnitCount = huUnitCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package de.avatic.lcc.dto.report;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ReportSearchRequestDTO {
|
||||||
|
|
||||||
|
List<Integer> supplierIds;
|
||||||
|
|
||||||
|
List<Integer> materialIds;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package de.avatic.lcc.service.bulk;
|
||||||
import de.avatic.lcc.dto.bulk.BulkFileType;
|
import de.avatic.lcc.dto.bulk.BulkFileType;
|
||||||
import de.avatic.lcc.model.bulk.BulkFileTypes;
|
import de.avatic.lcc.model.bulk.BulkFileTypes;
|
||||||
import de.avatic.lcc.model.bulk.BulkOperation;
|
import de.avatic.lcc.model.bulk.BulkOperation;
|
||||||
|
import de.avatic.lcc.model.db.materials.Material;
|
||||||
import de.avatic.lcc.service.api.BatchGeoApiService;
|
import de.avatic.lcc.service.api.BatchGeoApiService;
|
||||||
import de.avatic.lcc.service.bulk.bulkImport.*;
|
import de.avatic.lcc.service.bulk.bulkImport.*;
|
||||||
import de.avatic.lcc.service.excelMapper.*;
|
import de.avatic.lcc.service.excelMapper.*;
|
||||||
|
|
@ -11,6 +12,8 @@ import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.apache.poi.util.RecordFormatException;
|
import org.apache.poi.util.RecordFormatException;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
|
@ -34,6 +37,10 @@ public class BulkImportService {
|
||||||
private final BatchGeoApiService batchGeoApiService;
|
private final BatchGeoApiService batchGeoApiService;
|
||||||
private final MaterialFastExcelMapper materialFastExcelMapper;
|
private final MaterialFastExcelMapper materialFastExcelMapper;
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BulkImportService.class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public BulkImportService(MatrixRateExcelMapper matrixRateExcelMapper, ContainerRateExcelMapper containerRateExcelMapper, MaterialExcelMapper materialExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, NodeBulkImportService nodeBulkImportService, PackagingBulkImportService packagingBulkImportService, MaterialBulkImportService materialBulkImportService, MatrixRateImportService matrixRateImportService, ContainerRateImportService containerRateImportService, BatchGeoApiService batchGeoApiService, MaterialFastExcelMapper materialFastExcelMapper) {
|
public BulkImportService(MatrixRateExcelMapper matrixRateExcelMapper, ContainerRateExcelMapper containerRateExcelMapper, MaterialExcelMapper materialExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, NodeBulkImportService nodeBulkImportService, PackagingBulkImportService packagingBulkImportService, MaterialBulkImportService materialBulkImportService, MatrixRateImportService matrixRateImportService, ContainerRateImportService containerRateImportService, BatchGeoApiService batchGeoApiService, MaterialFastExcelMapper materialFastExcelMapper) {
|
||||||
this.matrixRateExcelMapper = matrixRateExcelMapper;
|
this.matrixRateExcelMapper = matrixRateExcelMapper;
|
||||||
this.containerRateExcelMapper = containerRateExcelMapper;
|
this.containerRateExcelMapper = containerRateExcelMapper;
|
||||||
|
|
@ -63,7 +70,15 @@ public class BulkImportService {
|
||||||
|
|
||||||
private void processOperationWithFastExcel(BulkOperation op) throws IOException {
|
private void processOperationWithFastExcel(BulkOperation op) throws IOException {
|
||||||
var materials = materialFastExcelMapper.importFromExcel(op.getFile());
|
var materials = materialFastExcelMapper.importFromExcel(op.getFile());
|
||||||
materials.forEach(materialBulkImportService::processMaterialInstructions);
|
|
||||||
|
int processed = 0;
|
||||||
|
for(var material : materials) {
|
||||||
|
|
||||||
|
if(processed++ % 1000 == 0)
|
||||||
|
log.info("Processed {} of {} materials", processed, materials.size());
|
||||||
|
|
||||||
|
materialBulkImportService.processMaterialInstructions(material);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processOperationWithApachePOI(BulkOperation op) throws IOException {
|
private void processOperationWithApachePOI(BulkOperation op) throws IOException {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import de.avatic.lcc.dto.generic.TransportType;
|
||||||
import de.avatic.lcc.dto.report.ReportDTO;
|
import de.avatic.lcc.dto.report.ReportDTO;
|
||||||
import de.avatic.lcc.dto.report.ReportDestinationDTO;
|
import de.avatic.lcc.dto.report.ReportDestinationDTO;
|
||||||
import de.avatic.lcc.dto.report.ReportEntryDTO;
|
import de.avatic.lcc.dto.report.ReportEntryDTO;
|
||||||
|
import de.avatic.lcc.dto.report.ReportPremisesDTO;
|
||||||
import de.avatic.lcc.service.bulk.helper.HeaderCellStyleProvider;
|
import de.avatic.lcc.service.bulk.helper.HeaderCellStyleProvider;
|
||||||
import de.avatic.lcc.service.bulk.helper.HeaderGenerator;
|
import de.avatic.lcc.service.bulk.helper.HeaderGenerator;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
|
|
@ -140,11 +141,26 @@ public class ExcelReportingService {
|
||||||
|
|
||||||
// TODO: hardcoded (otherwise values wont match
|
// TODO: hardcoded (otherwise values wont match
|
||||||
report.getCost().keySet().forEach(costName -> addData(costName, report.getCost().get(costName)));
|
report.getCost().keySet().forEach(costName -> addData(costName, report.getCost().get(costName)));
|
||||||
report.getRisk().keySet().forEach(riskName -> addData(riskName, report.getRisk().get(riskName)));
|
report.getOverview().keySet().forEach(riskName -> addData(riskName, report.getOverview().get(riskName)));
|
||||||
|
|
||||||
|
commonPremisses(report.getPremises());
|
||||||
|
|
||||||
report.getDestinations().forEach(this::flattenDestination);
|
report.getDestinations().forEach(this::flattenDestination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void commonPremisses(ReportPremisesDTO premises) {
|
||||||
|
addData(DESTINATION_HS_CODE, premises.getHsCode());
|
||||||
|
addData(DESTINATION_TARIFF_RATE, premises.getTariffRate().toString());
|
||||||
|
|
||||||
|
addData(DESTINATION_WIDTH, premises.getWidth().toString());
|
||||||
|
addData(DESTINATION_HEIGHT, premises.getHeight().toString());
|
||||||
|
addData(DESTINATION_LENGTH, premises.getLength().toString());
|
||||||
|
addData(DESTINATION_DIMENSION_UNIT, premises.getDimensionUnit().toString());
|
||||||
|
addData(DESTINATION_WEIGHT, premises.getWeight().toString());
|
||||||
|
addData(DESTINATION_WEIGHT_UNIT, premises.getWeightUnit().toString());
|
||||||
|
addData(DESTINATION_HU_UNIT_COUNT, premises.getHuUnitCount().toString());
|
||||||
|
}
|
||||||
|
|
||||||
private void flattenDestination(ReportDestinationDTO destination) {
|
private void flattenDestination(ReportDestinationDTO destination) {
|
||||||
|
|
||||||
var hasMainRun = destination.getSections().stream().anyMatch(s -> s.getTransportType().equals(TransportType.RAIL) || s.getTransportType().equals(TransportType.SEA));
|
var hasMainRun = destination.getSections().stream().anyMatch(s -> s.getTransportType().equals(TransportType.RAIL) || s.getTransportType().equals(TransportType.SEA));
|
||||||
|
|
@ -153,8 +169,7 @@ public class ExcelReportingService {
|
||||||
addData(DESTINATION_ADDRESS, destination.getDestination().getAddress());
|
addData(DESTINATION_ADDRESS, destination.getDestination().getAddress());
|
||||||
|
|
||||||
addData(DESTINATION_QUANTITY, destination.getAnnualQuantity().toString());
|
addData(DESTINATION_QUANTITY, destination.getAnnualQuantity().toString());
|
||||||
addData(DESTINATION_HS_CODE, destination.getHsCode());
|
|
||||||
addData(DESTINATION_TARIFF_RATE, destination.getTariffRate().toString());
|
|
||||||
addData(DESTINATION_OVERSHARE, destination.getOverseaShare().toString());
|
addData(DESTINATION_OVERSHARE, destination.getOverseaShare().toString());
|
||||||
|
|
||||||
if(destination.getAirFreightShare() != null)
|
if(destination.getAirFreightShare() != null)
|
||||||
|
|
@ -162,13 +177,7 @@ public class ExcelReportingService {
|
||||||
addData(DESTINATION_TRANSPORT_TIME, destination.getTransportTime().toString());
|
addData(DESTINATION_TRANSPORT_TIME, destination.getTransportTime().toString());
|
||||||
addData(DESTINATION_SAFETY_STOCK, destination.getSafetyStock().toString());
|
addData(DESTINATION_SAFETY_STOCK, destination.getSafetyStock().toString());
|
||||||
|
|
||||||
addData(DESTINATION_WIDTH, destination.getWidth().toString());
|
|
||||||
addData(DESTINATION_HEIGHT, destination.getHeight().toString());
|
|
||||||
addData(DESTINATION_LENGTH, destination.getLength().toString());
|
|
||||||
addData(DESTINATION_DIMENSION_UNIT, destination.getDimensionUnit().toString());
|
|
||||||
addData(DESTINATION_WEIGHT, destination.getWeight().toString());
|
|
||||||
addData(DESTINATION_WEIGHT_UNIT, destination.getWeightUnit().toString());
|
|
||||||
addData(DESTINATION_HU_UNIT_COUNT, destination.getHuUnitCount().toString());
|
|
||||||
addData(DESTINATION_CONTAINER_LAYER, !hasMainRun ? "-" : destination.getLayer().toString());
|
addData(DESTINATION_CONTAINER_LAYER, !hasMainRun ? "-" : destination.getLayer().toString());
|
||||||
|
|
||||||
addData(DESTINATION_CONTAINER_UNIT_COUNT, !hasMainRun ? "-" : destination.getUnitCount().toString());
|
addData(DESTINATION_CONTAINER_UNIT_COUNT, !hasMainRun ? "-" : destination.getUnitCount().toString());
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,7 @@ package de.avatic.lcc.service.transformer.report;
|
||||||
|
|
||||||
import de.avatic.lcc.dto.generic.NodeType;
|
import de.avatic.lcc.dto.generic.NodeType;
|
||||||
import de.avatic.lcc.dto.generic.RateType;
|
import de.avatic.lcc.dto.generic.RateType;
|
||||||
import de.avatic.lcc.dto.report.ReportDTO;
|
import de.avatic.lcc.dto.report.*;
|
||||||
import de.avatic.lcc.dto.report.ReportDestinationDTO;
|
|
||||||
import de.avatic.lcc.dto.report.ReportEntryDTO;
|
|
||||||
import de.avatic.lcc.dto.report.ReportSectionDTO;
|
|
||||||
import de.avatic.lcc.model.db.calculations.CalculationJob;
|
import de.avatic.lcc.model.db.calculations.CalculationJob;
|
||||||
import de.avatic.lcc.model.db.calculations.CalculationJobDestination;
|
import de.avatic.lcc.model.db.calculations.CalculationJobDestination;
|
||||||
import de.avatic.lcc.model.db.calculations.CalculationJobRouteSection;
|
import de.avatic.lcc.model.db.calculations.CalculationJobRouteSection;
|
||||||
|
|
@ -67,23 +64,18 @@ public class ReportTransformer {
|
||||||
|
|
||||||
public ReportDTO toReportDTO(CalculationJob job) {
|
public ReportDTO toReportDTO(CalculationJob job) {
|
||||||
|
|
||||||
ReportDTO reportDTO = new ReportDTO();
|
|
||||||
|
|
||||||
var reportingProperty = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.REPORTING).orElseThrow();
|
|
||||||
boolean includeAirfreight = reportingProperty.getCurrentValue().equals("MEK_C");
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* STEP 1: Fetch all infos.
|
||||||
|
*/
|
||||||
List<CalculationJobDestination> destinations = calculationJobDestinationRepository.getDestinationsByJobId(job.getId());
|
List<CalculationJobDestination> destinations = calculationJobDestinationRepository.getDestinationsByJobId(job.getId());
|
||||||
Map<Integer, List<CalculationJobRouteSection>> sections = calculationJobRouteSectionRepository.getRouteSectionsByDestinationIds(destinations.stream().map(CalculationJobDestination::getId).toList());
|
Map<Integer, List<CalculationJobRouteSection>> sections = calculationJobRouteSectionRepository.getRouteSectionsByDestinationIds(destinations.stream().map(CalculationJobDestination::getId).toList());
|
||||||
|
|
||||||
|
var reportingProperty = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.REPORTING).orElseThrow();
|
||||||
|
boolean includeAirfreight = reportingProperty.getCurrentValue().equals("MEK_C");
|
||||||
var weightedTotalCost = getWeightedTotalCosts(sections);
|
var weightedTotalCost = getWeightedTotalCosts(sections);
|
||||||
|
|
||||||
Premise premise = premiseRepository.getPremiseById(job.getPremiseId()).orElseThrow();
|
Premise premise = premiseRepository.getPremiseById(job.getPremiseId()).orElseThrow();
|
||||||
reportDTO.setMaterial(materialTransformer.toMaterialDTO(materialRepository.getByIdIncludeDeprecated(premise.getMaterialId()).orElseThrow()));
|
|
||||||
|
|
||||||
var period = getPeriod(job);
|
|
||||||
|
|
||||||
reportDTO.setStartDate(period.startDate);
|
|
||||||
reportDTO.setEndDate(period.endDate);
|
|
||||||
|
|
||||||
Node sourceNode = null;
|
Node sourceNode = null;
|
||||||
|
|
||||||
|
|
@ -93,10 +85,29 @@ public class ReportTransformer {
|
||||||
if (premise.getUserSupplierNodeId() != null)
|
if (premise.getUserSupplierNodeId() != null)
|
||||||
sourceNode = userNodeRepository.getById(premise.getUserSupplierNodeId()).orElseThrow();
|
sourceNode = userNodeRepository.getById(premise.getUserSupplierNodeId()).orElseThrow();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* STEP 2: Create report DTO.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ReportDTO reportDTO = new ReportDTO();
|
||||||
|
|
||||||
|
reportDTO.setMaterial(materialTransformer.toMaterialDTO(materialRepository.getByIdIncludeDeprecated(premise.getMaterialId()).orElseThrow()));
|
||||||
|
|
||||||
|
var period = getPeriod(job);
|
||||||
|
|
||||||
|
reportDTO.setStartDate(period.startDate);
|
||||||
|
reportDTO.setEndDate(period.endDate);
|
||||||
|
|
||||||
|
reportDTO.setPremises(getPremisesDTO(job, premise));
|
||||||
|
|
||||||
|
|
||||||
if (!destinations.isEmpty()) {
|
if (!destinations.isEmpty()) {
|
||||||
reportDTO.setCost(getCostMap(job, destinations, weightedTotalCost, includeAirfreight));
|
var costs = getCostMap(job, destinations, weightedTotalCost, includeAirfreight);
|
||||||
reportDTO.setRisk(getRisk(job, destinations, weightedTotalCost, includeAirfreight));
|
reportDTO.setCost(costs);
|
||||||
|
|
||||||
|
/* costs.total contains all logistic costs */
|
||||||
|
reportDTO.setOverview(getOverview(job, destinations, weightedTotalCost, includeAirfreight, costs));
|
||||||
|
|
||||||
Node finalSourceNode = sourceNode;
|
Node finalSourceNode = sourceNode;
|
||||||
reportDTO.setDestination(destinations.stream().map(d -> getDestinationDTO(d, sections.get(d.getId()), premise, finalSourceNode, includeAirfreight)).toList());
|
reportDTO.setDestination(destinations.stream().map(d -> getDestinationDTO(d, sections.get(d.getId()), premise, finalSourceNode, includeAirfreight)).toList());
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -160,12 +171,32 @@ public class ReportTransformer {
|
||||||
return new WeightedTotalCosts(totalPreRunCost, totalMainRunCost, totalPostRunCost, totalD2D, totalCost);
|
return new WeightedTotalCosts(totalPreRunCost, totalMainRunCost, totalPostRunCost, totalD2D, totalCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReportDestinationDTO getDestinationDTO(CalculationJobDestination destination, List<CalculationJobRouteSection> sections, Premise premise, Node sourceNode, boolean includeAirfreight) {
|
private ReportPremisesDTO getPremisesDTO(CalculationJob job, Premise premise) {
|
||||||
var destinationNode = nodeRepository.getByDestinationId(destination.getPremiseDestinationId()).orElseThrow();
|
ReportPremisesDTO premisesDTO = new ReportPremisesDTO();
|
||||||
|
|
||||||
var dimensionUnit = premise.getHuDisplayedDimensionUnit();
|
var dimensionUnit = premise.getHuDisplayedDimensionUnit();
|
||||||
var weightUnit = premise.getHuDisplayedWeightUnit();
|
var weightUnit = premise.getHuDisplayedWeightUnit();
|
||||||
|
|
||||||
|
premisesDTO.setDimensionUnit(dimensionUnit);
|
||||||
|
premisesDTO.setWeightUnit(weightUnit);
|
||||||
|
premisesDTO.setHeight(dimensionUnit.convertFromMM(premise.getIndividualHuHeight()));
|
||||||
|
premisesDTO.setWidth(dimensionUnit.convertFromMM(premise.getIndividualHuWidth()));
|
||||||
|
premisesDTO.setLength(dimensionUnit.convertFromMM(premise.getIndividualHuLength()));
|
||||||
|
premisesDTO.setWeight(weightUnit.convertFromG(premise.getIndividualHuWeight()));
|
||||||
|
premisesDTO.setHuUnitCount(premise.getHuUnitCount());
|
||||||
|
|
||||||
|
premisesDTO.setHsCode(premise.getHsCode());
|
||||||
|
premisesDTO.setTariffRate(premise.getTariffRate());
|
||||||
|
|
||||||
|
|
||||||
|
return premisesDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportDestinationDTO getDestinationDTO(CalculationJobDestination destination, List<CalculationJobRouteSection> sections, Premise premise, Node sourceNode, boolean includeAirfreight) {
|
||||||
|
var destinationNode = nodeRepository.getByDestinationId(destination.getPremiseDestinationId()).orElseThrow();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ReportDestinationDTO destinationDTO = new ReportDestinationDTO();
|
ReportDestinationDTO destinationDTO = new ReportDestinationDTO();
|
||||||
destinationDTO.setSections(sections.stream().map(s -> getSection(s, sourceNode, destinationNode, premise)).toList());
|
destinationDTO.setSections(sections.stream().map(s -> getSection(s, sourceNode, destinationNode, premise)).toList());
|
||||||
|
|
||||||
|
|
@ -182,14 +213,6 @@ public class ReportTransformer {
|
||||||
|
|
||||||
destinationDTO.setDestination(nodeTransformer.toNodeDTO(destinationNode));
|
destinationDTO.setDestination(nodeTransformer.toNodeDTO(destinationNode));
|
||||||
|
|
||||||
destinationDTO.setDimensionUnit(dimensionUnit);
|
|
||||||
destinationDTO.setWeightUnit(weightUnit);
|
|
||||||
destinationDTO.setHeight(dimensionUnit.convertFromMM(premise.getIndividualHuHeight()));
|
|
||||||
destinationDTO.setWidth(dimensionUnit.convertFromMM(premise.getIndividualHuWidth()));
|
|
||||||
destinationDTO.setLength(dimensionUnit.convertFromMM(premise.getIndividualHuLength()));
|
|
||||||
destinationDTO.setWeight(weightUnit.convertFromG(premise.getIndividualHuWeight()));
|
|
||||||
destinationDTO.setHuUnitCount(premise.getHuUnitCount());
|
|
||||||
|
|
||||||
CalculationJobRouteSection mainRun = sections.stream().filter(CalculationJobRouteSection::getMainRun).findFirst().orElse(null);
|
CalculationJobRouteSection mainRun = sections.stream().filter(CalculationJobRouteSection::getMainRun).findFirst().orElse(null);
|
||||||
|
|
||||||
destinationDTO.setLayer(destination.getLayerCount());
|
destinationDTO.setLayer(destination.getLayerCount());
|
||||||
|
|
@ -209,8 +232,7 @@ public class ReportTransformer {
|
||||||
destinationDTO.setUnitCount(destination.getHuCount());
|
destinationDTO.setUnitCount(destination.getHuCount());
|
||||||
destinationDTO.setWeightExceeded(destination.getTransportWeightExceeded());
|
destinationDTO.setWeightExceeded(destination.getTransportWeightExceeded());
|
||||||
|
|
||||||
destinationDTO.setHsCode(premise.getHsCode());
|
|
||||||
destinationDTO.setTariffRate(destination.getTariffRate());
|
|
||||||
|
|
||||||
return destinationDTO;
|
return destinationDTO;
|
||||||
}
|
}
|
||||||
|
|
@ -247,7 +269,7 @@ public class ReportTransformer {
|
||||||
return sectionDTO;
|
return sectionDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, ReportEntryDTO> getRisk(CalculationJob job, List<CalculationJobDestination> destination, WeightedTotalCosts weightedTotalCost, boolean includeAirfreight) {
|
private Map<String, ReportEntryDTO> getOverview(CalculationJob job, List<CalculationJobDestination> destination, WeightedTotalCosts weightedTotalCost, boolean includeAirfreight, Map<String, ReportEntryDTO> weightedCostBreakDown) {
|
||||||
Map<String, ReportEntryDTO> risk = new HashMap<>();
|
Map<String, ReportEntryDTO> risk = new HashMap<>();
|
||||||
|
|
||||||
var annualAmount = destination.stream().map(CalculationJobDestination::getAnnualAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
var annualAmount = destination.stream().map(CalculationJobDestination::getAnnualAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
|
@ -261,6 +283,18 @@ public class ReportTransformer {
|
||||||
|
|
||||||
totalValue = totalValue.add(airfreightValue.multiply(BigDecimal.valueOf(includeAirfreight ? 1 : 0)));
|
totalValue = totalValue.add(airfreightValue.multiply(BigDecimal.valueOf(includeAirfreight ? 1 : 0)));
|
||||||
|
|
||||||
|
var totalLogistics = getTotalLogistics(weightedCostBreakDown);
|
||||||
|
|
||||||
|
ReportEntryDTO mekA = new ReportEntryDTO();
|
||||||
|
mekA.setTotal(weightedCostBreakDown.get("mek_a").getTotal());
|
||||||
|
mekA.setPercentage(weightedCostBreakDown.get("mek_a").getTotal().doubleValue() / (totalValue.doubleValue()));
|
||||||
|
risk.put("mek_a", mekA);
|
||||||
|
|
||||||
|
ReportEntryDTO logistics = new ReportEntryDTO();
|
||||||
|
logistics.setTotal(totalLogistics);
|
||||||
|
logistics.setPercentage(totalLogistics / (totalValue.doubleValue()));
|
||||||
|
risk.put("logistics", logistics);
|
||||||
|
|
||||||
ReportEntryDTO total = new ReportEntryDTO();
|
ReportEntryDTO total = new ReportEntryDTO();
|
||||||
total.setTotal(totalValue);
|
total.setTotal(totalValue);
|
||||||
total.setPercentage(totalValue.divide(totalValue, 4, RoundingMode.HALF_UP));
|
total.setPercentage(totalValue.divide(totalValue, 4, RoundingMode.HALF_UP));
|
||||||
|
|
@ -279,6 +313,11 @@ public class ReportTransformer {
|
||||||
return risk;
|
return risk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Double getTotalLogistics(Map<String, ReportEntryDTO> weightedCostBreakDown) {
|
||||||
|
return weightedCostBreakDown.get("total").getTotal().doubleValue() - weightedCostBreakDown.get("mek_a").getTotal().doubleValue();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, ReportEntryDTO> getCostMap(CalculationJob job, List<CalculationJobDestination> destination, WeightedTotalCosts weightedTotalCost, boolean includeAirfreight) {
|
private Map<String, ReportEntryDTO> getCostMap(CalculationJob job, List<CalculationJobDestination> destination, WeightedTotalCosts weightedTotalCost, boolean includeAirfreight) {
|
||||||
Map<String, ReportEntryDTO> cost = new HashMap<>();
|
Map<String, ReportEntryDTO> cost = new HashMap<>();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue