reworked "my calculation" page:
- select over multiple pages - reopen completed calculations
This commit is contained in:
parent
3141e62b08
commit
20fa52826a
25 changed files with 746 additions and 303 deletions
|
|
@ -5,9 +5,11 @@
|
|||
type="checkbox"
|
||||
:checked="isChecked"
|
||||
:disabled="disabled"
|
||||
:indeterminate.prop="isIndeterminate"
|
||||
v-model="isChecked"
|
||||
ref="checkboxInput"
|
||||
>
|
||||
<span class="checkmark"></span>
|
||||
<span class="checkmark" :class="{ indeterminate: isIndeterminate }"></span>
|
||||
<span class="checkbox-label"><slot></slot></span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -26,12 +28,18 @@ export default{
|
|||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
},
|
||||
indeterminate: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
name: "Checkbox",
|
||||
data() {
|
||||
return {
|
||||
internalChecked: this.checked,
|
||||
internalIndeterminate: this.indeterminate,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -42,20 +50,36 @@ export default{
|
|||
set(value) {
|
||||
if (this.disabled) return; // Prevent changes when disabled
|
||||
this.internalChecked = value;
|
||||
this.internalIndeterminate = false;
|
||||
this.$emit('checkbox-changed', value);
|
||||
}
|
||||
},
|
||||
isIndeterminate() {
|
||||
return this.internalIndeterminate && !this.internalChecked;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
checked(newVal) {
|
||||
this.internalChecked = newVal;
|
||||
this.updateIndeterminateState(this.internalIndeterminate);
|
||||
},
|
||||
indeterminate(newVal) {
|
||||
this.internalIndeterminate = newVal;
|
||||
this.updateIndeterminateState(newVal);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateIndeterminateState(this.isIndeterminate);
|
||||
},
|
||||
methods: {
|
||||
setFilter(event) {
|
||||
if (this.disabled) return; // Prevent action when disabled
|
||||
// The computed setter will handle the emit
|
||||
if (this.disabled) return;
|
||||
this.isChecked = event.target.checked;
|
||||
},
|
||||
updateIndeterminateState(value) {
|
||||
if (this.$refs.checkboxInput) {
|
||||
this.$refs.checkboxInput.indeterminate = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -130,6 +154,16 @@ export default{
|
|||
border-color: #6b7280;
|
||||
}
|
||||
|
||||
.checkmark.indeterminate {
|
||||
background-color: #002F54;
|
||||
border-color: #002F54;
|
||||
}
|
||||
|
||||
.checkbox-item.disabled .checkmark.indeterminate {
|
||||
background-color: #6b7280;
|
||||
border-color: #6b7280;
|
||||
}
|
||||
|
||||
.checkmark::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
|
|
@ -148,10 +182,26 @@ export default{
|
|||
display: block;
|
||||
}
|
||||
|
||||
.checkmark.indeterminate::after {
|
||||
display: block;
|
||||
width: 1rem;
|
||||
height: 0;
|
||||
border-width: 0 0 0.2rem 0;
|
||||
transform: rotate(0deg);
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -0.5rem;
|
||||
margin-top: -0.1rem;
|
||||
}
|
||||
|
||||
.checkbox-item:not(.disabled):hover input:checked ~ .checkmark::after {
|
||||
border-color: #8DB3FE;
|
||||
}
|
||||
|
||||
.checkbox-item:not(.disabled):hover .checkmark.indeterminate::after {
|
||||
border-color: #8DB3FE;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
color: #002F54;
|
||||
font-size: 1.4rem;
|
||||
|
|
|
|||
|
|
@ -6,12 +6,16 @@
|
|||
|
||||
>
|
||||
<div v-if="show" class="list-edit">
|
||||
<icon-button variant="blue" icon="pencil-simple" help-text="Edit all selected calculations" @click="handleAction('edit')"></icon-button>
|
||||
<icon-button variant="blue" icon="trash" help-text="Delete all selected calculations" @click="handleAction('delete')"></icon-button>
|
||||
<icon-button variant="blue" icon="archive" help-text="Archive all selected calculations" @click="handleAction('archive')"></icon-button>
|
||||
<!-- <icon-button variant="blue" icon="pencil-simple" ></icon-button>-->
|
||||
<!-- <icon-button variant="blue" icon="trash" ></icon-button>-->
|
||||
<!-- <icon-button variant="blue" icon="archive" ></icon-button>-->
|
||||
<div class="icon-container">
|
||||
<ph-selection size="24"/>
|
||||
<span class="number-circle">{{ selectCount }}</span></div>
|
||||
|
||||
<basic-button icon="pencil-simple" @click="handleAction('edit')">Edit</basic-button>
|
||||
<basic-button icon="trash" @click="handleAction('delete')">Delete</basic-button>
|
||||
<basic-button icon="archive" @click="handleAction('archive')">Archive</basic-button>
|
||||
<basic-button icon="X" @click="handleAction('deselect')">Cancel</basic-button>
|
||||
|
||||
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
|
|
@ -19,15 +23,21 @@
|
|||
|
||||
<script>
|
||||
import IconButton from "@/components/UI/IconButton.vue";
|
||||
import {PhSelection} from "@phosphor-icons/vue";
|
||||
import BasicButton from "@/components/UI/BasicButton.vue";
|
||||
|
||||
export default {
|
||||
name: "ListEdit",
|
||||
components: {IconButton},
|
||||
components: {BasicButton, PhSelection, IconButton},
|
||||
emits: ['action'],
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
selectCount: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -45,21 +55,49 @@ export default{
|
|||
bottom: 2rem;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
z-index: 9999;
|
||||
z-index: 4000;
|
||||
}
|
||||
|
||||
.list-edit {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
gap: 1.2rem;
|
||||
background-color: #5AF0B4;
|
||||
border-radius: 0.8rem;
|
||||
flex: 0 0 auto;
|
||||
padding: 0.8rem 1.6rem;
|
||||
box-shadow: 0 0.4rem 0.6rem -0.1rem rgba(0, 0, 0, 0.1);
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.list-edit-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.2rem;
|
||||
}
|
||||
|
||||
.number-circle {
|
||||
position: relative;
|
||||
top: 0.8rem;
|
||||
left: -1.2rem;
|
||||
display: inline-block;
|
||||
|
||||
border-radius: 50%;
|
||||
/*background-color: #002F54;
|
||||
color: white;*/
|
||||
color: #002F54;
|
||||
text-align: center;
|
||||
line-height: 1.6rem;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.2rem;
|
||||
}
|
||||
|
||||
|
||||
/* Transition animations */
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
<div class="list-edit-button" @click="handleAction('material')">Material</div>
|
||||
<div class="list-edit-button" @click="handleAction('price')">Price</div>
|
||||
<div class="list-edit-button" @click="handleAction('packaging')">Packaging</div>
|
||||
<div class="list-edit-button" @click="handleAction('supplier')">Supplier</div>
|
||||
<div class="list-edit-button" @click="handleAction('destinations')">Destinations & Routes</div>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<div class="modal-dialog-title sub-header">{{ title }}</div>
|
||||
<div class="modal-dialog-message">{{ message }}</div>
|
||||
<div class="modal-dialog-actions">
|
||||
<basic-button :show-icon="false" @click="action('accept')">{{ acceptText }}</basic-button>
|
||||
<basic-button :show-icon="false" @click="action('accept')" v-if="acceptText!=null">{{ acceptText }}</basic-button>
|
||||
<basic-button :show-icon="false" @click="action('deny')" v-if="denyText!=null">{{ denyText }}</basic-button>
|
||||
<basic-button :show-icon="false" @click="action('dismiss')" variant="secondary">{{ dismissText }}</basic-button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -142,8 +142,8 @@ export default {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin: 20px 0;
|
||||
gap: 0.8rem;
|
||||
margin: 2.4rem 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
|
|
@ -151,9 +151,9 @@ export default {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
padding: 8px 12px;
|
||||
border: 0.2rem solid #E3EDFF;
|
||||
gap: 0.4rem;
|
||||
padding: 0.8rem 1.6rem;
|
||||
border: 0 solid rgba(107, 134, 156, 0.1);
|
||||
background: transparent;
|
||||
color: #002F54;
|
||||
cursor: pointer;
|
||||
|
|
@ -161,24 +161,22 @@ export default {
|
|||
font-size: 1.4rem;
|
||||
font-family: inherit;
|
||||
transition: all 0.2s ease;
|
||||
min-width: 40px;
|
||||
min-width: 4rem;
|
||||
}
|
||||
|
||||
.pagination-btn:hover:not(:disabled) {
|
||||
background: #EEF4FF;
|
||||
border-color: #8DB3FE;
|
||||
transform: scale(1.01);
|
||||
background: rgba(107, 134, 156, 0.1);
|
||||
}
|
||||
|
||||
.pagination-btn:disabled {
|
||||
background: rgba(238, 244, 255, 0.2);
|
||||
|
||||
border-color: rgba(141, 179, 254, 0.2);
|
||||
color: rgba(0, 47, 84, 0.2);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.pagination-btn.active {
|
||||
background: #EEF4FF;
|
||||
background: #5AF0B4;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -187,9 +185,9 @@ export default {
|
|||
}
|
||||
|
||||
.ellipsis {
|
||||
padding: 8px 4px;
|
||||
padding: 0.8rem 0.4rem;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.page-info {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@
|
|||
<div class="edit-calculation-checkbox-cell">
|
||||
<checkbox :checked="isSelected" @checkbox-changed="updateSelected"></checkbox>
|
||||
</div>
|
||||
<div class="edit-calculation-cell--material copyable-cell"
|
||||
@click="action('material')">
|
||||
|
||||
|
||||
<div class="edit-calculation-cell-container">
|
||||
<div class="edit-calculation-cell copyable-cell" @click="action('material')">
|
||||
<div class="edit-calculation-cell-line">{{ premise.material.part_number }}</div>
|
||||
<!-- <div class="edit-calculation-cell-line edit-calculation-cell-subline" v-if="premise.material.name">-->
|
||||
<!-- {{ premise.material.name }}-->
|
||||
<!-- </div>-->
|
||||
<div class="edit-calculation-cell-line edit-calculation-cell-subline" v-if="premise.hs_code">
|
||||
HS Code:
|
||||
{{ premise.material.hs_code }}
|
||||
|
|
@ -19,8 +18,11 @@
|
|||
{{ toPercent(premise.tariff_rate) }} %
|
||||
</div>
|
||||
</div>
|
||||
<div class="edit-calculation-cell--price copyable-cell" v-if="showPrice"
|
||||
@click="action('price')">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="edit-calculation-cell-container">
|
||||
<div class="edit-calculation-cell copyable-cell" @click="action('price')" v-if="showPrice">
|
||||
<div class="edit-calculation-cell-line">{{ toFixed(premise.material_cost) }} EUR</div>
|
||||
<div class="edit-calculation-cell-line edit-calculation-cell-subline">Oversea share:
|
||||
{{ toPercent(premise.oversea_share) }} %
|
||||
|
|
@ -35,7 +37,11 @@
|
|||
<div class="edit-calculation-empty copyable-cell" v-else @click="action('price')">
|
||||
<basic-badge variant="exception" icon="warning">INCOMPLETE</basic-badge>
|
||||
</div>
|
||||
<div v-if="showHu" class="edit-calculation-cell edit-calculation-cell--packaging copyable-cell"
|
||||
</div>
|
||||
|
||||
|
||||
<div class="edit-calculation-cell-container">
|
||||
<div v-if="showHu" class="edit-calculation-cell copyable-cell"
|
||||
@click="action('packaging')">
|
||||
<div class="edit-calculation-cell-line">
|
||||
<PhVectorThree/>
|
||||
|
|
@ -60,19 +66,23 @@
|
|||
@click="action('packaging')">
|
||||
<basic-badge variant="exception" icon="warning">INCOMPLETE</basic-badge>
|
||||
</div>
|
||||
<div class="edit-calculation-cell--supplier copyable-cell"
|
||||
@click="action('supplier')">
|
||||
<div class="edit-calculation-cell--supplier-container" v-if="premise.supplier">
|
||||
<!-- <div class="edit-calculation-cell--supplier-flag">-->
|
||||
<!-- <flag :iso="premise.supplier.country.iso_code" size="m"></flag>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="edit-calculation-cell-container">
|
||||
<div class="edit-calculation-cell" v-if="premise.supplier">
|
||||
<div class="calculation-list-supplier-data">
|
||||
<div class="edit-calculation-cell-line">{{ premise.supplier.name }}</div>
|
||||
<div class="edit-calculation-cell-subline"> {{ premise.supplier.address }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="edit-calculation-cell--destination copyable-cell" v-if="showDestinations"
|
||||
|
||||
|
||||
<div class="edit-calculation-cell-container">
|
||||
<div class="edit-calculation-cell copyable-cell" v-if="showDestinations"
|
||||
@click="action('destinations')">
|
||||
<div class="edit-calculation-cell-line">
|
||||
<span class="number-circle"> {{ destinationsCount }} </span> Destinations
|
||||
|
|
@ -89,6 +99,9 @@
|
|||
@click="action('destinations')">
|
||||
<basic-badge variant="exception" icon="warning">INCOMPLETE</basic-badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="edit-calculation-actions-cell">
|
||||
<icon-button icon="pencil-simple" help-text="Edit this calculation" help-text-position="left"
|
||||
|
|
@ -150,9 +163,9 @@ export default {
|
|||
return this.premise.destinations.map(d => d.destination_node.name).join(', ');
|
||||
},
|
||||
destinationNames() {
|
||||
const spliceCnt = ((this.premise.destinations.length === 4) ? 4 : 3) - this.showDestinationIncomplete;
|
||||
const spliceCnt = ((this.premise.destinations.length === 4) ? 4 : 3) - (this.showDestinationIncomplete ? 1 : 0);
|
||||
const names = this.premise.destinations.map(d => d.destination_node.name).slice(0, spliceCnt);
|
||||
if (this.premise.destinations.length > 4) {
|
||||
if (this.premise.destinations.length > names.length) {
|
||||
names.push('and more ...');
|
||||
}
|
||||
|
||||
|
|
@ -216,18 +229,33 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
|
||||
.edit-calculation-cell-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: stretch;
|
||||
justify-self: stretch;
|
||||
}
|
||||
|
||||
.edit-calculation-cell {
|
||||
flex: 1 1 auto;
|
||||
margin: 1.6rem 0;
|
||||
}
|
||||
|
||||
.edit-calculation-empty {
|
||||
flex: 1 1 auto;
|
||||
margin: 1.6rem 0;
|
||||
}
|
||||
|
||||
.copyable-cell {
|
||||
padding: 0.8rem;
|
||||
border-radius: 0.8rem;
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
/* Standard hover ohne copy mode */
|
||||
.copyable-cell:hover {
|
||||
cursor: pointer;
|
||||
background-color: rgba(107, 134, 156, 0.05);
|
||||
background-color: #f8fafc;
|
||||
border-radius: 0.8rem;
|
||||
box-shadow: 0 0.4rem 0.6rem -0.1rem rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.bulk-edit-row {
|
||||
|
|
@ -254,31 +282,6 @@ export default {
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
.edit-calculation-cell {
|
||||
padding: 0.8rem;
|
||||
border-radius: 0.8rem;
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.edit-calculation-cell:hover {
|
||||
cursor: pointer;
|
||||
background-color: rgba(107, 134, 156, 0.05);
|
||||
border-radius: 0.8rem;
|
||||
box-shadow: 0 0.4rem 0.6rem -0.1rem rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.edit-calculation-cell--copy-mode {
|
||||
padding: 0.8rem;
|
||||
border-radius: 0.8rem;
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.edit-calculation-cell--copy-mode:hover {
|
||||
cursor: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOCIgaGVpZ2h0PSIyOCIgdmlld0JveD0iMCAwIDI1NiAyNTYiPgogIDxyZWN0IHg9Ijg0IiB5PSIzMiIgd2lkdGg9IjEzNiIgaGVpZ2h0PSIxMzYiIGZpbGw9IndoaXRlIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iOCIgcng9IjQiLz4KICA8cmVjdCB4PSIzNiIgeT0iODQiIHdpZHRoPSIxMzYiIGhlaWdodD0iMTM2IiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjgiIHJ4PSI0Ii8+Cjwvc3ZnPg==") 12 12, pointer;
|
||||
background-color: rgba(107, 134, 156, 0.05);
|
||||
border-radius: 0.8rem;
|
||||
box-shadow: 0 0.4rem 0.6rem -0.1rem rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.edit-calculation-cell--price {
|
||||
display: flex;
|
||||
|
|
@ -289,11 +292,11 @@ export default {
|
|||
.edit-calculation-cell--supplier {
|
||||
display: flex;
|
||||
gap: 1.2rem;
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.edit-calculation-cell--supplier-container {
|
||||
display: flex;
|
||||
height: fit-content;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
|
|
@ -325,15 +328,7 @@ export default {
|
|||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.edit-calculation-empty {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 400;
|
||||
color: #6b7280;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
|
||||
.edit-calculation-actions-cell {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import {UrlSafeBase64} from "@/common.js";
|
|||
export default {
|
||||
name: "CalculationListItem",
|
||||
components: {Flag, Checkbox, BasicBadge, IconButton},
|
||||
emits: ['updateCheckbox', 'updatePagination'],
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
|
|
@ -95,7 +96,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
updateCheckBox(checked) {
|
||||
this.premise.checked = checked;
|
||||
this.$emit('updateCheckbox', {checked: checked, id: this.id});
|
||||
},
|
||||
editClick() {
|
||||
if(this.premise.state === 'DRAFT') {
|
||||
|
|
@ -106,11 +107,13 @@ export default {
|
|||
deleteClick() {
|
||||
if(this.premise.state === 'DRAFT') {
|
||||
this.premiseStore.deletePremisses([this.id])
|
||||
this.$emit('updatePagination');
|
||||
}
|
||||
},
|
||||
archiveClick() {
|
||||
if(this.premise.state !== 'DRAFT' && this.premise.state !== 'ARCHIVED') {
|
||||
this.premiseStore.archivePremisses([this.id])
|
||||
this.$emit('updatePagination');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -123,7 +126,7 @@ export default {
|
|||
display: grid;
|
||||
grid-template-columns: 6rem 1fr 2fr 14rem 10rem;
|
||||
gap: 1.6rem;
|
||||
padding: 2.4rem;
|
||||
padding: 1.6rem;
|
||||
border-bottom: 0.16rem solid #f3f4f6;
|
||||
align-items: center;
|
||||
transition: background-color 0.2s ease;
|
||||
|
|
@ -179,6 +182,7 @@ export default {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
height: 90%
|
||||
}
|
||||
|
||||
.supplier-name {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@
|
|||
autocomplete="off"
|
||||
>
|
||||
</div>
|
||||
<checkbox :checked="archived" @checkbox-changed="setArchived">archived</checkbox>
|
||||
<checkbox :checked="draft" @checkbox-changed="setDraft">draft</checkbox>
|
||||
<checkbox :checked="done" @checkbox-changed="setDone">completed</checkbox>
|
||||
<checkbox :checked="archived" @checkbox-changed="setArchived">archived</checkbox>
|
||||
<basic-button variant="primary" :showIcon="true" icon="plus" :link="true" to="assistant">New calculation</basic-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -33,6 +34,7 @@ export default {
|
|||
searchTerm: null,
|
||||
archived: false,
|
||||
done: false,
|
||||
draft: true,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
|
@ -46,6 +48,7 @@ export default {
|
|||
searchTerm: this.searchTerm,
|
||||
archived: this.archived,
|
||||
done: this.done,
|
||||
draft: this.draft,
|
||||
}
|
||||
|
||||
this.debouncedSearch(searchQuery);
|
||||
|
|
@ -60,6 +63,10 @@ export default {
|
|||
setDone(value) {
|
||||
this.done = value;
|
||||
this.updateQuery();
|
||||
},
|
||||
setDraft(value) {
|
||||
this.draft = value;
|
||||
this.updateQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
<modal :state="modalSelectMaterial" @close="closeEditModal">
|
||||
<select-material :part-number="partNumber" @close="modalEditClick"/>
|
||||
</modal>
|
||||
<!-- <icon-button icon="pencil-simple" @click="activateEditMode"></icon-button>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -69,7 +68,7 @@ export default {
|
|||
emits: ["update:tariffRate", "updateMaterial", "update:partNumber", "update:hsCode", "save", "close"],
|
||||
props: {
|
||||
description: {
|
||||
type: String,
|
||||
type: [String, null],
|
||||
required: true,
|
||||
},
|
||||
hsCode: {
|
||||
|
|
|
|||
|
|
@ -55,8 +55,9 @@ export default {
|
|||
validator: (value) => value === null || typeof value === 'number',
|
||||
},
|
||||
includeFcaFee: {
|
||||
type: Boolean,
|
||||
type: [Boolean, null],
|
||||
required: true,
|
||||
|
||||
},
|
||||
responsive: {
|
||||
type: Boolean,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import AutosuggestSearchbar from "@/components/UI/AutoSuggestSearchBar.vue";
|
|||
import {mapStores} from "pinia";
|
||||
import {useNodeStore} from "@/store/node.js";
|
||||
import Checkbox from "@/components/UI/Checkbox.vue";
|
||||
import logger from "@/logger.js";
|
||||
|
||||
export default {
|
||||
name: "SelectNode",
|
||||
|
|
@ -65,7 +66,7 @@ export default {
|
|||
},
|
||||
},
|
||||
created() {
|
||||
console.log("SelectNode created with openSelectDirect: " + this.openSelectDirect, this.preSelectedNode);
|
||||
logger.info("SelectNode created with openSelectDirect: " + this.openSelectDirect, this.preSelectedNode);
|
||||
if(this.openSelectDirect) {
|
||||
this.node = this.preSelectedNode;
|
||||
|
||||
|
|
@ -79,7 +80,7 @@ export default {
|
|||
this.updateMasterData = value;
|
||||
},
|
||||
async fetchSupplier(query) {
|
||||
console.log("Fetching supplier for query: " + query);
|
||||
logger.info("Fetching supplier for query: " + query);
|
||||
await this.nodeStore.setSearch({searchTerm: query, nodeType: 'SOURCE', includeUserNode: true});
|
||||
return this.nodeStore.nodes;
|
||||
},
|
||||
|
|
@ -87,7 +88,7 @@ export default {
|
|||
return node.country.iso_code;
|
||||
},
|
||||
selected(node) {
|
||||
console.log("Selected node: ", node);
|
||||
logger.info("Selected node: ", node);
|
||||
this.$refs.searchbar.clearSuggestions();
|
||||
this.node = node;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -84,11 +84,7 @@
|
|||
v-model:unitCount="componentProps.unitCount"
|
||||
v-model:mixable="componentProps.mixable"
|
||||
v-model:stackable="componentProps.stackable"
|
||||
v-model:preSelectedNode="componentProps.preSelectedNode"
|
||||
v-model:openSelectDirect="componentProps.openSelectDirect"
|
||||
:responsive="false"
|
||||
@update-material="updateMaterial"
|
||||
@update-supplier="updateSupplier"
|
||||
@close="closeEditModalAction('cancel')"
|
||||
|
||||
>
|
||||
|
|
@ -123,6 +119,7 @@ import PackagingEdit from "@/components/layout/edit/PackagingEdit.vue";
|
|||
import DestinationListView from "@/components/layout/edit/DestinationListView.vue";
|
||||
import SelectNode from "@/components/layout/node/SelectNode.vue";
|
||||
import Toast from "@/components/UI/Toast.vue";
|
||||
import logger from "@/logger.js";
|
||||
|
||||
|
||||
const COMPONENT_TYPES = {
|
||||
|
|
@ -196,7 +193,7 @@ export default {
|
|||
modalType: null,
|
||||
componentsData: {
|
||||
price: {props: {price: 0, overSeaShare: 0, includeFcaFee: false}},
|
||||
material: {props: {partNumber: "", hsCode: "", tariffRate: 0.00, description: "", openSelectDirect: true}},
|
||||
material: {props: {partNumber: "", hsCode: "", tariffRate: 0.00, description: "", openSelectDirect: false}},
|
||||
packaging: {
|
||||
props: {
|
||||
length: 0,
|
||||
|
|
@ -210,12 +207,6 @@ export default {
|
|||
stackable: true
|
||||
}
|
||||
},
|
||||
supplier: {
|
||||
props: {
|
||||
preSelectedNode: null,
|
||||
openSelectDirect: false
|
||||
}
|
||||
},
|
||||
destinations: {props: {}},
|
||||
},
|
||||
editIds: null,
|
||||
|
|
@ -244,24 +235,6 @@ export default {
|
|||
closeMassEdit() {
|
||||
this.$router.push({name: "calculation-list"});
|
||||
},
|
||||
async updateSupplier(data) {
|
||||
console.log("update supplier", data.nodeId, data.action, data.updateMasterData, this.editIds);
|
||||
console.log("update supplier", data.nodeId, data.action, data.updateMasterData, this.editIds);
|
||||
this.modalType = null;
|
||||
if (data.action === 'accept') {
|
||||
await this.premiseEditStore.setSupplier(data.nodeId, data.updateMasterData, this.editIds);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
async updateMaterial(id, action) {
|
||||
console.log(id, action, this.editIds);
|
||||
await this.premiseEditStore.setMaterial(id, action === 'updateMasterData', this.editIds);
|
||||
|
||||
if (this.editIds[0] !== null) {
|
||||
this.fillData("material", this.editIds[0]);
|
||||
}
|
||||
},
|
||||
updateCheckBoxes(value) {
|
||||
this.premiseEditStore.setAll(value);
|
||||
},
|
||||
|
|
@ -284,7 +257,7 @@ export default {
|
|||
this.editIds = ids;
|
||||
this.modalType = type;
|
||||
|
||||
console.log("open modal", massEdit, this.modalType, this.editIds, this.dataSourceId)
|
||||
logger.info("open modal", massEdit, this.modalType, this.editIds, this.dataSourceId)
|
||||
|
||||
},
|
||||
async closeEditModalAction(action) {
|
||||
|
|
@ -319,27 +292,21 @@ export default {
|
|||
if (id === -1) {
|
||||
// clear
|
||||
this.componentsData = {
|
||||
price: {props: {price: 0, overSeaShare: 0.0, includeFcaFee: false}},
|
||||
material: {props: {partNumber: "", hsCode: "", tariffRate: 0.00, description: "", openSelectDirect: true}},
|
||||
price: {props: {price: null, overSeaShare: null, includeFcaFee: null}},
|
||||
material: {props: {partNumber: "", hsCode: "", tariffRate: null, description: null, openSelectDirect: true}},
|
||||
packaging: {
|
||||
props: {
|
||||
length: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
weight: 0,
|
||||
length: null,
|
||||
width: null,
|
||||
height: null,
|
||||
weight: null,
|
||||
weightUnit: "KG",
|
||||
dimensionUnit: "MM",
|
||||
unitCount: 1,
|
||||
unitCount: null,
|
||||
mixable: true,
|
||||
stackable: true
|
||||
}
|
||||
},
|
||||
supplier: {
|
||||
props: {
|
||||
preSelectedNode: null,
|
||||
openSelectDirect: false
|
||||
}
|
||||
},
|
||||
destinations: {props: {}},
|
||||
};
|
||||
} else {
|
||||
|
|
@ -389,11 +356,11 @@ export default {
|
|||
/* Global style für copy-mode cursor */
|
||||
.edit-calculation-container.has-selection :deep(.copyable-cell:hover) {
|
||||
cursor: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOCIgaGVpZ2h0PSIyOCIgdmlld0JveD0iMCAwIDI1NiAyNTYiPgogIDxyZWN0IHg9Ijg0IiB5PSIzMiIgd2lkdGg9IjEzNiIgaGVpZ2h0PSIxMzYiIGZpbGw9IndoaXRlIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iOCIgcng9IjQiLz4KICA8cmVjdCB4PSIzNiIgeT0iODQiIHdpZHRoPSIxMzYiIGhlaWdodD0iMTM2IiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjgiIHJ4PSI0Ii8+Cjwvc3ZnPg==") 12 12, pointer;
|
||||
background-color: rgba(107, 134, 156, 0.05);
|
||||
background-color: #f8fafc;
|
||||
border-radius: 0.8rem;
|
||||
box-shadow: 0 0.4rem 0.6rem -0.1rem rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
|
||||
.space-around {
|
||||
margin: 3rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@
|
|||
|
||||
<div class="calculation-list-container">
|
||||
|
||||
<the-calculation-search @execute-search="executeSearch"/>
|
||||
<the-calculation-search @execute-search="updateFilter"/>
|
||||
|
||||
<!-- Header -->
|
||||
<div class="calculation-list-header">
|
||||
<div>
|
||||
<checkbox @checkbox-changed="updateCheckBoxes" :checked="overallCheck"></checkbox>
|
||||
<checkbox @checkbox-changed="updateCheckBoxes" :checked="overallCheck"
|
||||
:indeterminate="overallIndeterminate"></checkbox>
|
||||
</div>
|
||||
<div>Material</div>
|
||||
<div>Supplier</div>
|
||||
|
|
@ -21,7 +22,9 @@
|
|||
<transition name="list-container" mode="out-in">
|
||||
<div v-if="premiseStore.showData">
|
||||
<calculation-list-item v-for="premise in premiseStore.premises" :key="premise.id" :id="premise.id"
|
||||
:checked="premise.checked"></calculation-list-item>
|
||||
:checked="premiseStore.isChecked(premise.id)"
|
||||
@update-checkbox="updateCheckbox"
|
||||
@update-pagination="updatePagination"></calculation-list-item>
|
||||
</div>
|
||||
<div v-else-if="premiseStore.showEmpty" class="empty-container">
|
||||
<span class="space-around">No Calculations found.</span>
|
||||
|
|
@ -31,10 +34,15 @@
|
|||
<spinner class="space-around"></spinner>
|
||||
</div>
|
||||
</transition>
|
||||
<pagination :page="pagination.page" :page-count="pagination.pageCount"
|
||||
:total-count="pagination.totalCount" @page-change="updatePage"></pagination>
|
||||
</div>
|
||||
|
||||
|
||||
<list-edit :show="showListEdit" @action="handleMultiselectAction"></list-edit>
|
||||
<modal-dialog :title="modal.title" :state="modal.state" :message="modal.message" :accept-text="modal.acceptText"
|
||||
:deny-text="modal.denyText" :dismiss-text="modal.dismissText"
|
||||
@click="handleModalAction"></modal-dialog>
|
||||
<list-edit :show="showListEdit" :select-count="premiseStore.selectedIds.length"
|
||||
@action="handleMultiselectAction"></list-edit>
|
||||
|
||||
|
||||
</div>
|
||||
|
|
@ -57,10 +65,15 @@ import {mapStores} from "pinia";
|
|||
import Spinner from "@/components/UI/Spinner.vue";
|
||||
import ListEdit from "@/components/UI/ListEdit.vue";
|
||||
import {UrlSafeBase64} from "@/common.js";
|
||||
import Pagination from "@/components/UI/Pagination.vue";
|
||||
import ModalDialog from "@/components/UI/ModalDialog.vue";
|
||||
import modal from "@/components/UI/Modal.vue";
|
||||
|
||||
export default {
|
||||
name: "Calculation",
|
||||
components: {
|
||||
ModalDialog,
|
||||
Pagination,
|
||||
ListEdit,
|
||||
Spinner,
|
||||
CalculationListItem, Checkbox, NotificationBar, IconButton, BasicBadge, TheCalculationSearch, Flag
|
||||
|
|
@ -68,59 +81,210 @@ export default {
|
|||
computed: {
|
||||
...mapStores(usePremiseStore),
|
||||
showListEdit() {
|
||||
return usePremiseStore().premises.some(p => p.checked === true);
|
||||
return this.premiseStore.globallySomeChecked;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
overallCheck: false
|
||||
selectedStatus: null,
|
||||
modal: {
|
||||
title: "",
|
||||
message: "",
|
||||
acceptText: "OK",
|
||||
denyText: null,
|
||||
dismissText: "Cancel",
|
||||
state: false,
|
||||
action: "",
|
||||
},
|
||||
overallCheck: false,
|
||||
overallIndeterminate: false,
|
||||
pagination: {
|
||||
page: 1,
|
||||
pageCount: 1,
|
||||
totalCount: 0
|
||||
},
|
||||
query: {
|
||||
searchTerm: null,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
archived: false,
|
||||
done: false,
|
||||
draft: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.premiseStore.setQuery({});
|
||||
async created() {
|
||||
this.premiseStore.resetSelectedIds();
|
||||
await this.executeSearch();
|
||||
},
|
||||
methods: {
|
||||
handleMultiselectAction(action) {
|
||||
const selectedPremisses = this.premiseStore.premises.filter(p => p.checked === true);
|
||||
if (action === "delete") {
|
||||
|
||||
const ids = selectedPremisses.filter(p => p.state === "DRAFT").map(p => p.id)
|
||||
|
||||
if (ids.length !== 0) {
|
||||
this.premiseStore.deletePremisses(ids);
|
||||
async handleModalAction(action) {
|
||||
if (action === 'dismiss') {
|
||||
this.modal.state = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'accept' && this.modal.action === "delete") {
|
||||
await this.executeMultiselectAction(this.modal.action, this.selectedStatus.draft)
|
||||
}
|
||||
|
||||
if (action === 'accept' && this.modal.action === "archive") {
|
||||
await this.executeMultiselectAction(this.modal.action, this.selectedStatus.completed)
|
||||
}
|
||||
|
||||
if (this.modal.action === "edit") {
|
||||
if (action === 'deny')
|
||||
await this.executeMultiselectAction(this.modal.action, this.selectedStatus.draft);
|
||||
else {
|
||||
const ids = await this.premiseStore.createDrafts([...this.selectedStatus.archived, ...this.selectedStatus.completed]);
|
||||
await this.executeMultiselectAction(this.modal.action, [...this.selectedStatus.draft, ...ids]);
|
||||
}
|
||||
}
|
||||
|
||||
this.modal.state = false;
|
||||
},
|
||||
async executeMultiselectAction(action, ids) {
|
||||
if (action === "delete") {
|
||||
if (ids.length !== 0) {
|
||||
await this.premiseStore.deletePremisses(ids);
|
||||
this.premiseStore.resetSelectedIds();
|
||||
this.updateOverallCheckBox();
|
||||
this.updatePagination();
|
||||
}
|
||||
} else if (action === "edit") {
|
||||
|
||||
const ids = selectedPremisses.filter(p => p.state === "DRAFT").map(p => p.id)
|
||||
|
||||
if (ids.length === 1) {
|
||||
this.$router.push({name: "edit", params: {id: new UrlSafeBase64().encodeIds([ids[0]])}});
|
||||
} else if (ids.length !== 0) {
|
||||
this.$router.push({name: "bulk", params: {ids: new UrlSafeBase64().encodeIds(ids)}});
|
||||
}
|
||||
} else if (action === "archive") {
|
||||
if (ids.length !== 0) {
|
||||
await this.premiseStore.archivePremisses(ids);
|
||||
this.premiseStore.resetSelectedIds();
|
||||
this.updateOverallCheckBox();
|
||||
this.updatePagination();
|
||||
}
|
||||
}
|
||||
},
|
||||
async handleMultiselectAction(action) {
|
||||
this.selectedStatus = await this.premiseStore.resolveStatus();
|
||||
|
||||
console.log("status: ", this.selectedStatus)
|
||||
|
||||
if (action === "delete") {
|
||||
|
||||
if (0 === this.selectedStatus.draft.length) {
|
||||
this.modal.title = "Unable to delete calculations";
|
||||
this.modal.message = `All of the ${this.premiseStore.selectedIds.length} selected calculations are already completed or archived and can no longer be deleted.`;
|
||||
this.modal.action = "delete";
|
||||
this.modal.state = true;
|
||||
this.modal.acceptText = null;
|
||||
this.modal.denyText = null;
|
||||
this.modal.dismissText = "OK";
|
||||
} else if (0 < (this.selectedStatus.completed.length + this.selectedStatus.archived.length)) {
|
||||
this.modal.title = "Delete calculations";
|
||||
this.modal.message = `${(this.selectedStatus.completed.length + this.selectedStatus.archived.length)} of the ${this.premiseStore.selectedIds.length} selected calculations are already completed or archived and can no longer be deleted. Do you still want to delete the remaining ${this.selectedStatus.draft.length} calculations?`;
|
||||
this.modal.action = "delete";
|
||||
this.modal.state = true;
|
||||
this.modal.acceptText = "Delete";
|
||||
this.modal.denyText = null;
|
||||
this.modal.dismissText = "Cancel";
|
||||
} else
|
||||
this.executeMultiselectAction(action, this.selectedStatus.draft);
|
||||
|
||||
|
||||
} else if (action === "edit") {
|
||||
|
||||
if (0 === this.selectedStatus.draft.length) {
|
||||
this.modal.title = "Edit calculations";
|
||||
this.modal.message = `All of the ${this.premiseStore.selectedIds.length} selected calculations are already completed or archived and can no longer be edited. Would you like to create new drafts based on the data from the existing calculations, or continue the operation without these calculations?`;
|
||||
this.modal.action = "edit";
|
||||
this.modal.state = true;
|
||||
this.modal.acceptText = "Create new drafts & edit";
|
||||
this.modal.denyText = null;
|
||||
this.modal.dismissText = "Cancel";
|
||||
} else if (0 < (this.selectedStatus.completed.length + this.selectedStatus.archived.length)) {
|
||||
this.modal.title = "Edit calculations";
|
||||
this.modal.message = `${(this.selectedStatus.completed.length + this.selectedStatus.archived.length)} of the ${this.premiseStore.selectedIds.length} selected calculations are already completed or archived and can no longer be edited. Would you like to create new drafts based on the data from the existing calculations, or continue the operation without these calculations?`;
|
||||
this.modal.action = "edit";
|
||||
this.modal.state = true;
|
||||
this.modal.acceptText = "Create new drafts & edit";
|
||||
this.modal.denyText = "Edit drafts only";
|
||||
this.modal.dismissText = "Cancel";
|
||||
} else
|
||||
this.executeMultiselectAction(action, this.selectedStatus.draft);
|
||||
|
||||
} else if (action === "archive") {
|
||||
|
||||
const ids = selectedPremisses.filter(p => p.state !== "DRAFT" && p.state !== "ARCHIVED").map(p => p.id)
|
||||
|
||||
if (ids.length !== 0) {
|
||||
this.premiseStore.archivePremisses(ids);
|
||||
}
|
||||
|
||||
if (0 === this.selectedStatus.completed.length) {
|
||||
this.modal.title = "Unable to archive calculations";
|
||||
this.modal.message = `All of the ${this.premiseStore.selectedIds.length} selected calculations are in draft status or already archived and cannot be archived.`;
|
||||
this.modal.action = "archive";
|
||||
this.modal.state = true;
|
||||
this.modal.acceptText = null;
|
||||
this.modal.denyText = null;
|
||||
this.modal.dismissText = "OK";
|
||||
} else if (0 < (this.selectedStatus.draft.length + this.selectedStatus.archived.length)) {
|
||||
this.modal.title = "Archive calculations";
|
||||
this.modal.message = `${(this.selectedStatus.draft.length + this.selectedStatus.archived.length)} of the ${this.premiseStore.selectedIds.length} selected calculations are in draft status or already archived and cannot be archived. Do you still want to archive the remaining ${this.selectedStatus.completed.length} calculations?`;
|
||||
this.modal.action = "archive";
|
||||
this.modal.state = true;
|
||||
this.modal.acceptText = "Archive";
|
||||
this.modal.denyText = null;
|
||||
this.modal.dismissText = "Cancel";
|
||||
} else
|
||||
this.executeMultiselectAction(action, this.selectedStatus.completed);
|
||||
|
||||
} else if (action === "deselect") {
|
||||
this.selectedStatus = null;
|
||||
this.premiseStore.resetSelectedIds();
|
||||
this.updateOverallCheckBox();
|
||||
}
|
||||
},
|
||||
updatePagination() {
|
||||
this.pagination = this.premiseStore.pagination;
|
||||
},
|
||||
updateCheckbox(data) {
|
||||
this.premiseStore.setChecked(data.id, data.checked);
|
||||
this.updateOverallCheckBox();
|
||||
},
|
||||
updateCheckBoxes(checked) {
|
||||
this.overallCheck = checked;
|
||||
this.premiseStore.premises.forEach(p => {
|
||||
p.checked = checked;
|
||||
this.premiseStore.setChecked(p.id, checked);
|
||||
})
|
||||
this.updateOverallCheckBox();
|
||||
},
|
||||
executeSearch(query) {
|
||||
this.overallCheck = false;
|
||||
this.premiseStore.setQuery(query);
|
||||
updateOverallCheckBox() {
|
||||
this.overallCheck = this.premiseStore.allChecked;
|
||||
|
||||
if (!this.overallCheck)
|
||||
this.overallIndeterminate = this.premiseStore.someChecked;
|
||||
},
|
||||
async updatePage(page) {
|
||||
this.query.page = page;
|
||||
await this.executeSearch();
|
||||
},
|
||||
async updateFilter(query) {
|
||||
|
||||
if (this.query.archived !== query.archived ||
|
||||
this.query.done !== query.done ||
|
||||
this.query.draft !== query.draft ||
|
||||
this.query.searchTerm !== query.searchTerm) {
|
||||
this.query.page = 1;
|
||||
}
|
||||
|
||||
this.query.searchTerm = query.searchTerm;
|
||||
this.query.archived = query.archived;
|
||||
this.query.done = query.done;
|
||||
this.query.draft = query.draft;
|
||||
|
||||
await this.executeSearch();
|
||||
},
|
||||
async executeSearch() {
|
||||
|
||||
await this.premiseStore.setQuery(this.query);
|
||||
this.updatePagination();
|
||||
this.updateOverallCheckBox();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -209,7 +373,7 @@ export default {
|
|||
display: grid;
|
||||
grid-template-columns: 6rem 1fr 2fr 14rem 10rem;
|
||||
gap: 1.6rem;
|
||||
padding: 2.4rem;
|
||||
padding: 1.6rem;
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid rgba(107, 134, 156, 0.2);
|
||||
font-weight: 500;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ import {defineStore} from 'pinia'
|
|||
import {config} from '@/config'
|
||||
import {useErrorStore} from "@/store/error.js";
|
||||
import performRequest from "@/backend.js";
|
||||
import logger from "@/logger.js";
|
||||
|
||||
export const usePremiseStore = defineStore('premise', {
|
||||
state: () => ({
|
||||
premises: [],
|
||||
selectedIds: [],
|
||||
loading: false,
|
||||
empty: true,
|
||||
error: null,
|
||||
|
|
@ -16,17 +18,74 @@ export const usePremiseStore = defineStore('premise', {
|
|||
getById: (state) => {
|
||||
return (id) => state.premises.find(p => p.id === id)
|
||||
},
|
||||
isChecked(state) {
|
||||
return function (premiseId) {
|
||||
return state.selectedIds.includes(premiseId);
|
||||
}
|
||||
},
|
||||
allChecked(state) {
|
||||
if (state.premises.length > state.selectedIds.length)
|
||||
return false;
|
||||
|
||||
for (const premise of state.premises) {
|
||||
if (!state.selectedIds.includes(premise.id))
|
||||
return false;
|
||||
}
|
||||
|
||||
return state.premises.length !== 0;
|
||||
},
|
||||
globallySomeChecked(state) {
|
||||
return state.selectedIds.length > 0;
|
||||
},
|
||||
someChecked(state) {
|
||||
for (const premise of state.premises) {
|
||||
if (state.selectedIds.includes(premise.id))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
showData: (state) => !state.loading && state.empty === false,
|
||||
showLoading: (state) => state.loading,
|
||||
showEmpty: (state) => !state.loading && state.empty === true,
|
||||
selectedIds: state => state.premises?.filter(p => p.checked).map(p => p.id) ?? [],
|
||||
},
|
||||
actions: {
|
||||
setQuery(query) {
|
||||
async createDrafts(ids) {
|
||||
const params = new URLSearchParams();
|
||||
params.append('premissIds', ids.join(', '));
|
||||
const data = await performRequest(this, "GET", `${config.backendUrl}/calculation/duplicate/${params.size === 0 ? '' : '?'}${params.toString()}`, null, true)
|
||||
|
||||
return data.data;
|
||||
},
|
||||
async resolveStatus() {
|
||||
const params = new URLSearchParams();
|
||||
params.append('premissIds', this.selectedIds.join(', '));
|
||||
|
||||
const data = await performRequest(this, 'GET', `${config.backendUrl}/calculation/resolve/${params.size === 0 ? '' : '?'}${params.toString()}`, null, true);
|
||||
return data.data;
|
||||
},
|
||||
resetSelectedIds() {
|
||||
this.selectedIds = [];
|
||||
},
|
||||
setChecked(premiseId, checked) {
|
||||
if (checked) {
|
||||
if (!this.selectedIds.includes(premiseId)) {
|
||||
this.selectedIds.push(premiseId);
|
||||
}
|
||||
} else {
|
||||
const idx = this.selectedIds.indexOf(premiseId);
|
||||
if (idx !== -1)
|
||||
this.selectedIds.splice(idx, 1);
|
||||
}
|
||||
},
|
||||
async setQuery(query) {
|
||||
this.query = query;
|
||||
this.updatePremises();
|
||||
await this.updatePremises();
|
||||
},
|
||||
async deletePremisses(ids) {
|
||||
|
||||
ids.forEach(id => this.setChecked(id, false));
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('premissIds', ids.join(', '));
|
||||
await performRequest(this, 'POST', `${config.backendUrl}/calculation/delete/${params.size === 0 ? '' : '?'}${params.toString()}`, null, false);
|
||||
|
|
@ -55,17 +114,29 @@ export const usePremiseStore = defineStore('premise', {
|
|||
if (this.query.done)
|
||||
params.append('done', this.query.done);
|
||||
|
||||
if (this.query.deleted)
|
||||
params.append('deleted', this.query.deleted);
|
||||
if (this.query.draft)
|
||||
params.append('draft', this.query.draft);
|
||||
|
||||
if (this.query?.page)
|
||||
params.append('page', this.query.page);
|
||||
|
||||
if (this.query?.pageSize)
|
||||
params.append('limit', this.query.pageSize);
|
||||
|
||||
const url = `${config.backendUrl}/calculation/view/${params.size === 0 ? '' : '?'}${params.toString()}`;
|
||||
|
||||
const resp = await performRequest(this, 'GET', url, null, true);
|
||||
const data = resp.data;
|
||||
const {data: data, headers: headers} = await performRequest(this, 'GET', url, null, true);
|
||||
|
||||
this.pagination = {
|
||||
page: parseInt(headers.get('X-Current-Page')),
|
||||
pageCount: parseInt(headers.get('X-Page-Count')),
|
||||
totalCount: parseInt(headers.get('X-Total-Count'))
|
||||
};
|
||||
|
||||
logger.log("pagination (premise store)", this.pagination);
|
||||
|
||||
this.loading = false;
|
||||
this.empty = data.length === 0;
|
||||
data.forEach(p => p.checked = false);
|
||||
this.premises = data;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,9 +255,9 @@ export const usePremiseEditStore = defineStore('premiseEdit', {
|
|||
if (ids.includes(p.id)) {
|
||||
return {
|
||||
...p,
|
||||
material_cost: priceData.price,
|
||||
oversea_share: priceData.overSeaShare,
|
||||
is_fca_enabled: priceData.includeFcaFee
|
||||
...(priceData.price !== null && {material_cost: priceData.price}),
|
||||
...(priceData.overSeaShare !== null && {oversea_share: priceData.overSeaShare}),
|
||||
...(priceData.includeFcaFee !== null && {is_fca_enabled: priceData.includeFcaFee})
|
||||
};
|
||||
}
|
||||
return p;
|
||||
|
|
@ -273,10 +273,10 @@ export const usePremiseEditStore = defineStore('premiseEdit', {
|
|||
...p,
|
||||
material: {
|
||||
...p.material,
|
||||
part_number: materialData.partNumber,
|
||||
hs_code: materialData.hsCode
|
||||
...(materialData.partNumber !== null && {part_number: materialData.partNumber}),
|
||||
...(materialData.hsCode !== null && {hs_code: materialData.hsCode})
|
||||
},
|
||||
tariff_rate: materialData.tariffRate
|
||||
...(materialData.tariffRate !== null && {tariff_rate: materialData.tariffRate})
|
||||
};
|
||||
}
|
||||
return p;
|
||||
|
|
@ -292,16 +292,16 @@ export const usePremiseEditStore = defineStore('premiseEdit', {
|
|||
...p,
|
||||
handling_unit: {
|
||||
...p.handling_unit,
|
||||
weight: packagingData.weight,
|
||||
width: packagingData.width,
|
||||
length: packagingData.length,
|
||||
height: packagingData.height,
|
||||
weight_unit: packagingData.weightUnit,
|
||||
dimension_unit: packagingData.dimensionUnit,
|
||||
content_unit_count: packagingData.unitCount
|
||||
...(packagingData.weight !== null && {weight: packagingData.weight}),
|
||||
...(packagingData.width !== null && {width: packagingData.width}),
|
||||
...(packagingData.length !== null && {length: packagingData.length}),
|
||||
...(packagingData.height !== null && {height: packagingData.height}),
|
||||
...(packagingData.weightUnit !== null && {weight_unit: packagingData.weightUnit}),
|
||||
...(packagingData.dimensionUnit !== null && {dimension_unit: packagingData.dimensionUnit}),
|
||||
...(packagingData.unitCount !== null && {content_unit_count: packagingData.unitCount})
|
||||
},
|
||||
is_stackable: packagingData.stackable,
|
||||
is_mixable: packagingData.mixable
|
||||
...(packagingData.stackable !== null && {is_stackable: packagingData.stackable}),
|
||||
...(packagingData.mixable !== null && {is_mixable: packagingData.mixable})
|
||||
};
|
||||
}
|
||||
return p;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package de.avatic.lcc.controller.calculation;
|
|||
import de.avatic.lcc.dto.calculation.CalculationStatus;
|
||||
import de.avatic.lcc.dto.calculation.DestinationDTO;
|
||||
import de.avatic.lcc.dto.calculation.PremiseDTO;
|
||||
import de.avatic.lcc.dto.calculation.ResolvePremiseDTO;
|
||||
import de.avatic.lcc.dto.calculation.create.CreatePremiseDTO;
|
||||
import de.avatic.lcc.dto.calculation.create.PremiseSearchResultDTO;
|
||||
import de.avatic.lcc.dto.calculation.edit.PremiseDetailDTO;
|
||||
|
|
@ -65,11 +66,11 @@ public class PremiseController {
|
|||
@RequestParam(defaultValue = "20") @Min(1) int limit,
|
||||
@RequestParam(defaultValue = "1") @Min(1) int page,
|
||||
@RequestParam(name = "user", required = false) Integer userId,
|
||||
@RequestParam(required = false) Boolean deleted,
|
||||
@RequestParam(required = false) Boolean draft,
|
||||
@RequestParam(required = false) Boolean archived,
|
||||
@RequestParam(required = false) Boolean done) {
|
||||
|
||||
var premises = premisesServices.listPremises(filter, page, limit, userId, deleted, archived, done);
|
||||
var premises = premisesServices.listPremises(filter, page, limit, userId, draft, archived, done);
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.header("X-Total-Count", String.valueOf(premises.getTotalElements()))
|
||||
|
|
@ -106,6 +107,17 @@ public class PremiseController {
|
|||
dto.createEmpty()));
|
||||
}
|
||||
|
||||
@GetMapping({"/resolve", "/resolve/"})
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
|
||||
public ResponseEntity<ResolvePremiseDTO> resolvePremiseStatus(@RequestParam List<Integer> premissIds) {
|
||||
return ResponseEntity.ok(premisesServices.resolveStatus(premissIds));
|
||||
}
|
||||
|
||||
@GetMapping({"/duplicate", "/duplicate/"})
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
|
||||
public ResponseEntity<List<Integer>> duplicate(@RequestParam List<Integer> premissIds) {
|
||||
return ResponseEntity.ok(premisesServices.duplicate(premissIds));
|
||||
}
|
||||
|
||||
@PostMapping({"/delete", "/delete/"})
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package de.avatic.lcc.dto.calculation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ResolvePremiseDTO {
|
||||
|
||||
private List<Integer> completed;
|
||||
|
||||
private List<Integer> draft;
|
||||
|
||||
private List<Integer> archived;
|
||||
|
||||
public List<Integer> getArchived() {
|
||||
return archived;
|
||||
}
|
||||
|
||||
public void setArchived(List<Integer> archive) {
|
||||
this.archived = archive;
|
||||
}
|
||||
|
||||
public List<Integer> getCompleted() {
|
||||
return completed;
|
||||
}
|
||||
|
||||
public void setCompleted(List<Integer> completed) {
|
||||
this.completed = completed;
|
||||
}
|
||||
|
||||
public List<Integer> getDraft() {
|
||||
return draft;
|
||||
}
|
||||
|
||||
public void setDraft(List<Integer> draft) {
|
||||
this.draft = draft;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,5 +2,5 @@ package de.avatic.lcc.model.premises;
|
|||
|
||||
|
||||
public enum PremiseState {
|
||||
DRAFT, COMPLETED, ARCHIVED, DELETED
|
||||
DRAFT, COMPLETED, ARCHIVED
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,17 @@ public class CalculationJobRepository {
|
|||
return Optional.of(job.getFirst());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void reschedule(Integer id) {
|
||||
String sql = "UPDATE calculation_job SET job_state = ?, calculation_date = ? WHERE id = ?";
|
||||
|
||||
var affectedRows = jdbcTemplate.update(sql, CalculationJobState.CREATED.name(), java.time.LocalDateTime.now(), id);
|
||||
|
||||
if(1 != affectedRows) {
|
||||
throw new DatabaseException("Unable to update calculation job with id " + id);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Optional<CalculationJob> getCalculationJobWithJobStateValid(Integer periodId, Integer nodeId, Integer materialId) {
|
||||
|
||||
|
|
@ -86,6 +97,27 @@ public class CalculationJobRepository {
|
|||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Optional<CalculationJob> findJob(Integer premiseId, Integer validSetId, Integer validPeriodId) {
|
||||
String sql = "SELECT * FROM calculation_job WHERE premise_id = ? AND validity_period_id = ? AND property_set_id = ?";
|
||||
|
||||
var jobs = jdbcTemplate.query(sql, new CalculationJobMapper(), premiseId, validPeriodId, validSetId);
|
||||
|
||||
return jobs.isEmpty() ? Optional.empty() : Optional.ofNullable(jobs.getFirst());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void invalidateByPropertySetId(Integer id) {
|
||||
String sql = "UPDATE calculation_job SET job_state = ? WHERE property_set_id = ?";
|
||||
jdbcTemplate.update(sql, CalculationJobState.INVALIDATED.name(), id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void invalidateByPeriodId(Integer id) {
|
||||
String sql = "UPDATE calculation_job SET job_state = ? WHERE validity_period_id = ?";
|
||||
jdbcTemplate.update(sql, CalculationJobState.INVALIDATED.name(), id);
|
||||
}
|
||||
|
||||
|
||||
private static class CalculationJobMapper implements RowMapper<CalculationJob> {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -45,11 +45,11 @@ public class PremiseRepository {
|
|||
|
||||
@Transactional
|
||||
public SearchQueryResult<PremiseListEntry> listPremises(String filter, SearchQueryPagination pagination,
|
||||
Integer userId, Boolean deleted, Boolean archived, Boolean done) {
|
||||
Integer userId, Boolean draft, Boolean archived, Boolean done) {
|
||||
|
||||
QueryBuilder queryBuilder = new QueryBuilder()
|
||||
.withFilter(filter)
|
||||
.withDeleted(deleted)
|
||||
.withDraft(draft)
|
||||
.withArchived(archived)
|
||||
.withDone(done);
|
||||
|
||||
|
|
@ -428,12 +428,15 @@ public class PremiseRepository {
|
|||
if (premiseIds == null || premiseIds.isEmpty()) return;
|
||||
|
||||
String placeholders = String.join(",", Collections.nCopies(premiseIds.size(), "?"));
|
||||
String query = """
|
||||
DELETE FROM premise
|
||||
WHERE id IN (""" + placeholders + ") AND state = '" + PremiseState.DRAFT.name() + "'";
|
||||
String query = "DELETE FROM premise WHERE id IN (" + placeholders + ") AND state = ?";
|
||||
|
||||
Object[] params = new Object[premiseIds.size() + 1];
|
||||
for (int i = 0; i < premiseIds.size(); i++) {
|
||||
params[i] = premiseIds.get(i);
|
||||
}
|
||||
params[premiseIds.size()] = PremiseState.DRAFT.name();
|
||||
|
||||
jdbcTemplate.update(query, premiseIds.toArray());
|
||||
jdbcTemplate.update(query, params);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -678,7 +681,7 @@ public class PremiseRepository {
|
|||
"user_n.name LIKE ? OR m.name LIKE ? OR m.name LIKE ? OR m.part_number LIKE ?)";
|
||||
|
||||
private String filter;
|
||||
private Boolean deleted;
|
||||
private Boolean draft;
|
||||
private Boolean archived;
|
||||
private Boolean done;
|
||||
|
||||
|
|
@ -687,8 +690,8 @@ public class PremiseRepository {
|
|||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder withDeleted(Boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
public QueryBuilder withDraft(Boolean draft) {
|
||||
this.draft = draft;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -725,7 +728,7 @@ public class PremiseRepository {
|
|||
user_n.country_id as 'user_n.country_id', user_n.geo_lat as 'user_n.geo_lat', user_n.geo_lng as 'user_n.geo_lng'
|
||||
""").append(BASE_JOIN_QUERY);
|
||||
appendConditions(queryBuilder);
|
||||
queryBuilder.append(" ORDER BY p.updated_at DESC");
|
||||
queryBuilder.append(" ORDER BY p.updated_at, p.id DESC");
|
||||
queryBuilder.append(" LIMIT ? OFFSET ?");
|
||||
return queryBuilder.toString();
|
||||
}
|
||||
|
|
@ -735,13 +738,13 @@ public class PremiseRepository {
|
|||
queryBuilder.append(FILTER_CONDITION);
|
||||
}
|
||||
|
||||
if (deleted != null && deleted || archived != null && archived || done != null && done) {
|
||||
if (draft != null && draft || archived != null && archived || done != null && done) {
|
||||
boolean concat = false;
|
||||
|
||||
queryBuilder.append(" AND (");
|
||||
|
||||
if (deleted != null && deleted) {
|
||||
queryBuilder.append(" p.state").append(" = 'DELETED'");
|
||||
if (draft != null && draft) {
|
||||
queryBuilder.append(" p.state").append(" = 'DRAFT'");
|
||||
concat = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package de.avatic.lcc.service.access;
|
||||
|
||||
import de.avatic.lcc.config.LccOidcUser;
|
||||
import de.avatic.lcc.dto.calculation.CalculationStatus;
|
||||
import de.avatic.lcc.dto.calculation.ResolvePremiseDTO;
|
||||
import de.avatic.lcc.dto.calculation.PremiseDTO;
|
||||
import de.avatic.lcc.dto.calculation.edit.PremiseDetailDTO;
|
||||
import de.avatic.lcc.dto.calculation.edit.masterData.MaterialUpdateDTO;
|
||||
|
|
@ -29,14 +29,13 @@ import de.avatic.lcc.service.users.AuthorizationService;
|
|||
import de.avatic.lcc.util.exception.base.InternalErrorException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
|
@ -83,10 +82,10 @@ public class PremisesService {
|
|||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public SearchQueryResult<PremiseDTO> listPremises(String filter, Integer page, Integer limit, Integer userId, Boolean deleted, Boolean archived, Boolean done) {
|
||||
public SearchQueryResult<PremiseDTO> listPremises(String filter, Integer page, Integer limit, Integer userId, Boolean draft, Boolean archived, Boolean done) {
|
||||
var admin = authorizationService.isSuper();
|
||||
userId = authorizationService.getUserId();
|
||||
return SearchQueryResult.map(premiseRepository.listPremises(filter, new SearchQueryPagination(page, limit), userId, deleted, archived, done), admin ? premiseTransformer::toPremiseDTOWithUserInfo : premiseTransformer::toPremiseDTO);
|
||||
return SearchQueryResult.map(premiseRepository.listPremises(filter, new SearchQueryPagination(page, limit), userId, draft, archived, done), admin ? premiseTransformer::toPremiseDTOWithUserInfo : premiseTransformer::toPremiseDTO);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
|
|
@ -112,6 +111,18 @@ public class PremisesService {
|
|||
var calculationIds = new ArrayList<Integer>();
|
||||
|
||||
premises.forEach(p -> {
|
||||
|
||||
var existingJob = calculationJobRepository.findJob(p, validSetId, validPeriodId);
|
||||
|
||||
if (existingJob.isPresent()) {
|
||||
if (CalculationJobState.EXCEPTION == existingJob.get().getJobState()) {
|
||||
calculationJobRepository.setStateTo(existingJob.get().getId(), CalculationJobState.CREATED);
|
||||
calculationIds.add(existingJob.get().getId());
|
||||
} else if (CalculationJobState.SCHEDULED == existingJob.get().getJobState() && existingJob.get().getCalculationDate().plusMinutes(15).isBefore(LocalDateTime.now())) {
|
||||
calculationJobRepository.reschedule(existingJob.get().getId());
|
||||
calculationIds.add(existingJob.get().getId());
|
||||
}
|
||||
} else {
|
||||
CalculationJob job = new CalculationJob();
|
||||
|
||||
job.setPremiseId(p);
|
||||
|
|
@ -122,6 +133,9 @@ public class PremisesService {
|
|||
job.setValidityPeriodId(validPeriodId);
|
||||
|
||||
calculationIds.add(calculationJobRepository.insert(job));
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
premiseRepository.setStatus(premises, PremiseState.COMPLETED);
|
||||
|
|
@ -157,8 +171,6 @@ public class PremisesService {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} catch (CompletionException | InterruptedException | ExecutionException e) {
|
||||
throw new InternalErrorException("Calculation execution failed.", e);
|
||||
}
|
||||
|
|
@ -214,8 +226,7 @@ public class PremisesService {
|
|||
// only delete drafts.
|
||||
var toBeDeleted = premiseRepository.getPremisesById(premiseIds).stream().filter(p -> p.getState().equals(PremiseState.DRAFT)).map(Premise::getId).toList();
|
||||
|
||||
if(!toBeDeleted.isEmpty())
|
||||
{
|
||||
if (!toBeDeleted.isEmpty()) {
|
||||
destinationService.deleteAllDestinationsByPremiseId(toBeDeleted, false);
|
||||
premiseRepository.deletePremisesById(toBeDeleted);
|
||||
}
|
||||
|
|
@ -230,4 +241,49 @@ public class PremisesService {
|
|||
var premisses = premiseRepository.getPremisesById(premiseIds);
|
||||
premiseRepository.setStatus(premisses.stream().filter(p -> p.getState().equals(PremiseState.COMPLETED)).map(Premise::getId).toList(), PremiseState.ARCHIVED);
|
||||
}
|
||||
|
||||
public ResolvePremiseDTO resolveStatus(List<Integer> premissIds) {
|
||||
ResolvePremiseDTO resolveDTO = new ResolvePremiseDTO();
|
||||
var drafts = new ArrayList<Integer>();
|
||||
var completed = new ArrayList<Integer>();
|
||||
var archived = new ArrayList<Integer>();
|
||||
|
||||
var premisses = premiseRepository.getPremisesById(premissIds);
|
||||
|
||||
premisses.forEach(p -> {
|
||||
if(PremiseState.DRAFT.equals(p.getState())) drafts.add(p.getId());
|
||||
else if(PremiseState.COMPLETED.equals(p.getState())) completed.add(p.getId());
|
||||
else if(PremiseState.ARCHIVED.equals(p.getState())) archived.add(p.getId());
|
||||
});
|
||||
|
||||
resolveDTO.setCompleted(completed);
|
||||
resolveDTO.setDraft(drafts);
|
||||
resolveDTO.setArchived(archived);
|
||||
|
||||
return resolveDTO;
|
||||
}
|
||||
|
||||
public List<Integer> duplicate(List<Integer> premissIds) {
|
||||
var userId = authorizationService.getUserId();
|
||||
premiseRepository.checkOwner(premissIds, userId);
|
||||
var newIds = new ArrayList<Integer>();
|
||||
|
||||
premissIds.forEach(id -> {
|
||||
|
||||
var old = premiseRepository.getPremiseById(id).orElseThrow();
|
||||
var newId = premiseRepository.insert(old.getMaterialId(), old.getSupplierNodeId(), old.getUserSupplierNodeId(), BigDecimal.valueOf(old.getLocation().getLatitude()), BigDecimal.valueOf(old.getLocation().getLongitude()), old.getCountryId(), userId);
|
||||
|
||||
premiseRepository.updateMaterial(Collections.singletonList(newId), old.getHsCode(), old.getTariffRate());
|
||||
premiseRepository.updatePrice(Collections.singletonList(newId), old.getMaterialCost(), old.getFcaEnabled(), old.getOverseaShare());
|
||||
premiseRepository.updatePackaging(Collections.singletonList(newId), dimensionTransformer.toDimensionEntity(old), old.getHuStackable(), old.getHuMixable());
|
||||
premiseRepository.setPackagingId(newId, old.getPackagingId());
|
||||
|
||||
destinationService.duplicate(old.getId(), newId);
|
||||
|
||||
newIds.add(newId);
|
||||
|
||||
});
|
||||
|
||||
return newIds;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import de.avatic.lcc.dto.generic.PropertyDTO;
|
|||
import de.avatic.lcc.dto.generic.ValidityPeriodDTO;
|
||||
import de.avatic.lcc.model.properties.SystemPropertyMappingId;
|
||||
import de.avatic.lcc.model.rates.ValidityPeriodState;
|
||||
import de.avatic.lcc.repositories.calculation.CalculationJobRepository;
|
||||
import de.avatic.lcc.repositories.properties.PropertyRepository;
|
||||
import de.avatic.lcc.repositories.properties.PropertySetRepository;
|
||||
import de.avatic.lcc.service.transformer.rates.ValidityPeriodTransformer;
|
||||
|
|
@ -36,6 +37,7 @@ public class PropertyService {
|
|||
private final PropertySetRepository propertySetRepository;
|
||||
private final ValidityPeriodTransformer validityPeriodTransformer;
|
||||
private final PropertyValidationService propertyValidationService;
|
||||
private final CalculationJobRepository calculationJobRepository;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -45,11 +47,12 @@ public class PropertyService {
|
|||
* @param propertySetRepository the repository to manage property sets
|
||||
* @param validityPeriodTransformer the transformer to convert property sets to validity period DTOs
|
||||
*/
|
||||
public PropertyService(PropertyRepository propertyRepository, PropertySetRepository propertySetRepository, ValidityPeriodTransformer validityPeriodTransformer, PropertyValidationService propertyValidationService) {
|
||||
public PropertyService(PropertyRepository propertyRepository, PropertySetRepository propertySetRepository, ValidityPeriodTransformer validityPeriodTransformer, PropertyValidationService propertyValidationService, CalculationJobRepository calculationJobRepository) {
|
||||
this.propertyRepository = propertyRepository;
|
||||
this.propertySetRepository = propertySetRepository;
|
||||
this.validityPeriodTransformer = validityPeriodTransformer;
|
||||
this.propertyValidationService = propertyValidationService;
|
||||
this.calculationJobRepository = calculationJobRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -116,6 +119,7 @@ public class PropertyService {
|
|||
if (!propertySetRepository.invalidateById(id))
|
||||
throw new NotFoundException(NotFoundType.EXPIRED_PROPERTY_SET, "id", id.toString());
|
||||
|
||||
calculationJobRepository.invalidateByPropertySetId(id);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package de.avatic.lcc.service.access;
|
||||
|
||||
import de.avatic.lcc.dto.generic.ValidityPeriodDTO;
|
||||
import de.avatic.lcc.repositories.calculation.CalculationJobRepository;
|
||||
import de.avatic.lcc.repositories.rates.ValidityPeriodRepository;
|
||||
import de.avatic.lcc.service.transformer.rates.ValidityPeriodTransformer;
|
||||
import de.avatic.lcc.util.exception.badrequest.NotFoundException;
|
||||
|
|
@ -22,6 +23,7 @@ public class ValidityPeriodService {
|
|||
|
||||
private final ValidityPeriodRepository validityPeriodRepository;
|
||||
private final ValidityPeriodTransformer validityPeriodTransformer;
|
||||
private final CalculationJobRepository calculationJobRepository;
|
||||
|
||||
/**
|
||||
* Constructs a new ValidityPeriodService with the required dependencies.
|
||||
|
|
@ -29,9 +31,10 @@ public class ValidityPeriodService {
|
|||
* @param validityPeriodRepository Repository for accessing validity period data
|
||||
* @param validityPeriodTransformer Transformer for converting between entity and DTO representations
|
||||
*/
|
||||
public ValidityPeriodService(ValidityPeriodRepository validityPeriodRepository, ValidityPeriodTransformer validityPeriodTransformer) {
|
||||
public ValidityPeriodService(ValidityPeriodRepository validityPeriodRepository, ValidityPeriodTransformer validityPeriodTransformer, CalculationJobRepository calculationJobRepository) {
|
||||
this.validityPeriodRepository = validityPeriodRepository;
|
||||
this.validityPeriodTransformer = validityPeriodTransformer;
|
||||
this.calculationJobRepository = calculationJobRepository;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -60,5 +63,6 @@ public class ValidityPeriodService {
|
|||
if (!validityPeriodRepository.invalidateById(id))
|
||||
throw new NotFoundException(NotFoundException.NotFoundType.EXPIRED_VALIDITY_PERIOD, "id", id.toString());
|
||||
|
||||
calculationJobRepository.invalidateByPeriodId(id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ public class PremiseCreationService {
|
|||
return premiseRepository.getPremisesById(premises.stream().map(TemporaryPremise::getId).toList()).stream().map(premiseTransformer::toPremiseDetailDTO).toList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void copyPremise(TemporaryPremise p, Integer userId) {
|
||||
var old = p.getPremise();
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ CREATE TABLE IF NOT EXISTS premise
|
|||
FOREIGN KEY (packaging_id) REFERENCES packaging (id),
|
||||
FOREIGN KEY (user_id) REFERENCES sys_user (id),
|
||||
CONSTRAINT `chk_premise_state_values` CHECK (`state` IN
|
||||
('DRAFT', 'COMPLETED', 'ARCHIVED', 'DELETED')),
|
||||
('DRAFT', 'COMPLETED', 'ARCHIVED')),
|
||||
CONSTRAINT `chk_premise_displayed_dimension_unit` CHECK (`hu_displayed_dimension_unit` IN
|
||||
('MM', 'CM', 'M')),
|
||||
CONSTRAINT `chk_premise_displayed_weight_unit` CHECK (`hu_displayed_weight_unit` IN
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue