feat(account): add eligible Intern picker query
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
package com.lab.labtimesheet.feature.account.model.dto;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Immutable non-secret selection data for an eligible Intern.
|
||||
* The numeric user ID is the internal form submission identity; displayed fields are not authorization identifiers.
|
||||
*
|
||||
* @param userId persistent account identifier submitted by a consuming form
|
||||
* @param displayName user-facing Intern name
|
||||
* @param studentCode university student code shown to distinguish Interns
|
||||
* @param internshipStart inclusive internship eligibility start date
|
||||
* @param internshipEnd inclusive internship eligibility end date
|
||||
*/
|
||||
public record EligibleInternOption(
|
||||
long userId,
|
||||
String displayName,
|
||||
String studentCode,
|
||||
LocalDate internshipStart,
|
||||
LocalDate internshipEnd) {
|
||||
}
|
||||
+32
@@ -1,8 +1,12 @@
|
||||
package com.lab.labtimesheet.feature.account.repository;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import com.lab.labtimesheet.feature.account.model.AccountStatus;
|
||||
import com.lab.labtimesheet.feature.account.model.GlobalRole;
|
||||
import com.lab.labtimesheet.feature.account.model.InternshipStatus;
|
||||
import com.lab.labtimesheet.feature.account.model.dto.EligibleInternOption;
|
||||
import com.lab.labtimesheet.feature.account.model.entity.InternProfile;
|
||||
import jakarta.persistence.LockModeType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
@@ -19,6 +23,34 @@ public interface InternProfileRepository extends JpaRepository<InternProfile, Lo
|
||||
boolean existsByUserIdAndInternshipStatusAndInternshipStartDateLessThanEqualAndInternshipEndDateGreaterThanEqual(
|
||||
Long userId, InternshipStatus status, LocalDate latestStartDate, LocalDate earliestEndDate);
|
||||
|
||||
/**
|
||||
* Projects account-owned non-secret selection data for Interns eligible on one inclusive business date.
|
||||
* Results are ordered by display name, student code, then user ID for deterministic form rendering.
|
||||
*
|
||||
* @param globalRole required immutable Intern role
|
||||
* @param accountStatus required active account state
|
||||
* @param internshipStatus required active internship state
|
||||
* @param businessDate date that must fall within the inclusive internship range
|
||||
* @return eligible Intern selection projections without duplicate profile rows
|
||||
*/
|
||||
@Query("""
|
||||
select new com.lab.labtimesheet.feature.account.model.dto.EligibleInternOption(
|
||||
u.id, u.displayName, p.studentCode, p.internshipStartDate, p.internshipEndDate)
|
||||
from InternProfile p
|
||||
join AppUser u on u.id = p.userId
|
||||
where u.globalRole = :globalRole
|
||||
and u.accountStatus = :accountStatus
|
||||
and p.internshipStatus = :internshipStatus
|
||||
and p.internshipStartDate <= :businessDate
|
||||
and p.internshipEndDate >= :businessDate
|
||||
order by u.displayName asc, p.studentCode asc, u.id asc
|
||||
""")
|
||||
List<EligibleInternOption> findEligibleInternOptions(
|
||||
@Param("globalRole") GlobalRole globalRole,
|
||||
@Param("accountStatus") AccountStatus accountStatus,
|
||||
@Param("internshipStatus") InternshipStatus internshipStatus,
|
||||
@Param("businessDate") LocalDate businessDate);
|
||||
|
||||
/** Counts Intern profiles in a lifecycle state. */
|
||||
long countByInternshipStatus(InternshipStatus status);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import com.lab.labtimesheet.feature.account.model.AccountStatus;
|
||||
import com.lab.labtimesheet.feature.account.model.GlobalRole;
|
||||
@@ -17,6 +18,7 @@ import com.lab.labtimesheet.feature.account.model.dto.AccountCreation;
|
||||
import com.lab.labtimesheet.feature.account.model.dto.AccountIdentity;
|
||||
import com.lab.labtimesheet.feature.account.model.dto.AccountSummary;
|
||||
import com.lab.labtimesheet.feature.account.model.dto.CreateAccountCommand;
|
||||
import com.lab.labtimesheet.feature.account.model.dto.EligibleInternOption;
|
||||
import com.lab.labtimesheet.feature.account.model.entity.AppUser;
|
||||
import com.lab.labtimesheet.feature.account.model.entity.InternProfile;
|
||||
import com.lab.labtimesheet.feature.account.model.entity.UserActionToken;
|
||||
@@ -238,6 +240,24 @@ public class AccountService {
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists non-secret Intern selection options eligible on an explicit business date.
|
||||
* The result requires active account and internship states plus inclusive internship dates, but it does not
|
||||
* authorize a consuming Project operation; that operation must recheck its own ownership and membership rules.
|
||||
*
|
||||
* @param businessDate server-derived business date to evaluate inclusively
|
||||
* @return deterministic options ordered by display name, student code, then account ID
|
||||
* @throws IllegalArgumentException when {@code businessDate} is {@code null}
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public List<EligibleInternOption> eligibleInternOptions(LocalDate businessDate) {
|
||||
if (businessDate == null) {
|
||||
throw new IllegalArgumentException("Business date is required");
|
||||
}
|
||||
return internProfiles.findEligibleInternOptions(
|
||||
GlobalRole.INTERN, AccountStatus.ACTIVE, InternshipStatus.ACTIVE, businessDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the cross-feature identity of a currently eligible Intern.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user