diff --git a/src/frontend/src/components/layout/config/EditUser.vue b/src/frontend/src/components/layout/config/EditUser.vue index 04ef116..3840b48 100644 --- a/src/frontend/src/components/layout/config/EditUser.vue +++ b/src/frontend/src/components/layout/config/EditUser.vue @@ -3,20 +3,21 @@
Workday ID
-
+
+
Firstname
-
+
Lastname
-
+
E-Mail
-
+
Groups
@@ -62,6 +63,11 @@ export default { } }, methods: { + validate(type) { + if (type === "firstname") { + firstName + } + }, closeModal(save) { this.$emit("close", save); }, @@ -82,7 +88,7 @@ export default { } else { if ((idx ?? null) !== null && idx !== -1) - this.user.groups.splice(idx,1); + this.user.groups.splice(idx, 1); } }, @@ -122,22 +128,13 @@ export default { \ No newline at end of file diff --git a/src/frontend/src/pages/CalculationMassEdit.vue b/src/frontend/src/pages/CalculationMassEdit.vue index 136712a..ae2474b 100644 --- a/src/frontend/src/pages/CalculationMassEdit.vue +++ b/src/frontend/src/pages/CalculationMassEdit.vue @@ -18,7 +18,6 @@
- @@ -64,6 +63,7 @@ v-model:partNumber="componentProps.partNumber" v-model:hsCode="componentProps.hsCode" v-model:tariffRate="componentProps.tariffRate" + v-model:tariffUnlocked="componentProps.tariffUnlocked" v-model:description="componentProps.description" v-model:price="componentProps.price" v-model:overSeaShare="componentProps.overSeaShare" @@ -81,13 +81,12 @@ :countryId=null :responsive="false" @close="closeEditModalAction('cancel')" - @start-lookup="doLookupOnClose" > - @@ -113,9 +112,7 @@ import PriceEdit from "@/components/layout/edit/PriceEdit.vue"; import MaterialEdit from "@/components/layout/edit/MaterialEdit.vue"; import PackagingEdit from "@/components/layout/edit/PackagingEdit.vue"; import DestinationListView from "@/components/layout/edit/DestinationListView.vue"; -import Toast from "@/components/UI/Toast.vue"; import logger from "@/logger.js"; -import {useCustomsStore} from "@/store/customs.js"; import {useNotificationStore} from "@/store/notification.js"; @@ -129,7 +126,6 @@ const COMPONENT_TYPES = { export default { name: "MassEdit", components: { - Toast, Modal, MassEditDialog, ListEdit, @@ -140,7 +136,7 @@ export default { BasicButton }, computed: { - ...mapStores(usePremiseEditStore, useCustomsStore, useNotificationStore), + ...mapStores(usePremiseEditStore, useNotificationStore), hasSelection() { if (this.premiseEditStore.isLoading || this.premiseEditStore.selectedLoading) { return false; @@ -168,8 +164,8 @@ export default { showMultiselectAction() { return this.selectCount > 0; }, - showModalFooter() { - return this.modalType !== 'supplier'; + modalCloseOnly() { + return this.modalType === 'material' && !this.componentProps.tariffUnlocked; }, showEditModal() { return ((this.modalType ?? null) !== null); @@ -208,13 +204,12 @@ export default { data() { return { - doLookup: false, ids: [], bulkQuery: null, modalType: null, componentsData: { price: {props: {price: 0, overSeaShare: 0, includeFcaFee: false}}, - material: {props: {partNumber: "", hsCode: null, tariffRate: 0.00, description: "", hideDescription: false}}, + material: {props: {partNumber: "", hsCode: null, tariffRate: null, tariffUnlocked: false, description: "", hideDescription: false}}, packaging: { props: { length: 0, @@ -256,16 +251,7 @@ export default { this.showCalculationModal = true; const error = await this.premiseEditStore.startCalculation(); - if (error !== null) { - - this.$refs.toast.addToast({ - icon: 'warning', - message: error.message, - title: "Cannot start calculation", - variant: 'exception', - duration: 8000 - }) - } else { + if (error === null) { this.closeMassEdit() } this.showCalculationModal = false; @@ -298,9 +284,6 @@ export default { logger.info("open modal", massEdit, this.modalType, this.editIds, this.dataSourceId) }, - doLookupOnClose(doLookup) { - this.doLookup = doLookup; - }, async closeEditModalAction(action) { if (this.modalType === "destinations") { if (action === "accept") { @@ -316,11 +299,7 @@ export default { await this.premiseEditStore.batchUpdatePrice(this.editIds, props); break; case "material": - let tariffRates = null; - if (this.doLookup) { - tariffRates = await this.tariffLookUp(props.hsCode); - } - await this.premiseEditStore.batchUpdateMaterial(this.editIds, props, tariffRates); + await this.premiseEditStore.batchUpdateMaterial(this.editIds, props); break; case "packaging": await this.premiseEditStore.batchUpdatePackaging(this.editIds, props); @@ -332,24 +311,6 @@ export default { this.fillData(this.modalType); this.modalType = null; }, - async tariffLookUp(hsCode) { - - const countryIds = this.premiseEditStore.getCountryIdByPremiseIds(this.editIds); - - const query = {hsCode: hsCode, countryIds: [...new Set(Array.from(countryIds.values()))]}; - const tariffRates = await this.customsStore.findTariffRate(query); - - const found = new Map(); - for(const editId of this.editIds) { - const countryId = countryIds.get(editId); - - - found.set(editId, tariffRates.find(rate => rate.countryId === countryId).value); - } - - this.doLookup = false; - return found; - }, fillData(type, id = -1, hideDescription = false) { if (id === -1) { @@ -361,6 +322,7 @@ export default { partNumber: "", hsCode: null, tariffRate: null, + tariffUnlocked: false, description: null, hideDescription: hideDescription } @@ -394,7 +356,8 @@ export default { this.componentsData.material.props = { partNumber: premise.material.part_number, hsCode: premise.hs_code, - tariffRate: premise.tariff_rate ?? 0.00, + tariffRate: premise.tariff_rate ?? null, + tariffUnlocked: premise.tariff_unlocked, description: premise.material.name ?? "", hideDescription: hideDescription } @@ -431,20 +394,13 @@ export default { margin: 3rem; } -.edit-calculation-spinner-container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 3.6rem; - flex: 1 1 auto; - font-size: 1.6rem; -} .modal-content-container { display: flex; flex-direction: column; gap: 1.6rem; + margin-top: 1.6rem; + min-width: 50rem; } .modal-content-footer { @@ -512,23 +468,6 @@ export default { letter-spacing: 0.08rem; } - -.edit-calculation-spinner-container { - display: flex; - align-items: center; - justify-content: center; - flex: 1 1 30rem -} - -.spinner-box { - font-size: 1.6rem; - width: 24rem; - height: 12rem; - display: flex; - justify-content: center; - align-items: center; -} - .edit-calculation-container { display: flex; flex-direction: column; diff --git a/src/frontend/src/store/customs.js b/src/frontend/src/store/customs.js deleted file mode 100644 index ef47527..0000000 --- a/src/frontend/src/store/customs.js +++ /dev/null @@ -1,56 +0,0 @@ -import {defineStore} from 'pinia' -import {config} from '@/config' -import performRequest from "@/backend.js"; - -export const useCustomsStore = defineStore('customs', { - state() { - return { - hsCodes: [], - tariffInfo: null, - loadingTariff: false, - - } - }, - getters: { - showWarning(state) { - return function (countryId) { - const info = state.tariffInfo?.find(t => t.countryId === countryId); - - if ((info ?? null) !== null) { - return info.default || info.measures?.length > 1; - } - - return false; - } - }, - findByCountryId(state) { - return function (countryId) { - return state.tariffInfo?.find(t => t.countryId === countryId); - } - } - }, - actions: { - async findTariffRate(query) { - this.loadingTariff = true; - const url = `${config.backendUrl}/customs?hs_code=${query.hsCode}&country_ids=${query.countryIds}`; - const resp = await performRequest(this, 'GET', url, null).catch(() => { - this.tariffInfo = null; - this.loadingTariff = false; - }) - this.tariffInfo = resp.data; - - this.tariffInfo.forEach(info => info.measures.sort((m1, m2) => { return parseInt(m1.code) - parseInt(m2.code); })); - - this.loadingTariff = false; - return this.tariffInfo; - }, - async findHsCode(query) { - - const url = `${config.backendUrl}/customs/search?hs_code=${query}`; - const resp = await performRequest(this, 'GET', url, null); - this.hsCodes = resp.data; - return this.hsCodes; - - } - } -}); diff --git a/src/frontend/src/store/premiseEdit.js b/src/frontend/src/store/premiseEdit.js index 1a37870..68ea92a 100644 --- a/src/frontend/src/store/premiseEdit.js +++ b/src/frontend/src/store/premiseEdit.js @@ -263,7 +263,7 @@ export const usePremiseEditStore = defineStore('premiseEdit', { return await this.savePrice(ids, priceData); }, - async batchUpdateMaterial(ids, materialData, tariffRates = null) { + async batchUpdateMaterial(ids, materialData) { const updatedPremises = this.premisses.map(p => { if (ids.includes(p.id)) { return { @@ -272,7 +272,7 @@ export const usePremiseEditStore = defineStore('premiseEdit', { ...p.material, }, ...(materialData.hsCode !== null && {hs_code: materialData.hsCode}), - ...((tariffRates !== null) ? {tariff_rate: tariffRates.get(p.id)} : (materialData.tariffRate !== null && {tariff_rate: materialData.tariffRate})) + ...((materialData.tariffRate !== null && {tariff_rate: materialData.tariffRate})) }; } return p; @@ -281,7 +281,7 @@ export const usePremiseEditStore = defineStore('premiseEdit', { - return await this.saveMaterial(ids, materialData, tariffRates); + return await this.saveMaterial(ids, materialData); }, async batchUpdatePackaging(ids, packagingData) { @@ -706,7 +706,7 @@ export const usePremiseEditStore = defineStore('premiseEdit', { return success; }, - async saveMaterial(ids = null, materialData = null, tariffRates = null) { + async saveMaterial(ids = null, materialData = null) { let success = true; const toBeUpdated = this.premisses ? (ids ? (ids.map(id => this.premisses.find(p => String(p.id) === String(id)))) : (this.premisses.filter(p => p.selected))) : null; @@ -717,8 +717,7 @@ export const usePremiseEditStore = defineStore('premiseEdit', { premise_ids: toBeUpdated.map(p => p.id), hs_code: materialData === null ? toBeUpdated[0].hs_code : materialData.hsCode, - tariff_rate: (null !== tariffRates) ? null : materialData === null ? toBeUpdated[0].tariff_rate : materialData.tariffRate, - tariff_rates: (null === tariffRates) ? null : Object.fromEntries(tariffRates), + tariff_rate: (materialData === null ? toBeUpdated[0].tariff_rate : materialData.tariffRate), }; await performRequest(this, 'POST', `${config.backendUrl}/calculation/material/`, body, false).catch(() => { diff --git a/src/main/java/de/avatic/lcc/controller/SessionController.java b/src/main/java/de/avatic/lcc/controller/SessionController.java deleted file mode 100644 index 392bb42..0000000 --- a/src/main/java/de/avatic/lcc/controller/SessionController.java +++ /dev/null @@ -1,23 +0,0 @@ -package de.avatic.lcc.controller; - -import org.springframework.security.core.Authentication; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Map; - -@RestController -@RequestMapping("/api/session") -public class SessionController { - - @GetMapping("/keepalive") - public Map keepalive(Authentication authentication) { - - return Map.of( - "status", "ok", - "user", authentication.getName(), - "timestamp", System.currentTimeMillis() - ); - } -} \ No newline at end of file diff --git a/src/main/java/de/avatic/lcc/controller/calculation/PremiseController.java b/src/main/java/de/avatic/lcc/controller/calculation/PremiseController.java index 2ac123d..24bc8bd 100644 --- a/src/main/java/de/avatic/lcc/controller/calculation/PremiseController.java +++ b/src/main/java/de/avatic/lcc/controller/calculation/PremiseController.java @@ -78,8 +78,8 @@ public class PremiseController { public ResponseEntity findMaterialsAndSuppliers(@RequestParam String search) { try { - String decodedValue = URLDecoder.decode(search, StandardCharsets.UTF_8); - return ResponseEntity.ok(premiseSearchStringAnalyzerService.findMaterialAndSuppliers(decodedValue)); +// String decodedValue = URLDecoder.decode(search, StandardCharsets.UTF_8); + return ResponseEntity.ok(premiseSearchStringAnalyzerService.findMaterialAndSuppliers(search)); } catch (Exception e) { throw new BadRequestException("Bad string encoding", "Unable to decode request", e); } diff --git a/src/main/java/de/avatic/lcc/controller/users/UserController.java b/src/main/java/de/avatic/lcc/controller/users/UserController.java index ac50c5e..674f98c 100644 --- a/src/main/java/de/avatic/lcc/controller/users/UserController.java +++ b/src/main/java/de/avatic/lcc/controller/users/UserController.java @@ -6,6 +6,8 @@ import de.avatic.lcc.repositories.pagination.SearchQueryResult; import de.avatic.lcc.service.users.UserService; import jakarta.validation.Valid; import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import org.hibernate.validator.constraints.Length; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -52,6 +54,24 @@ public class UserController { .body(users.toList()); } + + + @PostMapping({"/{workdayId}/groups/{group}/", "/{workdayId}/groups/{group}"}) + @PreAuthorize("hasRole('RIGHT-MANAGEMENT')") + public ResponseEntity appendGroups(@PathVariable String workdayId, @PathVariable String group) { + + userService.appendGroups(workdayId, group); + return ResponseEntity.ok().build(); + } + + @DeleteMapping({"/{workdayId}/groups/{group}/", "/{workdayId}/groups/{group}"}) + @PreAuthorize("hasRole('RIGHT-MANAGEMENT')") + public ResponseEntity deleteGroups(@PathVariable String workdayId, @PathVariable String group) { + + userService.deleteGroups(workdayId, group); + return ResponseEntity.ok().build(); + } + /** * Retrieves a single user by its workday id. * @@ -68,6 +88,8 @@ public class UserController { .body(users); } + + /** * Updates the details of an existing user or creates a new one if it does not exist. * Users are identified by its workday id. If a group from the group membership does not exist diff --git a/src/main/java/de/avatic/lcc/dto/users/GroupDTO.java b/src/main/java/de/avatic/lcc/dto/users/GroupDTO.java index 39fec00..4b2ed4d 100644 --- a/src/main/java/de/avatic/lcc/dto/users/GroupDTO.java +++ b/src/main/java/de/avatic/lcc/dto/users/GroupDTO.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class GroupDTO { + private Integer id; + @JsonProperty("group_name") private String name; @@ -26,4 +28,12 @@ public class GroupDTO { public void setDescription(String description) { this.description = description; } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } } diff --git a/src/main/java/de/avatic/lcc/dto/users/UserDTO.java b/src/main/java/de/avatic/lcc/dto/users/UserDTO.java index 8fc22e5..27707ae 100644 --- a/src/main/java/de/avatic/lcc/dto/users/UserDTO.java +++ b/src/main/java/de/avatic/lcc/dto/users/UserDTO.java @@ -4,6 +4,7 @@ package de.avatic.lcc.dto.users; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; import jakarta.validation.constraints.*; +import org.hibernate.validator.constraints.Length; import java.util.List; @@ -11,18 +12,22 @@ public class UserDTO { @NotNull @JsonProperty("firstname") + @Length(max = 100, min= 1, message = "Firstname must be max 100 characters long") private String firstName; @NotNull @JsonProperty("lastname") + @Length(max = 100, min= 1, message = "Lastname must be max 100 characters long") private String lastName; - @Email + @Email(message = "Mail must be valid") @JsonProperty("mail") + @Length(max = 254, min = 1, message = "Email must be max 254 characters long") private String email; @NotNull @JsonProperty("workday_id") + @Length(max = 32, message = "Workday ID must be max 32 characters long") private String workdayId; @NotNull diff --git a/src/main/java/de/avatic/lcc/service/access/PremisesService.java b/src/main/java/de/avatic/lcc/service/access/PremisesService.java index d29f5ee..3ca68f5 100644 --- a/src/main/java/de/avatic/lcc/service/access/PremisesService.java +++ b/src/main/java/de/avatic/lcc/service/access/PremisesService.java @@ -214,6 +214,8 @@ public class PremisesService { var unlockedIds = premiseRepository.getIdsWithUnlockedTariffs(materialUpdateDTO.getPremiseIds()); + if (unlockedIds.isEmpty()) return; + var tariffRate = materialUpdateDTO.getTariffRate() == null ? null : BigDecimal.valueOf(materialUpdateDTO.getTariffRate().doubleValue()); premiseRepository.updateMaterial(unlockedIds, materialUpdateDTO.getHsCode(), tariffRate); diff --git a/src/main/java/de/avatic/lcc/service/calculation/PremiseCreationService.java b/src/main/java/de/avatic/lcc/service/calculation/PremiseCreationService.java index 5a2e2f4..e3bd5ab 100644 --- a/src/main/java/de/avatic/lcc/service/calculation/PremiseCreationService.java +++ b/src/main/java/de/avatic/lcc/service/calculation/PremiseCreationService.java @@ -128,7 +128,7 @@ public class PremiseCreationService { } tariffs.stream() - .filter(r -> r.material().getId().equals(p.getMaterialId())) + .filter(r -> r.material().getId().equals(p.getMaterialId()) && r.countryId().equals(p.getCountryId())) .findFirst() .ifPresent(value -> premiseRepository.updateMaterial(Collections.singletonList( p.getId()), diff --git a/src/main/java/de/avatic/lcc/service/calculation/PremiseSearchStringAnalyzerService.java b/src/main/java/de/avatic/lcc/service/calculation/PremiseSearchStringAnalyzerService.java index d0392fd..8a00057 100644 --- a/src/main/java/de/avatic/lcc/service/calculation/PremiseSearchStringAnalyzerService.java +++ b/src/main/java/de/avatic/lcc/service/calculation/PremiseSearchStringAnalyzerService.java @@ -26,6 +26,7 @@ import java.util.regex.Pattern; @Service public class PremiseSearchStringAnalyzerService { + private static final String PART_NUMBER_REGEX_NUMBER_ONLY = "(\\d{4,11})"; private static final String PART_NUMBER_REGEX = "([a-zA-Z0-9][a-zA-Z0-9\\-]{4,11})"; private static final Pattern PART_NUMBER_PATTERN = Pattern.compile(PART_NUMBER_REGEX); private final MaterialRepository materialRepository; @@ -98,6 +99,8 @@ public class PremiseSearchStringAnalyzerService { Set partNumbers = new HashSet<>(); Matcher matcher = PART_NUMBER_PATTERN.matcher(search); + Matcher numbersOnlyMatcher = Pattern.compile(PART_NUMBER_REGEX_NUMBER_ONLY).matcher(search); + // Find all matches while (matcher.find()) { // Get the match from group 1 (inside the lookahead) @@ -105,6 +108,12 @@ public class PremiseSearchStringAnalyzerService { partNumbers.add(normalizePartNumber(partNumber)); } + while (numbersOnlyMatcher.find()) { + // Get the match from group 1 (inside the lookahead) + String partNumber = numbersOnlyMatcher.group(1); + partNumbers.add(normalizePartNumber(partNumber)); + } + return partNumbers; } diff --git a/src/main/java/de/avatic/lcc/service/transformer/users/UserTransformer.java b/src/main/java/de/avatic/lcc/service/transformer/users/UserTransformer.java index 3cf59c9..f7386b7 100644 --- a/src/main/java/de/avatic/lcc/service/transformer/users/UserTransformer.java +++ b/src/main/java/de/avatic/lcc/service/transformer/users/UserTransformer.java @@ -34,7 +34,7 @@ public class UserTransformer { return entity; } - private Group fromGroupDTO(String name) { + public Group fromGroupDTO(String name) { var group = new Group(); group.setName(name); return group; diff --git a/src/main/java/de/avatic/lcc/service/users/GroupService.java b/src/main/java/de/avatic/lcc/service/users/GroupService.java index 3e740cf..76ad3ba 100644 --- a/src/main/java/de/avatic/lcc/service/users/GroupService.java +++ b/src/main/java/de/avatic/lcc/service/users/GroupService.java @@ -63,6 +63,7 @@ public class GroupService { private GroupDTO toGroupDTO(Group group) { var dto = new GroupDTO(); + dto.setId(group.getId()); dto.setDescription( group.getDescription()); dto.setName(group.getName()); diff --git a/src/main/java/de/avatic/lcc/service/users/UserService.java b/src/main/java/de/avatic/lcc/service/users/UserService.java index 28dad3e..399ff82 100644 --- a/src/main/java/de/avatic/lcc/service/users/UserService.java +++ b/src/main/java/de/avatic/lcc/service/users/UserService.java @@ -2,15 +2,21 @@ package de.avatic.lcc.service.users; import de.avatic.lcc.config.LccOidcUser; import de.avatic.lcc.dto.users.UserDTO; +import de.avatic.lcc.model.db.users.Group; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; import de.avatic.lcc.repositories.users.UserRepository; import de.avatic.lcc.service.transformer.users.UserTransformer; +import de.avatic.lcc.util.exception.badrequest.NotFoundException; +import de.avatic.lcc.util.exception.base.BadRequestException; +import jakarta.validation.constraints.NotNull; +import org.hibernate.validator.constraints.Length; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; /** * Service class responsible for handling business logic related to users. @@ -60,20 +66,43 @@ public class UserService { userAuthorityCacheService.invalidateUserAuthorities(userId); } - public boolean isSuper() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - //todo make a service. and simulate user rights in dev profile. - if (authentication != null && authentication.getPrincipal() instanceof LccOidcUser oidcUser) { + public void appendGroups(String workdayId, String group) { + var optUser = userRepository.getByWorkdayId(workdayId); - return oidcUser.getAuthorities().stream().anyMatch(authority -> authority.getAuthority().equals("ROLE_SUPER")); + if (optUser.isEmpty()) { + throw new NotFoundException(NotFoundException.NotFoundType.USER, "workday id", workdayId); } + var user = optUser.get(); - return false; + var existingGroups = new TreeSet<>(Comparator.comparing(Group::getName)); + existingGroups.addAll(user.getGroups()); + existingGroups.add(userTransformer.fromGroupDTO(group)); + user.setGroups(new ArrayList<>(existingGroups)); + + userRepository.update(user); } -// public boolean canCalculate() { -// Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); -// } + public void deleteGroups(String workdayId, String groupToDelete) { + var optUser = userRepository.getByWorkdayId(workdayId); + + if (optUser.isEmpty()) throw new NotFoundException(NotFoundException.NotFoundType.USER, "workday id", workdayId); + var user = optUser.get(); + + List uniqueGroups = user.getGroups().stream() + .filter(group -> !group.getName().equals(groupToDelete)) + .collect(Collectors.toMap( + Group::getName, + group -> group, + (existing, replacement) -> existing, + LinkedHashMap::new + )) + .values() + .stream() + .toList(); + + user.setGroups(uniqueGroups); + userRepository.update(user); + } } diff --git a/src/main/java/de/avatic/lcc/util/exception/badrequest/NotFoundException.java b/src/main/java/de/avatic/lcc/util/exception/badrequest/NotFoundException.java index 3d0bc53..1e18adf 100644 --- a/src/main/java/de/avatic/lcc/util/exception/badrequest/NotFoundException.java +++ b/src/main/java/de/avatic/lcc/util/exception/badrequest/NotFoundException.java @@ -29,7 +29,8 @@ public class NotFoundException extends BadRequestException { COUNTRY_PROPERTY("Country property"), CONTAINER_RATE("Container rate"), EXPIRED_VALIDITY_PERIOD("Expired validity period"), - USER_NODE("User node"); + USER_NODE("User node"), + USER("User"); private final String identifier; diff --git a/src/main/resources/db/migration/V1__Create_schema.sql b/src/main/resources/db/migration/V1__Create_schema.sql index 1cda347..529fd00 100644 --- a/src/main/resources/db/migration/V1__Create_schema.sql +++ b/src/main/resources/db/migration/V1__Create_schema.sql @@ -300,6 +300,9 @@ CREATE TABLE IF NOT EXISTS material hs_code CHAR(11), name VARCHAR(500) NOT NULL, is_deprecated BOOLEAN NOT NULL DEFAULT FALSE, + INDEX idx_part_number (part_number), + INDEX idx_normalized_part_number (normalized_part_number), + INDEX idx_hs_code (hs_code), CONSTRAINT `uq_normalized_part_number` UNIQUE (`normalized_part_number`) ); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 0e40024..a122343 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -300,6 +300,9 @@ CREATE TABLE IF NOT EXISTS material hs_code CHAR(11), name VARCHAR(500) NOT NULL, is_deprecated BOOLEAN NOT NULL DEFAULT FALSE, + INDEX idx_part_number (part_number), + INDEX idx_normalized_part_number (normalized_part_number), + INDEX idx_hs_code (hs_code), CONSTRAINT `uq_normalized_part_number` UNIQUE (`normalized_part_number`) ); @@ -521,7 +524,9 @@ CREATE TABLE IF NOT EXISTS calculation_job FOREIGN KEY (user_id) REFERENCES sys_user (id), INDEX idx_premise_id (premise_id), INDEX idx_validity_period_id (validity_period_id), - INDEX idx_property_set_id (property_set_id) + INDEX idx_property_set_id (property_set_id), + INDEX idx_user_id (user_id) + );