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

psp-9457 leases allow disposed properties to be added. #4532

Merged
merged 1 commit into from
Dec 17, 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
14 changes: 8 additions & 6 deletions source/backend/api/Services/LeaseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,6 @@ public PimsLease Update(PimsLease lease, IEnumerable<UserOverrideCode> userOverr
pimsUser.ThrowInvalidAccessToLeaseFile(lease.RegionCode);

var currentFileProperties = _propertyLeaseRepository.GetAllByLeaseId(lease.LeaseId);
var newPropertiesAdded = lease.PimsPropertyLeases.Where(x => !currentFileProperties.Any(y => y.Internal_Id == x.Internal_Id)).ToList();

if (newPropertiesAdded.Any(x => x.Property.IsRetired.HasValue && x.Property.IsRetired.Value))
{
throw new BusinessRuleViolationException("Retired property can not be selected.");
}

if (currentLease.LeaseStatusTypeCode != lease.LeaseStatusTypeCode)
{
Expand Down Expand Up @@ -553,8 +547,11 @@ private PimsLease AssociatePropertyLeases(PimsLease lease, IEnumerable<UserOverr
{
PimsProperty property = propertyLease.Property;
var existingPropertyLeases = _propertyLeaseRepository.GetAllByPropertyId(property.PropertyId);
var propertyWithAssociations = _propertyRepository.GetAllAssociationsById(property.PropertyId);
var isPropertyOnOtherLease = existingPropertyLeases.Any(p => p.LeaseId != lease.Internal_Id);
var isPropertyOnThisLease = existingPropertyLeases.Any(p => p.LeaseId == lease.Internal_Id);
var isDisposedOrRetired = existingPropertyLeases.Any(p => p.Property.IsRetired.HasValue && p.Property.IsRetired.Value)
|| propertyWithAssociations?.PimsDispositionFileProperties?.Any(d => d.DispositionFile.DispositionFileStatusTypeCode == DispositionFileStatusTypes.COMPLETE.ToString()) == true;

if (isPropertyOnOtherLease && !isPropertyOnThisLease && !userOverrides.Contains(UserOverrideCode.AddPropertyToInventory))
{
Expand All @@ -573,6 +570,11 @@ private PimsLease AssociatePropertyLeases(PimsLease lease, IEnumerable<UserOverr
throw new UserOverrideException(UserOverrideCode.AddPropertyToInventory, overrideError);
}

if (isDisposedOrRetired && !isPropertyOnThisLease)
{
throw new BusinessRuleViolationException("Disposed or retired properties may not be added to a Lease. Remove any disposed or retired properties before continuing.");
}

// If the property exist dont update it, just refer to it by id.
if (property.Internal_Id != 0)
{
Expand Down
166 changes: 164 additions & 2 deletions source/backend/tests/unit/api/Services/LeaseServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,63 @@ public void Add_WithRetiredProperty_Should_Fail()
propertyService.Verify(x => x.PopulateNewFileProperty(It.IsAny<PimsPropertyLease>()), Times.Never);
}

[Fact]
public void Add_WithDisposedProperty_Should_Fail()
{
// Arrange
var lease = EntityHelper.CreateLease(1);
lease.RegionCode = 1;
var user = EntityHelper.CreateUser("Test");
user.PimsRegionUsers.Add(new PimsRegionUser() { RegionCode = lease.RegionCode.Value });

PimsProperty newProperty = new PimsProperty()
{
PropertyId = 100,
Pid = 1000,
};

PimsProperty disposedProperty = new PimsProperty()
{
PropertyId = 100,
Pid = 1000,
PimsDispositionFileProperties = new List<PimsDispositionFileProperty>()
{
new PimsDispositionFileProperty()
{
DispositionFile = new PimsDispositionFile()
{
DispositionFileId = 1,
DispositionFileStatusTypeCode = DispositionFileStatusTypes.COMPLETE.ToString(),
},
},
},
};

var service = this.CreateLeaseService(Permissions.LeaseAdd);

var leaseRepository = this._helper.GetService<Mock<ILeaseRepository>>();
leaseRepository.Setup(x => x.Add(It.IsAny<PimsLease>())).Returns(lease);

var propertyRepository = this._helper.GetService<Mock<IPropertyRepository>>();
propertyRepository.Setup(x => x.GetByPid(It.IsAny<int>(), true)).Returns(newProperty);
propertyRepository.Setup(x => x.GetAllAssociationsById(It.IsAny<long>())).Returns(disposedProperty);

var userRepository = this._helper.GetService<Mock<IUserRepository>>();
userRepository.Setup(x => x.GetByKeycloakUserId(It.IsAny<Guid>())).Returns(user);

var propertyService = this._helper.GetService<Mock<IPropertyService>>();

// Act
Action act = () => service.Add(lease, new List<UserOverrideCode>());

// Assert
var ex = act.Should().Throw<BusinessRuleViolationException>();
ex.WithMessage("Disposed or retired properties may not be added to a Lease. Remove any disposed or retired properties before continuing.");

leaseRepository.Verify(x => x.Add(It.IsAny<PimsLease>()), Times.Never);
propertyService.Verify(x => x.PopulateNewFileProperty(It.IsAny<PimsPropertyLease>()), Times.Never);
}

#endregion

#region Properties
Expand Down Expand Up @@ -464,7 +521,56 @@ public void UpdateProperties_Success()
}

[Fact]
public void UpdateProperties_WithRetiredProperty_Should_Fail()
public void UpdateProperties_WithDisposedProperty_Should_Fail()
{
// Arrange
var lease = EntityHelper.CreateLease(1);

var service = this.CreateLeaseService(Permissions.LeaseEdit, Permissions.PropertyAdd, Permissions.PropertyView);
var leaseRepository = this._helper.GetService<Mock<ILeaseRepository>>();
var propertyLeaseRepository = this._helper.GetService<Mock<IPropertyLeaseRepository>>();
var propertyRepository = this._helper.GetService<Mock<IPropertyRepository>>();
var userRepository = this._helper.GetService<Mock<IUserRepository>>();

PimsProperty property = new PimsProperty()
{
PropertyId = 100,
Pid = 1,
};

PimsProperty disposedProperty = new PimsProperty()
{
PropertyId = 100,
Pid = 1000,
PimsDispositionFileProperties = new List<PimsDispositionFileProperty>()
{
new PimsDispositionFileProperty()
{
DispositionFile = new PimsDispositionFile()
{
DispositionFileId = 1,
DispositionFileStatusTypeCode = DispositionFileStatusTypes.COMPLETE.ToString(),
},
},
},
};

propertyRepository.Setup(x => x.GetByPid(It.IsAny<int>(), true)).Returns(property);
propertyRepository.Setup(x => x.GetAllAssociationsById(It.IsAny<long>())).Returns(disposedProperty);
leaseRepository.Setup(x => x.GetNoTracking(It.IsAny<long>())).Returns(lease);
leaseRepository.Setup(x => x.Get(It.IsAny<long>())).Returns(EntityHelper.CreateLease(1));
userRepository.Setup(x => x.GetByKeycloakUserId(It.IsAny<Guid>())).Returns(EntityHelper.CreateUser("Test"));

// Act
Action act = () => service.Update(lease, new List<UserOverrideCode>() { UserOverrideCode.AddLocationToProperty });

// Assert
var ex = act.Should().Throw<BusinessRuleViolationException>();
ex.WithMessage("Disposed or retired properties may not be added to a Lease. Remove any disposed or retired properties before continuing.");
}

[Fact]
public void UpdateProperties_WithExistingDisposedProperty_Should_Pass()
{
// Arrange
var lease = EntityHelper.CreateLease(1);
Expand All @@ -479,10 +585,65 @@ public void UpdateProperties_WithRetiredProperty_Should_Fail()
{
PropertyId = 100,
Pid = 1,
IsRetired = true,
};

PimsProperty disposedProperty = new PimsProperty()
{
PropertyId = 100,
Pid = 1000,
PimsDispositionFileProperties = new List<PimsDispositionFileProperty>()
{
new PimsDispositionFileProperty()
{
DispositionFile = new PimsDispositionFile()
{
DispositionFileId = 1,
DispositionFileStatusTypeCode = DispositionFileStatusTypes.COMPLETE.ToString(),
},
},
},
};
PimsPropertyLease propertyLease = new PimsPropertyLease()
{
Property = disposedProperty,
LeaseId = lease.LeaseId
};

propertyLeaseRepository.Setup(x => x.GetAllByPropertyId(It.IsAny<long>())).Returns(new List<PimsPropertyLease>() { propertyLease });
propertyRepository.Setup(x => x.GetByPid(It.IsAny<int>(), true)).Returns(property);
propertyRepository.Setup(x => x.GetAllAssociationsById(It.IsAny<long>())).Returns(disposedProperty);
leaseRepository.Setup(x => x.GetNoTracking(It.IsAny<long>())).Returns(lease);
leaseRepository.Setup(x => x.Get(It.IsAny<long>())).Returns(EntityHelper.CreateLease(1));
userRepository.Setup(x => x.GetByKeycloakUserId(It.IsAny<Guid>())).Returns(EntityHelper.CreateUser("Test"));

// Act
Action act = () => service.Update(lease, new List<UserOverrideCode>() { UserOverrideCode.AddLocationToProperty });

// Assert
var ex = act.Should().NotThrow<BusinessRuleViolationException>();
leaseRepository.Verify(x => x.Update(lease, false), Times.Once);
}

[Fact]
public void UpdateProperties_WithRetiredProperty_Should_Fail()
{
// Arrange
var lease = EntityHelper.CreateLease(1);

var service = this.CreateLeaseService(Permissions.LeaseEdit, Permissions.PropertyAdd, Permissions.PropertyView);
var leaseRepository = this._helper.GetService<Mock<ILeaseRepository>>();
var propertyLeaseRepository = this._helper.GetService<Mock<IPropertyLeaseRepository>>();
var propertyRepository = this._helper.GetService<Mock<IPropertyRepository>>();
var userRepository = this._helper.GetService<Mock<IUserRepository>>();

PimsProperty retiredProperty = new PimsProperty()
{
PropertyId = 100,
Pid = 1,
IsRetired = true,
};

propertyRepository.Setup(x => x.GetByPid(It.IsAny<int>(), true)).Returns(retiredProperty);
leaseRepository.Setup(x => x.GetNoTracking(It.IsAny<long>())).Returns(lease);
leaseRepository.Setup(x => x.Get(It.IsAny<long>())).Returns(EntityHelper.CreateLease(1));
userRepository.Setup(x => x.GetByKeycloakUserId(It.IsAny<Guid>())).Returns(EntityHelper.CreateUser("Test"));
Expand Down Expand Up @@ -542,6 +703,7 @@ public void UpdateProperties_MatchProperties_Success_NoInternalId()
Lease = lease,
Internal_Id = 1,
} };
lease.PimsPropertyLeases = propertyLeases;

propertyLeaseRepository.Setup(x => x.GetAllByLeaseId(It.IsAny<long>())).Returns(propertyLeases);
propertyRepository.Setup(x => x.GetByPid(It.IsAny<int>(), true)).Returns(lease.PimsPropertyLeases.FirstOrDefault().Property);
Expand Down
14 changes: 10 additions & 4 deletions source/frontend/src/features/leases/add/AddLeaseYupSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,16 @@ export const AddLeaseYupSchema = Yup.object().shape({
properties: Yup.array().of(
Yup.object().shape({
name: Yup.string().max(250, 'Property name must be at most ${max} characters'),
isRetired: Yup.boolean().notOneOf(
[true],
'Selected property is retired and can not be added to the file',
),
property: Yup.object().shape({
isRetired: Yup.boolean().notOneOf(
[true],
'Selected property is retired and can not be added to the file',
),
isDisposed: Yup.boolean().notOneOf(
[true],
'Selected property is disposed and can not be added to the file',
),
}),
}),
),
consultations: Yup.array().of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ export const SelectedPropertyRow: React.FunctionComponent<ISelectedPropertyRowPr
label=""
field={withNameSpace(nameSpace, 'name')}
displayErrorTooltips={true}
errorKeys={[
withNameSpace(nameSpace, 'property.isRetired'),
withNameSpace(nameSpace, 'property.isDisposed'),
]}
/>
</Col>
<Col md={1} className="pl-3">
Expand Down
2 changes: 2 additions & 0 deletions source/frontend/src/features/mapSideBar/shared/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export class PropertyForm {
public landArea?: number;
public areaUnit?: AreaUnitTypes;
public isRetired?: boolean;
public isDisposed?: boolean;

public constructor(baseModel?: Partial<PropertyForm>) {
Object.assign(this, baseModel);
Expand Down Expand Up @@ -152,6 +153,7 @@ export class PropertyForm {
? enumFromValue(model?.pimsFeature?.properties?.PROPERTY_AREA_UNIT_TYPE_CODE, AreaUnitTypes)
: AreaUnitTypes.SquareMeters,
isRetired: model?.pimsFeature?.properties?.IS_RETIRED ?? false,
isDisposed: model?.pimsFeature?.properties?.IS_DISPOSED ?? false,
legalDescription:
model?.pimsFeature?.properties?.LAND_LEGAL_DESCRIPTION ??
model?.parcelFeature?.properties?.LEGAL_DESCRIPTION ??
Expand Down
Loading