Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: inc seedlot status and draft update #1497

Merged
merged 6 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ public final class Constants {

public static final Integer CLASS_A_SEEDLOT_NUM_MIN = 63000;
public static final Integer CLASS_A_SEEDLOT_NUM_MAX = 69999;
public static final String CLASS_A_SEEDLOT_STATUS = "PND";
public static final String INCOMPLETE_SEEDLOT_STATUS = "INC";
public static final String PENDING_SEEDLOT_STATUS = "PND";
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package ca.bc.gov.backendstartapi.service;

import ca.bc.gov.backendstartapi.config.Constants;
import ca.bc.gov.backendstartapi.config.SparLog;
import ca.bc.gov.backendstartapi.dto.RevisionCountDto;
import ca.bc.gov.backendstartapi.dto.SaveSeedlotFormDtoClassA;
import ca.bc.gov.backendstartapi.entity.SaveSeedlotProgressEntityClassA;
import ca.bc.gov.backendstartapi.entity.SeedlotStatusEntity;
import ca.bc.gov.backendstartapi.entity.seedlot.Seedlot;
import ca.bc.gov.backendstartapi.exception.JsonParsingException;
import ca.bc.gov.backendstartapi.exception.RevisionCountMismatchException;
import ca.bc.gov.backendstartapi.exception.SeedlotFormProgressNotFoundException;
import ca.bc.gov.backendstartapi.exception.SeedlotNotFoundException;
import ca.bc.gov.backendstartapi.exception.SeedlotStatusNotFoundException;
import ca.bc.gov.backendstartapi.repository.SaveSeedlotProgressRepositoryClassA;
import ca.bc.gov.backendstartapi.repository.SeedlotRepository;
import ca.bc.gov.backendstartapi.security.LoggedUserService;
Expand All @@ -31,6 +34,7 @@ public class SaveSeedlotFormService {
private final SaveSeedlotProgressRepositoryClassA saveSeedlotProgressRepositoryClassA;
private final SeedlotRepository seedlotRepository;
private final LoggedUserService loggedUserService;
private final SeedlotStatusService seedlotStatusService;

/** Saves the {@link SaveSeedlotFormDtoClassA} to table. */
public RevisionCountDto saveFormClassA(
Expand Down Expand Up @@ -63,19 +67,40 @@ public RevisionCountDto saveFormClassA(
parsedAllStepData,
parsedProgressStatus,
loggedUserService.createAuditCurrentUser());

// Update the seedlot status to pending from incomplete.
if (relatedSeedlot
.getSeedlotStatus()
.getSeedlotStatusCode()
.equals(Constants.INCOMPLETE_SEEDLOT_STATUS)) {
SparLog.info("Updating seedlot {} status from INC to PND", seedlotNumber);

Optional<SeedlotStatusEntity> seedLotStatusEntity =
seedlotStatusService.findById(Constants.PENDING_SEEDLOT_STATUS);

relatedSeedlot.setSeedlotStatus(
seedLotStatusEntity.orElseThrow(SeedlotStatusNotFoundException::new));
}
} else {
// Revision Count verification
Integer prevRevCount = data.revisionCount();
Integer currRevCount = optionalEntityToSave.get().getRevisionCount();

if (prevRevCount != null && !prevRevCount.equals(currRevCount)) {
// Conflict detected
SparLog.info(
"Save progress failed due to revision count mismatch, prev revision count: {}, curr"
+ " revision count: {}",
prevRevCount,
currRevCount);
throw new RevisionCountMismatchException();

// Revision Count verification only for pending seedlots
if (relatedSeedlot
.getSeedlotStatus()
.getSeedlotStatusCode()
.equals(Constants.PENDING_SEEDLOT_STATUS)) {

Integer prevRevCount = data.revisionCount();
Integer currRevCount = optionalEntityToSave.get().getRevisionCount();

if (prevRevCount != null && !prevRevCount.equals(currRevCount)) {
// Conflict detected
SparLog.info(
"Save progress failed due to revision count mismatch, prev revision count: {}, curr"
+ " revision count: {}",
prevRevCount,
currRevCount);
throw new RevisionCountMismatchException();
}
}

SparLog.info(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,11 @@ public SeedlotStatusResponseDto createSeedlot(SeedlotCreateDto createDto) {

Seedlot seedlot = new Seedlot(nextSeedlotNumber(createDto.geneticClassCode()));

// Newly created seedlot has a status of INCOMPLETE, will change to PENDING once a row is
// created in the table seedlot_registration_a_class_save
Optional<SeedlotStatusEntity> seedLotStatusEntity =
seedlotStatusService.findById(Constants.CLASS_A_SEEDLOT_STATUS);
seedlot.setSeedlotStatus(seedLotStatusEntity.orElseThrow(InvalidSeedlotRequestException::new));
seedlotStatusService.findById(Constants.INCOMPLETE_SEEDLOT_STATUS);
seedlot.setSeedlotStatus(seedLotStatusEntity.orElseThrow(SeedlotStatusNotFoundException::new));

seedlot.setApplicantClientNumber(createDto.applicantClientNumber());
seedlot.setApplicantLocationCode(createDto.applicantLocationCode());
Expand All @@ -147,11 +149,11 @@ public SeedlotStatusResponseDto createSeedlot(SeedlotCreateDto createDto) {

Optional<GeneticClassEntity> classEntity =
geneticClassRepository.findById(createDto.geneticClassCode().toString());
seedlot.setGeneticClass(classEntity.orElseThrow(InvalidSeedlotRequestException::new));
seedlot.setGeneticClass(classEntity.orElseThrow(GeneticClassNotFoundException::new));

Optional<SeedlotSourceEntity> seedlotSourceEntity =
seedlotSourceRepository.findById(createDto.seedlotSourceCode());
seedlot.setSeedlotSource(seedlotSourceEntity.orElseThrow(InvalidSeedlotRequestException::new));
seedlot.setSeedlotSource(seedlotSourceEntity.orElseThrow(SeedlotSourceNotFoundException::new));

seedlot.setIntendedForCrownLand(createDto.toBeRegistrdInd());
seedlot.setSourceInBc(createDto.bcSourceInd());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import ca.bc.gov.backendstartapi.dto.SaveSeedlotFormDtoClassA;
import ca.bc.gov.backendstartapi.entity.SaveSeedlotProgressEntityClassA;
import ca.bc.gov.backendstartapi.entity.SeedlotStatusEntity;
import ca.bc.gov.backendstartapi.entity.seedlot.Seedlot;
import ca.bc.gov.backendstartapi.repository.SaveSeedlotProgressRepositoryClassA;
import ca.bc.gov.backendstartapi.repository.SeedlotRepository;
Expand All @@ -31,21 +32,29 @@ class SaveSeedlotFormServiceTest {
@Mock SaveSeedlotProgressRepositoryClassA saveSeedlotProgressRepositoryClassA;
@Mock SeedlotRepository seedlotRepository;
@Mock LoggedUserService loggedUserService;
@Mock SeedlotStatusService seedlotStatusService;

private SaveSeedlotFormService saveSeedlotFormService;

private static final String SEEDLOT_NUMBER = "678123";

private Seedlot testSeedlot = new Seedlot(SEEDLOT_NUMBER);

private SeedlotStatusEntity pndStatus = new SeedlotStatusEntity("PND", null, null);

@BeforeEach
void setup() {
saveSeedlotFormService =
new SaveSeedlotFormService(
saveSeedlotProgressRepositoryClassA, seedlotRepository, loggedUserService);
saveSeedlotProgressRepositoryClassA,
seedlotRepository,
loggedUserService,
seedlotStatusService);

when(loggedUserService.getLoggedUserInfo()).thenReturn(Optional.of(UserInfo.createDevUser()));

when(seedlotStatusService.findById(any())).thenReturn(Optional.of(pndStatus));

testSeedlot.setApplicantClientNumber(UserInfo.getDevClientNumber());
}

Expand All @@ -72,6 +81,8 @@ void saveSeedlotProgress_seedlotMissing_shouldFail() throws Exception {
@DisplayName("Save seedlot progress with missing seedlot should succeed.")
void saveSeedlotProgress_shouldSucceed() throws Exception {

testSeedlot.setSeedlotStatus(pndStatus);

when(seedlotRepository.findById(any())).thenReturn(Optional.of(testSeedlot));

when(saveSeedlotProgressRepositoryClassA.save(any()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@
import ca.bc.gov.backendstartapi.entity.seedlot.SeedlotOrchard;
import ca.bc.gov.backendstartapi.entity.seedlot.SeedlotOwnerQuantity;
import ca.bc.gov.backendstartapi.exception.ClientIdForbiddenException;
import ca.bc.gov.backendstartapi.exception.GeneticClassNotFoundException;
import ca.bc.gov.backendstartapi.exception.InvalidSeedlotRequestException;
import ca.bc.gov.backendstartapi.exception.SeedlotConflictDataException;
import ca.bc.gov.backendstartapi.exception.SeedlotNotFoundException;
import ca.bc.gov.backendstartapi.exception.SeedlotSourceNotFoundException;
import ca.bc.gov.backendstartapi.exception.SeedlotStatusNotFoundException;
import ca.bc.gov.backendstartapi.provider.Provider;
import ca.bc.gov.backendstartapi.repository.GeneticClassRepository;
import ca.bc.gov.backendstartapi.repository.SeedlotRepository;
Expand Down Expand Up @@ -178,9 +180,11 @@ void setup() {
@DisplayName("createSeedlotSuccessTest")
void createSeedlotTest_happyPath_shouldSucceed() {
when(seedlotRepository.findNextSeedlotNumber(anyInt(), anyInt())).thenReturn(63000);
String incStatusCode = "INC";

SeedlotStatusEntity statusEntity = new SeedlotStatusEntity("PND", "Pending", DATE_RANGE);
when(seedlotStatusService.findById("PND")).thenReturn(Optional.of(statusEntity));
SeedlotStatusEntity incStatusEntity =
new SeedlotStatusEntity(incStatusCode, "Incomplete", DATE_RANGE);
when(seedlotStatusService.findById(incStatusCode)).thenReturn(Optional.of(incStatusEntity));

SeedlotSourceEntity sourceEntity =
new SeedlotSourceEntity("TPT", "Tested Parent Trees", DATE_RANGE, null);
Expand Down Expand Up @@ -222,57 +226,54 @@ void createSeedlotTest_bClassSeedlot_shouldThrowException() {
void createSeedlotTest_noSeedlotStatus_shouldThrowException() {
when(seedlotRepository.findNextSeedlotNumber(anyInt(), anyInt())).thenReturn(63000);

when(seedlotStatusService.findById("PND")).thenReturn(Optional.empty());
when(seedlotStatusService.findById(any())).thenReturn(Optional.empty());

Exception exc =
Assertions.assertThrows(
InvalidSeedlotRequestException.class,
() -> {
seedlotService.createSeedlot(createSeedlotDto());
});

Assertions.assertEquals(BAD_REQUEST_STR, exc.getMessage());
Assertions.assertThrows(
SeedlotStatusNotFoundException.class,
() -> {
seedlotService.createSeedlot(createSeedlotDto());
});
}

@Test
@DisplayName("createSeedlotAClassWithoutGeneticClassEntity")
void createSeedlotTest_noGeneticClass_shouldThrowException() {
SeedlotStatusEntity statusEntity = new SeedlotStatusEntity("PND", "Pending", DATE_RANGE);
when(seedlotStatusService.findById("PND")).thenReturn(Optional.of(statusEntity));
String incStatusCode = "INC";

when(geneticClassRepository.findById("A")).thenReturn(Optional.empty());
SeedlotStatusEntity incStatusEntity =
new SeedlotStatusEntity(incStatusCode, "Incomplete", DATE_RANGE);
when(seedlotStatusService.findById(incStatusCode)).thenReturn(Optional.of(incStatusEntity));

Exception exc =
Assertions.assertThrows(
InvalidSeedlotRequestException.class,
() -> {
seedlotService.createSeedlot(createSeedlotDto());
});
when(geneticClassRepository.findById("A")).thenReturn(Optional.empty());

Assertions.assertEquals(BAD_REQUEST_STR, exc.getMessage());
Assertions.assertThrows(
GeneticClassNotFoundException.class,
() -> {
seedlotService.createSeedlot(createSeedlotDto());
});
}

@Test
@DisplayName("createSeedlotAClassWithoutSeedlotSourceEntity")
void createSeedlotTest_noSeedlotSource_shouldThrowException() {
when(seedlotRepository.findNextSeedlotNumber(anyInt(), anyInt())).thenReturn(63000);

SeedlotStatusEntity statusEntity = new SeedlotStatusEntity("PND", "Pending", DATE_RANGE);
when(seedlotStatusService.findById("PND")).thenReturn(Optional.of(statusEntity));
String incStatusCode = "INC";

SeedlotStatusEntity incStatusEntity =
new SeedlotStatusEntity(incStatusCode, "Incomplete", DATE_RANGE);
when(seedlotStatusService.findById(incStatusCode)).thenReturn(Optional.of(incStatusEntity));

GeneticClassEntity classEntity = new GeneticClassEntity("A", "A class seedlot", DATE_RANGE);
when(geneticClassRepository.findById("A")).thenReturn(Optional.of(classEntity));

when(seedlotSourceRepository.findById("TPT")).thenReturn(Optional.empty());

Exception exc =
Assertions.assertThrows(
InvalidSeedlotRequestException.class,
() -> {
seedlotService.createSeedlot(createSeedlotDto());
});

Assertions.assertEquals(BAD_REQUEST_STR, exc.getMessage());
Assertions.assertThrows(
SeedlotSourceNotFoundException.class,
() -> {
seedlotService.createSeedlot(createSeedlotDto());
});
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ describe('A Class Seedlot Registration form, Ownership', () => {
cy.saveSeedlotRegFormProgress();
});

it.only('Funding source and method of payment default values and change the values', () => {
it('Funding source and method of payment default values and change the values', () => {
// Expand the funding source combo box
cy.get('#ownership-funding-source-0')
.should('have.value', '')
Expand Down
2 changes: 1 addition & 1 deletion frontend/cypress/e2e/smoke-test/seedlot-dashboard.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('Seedlot Dashboard test', () => {
const seedlotNumber = sNumber as string;

cy.get(`#seedlot-table-cell-${seedlotNumber}-seedlotSpecies`).should('have.text', species);
cy.get(`#seedlot-table-cell-${seedlotNumber}-seedlotStatus`).should('have.text', 'Pending');
cy.get(`#seedlot-table-cell-${seedlotNumber}-seedlotStatus`).should('have.text', 'Incomplete');
});
});
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/cypress/e2e/smoke-test/seedlot-detail.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe('Seedlot detail page', () => {
cy.contains('p.seedlot-summary-info-label', 'Status')
.next()
.children('span')
.should('have.text', 'Pending');
.should('have.text', 'Incomplete');

cy.contains('p.seedlot-summary-info-label', 'Approved at')
.siblings('p.seedlot-summary-info-value')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Column, Row, FlexGrid } from '@carbon/react';

import ReadOnlyInput from '../../ReadOnlyInput';
import ClassAContext from '../../../views/Seedlot/ContextContainerClassA/context';
import { utcToIsoSlashStyle } from '../../../utils/DateUtils';

const AuditInfo = () => {
const {
Expand All @@ -29,7 +30,7 @@ const AuditInfo = () => {
<ReadOnlyInput
id="created-at"
label="Created at:"
value={seedlotData?.auditInformation.entryTimestamp}
value={utcToIsoSlashStyle(seedlotData?.auditInformation.entryTimestamp)}
showSkeleton={isFetchingData}
/>
</Column>
Expand All @@ -47,7 +48,7 @@ const AuditInfo = () => {
<ReadOnlyInput
id="last-updated-at"
label="Last updated at:"
value={seedlotData?.auditInformation.updateTimestamp}
value={utcToIsoSlashStyle(seedlotData?.auditInformation.updateTimestamp)}
showSkeleton={isFetchingData}
/>
</Column>
Expand All @@ -65,7 +66,7 @@ const AuditInfo = () => {
<ReadOnlyInput
id="submitted-at"
label="Submitted at:"
value={seedlotData?.declarationOfTrueInformationTimestamp}
value={utcToIsoSlashStyle(seedlotData?.declarationOfTrueInformationTimestamp)}
showSkeleton={isFetchingData}
/>
</Column>
Expand All @@ -83,7 +84,7 @@ const AuditInfo = () => {
<ReadOnlyInput
id="approved-at"
label="Approved at:"
value={seedlotData?.approvedTimestamp ?? undefined}
value={utcToIsoSlashStyle(seedlotData?.approvedTimestamp)}
showSkeleton={isFetchingData}
/>
</Column>
Expand Down
1 change: 0 additions & 1 deletion frontend/src/utils/DateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export const utcToApStyle = (utcDate: string | null | undefined): string => {
* Convert UTC timestamp to ISO 8601 style with slashes (e.g. 2023/10/26)
*/
export const utcToIsoSlashStyle = (utcDate: string | null | undefined): string => {
console.log(utcDate);
if (!utcDate) {
return '';
}
Expand Down
25 changes: 16 additions & 9 deletions frontend/src/views/Seedlot/SeedlotRegFormClassA/RegPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
InlineLoading,
InlineNotification,
ActionableNotification,
Loading
Loading,
ProgressIndicatorSkeleton
} from '@carbon/react';
import { ArrowRight } from '@carbon/icons-react';
import { useNavigate } from 'react-router-dom';
Expand Down Expand Up @@ -89,17 +90,23 @@ const RegPage = () => {
</Row>
<Row>
<Column className="seedlot-registration-progress">
<SeedlotRegistrationProgress
progressStatus={
seedlotData?.seedlotStatus.seedlotStatusCode === 'PND' || seedlotData?.seedlotStatus.seedlotStatusCode === 'INC'
{
seedlotData
? (
<SeedlotRegistrationProgress
progressStatus={
seedlotData.seedlotStatus.seedlotStatusCode === 'PND' || seedlotData.seedlotStatus.seedlotStatusCode === 'INC'
? progressStatus
: completeProgressConfig
}
interactFunction={(e: number) => {
updateProgressStatus(e, formStep);
setStep((e - formStep));
}}
/>
interactFunction={(e: number) => {
updateProgressStatus(e, formStep);
setStep((e - formStep));
}}
/>
)
: <ProgressIndicatorSkeleton />
}
</Column>
</Row>
{
Expand Down
Loading
Loading