Skip to content

Commit

Permalink
Holiday residence ads are now supported.
Browse files Browse the repository at this point in the history
  • Loading branch information
n.bitounis committed Apr 20, 2019
1 parent ca075b0 commit 981fca1
Show file tree
Hide file tree
Showing 11 changed files with 260 additions and 172 deletions.
29 changes: 29 additions & 0 deletions Projects/xe.bit.property.core/Ads/ResidenceAdHoliday.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using FluentValidation.Results;
using xe.bit.property.core.Lookups;
using xe.bit.property.core.Serializers;
using xe.bit.property.core.Serializers.Interfaces;
using xe.bit.property.core.Utility;
using xe.bit.property.core.Validators;

namespace xe.bit.property.core.Ads
{
public class ResidenceAdHoliday : ResidenceAd
{
public override ItemType AdType { get; protected set; } = Lookups.ItemType.re_residence_hol;
public virtual string Activity { get; set; }
public virtual string Utilities { get; set; }
public virtual string ProximityTo { get; set; }

public override IAddSerializer Serializer { get; } = new XmlResidenceAdHolidaySerializer();

public override ValidationResult Validate()
{
return ValidationChain.ChainValidators(this, new ResidenceAdHolidayValidator().Validate(this));
}

public override string Serialize(bool skipAssets)
{
return Serializer.Serialize(this, skipAssets);
}
}
}
1 change: 1 addition & 0 deletions Projects/xe.bit.property.core/Errors/Messages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static class Messages
public const string TooManyVideos = "Too many video assets - maximum of 1 allowed";
public const string MoreThanOnePrimaryAssets = "Only one asset can be set to primary";
public const string AddTypeMustBeResidence = "AdType must be re_residence for residence ads";
public const string AddTypeMustBeResidenceHoliday = "AdType must be re_residence_hol for holiday residence ads";
public const string AreaMustHaveValue = "Area must have a value";
public const string AreaMustHavePositiveValue = "Area must have a positive value";
public const string LevelMustHaveValue = "Level must have a value";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.IO;
using System.IO;
using System.Text;
using System.Xml;
using xe.bit.property.core.Request.Interfaces;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Xml;
using xe.bit.property.core.Ads;
using xe.bit.property.core.Utility.Xml;

namespace xe.bit.property.core.Serializers
{
public class XmlResidenceAdHolidaySerializer : XmlResidenceAdSerializer
{
protected override void SerializeAdditional(BaseAd ad, XmlWriter writer)
{
var r = (ResidenceAdHoliday)ad;
writer
.Field("Item.activity", r.Activity)
.Field("Item.utilities", r.Utilities)
.Field("Item.proximityTo", r.ProximityTo);
}
}
}
141 changes: 75 additions & 66 deletions Projects/xe.bit.property.core/Serializers/XmlResidenceAdSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,72 +14,8 @@ public override string Serialize(BaseAd ad, bool skipAssets)
using (var ms = new MemoryStream())
using (var writer = XmlWriter.Create(ms, new XmlWriterSettings { ConformanceLevel = ConformanceLevel.Fragment, OmitXmlDeclaration = true, Encoding = new UTF8Encoding(false)}))
{
var r = (ResidenceAd)ad;

writer
.ElementWithAttributes("Item",
new Dictionary<string, string> {{"type", ad.AdType.ToString()}, {"refId", ad.RefId}})
.NewLine()
.Element("Item.ownerId", ad.OwnerId)
.Element("Item.majorPhone", ad.MajorPhone)
.Element("Item.departmentOnCategory", ad.DepartmentOnCategory)
.Element("Item.otherPhones", ad.OtherPhones, "Item.phone")
.CData("Item.internetText", ad.InternetText)
.CData("Item.addOnText", ad.AddOnText)
.CData("Item.bodyText", ad.BodyText);

SerializeFinancial(writer, ad);

writer
.Field("Item.type", r.ItemType)
.Field("Item.subtype", r.SubType)
.Field("Item.area", r.Area)
.Field("Item.level", r.Level?.ToString())
.Field("Item.constructionType", r.ConstructionType)
.Field("Item.condition", r.Condition)
.Field("Item.conditionDetails", r.ConditionDetails)
.Field("Item.constructionYear", r.ConstructionYear)
.Field("Item.floors", r.Floors)
.Field("Item.floorsArea", r.FloorsArea)
.Field("Item.refurbishmentYear", r.RefurbishmentYear)
.Field("Item.orientation", r.Orientation)
.Field("Item.bedrooms", r.Bedrooms)
.Field("Item.masterBedrooms", r.MasterBedrooms)
.Field("Item.bathrooms", r.Bathrooms)
.Field("Item.wc", r.Wc)
.Field("Item.hasParking", r.HasParking, true)
.Field("Item.parkingType", r.ParkingType)
.Field("Item.hasStorage", r.HasStorage, true)
.Field("Item.storageArea", r.StorageArea)
.Field("Item.hasAutonomousHeating", r.HasAutonomousHeating, true)
.Field("Item.hasCentralHeating", r.HasCentralHeating, true)
.Field("Item.hasAirConditioning", r.HasAirConditioning, true)
.Field("Item.hasSecureDoor", r.HasSecureDoor, true)
.Field("Item.viewType", r.ViewType)
.Field("Item.hasFirePlace", r.HasFirePlace, true)
.Field("Item.hasSolarBoiler", r.HasSolarBoiler, true)
.Field("Item.withoutElevator", r.WithoutElevator, true)
.Field("Item.hasNaturalGas", r.HasNaturalGas, true)
.Field("Item.hasGarden", r.HasGarden, true)
.Field("Item.gardenArea", r.GardenArea)
.Field("Item.location", r.Location)
.Field("Item.land", r.Land)
.Field("Item.availabilityType", r.AvailabilityType)
.Field("Item.hasPrivateTerrace", r.HasTerraceArea, true)
.Field("Item.terraceArea", r.TerraceArea)
.Field("Item.hasPool", r.HasPool, true)
.Field("Item.hasTents", r.HasTents, true)
.Field("Item.isWithoutCommunalCharge", r.IsWithoutCommunalCharge, true)
.Field("Item.isSuitableForProfessionalUse", r.IsSuitableForProfessionalUse, true)
.Field("Item.isFurnished", r.IsFurnished, true)
.Field("Item.availableFrom", r.AvailableFrom)
.Field("Item.spacesPlan", r.SpacesPlan)
.Field("Item.isSuitableForStudents", r.IsSuitableForStudents, true)
.Field("Item.isAgentAccepted", r.IsAgentAccepted, true)
.Field("Item.hasSemiOpenSpaces", r.HasSemiOpenSpaces, true)
.Field("Item.semiOpenSpacesArea", r.SemiOpenSpacesArea)
.Field("Item.energy_class", r.EnergyClass);

SerializeResidence(ad, writer);
SerializeAdditional(ad, writer);
SerializeGeo(writer, ad);
if (!skipAssets)
{
Expand All @@ -93,5 +29,78 @@ public override string Serialize(BaseAd ad, bool skipAssets)
return new UTF8Encoding(false).GetString(ms.ToArray());
}
}

protected virtual void SerializeAdditional(BaseAd ad, XmlWriter writer)
{
}

private void SerializeResidence(BaseAd ad, XmlWriter writer)
{
var r = (ResidenceAd)ad;

writer
.ElementWithAttributes("Item",
new Dictionary<string, string> { { "type", ad.AdType.ToString() }, { "refId", ad.RefId } })
.NewLine()
.Element("Item.ownerId", ad.OwnerId)
.Element("Item.majorPhone", ad.MajorPhone)
.Element("Item.departmentOnCategory", ad.DepartmentOnCategory)
.Element("Item.otherPhones", ad.OtherPhones, "Item.phone")
.CData("Item.internetText", ad.InternetText)
.CData("Item.addOnText", ad.AddOnText)
.CData("Item.bodyText", ad.BodyText);

SerializeFinancial(writer, ad);

writer
.Field("Item.type", r.ItemType)
.Field("Item.subtype", r.SubType)
.Field("Item.area", r.Area)
.Field("Item.level", r.Level?.ToString())
.Field("Item.constructionType", r.ConstructionType)
.Field("Item.condition", r.Condition)
.Field("Item.conditionDetails", r.ConditionDetails)
.Field("Item.constructionYear", r.ConstructionYear)
.Field("Item.floors", r.Floors)
.Field("Item.floorsArea", r.FloorsArea)
.Field("Item.refurbishmentYear", r.RefurbishmentYear)
.Field("Item.orientation", r.Orientation)
.Field("Item.bedrooms", r.Bedrooms)
.Field("Item.masterBedrooms", r.MasterBedrooms)
.Field("Item.bathrooms", r.Bathrooms)
.Field("Item.wc", r.Wc)
.Field("Item.hasParking", r.HasParking, true)
.Field("Item.parkingType", r.ParkingType)
.Field("Item.hasStorage", r.HasStorage, true)
.Field("Item.storageArea", r.StorageArea)
.Field("Item.hasAutonomousHeating", r.HasAutonomousHeating, true)
.Field("Item.hasCentralHeating", r.HasCentralHeating, true)
.Field("Item.hasAirConditioning", r.HasAirConditioning, true)
.Field("Item.hasSecureDoor", r.HasSecureDoor, true)
.Field("Item.viewType", r.ViewType)
.Field("Item.hasFirePlace", r.HasFirePlace, true)
.Field("Item.hasSolarBoiler", r.HasSolarBoiler, true)
.Field("Item.withoutElevator", r.WithoutElevator, true)
.Field("Item.hasNaturalGas", r.HasNaturalGas, true)
.Field("Item.hasGarden", r.HasGarden, true)
.Field("Item.gardenArea", r.GardenArea)
.Field("Item.location", r.Location)
.Field("Item.land", r.Land)
.Field("Item.availabilityType", r.AvailabilityType)
.Field("Item.hasPrivateTerrace", r.HasTerraceArea, true)
.Field("Item.terraceArea", r.TerraceArea)
.Field("Item.hasPool", r.HasPool, true)
.Field("Item.hasTents", r.HasTents, true)
.Field("Item.isWithoutCommunalCharge", r.IsWithoutCommunalCharge, true)
.Field("Item.isSuitableForProfessionalUse", r.IsSuitableForProfessionalUse, true)
.Field("Item.isFurnished", r.IsFurnished, true)
.Field("Item.availableFrom", r.AvailableFrom)
.Field("Item.spacesPlan", r.SpacesPlan)
.Field("Item.isSuitableForStudents", r.IsSuitableForStudents, true)
.Field("Item.isAgentAccepted", r.IsAgentAccepted, true)
.Field("Item.hasSemiOpenSpaces", r.HasSemiOpenSpaces, true)
.Field("Item.semiOpenSpacesArea", r.SemiOpenSpacesArea)
.Field("Item.energy_class", r.EnergyClass);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using FluentValidation;
using xe.bit.property.core.Errors;
using xe.bit.property.core.Lookups;

namespace xe.bit.property.core.Validators
{
public class ResidenceAdHolidayValidator : ResidenceValidator
{
public ResidenceAdHolidayValidator()
{
RuleFor(ad => ad.AdType)
.Equal(ItemType.re_residence_hol)
.WithMessage(Messages.AddTypeMustBeResidenceHoliday);

AddOtherRules();
}
}
}
104 changes: 3 additions & 101 deletions Projects/xe.bit.property.core/Validators/ResidenceAdValidator.cs
Original file line number Diff line number Diff line change
@@ -1,116 +1,18 @@
using System;
using FluentValidation;
using xe.bit.property.core.Ads;
using FluentValidation;
using xe.bit.property.core.Errors;
using xe.bit.property.core.Lookups;

namespace xe.bit.property.core.Validators
{
public class ResidenceAdValidator : AbstractValidator<ResidenceAd>
public class ResidenceAdValidator : ResidenceValidator
{
public ResidenceAdValidator()
{
RuleFor(ad => ad.AdType)
.Equal(ItemType.re_residence)
.WithMessage(Messages.AddTypeMustBeResidence);

RuleFor(ad => ad.ItemType == ResidenceItemType.APARTMENT && !ad.SubType.HasValue)
.Equal(false)
.WithMessage(Messages.ResidenceSubTypeMustHaveValue);

RuleFor(ad => ad.ItemType != ResidenceItemType.APARTMENT && ad.SubType.HasValue)
.Equal(false)
.WithMessage(Messages.ResidenceSubTypeMustBeNull);

RuleFor(ad => ad.Area)
.NotNull().WithMessage(Messages.AreaMustHaveValue);

When(ad => ad.Area.HasValue, () =>
{
RuleFor(ad => ad.Area.Value)
.GreaterThan(0).WithMessage(Messages.AreaMustHavePositiveValue);
});

RuleFor(ad => ad.Level)
.NotNull()
.WithMessage(Messages.LevelMustHaveValue);

RuleFor(ad => ad.Condition)
.NotNull()
.WithMessage(Messages.ConditionMustHaveValue);

RuleFor(ad => ad.ConstructionYear)
.GreaterThan(1900).WithMessage(Messages.ConstructionYearOutOfBounds)
.LessThanOrEqualTo(DateTime.UtcNow.Year).WithMessage(Messages.ConstructionYearOutOfBounds);

When(ad => ad.RefurbishmentYear.HasValue, () =>
{
RuleFor(ad => ad.RefurbishmentYear.Value)
.GreaterThan(1900).WithMessage(Messages.RefurbishmentYearOutOfBounds)
.LessThanOrEqualTo(DateTime.UtcNow.Year).WithMessage(Messages.RefurbishmentYearOutOfBounds);
});

RuleFor(ad => ad.Bedrooms - ad.MasterBedrooms)
.GreaterThan(0)
.WithMessage(Messages.BedroomsOutOfBound);

RuleFor(ad => ComplexFlagCheck(ad.HasStorage, ad.StorageArea.HasValue))
.Equal(false)
.WithMessage(Messages.HasStorageConstraint);

RuleFor(ad => ComplexFlagCheck(ad.HasSemiOpenSpaces, ad.SemiOpenSpacesArea.HasValue))
.Equal(false)
.WithMessage(Messages.HasSemiOpenSpacesConstraint);

RuleFor(ad => ComplexFlagCheck(ad.HasGarden, ad.GardenArea.HasValue))
.Equal(false)
.WithMessage(Messages.HasGardenConstraint);

RuleFor(ad => ComplexFlagCheck(ad.HasTerraceArea, ad.TerraceArea.HasValue))
.Equal(false)
.WithMessage(Messages.HasTerraceConstraint);

RuleFor(ad => (ad.Floors.HasValue ^ ad.FloorsArea.HasValue) && (ad.Floors.HasValue && ad.Floors != 0 && !ad.FloorsArea.HasValue))
.Equal(false)
.WithMessage(Messages.FloorsConstraint);

RuleFor(ad => ComplexFlagCheck(ad.HasParking, ad.ParkingType.HasValue))
.Equal(false)
.WithMessage(Messages.HasParkingConstraint);

RuleFor(ad => ad.Geo)
.Custom((geo, context) =>
{
new GeoValidator().Validate(geo, context);
});

RuleFor(ad => ad.Assets)
.Custom((assets, context) =>
{
new AssetsValidator().Validate(assets, context);
});
}

/// <summary>
/// Checks valid conditions if a flag and a value are specified (for example,
/// hasTerrace and TerraceArea). We want both these to have values, but if
/// a flag is specified and is false, we do not care of the specified value
/// (for example if hasTerrace has a value and is false, this is allowed).
/// </summary>
/// <returns></returns>
private bool ComplexFlagCheck(bool? flag, bool hasValue)
{
if (flag.HasValue && flag.Value == false && hasValue)
{
return true;
}

if (!flag.HasValue && hasValue)
{
return true;
}

return false;
AddOtherRules();
}
}
}
Loading

0 comments on commit 981fca1

Please sign in to comment.