Intermediate commit:
- bulk operations
This commit is contained in:
parent
ac85db0064
commit
fa01115c03
20 changed files with 482 additions and 127 deletions
|
|
@ -32,9 +32,6 @@ export default {
|
|||
box-shadow: 0 0.4rem 0.6rem -0.1rem rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.box-bordered:hover {
|
||||
background-color: rgba(107, 134, 156, 0.02);
|
||||
}
|
||||
|
||||
|
||||
.box-bordered {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ export default {
|
|||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
minWidth: {
|
||||
type: String,
|
||||
default: '200px'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
@ -52,8 +56,9 @@ export default {
|
|||
return `tooltip-${this.position}`
|
||||
},
|
||||
tooltipStyles() {
|
||||
// Hier können zusätzliche dynamische Styles hinzugefügt werden
|
||||
return {}
|
||||
return {
|
||||
minWidth: this.minWidth
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -99,9 +104,11 @@ export default {
|
|||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
z-index: 1000;
|
||||
white-space: nowrap;
|
||||
white-space: normal; /* Changed from nowrap to normal */
|
||||
word-wrap: break-word; /* Only break very long words */
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
pointer-events: none;
|
||||
max-width: 800px; /* Further increased default max width */
|
||||
}
|
||||
|
||||
/* Positionierung */
|
||||
|
|
@ -146,7 +153,7 @@ export default {
|
|||
transform: translateX(-50%);
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-top: 6px solid #333;
|
||||
border-top: 6px solid #001D33; /* Fixed color to match background */
|
||||
}
|
||||
|
||||
.tooltip-arrow-bottom {
|
||||
|
|
@ -155,7 +162,7 @@ export default {
|
|||
transform: translateX(-50%);
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #333;
|
||||
border-bottom: 6px solid #001D33; /* Fixed color to match background */
|
||||
}
|
||||
|
||||
.tooltip-arrow-left {
|
||||
|
|
@ -164,7 +171,7 @@ export default {
|
|||
transform: translateY(-50%);
|
||||
border-top: 6px solid transparent;
|
||||
border-bottom: 6px solid transparent;
|
||||
border-left: 6px solid #333;
|
||||
border-left: 6px solid #001D33; /* Fixed color to match background */
|
||||
}
|
||||
|
||||
.tooltip-arrow-right {
|
||||
|
|
@ -173,7 +180,7 @@ export default {
|
|||
transform: translateY(-50%);
|
||||
border-top: 6px solid transparent;
|
||||
border-bottom: 6px solid transparent;
|
||||
border-right: 6px solid #333;
|
||||
border-right: 6px solid #001D33; /* Fixed color to match background */
|
||||
}
|
||||
|
||||
/* Animation */
|
||||
|
|
@ -244,8 +251,8 @@ export default {
|
|||
.tooltip {
|
||||
font-size: 12px;
|
||||
padding: 6px 10px;
|
||||
max-width: 200px;
|
||||
white-space: normal;
|
||||
max-width: 350px; /* Increased mobile max width */
|
||||
white-space: normal; /* Ensure line breaks on mobile */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
<template>
|
||||
<div class="bulk-operation-container">
|
||||
<div class="bulk-operation-info-container">
|
||||
<div class="bulk-operation-info-icon">
|
||||
<ph-file size="28"></ph-file>
|
||||
</div>
|
||||
<div class="bulk-operation-info">
|
||||
<div>{{ operation.processing_type.toLowerCase() }} {{ operation.file_type.toLowerCase() }}</div>
|
||||
<div class="bulk-operation-date">{{ buildDate(operation.timestamp) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bulk-operation-status">
|
||||
<div v-if="operation.state === 'EXCEPTION'">
|
||||
<tooltip min-width="500px" :text="shortend(operation.error.message)" position="left">
|
||||
<basic-badge variant="exception">ERROR</basic-badge>
|
||||
</tooltip>
|
||||
</div>
|
||||
<basic-badge v-else-if="operation.state === 'COMPLETED'">COMPLETED</basic-badge>
|
||||
<basic-badge v-else-if="operation.state === 'SCHEDULED'" variant="skeleton">SCHEDULED</basic-badge>
|
||||
<basic-badge v-else-if="operation.state === 'PROCESSING'" variant="skeleton">PROCESSING</basic-badge>
|
||||
|
||||
</div>
|
||||
<div class="bulk-operation-file">
|
||||
|
||||
<spinner size="s" v-if="operation.state === 'PROCESSING' || operation.state === 'SCHEDULED'"></spinner>
|
||||
<div v-else-if="operation.processing_type === 'EXPORT'">
|
||||
<tooltip text="Download data export" position="left">
|
||||
<icon-button icon="download" @click="$emit('download' , operation.id)"></icon-button>
|
||||
</tooltip>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import BasicButton from "@/components/UI/BasicButton.vue";
|
||||
import IconButton from "@/components/UI/IconButton.vue";
|
||||
import Tooltip from "@/components/UI/Tooltip.vue";
|
||||
import Spinner from "@/components/UI/Spinner.vue";
|
||||
import BasicBadge from "@/components/UI/BasicBadge.vue";
|
||||
|
||||
export default {
|
||||
name: "BulkOperation",
|
||||
components: {BasicBadge, Spinner, Tooltip, IconButton, BasicButton},
|
||||
props: {
|
||||
operation: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
shortend(string) {
|
||||
if(((string ?? null) === null) || string.length < 350)
|
||||
return string;
|
||||
|
||||
return string.substring(0,350) + "..."
|
||||
},
|
||||
buildDate(date) {
|
||||
return `${date[0]}-${date[1].toString().padStart(2, '0')}-${date[2].toString().padStart(2, '0')} ${date[3].toString().padStart(2, '0')}:${date[4]?.toString().padStart(2, '0') || '00'}:${date[5]?.toString().padStart(2, '0') || '00'}`
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
.bulk-operation-file {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bulk-operation-info-icon {
|
||||
color: #6B869C;
|
||||
}
|
||||
|
||||
.bulk-operation-info-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 1.2rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bulk-operation-container {
|
||||
padding: 0.8rem 0;
|
||||
|
||||
}
|
||||
|
||||
.bulk-operation-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.bulk-operation-status {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.bulk-operation-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 3fr 5rem;
|
||||
font-size: 1.4rem;
|
||||
gap: 3.6rem;
|
||||
color: #001D33;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bulk-operation-date {
|
||||
font-size: 1.2rem;
|
||||
color: #6B869C;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -2,11 +2,6 @@
|
|||
<div>
|
||||
<div class="bulk-operations-container">
|
||||
|
||||
<box variant="border" class="bulk-operation-box-status-container">
|
||||
<div class="bulk-operations-sub-container">
|
||||
<div class="bulk-operation-header">Bulk operation status</div>
|
||||
</div>
|
||||
</box>
|
||||
|
||||
<box variant="border" class="bulk-operations-box-container">
|
||||
<div class="bulk-operations-sub-container">
|
||||
|
|
@ -40,7 +35,7 @@
|
|||
</div>
|
||||
|
||||
<div class="bulk-operation-action-footer">
|
||||
<basic-button @click="downloadFile" icon="download">Schedule Export</basic-button>
|
||||
<basic-button @click="downloadFile" icon="download">Export</basic-button>
|
||||
</div>
|
||||
</div>
|
||||
</box>
|
||||
|
|
@ -73,16 +68,20 @@
|
|||
<div id="selectedFile" class="selected-file" v-if="selectedFileName">{{ selectedFileName }}</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="bulk-operation-action-footer">
|
||||
<basic-button @click="uploadFile" icon="upload" :disabled="!selectedFile">Import</basic-button>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</box>
|
||||
|
||||
<div class="bulk-operation-box-status-container">
|
||||
<div class="bulk-operation-status">
|
||||
<div class="bulk-operation-header">History</div>
|
||||
<div v-if="this.bulkOperationStore.getBulkOperations.length === 0" class="empty-container">No recent bulk operations</div>
|
||||
<bulk-operation v-else v-for="bulk in this.bulkOperationStore.getBulkOperations" :key="bulk.id" :operation="bulk" @download="fetchFile"></bulk-operation>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -97,10 +96,13 @@ import {config} from "@/config.js";
|
|||
import Dropdown from "@/components/UI/Dropdown.vue";
|
||||
import {mapStores} from "pinia";
|
||||
import {useValidityPeriodStore} from "@/store/validityPeriod.js";
|
||||
import {useBulkOperationStore} from "@/store/bulkOperation.js";
|
||||
import BulkOperation from "@/components/layout/bulkoperation/BulkOperation.vue";
|
||||
import logger from "@/logger.js";
|
||||
|
||||
export default {
|
||||
name: "BulkOperations",
|
||||
components: {Dropdown, RadioOption, BasicButton, Box},
|
||||
components: {BulkOperation, Dropdown, RadioOption, BasicButton, Box},
|
||||
data() {
|
||||
return {
|
||||
exportType: "templates",
|
||||
|
|
@ -113,10 +115,13 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useValidityPeriodStore),
|
||||
...mapStores(useValidityPeriodStore, useBulkOperationStore),
|
||||
showValidityPeriod() {
|
||||
return this.exportType === "download" && (this.exportDataset === "COUNTRY_MATRIX" || this.exportDataset === "CONTAINER_RATE");
|
||||
},
|
||||
currentPeriod() {
|
||||
return this.validityPeriodStore.getCurrentPeriodId;
|
||||
},
|
||||
selectedPeriod: {
|
||||
get() {
|
||||
return this.validityPeriodStore.getSelectedPeriod
|
||||
|
|
@ -148,13 +153,22 @@ export default {
|
|||
},
|
||||
created() {
|
||||
this.validityPeriodStore.loadPeriods();
|
||||
this.bulkOperationStore.updateStatus();
|
||||
},
|
||||
methods: {
|
||||
async fetchFile(id) {
|
||||
logger.info(`Fetching file ${id}`);
|
||||
this.bulkOperationStore.downloadBulkFile(id);
|
||||
},
|
||||
async downloadFile() {
|
||||
|
||||
const fileName = `lcc_export_${this.exportDataset.toLowerCase()}_${this.exportType.toLowerCase()}.xlsx`;
|
||||
const url = `${config.backendUrl}/bulk/${this.exportType}/${this.exportDataset}/`
|
||||
this.processId = await performDownload(url, fileName);
|
||||
if (this.exportType === "templates") {
|
||||
const fileName = `lcc_export_${this.exportType.toLowerCase()}_${this.exportDataset.toLowerCase()}.xlsx`;
|
||||
const url = `${config.backendUrl}/bulk/templates/${this.exportDataset}/`
|
||||
await performDownload(url, fileName);
|
||||
} else {
|
||||
const isCurrent = this.selectedPeriod === this.currentPeriod;
|
||||
await this.bulkOperationStore.scheduleDownload(this.exportDataset, isCurrent ? null : this.selectedPeriod);
|
||||
}
|
||||
},
|
||||
inputFile(event) {
|
||||
const file = event.target.files[0];
|
||||
|
|
@ -171,8 +185,7 @@ export default {
|
|||
if (!this.selectedFile)
|
||||
return;
|
||||
|
||||
const url = `${config.backendUrl}/bulk/upload/${this.importDataset}/`
|
||||
this.processId = await performUpload(url, this.selectedFile).catch(error => {});
|
||||
await this.bulkOperationStore.scheduleUpload(this.importDataset, this.selectedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -181,6 +194,23 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
|
||||
.empty-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 1.6rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.bulk-operation-status {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
gap: 1.2rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.bulk-operations-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
|
|
|||
|
|
@ -26,16 +26,6 @@
|
|||
</box>
|
||||
</div>
|
||||
<div v-if="selectedCountry" >
|
||||
|
||||
<div v-if="!loading" class="period-select-container">
|
||||
<span class="period-select-caption">Property set:</span>
|
||||
<dropdown :options="periods"
|
||||
emptyText="No property set available"
|
||||
class="period-select"
|
||||
placeholder="Select a property set"
|
||||
v-model="selectedPeriod"
|
||||
></dropdown>
|
||||
</div>
|
||||
<transition name="properties-fade" mode="out-in">
|
||||
<div v-if="!loading" class="properties-list">
|
||||
<transition-group name="property-item" tag="div">
|
||||
|
|
@ -209,7 +199,7 @@ export default {
|
|||
.country-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 50vh;
|
||||
|
||||
}
|
||||
|
||||
.country-search-container {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,12 @@
|
|||
</transition-group>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<box variant="border">
|
||||
<country-properties></country-properties>
|
||||
</box>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -48,10 +54,14 @@ import ModalDialog from "@/components/UI/ModalDialog.vue";
|
|||
import NotificationBar from "@/components/UI/NotificationBar.vue";
|
||||
import {usePropertySetsStore} from "@/store/propertySets.js";
|
||||
import {useCountryStore} from "@/store/country.js";
|
||||
import CountryProperties from "@/components/layout/config/CountryProperties.vue";
|
||||
import Box from "@/components/UI/Box.vue";
|
||||
|
||||
export default {
|
||||
name: "Properties",
|
||||
components: {NotificationBar, ModalDialog, Tooltip, IconButton, BasicButton, Dropdown, Property},
|
||||
components: {
|
||||
Box,
|
||||
CountryProperties, NotificationBar, ModalDialog, Tooltip, IconButton, BasicButton, Dropdown, Property},
|
||||
data() {
|
||||
return {
|
||||
modalDialogDeleteState: false,
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@ import TabContainer from "@/components/UI/TabContainer.vue";
|
|||
import {markRaw} from "vue";
|
||||
import Properties from "@/components/layout/config/Properties.vue";
|
||||
import Box from "@/components/UI/Box.vue";
|
||||
import CountryProperties from "@/components/layout/config/CountryProperties.vue";
|
||||
import StagedChanges from "@/components/layout/config/StagedChanges.vue";
|
||||
import BulkOperations from "@/components/layout/config/BulkOperations.vue";
|
||||
import Rates from "@/components/layout/config/Rates.vue";
|
||||
import Nodes from "@/components/layout/config/Nodes.vue";
|
||||
import Materials from "@/components/layout/config/Materials.vue";
|
||||
import ErrorLog from "@/pages/ErrorLog.vue";
|
||||
|
||||
export default {
|
||||
name: "Config",
|
||||
|
|
@ -39,8 +39,8 @@ export default {
|
|||
component: markRaw(Properties),
|
||||
},
|
||||
{
|
||||
title: 'Countries',
|
||||
component: markRaw(CountryProperties),
|
||||
title: 'System error log',
|
||||
component: markRaw(ErrorLog),
|
||||
},
|
||||
{
|
||||
title: 'Materials',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2 class="page-header">Errors</h2>
|
||||
|
||||
<modal :state="showModal">
|
||||
<error-log-modal :error="error" @close="showModal = false"></error-log-modal>
|
||||
</modal>
|
||||
|
|
@ -30,12 +28,12 @@ export default {
|
|||
pageSize: 10,
|
||||
pagination: { page: 1, pageCount: 10, totalCount: 1 },
|
||||
columns: [
|
||||
{key: 'timestamp', label: 'Timestamp', formatter: (value) => this.buildDate(value) },
|
||||
{key: 'user_id', label: 'User'},
|
||||
{key: 'type', label: 'Type'},
|
||||
{key: 'title', label: 'Title'},
|
||||
{key: 'message', label: 'Message'},
|
||||
{key: 'code', label: 'Exception'},
|
||||
{key: 'timestamp', label: 'Timestamp', formatter: (value) => this.buildDate(value) },
|
||||
{key: 'user_id', label: 'User'},
|
||||
|
||||
],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
import {defineStore} from 'pinia'
|
||||
import {config} from '@/config'
|
||||
import {useErrorStore} from "@/store/error.js";
|
||||
import performRequest, {performDownload, performUpload} from "@/backend.js";
|
||||
|
||||
export const useBulkOperationStore = defineStore('bulkOperation', {
|
||||
state() {
|
||||
return {
|
||||
bulkOperations: [],
|
||||
loading: false,
|
||||
updateInterval: 3000,
|
||||
updateTimer: null
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getBulkOperations(state) {
|
||||
return state.bulkOperations;
|
||||
},
|
||||
isLoading(state) {
|
||||
return state.loading;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async scheduleDownload(dataset, period) {
|
||||
const url = `${config.backendUrl}/bulk/download/${dataset}/${period === null ? '' : period}`;
|
||||
await performRequest(this, 'GET', url, null, false);
|
||||
await this.updateStatus();
|
||||
this.startTimer();
|
||||
},
|
||||
async scheduleUpload(dataset, file) {
|
||||
const url = `${config.backendUrl}/bulk/upload/${dataset}/`
|
||||
await performUpload(url, file, false);
|
||||
await this.updateStatus();
|
||||
this.startTimer();
|
||||
},
|
||||
async timerMethod() {
|
||||
this.updateStatus();
|
||||
const restart = this.restartNeeded();
|
||||
|
||||
console.log("state " + this.bulkOperations.map(b => b.state).join(", ") + "restarting " + restart);
|
||||
|
||||
this.stopTimer();
|
||||
|
||||
if(restart) {
|
||||
this.startTimer();
|
||||
}
|
||||
|
||||
},
|
||||
async updateStatus() {
|
||||
this.loading = true;
|
||||
|
||||
const url = `${config.backendUrl}/bulk/status`;
|
||||
const {data: data, headers: headers} = await performRequest(this, "GET", url, null, true);
|
||||
this.bulkOperations = data;
|
||||
|
||||
this.loading = false;
|
||||
},
|
||||
restartNeeded() {
|
||||
if((this.updateTimer === null) && this.bulkOperations.some(op => (op.state === 'SCHEDULED' || op.state === 'PROCESSING')))
|
||||
return true;
|
||||
|
||||
if (!this.bulkOperations.some(op => (op.state === 'SCHEDULED' || op.state === 'PROCESSING')))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
async downloadBulkFile(id) {
|
||||
const op = this.bulkOperations.find(op => op.id === id);
|
||||
if ((op ?? null) === null) return;
|
||||
|
||||
const fileName = this.getFileName(op.file_type.toLowerCase(), op.processing_type.toLowerCase());
|
||||
const url = `${config.backendUrl}/bulk/file/${id}`;
|
||||
|
||||
await performDownload(url, fileName);
|
||||
},
|
||||
getFileName(dataset, type) {
|
||||
return `lcc_export_${type}_${dataset}.xlsx`;
|
||||
},
|
||||
startTimer() {
|
||||
if (this.updateTimer) return
|
||||
|
||||
console.log("start timer")
|
||||
this.updateTimer = setTimeout(() => {
|
||||
this.timerMethod()
|
||||
}, this.updateInterval)
|
||||
},
|
||||
stopTimer() {
|
||||
if (this.updateTimer) {
|
||||
console.log("stop timer")
|
||||
|
||||
clearTimeout(this.updateTimer)
|
||||
this.updateTimer = null
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
|
@ -36,7 +36,7 @@ public class BulkOperationController {
|
|||
|
||||
|
||||
@GetMapping({"/status/", "/status"})
|
||||
public ResponseEntity<List<BulkOperationDTO>> getUploadStatus() {
|
||||
public ResponseEntity<List<BulkOperationDTO>> getBulkStatus() {
|
||||
return ResponseEntity.ok(bulkOperationService.getStatus());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package de.avatic.lcc.dto.bulk;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import de.avatic.lcc.dto.error.ErrorLogDTO;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
|
|
@ -19,6 +20,8 @@ public class BulkOperationDTO {
|
|||
@JsonProperty("timestamp")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
private ErrorLogDTO error;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
@ -58,4 +61,12 @@ public class BulkOperationDTO {
|
|||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public void setError(ErrorLogDTO error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public ErrorLogDTO getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ public class BulkOperationRepository {
|
|||
@Transactional
|
||||
public Integer insert(BulkOperation operation) {
|
||||
|
||||
removeOld(operation.getUserId());
|
||||
|
||||
String sql = """
|
||||
INSERT INTO bulk_operation (user_id, bulk_file_type, bulk_processing_type, state, file, validity_period_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
|
|
@ -63,14 +65,44 @@ public class BulkOperationRepository {
|
|||
}
|
||||
|
||||
@Transactional
|
||||
public void removeOld() {
|
||||
String sql = """
|
||||
DELETE FROM bulk_operation
|
||||
WHERE created_at < DATE_SUB(NOW(), INTERVAL 7 DAY)
|
||||
AND state NOT IN ('QUEUED', 'PROCESSING')
|
||||
""";
|
||||
public void removeOld(Integer userId) {
|
||||
// First, update sys_error records to set bulk_operation_id to NULL
|
||||
// for bulk operations that will be deleted (all but the 10 newest for the current user)
|
||||
String updateErrorsSql = """
|
||||
UPDATE sys_error
|
||||
SET bulk_operation_id = NULL
|
||||
WHERE bulk_operation_id IN (
|
||||
SELECT id FROM (
|
||||
SELECT id
|
||||
FROM bulk_operation
|
||||
WHERE user_id = ?
|
||||
AND state NOT IN ('SCHEDULED', 'PROCESSING')
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 18446744073709551615 OFFSET 10
|
||||
) AS old_operations
|
||||
)
|
||||
""";
|
||||
|
||||
jdbcTemplate.update(sql);
|
||||
jdbcTemplate.update(updateErrorsSql, userId);
|
||||
|
||||
// Then delete the old bulk_operation entries (keeping only the 10 newest for the current user)
|
||||
String deleteBulkSql = """
|
||||
DELETE FROM bulk_operation
|
||||
WHERE user_id = ?
|
||||
AND state NOT IN ('SCHEDULED', 'PROCESSING')
|
||||
AND id NOT IN (
|
||||
SELECT id FROM (
|
||||
SELECT id
|
||||
FROM bulk_operation
|
||||
WHERE user_id = ?
|
||||
AND state NOT IN ('SCHEDULED', 'PROCESSING')
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 10
|
||||
) AS newest_operations
|
||||
)
|
||||
""";
|
||||
|
||||
jdbcTemplate.update(deleteBulkSql, userId, userId);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
|
@ -90,7 +122,8 @@ public class BulkOperationRepository {
|
|||
SELECT id, user_id, bulk_file_type, bulk_processing_type, state, created_at
|
||||
FROM bulk_operation
|
||||
WHERE user_id = ?
|
||||
ORDER BY created_at DESC
|
||||
|
||||
ORDER BY created_at DESC LIMIT 10
|
||||
""";
|
||||
|
||||
return jdbcTemplate.query(sql, new BulkOperationRowMapper(true), userId);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import de.avatic.lcc.model.error.SysErrorType;
|
|||
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
|
||||
import de.avatic.lcc.repositories.pagination.SearchQueryResult;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||
|
|
@ -14,7 +15,10 @@ import org.springframework.jdbc.support.KeyHolder;
|
|||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.swing.text.html.Option;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -137,20 +141,7 @@ public class SysErrorRepository {
|
|||
parameters.addValue("offset", pagination.getOffset());
|
||||
|
||||
// Execute query
|
||||
List<SysError> errors = namedParameterJdbcTemplate.query(sql, parameters, (rs, rowNum) -> {
|
||||
SysError error = new SysError();
|
||||
error.setId(rs.getInt("id"));
|
||||
error.setUserId(rs.getObject("user_id", Integer.class));
|
||||
error.setTitle(rs.getString("title"));
|
||||
error.setCode(rs.getString("code"));
|
||||
error.setMessage(rs.getString("message"));
|
||||
error.setPinia(rs.getString("pinia"));
|
||||
error.setCalculationJobId(rs.getObject("calculation_job_id", Integer.class));
|
||||
error.setBulkOperationId(rs.getObject("bulk_operation_id", Integer.class));
|
||||
error.setType(SysErrorType.valueOf(rs.getString("type")));
|
||||
error.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
|
||||
return error;
|
||||
});
|
||||
List<SysError> errors = namedParameterJdbcTemplate.query(sql, parameters, new SysErrorMapper());
|
||||
|
||||
// Load trace items for each error
|
||||
if (!errors.isEmpty()) {
|
||||
|
|
@ -183,16 +174,7 @@ public class SysErrorRepository {
|
|||
List<SysErrorTraceItem> allTraceItems = namedParameterJdbcTemplate.query(
|
||||
traceSql,
|
||||
traceParameters,
|
||||
(rs, rowNum) -> {
|
||||
SysErrorTraceItem traceItem = new SysErrorTraceItem();
|
||||
traceItem.setErrorId(rs.getInt("error_id"));
|
||||
traceItem.setId(rs.getInt("id"));
|
||||
traceItem.setLine(rs.getObject("line", Integer.class));
|
||||
traceItem.setFile(rs.getString("file"));
|
||||
traceItem.setMethod(rs.getString("method"));
|
||||
traceItem.setFullPath(rs.getString("fullPath"));
|
||||
return traceItem;
|
||||
}
|
||||
new SysErrorTraceItemMapper()
|
||||
);
|
||||
|
||||
// Group trace items by error ID
|
||||
|
|
@ -206,4 +188,55 @@ public class SysErrorRepository {
|
|||
});
|
||||
}
|
||||
|
||||
public Optional<SysError> getByBulkOperationId(Integer id) {
|
||||
|
||||
String sql = """
|
||||
SELECT * FROM sys_error WHERE bulk_operation_id = :id
|
||||
""";
|
||||
|
||||
MapSqlParameterSource parameters = new MapSqlParameterSource("id", id);
|
||||
|
||||
List<SysError> errors = namedParameterJdbcTemplate.query(sql, parameters, new SysErrorMapper());
|
||||
|
||||
if(errors.isEmpty()) return Optional.empty();
|
||||
|
||||
SysError error = errors.getFirst();
|
||||
loadTraceItemsForErrors(List.of(error));
|
||||
return Optional.of(error);
|
||||
}
|
||||
|
||||
public static class SysErrorMapper implements RowMapper<SysError> {
|
||||
|
||||
@Override
|
||||
public SysError mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
SysError error = new SysError();
|
||||
error.setId(rs.getInt("id"));
|
||||
error.setUserId(rs.getObject("user_id", Integer.class));
|
||||
error.setTitle(rs.getString("title"));
|
||||
error.setCode(rs.getString("code"));
|
||||
error.setMessage(rs.getString("message"));
|
||||
error.setPinia(rs.getString("pinia"));
|
||||
error.setCalculationJobId(rs.getObject("calculation_job_id", Integer.class));
|
||||
error.setBulkOperationId(rs.getObject("bulk_operation_id", Integer.class));
|
||||
error.setType(SysErrorType.valueOf(rs.getString("type")));
|
||||
error.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SysErrorTraceItemMapper implements RowMapper<SysErrorTraceItem> {
|
||||
|
||||
@Override
|
||||
public SysErrorTraceItem mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
SysErrorTraceItem traceItem = new SysErrorTraceItem();
|
||||
traceItem.setErrorId(rs.getInt("error_id"));
|
||||
traceItem.setId(rs.getInt("id"));
|
||||
traceItem.setLine(rs.getObject("line", Integer.class));
|
||||
traceItem.setFile(rs.getString("file"));
|
||||
traceItem.setMethod(rs.getString("method"));
|
||||
traceItem.setFullPath(rs.getString("fullPath"));
|
||||
return traceItem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
package de.avatic.lcc.service.bulk;
|
||||
|
||||
import de.avatic.lcc.excelmodel.ExcelNode;
|
||||
import de.avatic.lcc.model.bulk.BulkFileTypes;
|
||||
import de.avatic.lcc.model.bulk.BulkInstruction;
|
||||
import de.avatic.lcc.model.bulk.BulkInstructionType;
|
||||
import de.avatic.lcc.model.bulk.BulkOperation;
|
||||
import de.avatic.lcc.model.nodes.Node;
|
||||
import de.avatic.lcc.repositories.NodeRepository;
|
||||
import de.avatic.lcc.service.bulk.bulkImport.NodeBulkImportService;
|
||||
import de.avatic.lcc.service.bulk.bulkImport.PackagingBulkImportService;
|
||||
|
|
@ -14,13 +10,13 @@ import de.avatic.lcc.service.transformer.generic.NodeTransformer;
|
|||
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.util.RecordFormatException;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class BulkImportService {
|
||||
|
|
@ -54,34 +50,36 @@ public class BulkImportService {
|
|||
|
||||
InputStream in = new ByteArrayInputStream(file);
|
||||
|
||||
Workbook workbook = new XSSFWorkbook(in);
|
||||
Sheet sheet = workbook.getSheet(BulkFileTypes.valueOf(type.name()).getSheetName());
|
||||
|
||||
switch (type) {
|
||||
case CONTAINER_RATE:
|
||||
var containerRates = containerRateExcelMapper.extractSheet(sheet);
|
||||
try (Workbook workbook = new XSSFWorkbook(in)) {
|
||||
Sheet sheet = workbook.getSheet(BulkFileTypes.valueOf(type.name()).getSheetName());
|
||||
|
||||
|
||||
break;
|
||||
case COUNTRY_MATRIX:
|
||||
var matrixRates = matrixRateExcelMapper.extractSheet(sheet);
|
||||
break;
|
||||
case MATERIAL:
|
||||
var materials = materialExcelMapper.extractSheet(sheet);
|
||||
break;
|
||||
case PACKAGING:
|
||||
var packaging = packagingExcelMapper.extractSheet(sheet);
|
||||
packaging.forEach(packagingBulkImportService::processPackagingInstructions);
|
||||
break;
|
||||
case NODE:
|
||||
var nodeInstructions = nodeExcelMapper.extractSheet(sheet);
|
||||
nodeInstructions.forEach(nodeBulkImportService::processNodeInstructions);
|
||||
break;
|
||||
default:
|
||||
switch (type) {
|
||||
case CONTAINER_RATE:
|
||||
var containerRates = containerRateExcelMapper.extractSheet(sheet);
|
||||
break;
|
||||
case COUNTRY_MATRIX:
|
||||
var matrixRates = matrixRateExcelMapper.extractSheet(sheet);
|
||||
break;
|
||||
case MATERIAL:
|
||||
var materials = materialExcelMapper.extractSheet(sheet);
|
||||
// materials.forEach((material) -> materialBulkImportService);
|
||||
break;
|
||||
case PACKAGING:
|
||||
var packaging = packagingExcelMapper.extractSheet(sheet);
|
||||
packaging.forEach(packagingBulkImportService::processPackagingInstructions);
|
||||
break;
|
||||
case NODE:
|
||||
var nodeInstructions = nodeExcelMapper.extractSheet(sheet);
|
||||
nodeInstructions.forEach(nodeBulkImportService::processNodeInstructions);
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
} catch (RecordFormatException e) {
|
||||
throw new ExcelValidationError("Unable to open excel file. File is too large.");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ public class BulkOperationExecutionService {
|
|||
this.sysErrorTransformer = sysErrorTransformer;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Async("bulkProcessingExecutor")
|
||||
public void launchExecution(Integer id) {
|
||||
|
||||
|
|
@ -54,12 +53,10 @@ public class BulkOperationExecutionService {
|
|||
} catch (Exception e) {
|
||||
op.setProcessState(BulkOperationState.EXCEPTION);
|
||||
|
||||
|
||||
|
||||
var error = new SysError();
|
||||
error.setType(SysErrorType.BULK);
|
||||
error.setCode(e.getClass().getSimpleName());
|
||||
error.setTitle("Bulk Operation Execution " + op.getId() + " failed");
|
||||
error.setTitle("Bulk operation execution " + op.getProcessingType() + " of " + op.getFileType() + " failed");
|
||||
error.setMessage(e.getMessage());
|
||||
error.setUserId(op.getUserId());
|
||||
error.setBulkOperationId(op.getId());
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ public class ConstraintGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected numeric value within range: " + min + " - " + max);
|
||||
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected numeric value within range: [" + min + ", " + max+ "]");
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -157,7 +157,7 @@ public class ConstraintGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected string with length within range: " + min + " - " + max);
|
||||
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected string with length within range: [" + min + ", " + max+ "]");
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +233,7 @@ public class ConstraintGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected numeric integer value within range: " + min + " - " + max);
|
||||
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected numeric integer value within range: [" + min + " , " + max + "]");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class HeaderGenerator {
|
|||
for(H header : EnumSet.allOf(headers)){
|
||||
Cell cell = row.getCell(header.ordinal());
|
||||
if(cell == null || !cell.getStringCellValue().equals(header.getHeader())){
|
||||
throw new ExcelValidationError("Unable to validate header " + header.getHeader() + ": Header of column " + toExcelLetter(header.ordinal()) + " has to be " + header.getHeader());
|
||||
throw new ExcelValidationError("Unable to validate header \"" + header.getHeader() + "\": Header of column " + toExcelLetter(header.ordinal()) + " has to be \"" + header.getHeader() + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ public class HeaderGenerator {
|
|||
for(String header : headers){
|
||||
Cell cell = row.getCell(idx++);
|
||||
if(cell == null || !cell.getStringCellValue().equals(header)){
|
||||
throw new ExcelValidationError("Unable to validate header " + header + ": Header of column " + toExcelLetter(idx) + " has to be " + header);
|
||||
throw new ExcelValidationError("Unable to validate header \"" + header + "\": Header of column " + toExcelLetter(idx) + " has to be \"" + header + "\"");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,14 +42,6 @@ public class HandlingCostCalculationService {
|
|||
var destinationDisposal = destination.getDisposalCost();
|
||||
var destinationRepacking = destination.getRepackingCost();
|
||||
|
||||
|
||||
// BigDecimal huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(hu.getContentUnitCount()),4,RoundingMode.UP);
|
||||
// double handling = Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.KLT_HANDLING).orElseThrow().getCurrentValue());
|
||||
// double release = Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.KLT_RELEASE).orElseThrow().getCurrentValue());
|
||||
// double dispatch = Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.KLT_DISPATCH).orElseThrow().getCurrentValue());
|
||||
// double wageFactor = Double.parseDouble(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.WAGE, destination.getCountryId()).orElseThrow().getCurrentValue());
|
||||
// double booking = Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.BOOKING).orElseThrow().getCurrentValue());
|
||||
|
||||
BigDecimal huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(hu.getContentUnitCount()),4, RoundingMode.UP );
|
||||
BigDecimal handling = destinationHandling != null ? destinationHandling : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_HANDLING).orElseThrow().getCurrentValue()));
|
||||
BigDecimal release = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_RELEASE).orElseThrow().getCurrentValue()));
|
||||
|
|
|
|||
|
|
@ -1,13 +1,24 @@
|
|||
package de.avatic.lcc.service.transformer.bulk;
|
||||
|
||||
import de.avatic.lcc.dto.bulk.BulkOperationDTO;
|
||||
import de.avatic.lcc.dto.bulk.BulkOperationState;
|
||||
import de.avatic.lcc.model.bulk.BulkOperation;
|
||||
import de.avatic.lcc.repositories.error.SysErrorRepository;
|
||||
import de.avatic.lcc.service.transformer.error.SysErrorTransformer;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class BulkOperationTransformer {
|
||||
|
||||
|
||||
private final SysErrorRepository sysErrorRepository;
|
||||
private final SysErrorTransformer sysErrorTransformer;
|
||||
|
||||
public BulkOperationTransformer(SysErrorRepository sysErrorRepository, SysErrorTransformer sysErrorTransformer) {
|
||||
this.sysErrorRepository = sysErrorRepository;
|
||||
this.sysErrorTransformer = sysErrorTransformer;
|
||||
}
|
||||
|
||||
public BulkOperationDTO toBulkOperationDTO(BulkOperation entity) {
|
||||
|
||||
BulkOperationDTO dto = new BulkOperationDTO();
|
||||
|
|
@ -18,6 +29,13 @@ public class BulkOperationTransformer {
|
|||
dto.setState(entity.getProcessState());
|
||||
dto.setCreatedAt(entity.getCreatedAt());
|
||||
|
||||
if (entity.getProcessState() == BulkOperationState.EXCEPTION) {
|
||||
var error = sysErrorRepository.getByBulkOperationId(entity.getId());
|
||||
|
||||
error.ifPresent(sysError -> dto.setError(sysErrorTransformer.toSysErrorDto(sysError)));
|
||||
}
|
||||
|
||||
|
||||
return dto;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -410,113 +410,132 @@ SET @packaging_28523500576 = LAST_INSERT_ID();
|
|||
-- Stackable und Rust Prevention Property Type IDs ermitteln
|
||||
SET @stackable_type_id = (SELECT id FROM packaging_property_type WHERE external_mapping_id = 'STACKABLE' LIMIT 1);
|
||||
SET @rust_prevention_type_id = (SELECT id FROM packaging_property_type WHERE external_mapping_id = 'RUST_PREVENTION' LIMIT 1);
|
||||
SET @mixable_type_id = (SELECT id FROM packaging_property_type WHERE external_mapping_id = 'MIXABLE' LIMIT 1);
|
||||
|
||||
-- Part Number: 28152640129 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_28152640129, 'true'),
|
||||
(@mixable_type_id, @packaging_28152640129, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_28152640129, 'false');
|
||||
|
||||
-- Part Number: 8222640822 - Stackable: No, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_8222640822, 'false'),
|
||||
(@mixable_type_id, @packaging_8222640822, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_8222640822, 'false');
|
||||
|
||||
-- Part Number: 3064540201 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_3064540201, 'true'),
|
||||
(@mixable_type_id, @packaging_3064540201, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_3064540201, 'false');
|
||||
|
||||
-- Part Number: 8212640113 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_8212640113, 'true'),
|
||||
(@mixable_type_id, @packaging_8212640113, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_8212640113, 'false');
|
||||
|
||||
-- Part Number: 28152643516 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_28152643516, 'true'),
|
||||
(@mixable_type_id, @packaging_28152643516, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_28152643516, 'false');
|
||||
|
||||
-- Part Number: 4222640104 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_4222640104, 'true'),
|
||||
(@mixable_type_id, @packaging_4222640104, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_4222640104, 'false');
|
||||
|
||||
-- Part Number: 28152643502 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_28152643502, 'true'),
|
||||
(@mixable_type_id, @packaging_28152643502, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_28152643502, 'false');
|
||||
|
||||
-- Part Number: 28152640804 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_28152640804, 'true'),
|
||||
(@mixable_type_id, @packaging_28152640804, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_28152640804, 'false');
|
||||
|
||||
-- Part Number: 4222640805 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_4222640805, 'true'),
|
||||
(@mixable_type_id, @packaging_4222640805, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_4222640805, 'false');
|
||||
|
||||
-- Part Number: 4222640803 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_4222640803, 'true'),
|
||||
(@mixable_type_id, @packaging_4222640803, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_4222640803, 'false');
|
||||
|
||||
-- Part Number: 8212640811 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_8212640811, 'true'),
|
||||
(@mixable_type_id, @packaging_8212640811, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_8212640811, 'false');
|
||||
|
||||
-- Part Number: 8212640827 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_8212640827, 'true'),
|
||||
(@mixable_type_id, @packaging_8212640827, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_8212640827, 'false');
|
||||
|
||||
-- Part Number: 5512640104 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_5512640104, 'true'),
|
||||
(@mixable_type_id, @packaging_5512640104, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_5512640104, 'false');
|
||||
|
||||
-- Part Number: 5512640106 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_5512640106, 'true'),
|
||||
(@mixable_type_id, @packaging_5512640106, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_5512640106, 'false');
|
||||
|
||||
-- Part Number: 8263500575 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_8263500575, 'true'),
|
||||
(@mixable_type_id, @packaging_8263500575, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_8263500575, 'false');
|
||||
|
||||
-- Part Number: 8263500576 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_8263500576, 'true'),
|
||||
(@mixable_type_id, @packaging_8263500576, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_8263500576, 'false');
|
||||
|
||||
-- Part Number: 28523500575 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_28523500575, 'true'),
|
||||
(@mixable_type_id, @packaging_28523500575, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_28523500575, 'false');
|
||||
|
||||
-- Part Number: 28523500576 - Stackable: Yes, Rust Prevention: No
|
||||
INSERT INTO packaging_property (packaging_property_type_id, packaging_id, property_value)
|
||||
VALUES
|
||||
(@stackable_type_id, @packaging_28523500576, 'true'),
|
||||
(@mixable_type_id, @packaging_28523500576, 'true'),
|
||||
(@rust_prevention_type_id, @packaging_28523500576, 'false');
|
||||
|
||||
-- ============================================
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue