autocomit

This commit is contained in:
2026-02-08 10:06:41 +01:00
parent c6bab3bd68
commit b69ff3965b
23 changed files with 1203 additions and 2 deletions
@@ -0,0 +1,89 @@
package com.ldpv2.controller;
import com.ldpv2.dto.request.CreateBusinessUnitRequest;
import com.ldpv2.dto.request.UpdateBusinessUnitRequest;
import com.ldpv2.dto.response.BusinessUnitResponse;
import com.ldpv2.service.BusinessUnitService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.UUID;
@RestController
@RequestMapping("/business-units")
@Tag(name = "Business Units", description = "Business unit management endpoints")
@SecurityRequirement(name = "bearerAuth")
public class BusinessUnitController {
@Autowired
private BusinessUnitService businessUnitService;
@PostMapping
@Operation(summary = "Create business unit", description = "Create a new business unit")
public ResponseEntity<BusinessUnitResponse> create(@Valid @RequestBody CreateBusinessUnitRequest request) {
BusinessUnitResponse response = businessUnitService.create(request);
return new ResponseEntity<>(response, HttpStatus.CREATED);
}
@PutMapping("/{id}")
@Operation(summary = "Update business unit", description = "Update an existing business unit")
public ResponseEntity<BusinessUnitResponse> update(
@PathVariable UUID id,
@Valid @RequestBody UpdateBusinessUnitRequest request) {
BusinessUnitResponse response = businessUnitService.update(id, request);
return ResponseEntity.ok(response);
}
@GetMapping("/{id}")
@Operation(summary = "Get business unit", description = "Get business unit by ID")
public ResponseEntity<BusinessUnitResponse> getById(@PathVariable UUID id) {
BusinessUnitResponse response = businessUnitService.findById(id);
return ResponseEntity.ok(response);
}
@GetMapping
@Operation(summary = "List business units", description = "Get paginated list of business units")
public ResponseEntity<Page<BusinessUnitResponse>> getAll(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(defaultValue = "name") String sortBy,
@RequestParam(defaultValue = "asc") String sortDirection) {
Sort sort = sortDirection.equalsIgnoreCase("desc")
? Sort.by(sortBy).descending()
: Sort.by(sortBy).ascending();
Pageable pageable = PageRequest.of(page, size, sort);
Page<BusinessUnitResponse> response = businessUnitService.findAll(pageable);
return ResponseEntity.ok(response);
}
@GetMapping("/search")
@Operation(summary = "Search business units", description = "Search business units by name")
public ResponseEntity<Page<BusinessUnitResponse>> search(
@RequestParam String q,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
Pageable pageable = PageRequest.of(page, size);
Page<BusinessUnitResponse> response = businessUnitService.search(q, pageable);
return ResponseEntity.ok(response);
}
@DeleteMapping("/{id}")
@Operation(summary = "Delete business unit", description = "Delete a business unit")
public ResponseEntity<Void> delete(@PathVariable UUID id) {
businessUnitService.delete(id);
return ResponseEntity.noContent().build();
}
}
@@ -0,0 +1,25 @@
package com.ldpv2.domain.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* Business Unit entity representing organizational units
*/
@Data
@Entity
@Table(name = "business_unit")
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class BusinessUnit extends BaseEntity {
@Column(nullable = false, unique = true, length = 255)
private String name;
@Column(columnDefinition = "TEXT")
private String description;
}
@@ -0,0 +1,19 @@
package com.ldpv2.dto.request;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CreateBusinessUnitRequest {
@NotBlank(message = "Name is required")
@Size(max = 255, message = "Name must not exceed 255 characters")
private String name;
private String description;
}
@@ -0,0 +1,17 @@
package com.ldpv2.dto.request;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UpdateBusinessUnitRequest {
@Size(max = 255, message = "Name must not exceed 255 characters")
private String name;
private String description;
}
@@ -0,0 +1,19 @@
package com.ldpv2.dto.response;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.UUID;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BusinessUnitResponse {
private UUID id;
private String name;
private String description;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
@@ -0,0 +1,15 @@
package com.ldpv2.dto.response;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.UUID;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BusinessUnitSummaryResponse {
private UUID id;
private String name;
}
@@ -0,0 +1,17 @@
package com.ldpv2.repository;
import com.ldpv2.domain.entity.BusinessUnit;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
import java.util.UUID;
@Repository
public interface BusinessUnitRepository extends JpaRepository<BusinessUnit, UUID> {
Optional<BusinessUnit> findByName(String name);
boolean existsByName(String name);
Page<BusinessUnit> findByNameContainingIgnoreCase(String name, Pageable pageable);
}
@@ -0,0 +1,92 @@
package com.ldpv2.service;
import com.ldpv2.domain.entity.BusinessUnit;
import com.ldpv2.dto.request.CreateBusinessUnitRequest;
import com.ldpv2.dto.request.UpdateBusinessUnitRequest;
import com.ldpv2.dto.response.BusinessUnitResponse;
import com.ldpv2.exception.BadRequestException;
import com.ldpv2.exception.ResourceNotFoundException;
import com.ldpv2.repository.BusinessUnitRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.UUID;
@Service
public class BusinessUnitService {
@Autowired
private BusinessUnitRepository businessUnitRepository;
@Transactional
public BusinessUnitResponse create(CreateBusinessUnitRequest request) {
// Check if name already exists
if (businessUnitRepository.existsByName(request.getName())) {
throw new BadRequestException("Business unit with name '" + request.getName() + "' already exists");
}
BusinessUnit businessUnit = new BusinessUnit();
businessUnit.setName(request.getName());
businessUnit.setDescription(request.getDescription());
businessUnit = businessUnitRepository.save(businessUnit);
return mapToResponse(businessUnit);
}
@Transactional
public BusinessUnitResponse update(UUID id, UpdateBusinessUnitRequest request) {
BusinessUnit businessUnit = businessUnitRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Business unit not found with id: " + id));
// Check if new name already exists (excluding current business unit)
if (request.getName() != null && !request.getName().equals(businessUnit.getName())) {
if (businessUnitRepository.existsByName(request.getName())) {
throw new BadRequestException("Business unit with name '" + request.getName() + "' already exists");
}
businessUnit.setName(request.getName());
}
if (request.getDescription() != null) {
businessUnit.setDescription(request.getDescription());
}
businessUnit = businessUnitRepository.save(businessUnit);
return mapToResponse(businessUnit);
}
public BusinessUnitResponse findById(UUID id) {
BusinessUnit businessUnit = businessUnitRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Business unit not found with id: " + id));
return mapToResponse(businessUnit);
}
public Page<BusinessUnitResponse> findAll(Pageable pageable) {
return businessUnitRepository.findAll(pageable).map(this::mapToResponse);
}
public Page<BusinessUnitResponse> search(String query, Pageable pageable) {
return businessUnitRepository.findByNameContainingIgnoreCase(query, pageable)
.map(this::mapToResponse);
}
@Transactional
public void delete(UUID id) {
if (!businessUnitRepository.existsById(id)) {
throw new ResourceNotFoundException("Business unit not found with id: " + id);
}
businessUnitRepository.deleteById(id);
}
private BusinessUnitResponse mapToResponse(BusinessUnit businessUnit) {
return new BusinessUnitResponse(
businessUnit.getId(),
businessUnit.getName(),
businessUnit.getDescription(),
businessUnit.getCreatedAt(),
businessUnit.getUpdatedAt()
);
}
}
@@ -12,7 +12,7 @@
<insert tableName="users">
<column name="username" value="admin"/>
<!-- <column name="password" value="$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"/>-->
<column name="password" value="$2a$12$ZDflpzoNCyt/hDu9PyMqE.jinzhLtQ8Cjc/NgvXU7BIxni.SH2PnW"/>
<column name="password" value="$2a$12$mCGWGeNM3r11.yFhPFi22e./YQl2pRTIpJBVUwydScZioE3y6xm3m"/>
<column name="email" value="admin@ldpv2.com"/>
<column name="role" value="ADMIN"/>
</insert>
@@ -10,4 +10,7 @@
<include file="db/changelog/v1.0/002-create-environment-table.xml"/>
<include file="db/changelog/data/initial-data.xml"/>
<!-- Story 1: Business Units -->
<include file="db/changelog/v1.0/003-create-business-unit-table.xml"/>
</databaseChangeLog>
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="003-create-business-unit-table" author="ldpv2-team">
<!-- Create business_unit table -->
<createTable tableName="business_unit">
<column name="id" type="UUID" defaultValueComputed="uuid_generate_v4()">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="VARCHAR(255)">
<constraints nullable="false" unique="true"/>
</column>
<column name="description" type="TEXT"/>
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP">
<constraints nullable="false"/>
</column>
<column name="updated_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP">
<constraints nullable="false"/>
</column>
</createTable>
<!-- Create index on name for search performance -->
<createIndex tableName="business_unit" indexName="idx_business_unit_name">
<column name="name"/>
</createIndex>
<!-- Insert sample data for testing -->
<insert tableName="business_unit">
<column name="name" value="Digital Services"/>
<column name="description" value="Digital transformation initiatives and online services"/>
</insert>
<insert tableName="business_unit">
<column name="name" value="Operations"/>
<column name="description" value="Core business operations and support"/>
</insert>
<insert tableName="business_unit">
<column name="name" value="Finance"/>
<column name="description" value="Financial services and accounting systems"/>
</insert>
<insert tableName="business_unit">
<column name="name" value="Human Resources"/>
<column name="description" value="HR management and employee services"/>
</insert>
</changeSet>
</databaseChangeLog>