Skip to content

Commit

Permalink
Merge pull request #664 from bcgov/yj
Browse files Browse the repository at this point in the history
Yj
  • Loading branch information
ychung-mot authored Sep 20, 2024
2 parents 8d5b65f + 4d0ba47 commit b37f1a0
Show file tree
Hide file tree
Showing 17 changed files with 154 additions and 89 deletions.
1 change: 1 addition & 0 deletions database/ddl/STR_DSS_Views_Sprint_14.sql
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ CREATE OR REPLACE VIEW dss_rental_listing_vw AS select drl.rental_listing_id
, drl.effective_business_licence_no
, drl.effective_host_nm
, drl.is_changed_business_licence
, drl.lg_transfer_dtm
FROM dss_rental_listing drl
join dss_organization org on org.organization_id=drl.offering_organization_id
LEFT JOIN dss_listing_status_type dlst on drl.listing_status_type=dlst.listing_status_type
Expand Down
9 changes: 9 additions & 0 deletions server/StrDss.Data/Entities/DssDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
entity.Property(e => e.IsPrincipalResidenceRequired)
.HasComment("Indicates whether a LOCAL GOVERNMENT SUBDIVISION is subject to Provincial Principal Residence Short Term Rental restrictions")
.HasColumnName("is_principal_residence_required");
entity.Property(e => e.IsStrProhibited)
.HasComment("Indicates whether a LOCAL GOVERNMENT ORGANIZATION entirely prohibits short term housing rentals")
.HasColumnName("is_str_prohibited");
entity.Property(e => e.LocalGovernmentType)
.HasMaxLength(50)
.HasComment("A sub-type of local government organization used for sorting and grouping or members")
Expand Down Expand Up @@ -663,6 +666,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
entity.HasIndex(e => new { e.OfferingOrganizationId, e.PlatformListingNo }, "dss_rental_listing_i1");
entity.HasIndex(e => e.LgTransferDtm, "dss_rental_listing_i11");
entity.HasIndex(e => e.IncludingRentalListingReportId, "dss_rental_listing_i2");
entity.HasIndex(e => e.DerivedFromRentalListingId, "dss_rental_listing_i3");
Expand Down Expand Up @@ -738,6 +743,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
entity.Property(e => e.IsTakenDown)
.HasComment("Indicates whether a CURRENT RENTAL LISTING has been reported as taken down by the offering platform")
.HasColumnName("is_taken_down");
entity.Property(e => e.LgTransferDtm)
.HasComment("Indicates when a CURRENT RENTAL LISTING was most recently transferred to a different Local Goverment Organization as a result of address changes")
.HasColumnName("lg_transfer_dtm");
entity.Property(e => e.ListingStatusType)
.HasMaxLength(2)
.HasComment("Foreign key")
Expand Down Expand Up @@ -989,6 +997,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.HasMaxLength(250)
.HasColumnName("last_action_nm");
entity.Property(e => e.LatestReportPeriodYm).HasColumnName("latest_report_period_ym");
entity.Property(e => e.LgTransferDtm).HasColumnName("lg_transfer_dtm");
entity.Property(e => e.LicenceStatusType)
.HasMaxLength(25)
.HasColumnName("licence_status_type");
Expand Down
5 changes: 5 additions & 0 deletions server/StrDss.Data/Entities/DssOrganization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ public partial class DssOrganization
/// </summary>
public string? LocalGovernmentType { get; set; }

/// <summary>
/// Indicates whether a LOCAL GOVERNMENT ORGANIZATION entirely prohibits short term housing rentals
/// </summary>
public bool? IsStrProhibited { get; set; }

public virtual ICollection<DssBusinessLicence> DssBusinessLicences { get; set; } = new List<DssBusinessLicence>();

public virtual ICollection<DssEmailMessage> DssEmailMessageInvolvedInOrganizations { get; set; } = new List<DssEmailMessage>();
Expand Down
5 changes: 5 additions & 0 deletions server/StrDss.Data/Entities/DssRentalListing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ public partial class DssRentalListing
/// </summary>
public long? GoverningBusinessLicenceId { get; set; }

/// <summary>
/// Indicates when a CURRENT RENTAL LISTING was most recently transferred to a different Local Goverment Organization as a result of address changes
/// </summary>
public DateTime? LgTransferDtm { get; set; }

public virtual DssRentalListing? DerivedFromRentalListing { get; set; }

public virtual ICollection<DssEmailMessage> DssEmailMessages { get; set; } = new List<DssEmailMessage>();
Expand Down
2 changes: 2 additions & 0 deletions server/StrDss.Data/Entities/DssRentalListingVw.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,6 @@ public partial class DssRentalListingVw
public string? EffectiveHostNm { get; set; }

public bool? IsChangedBusinessLicence { get; set; }

public DateTime? LgTransferDtm { get; set; }
}
2 changes: 1 addition & 1 deletion server/StrDss.Data/Repositories/OrganizationRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ FROM dss_organization
OrganizationNm = o.OrganizationNm,
IsPrincipalResidenceRequired = o.IsPrincipalResidenceRequired,
IsBusinessLicenceRequired = o.IsBusinessLicenceRequired,
IsStrProhibited = null //todo: map with the new column
IsStrProhibited = o.IsStrProhibited,
})
.OrderBy(o => o.OrganizationNm)
.FirstOrDefaultAsync();
Expand Down
25 changes: 22 additions & 3 deletions server/StrDss.Data/Repositories/RentalListingRepository.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Npgsql;
using StrDss.Common;
using StrDss.Data.Entities;
using StrDss.Model;
using StrDss.Model.DelistingDtos;
using StrDss.Model.RentalReportDtos;
using System.Diagnostics;
using System.Reflection;

namespace StrDss.Data.Repositories
{
Expand All @@ -28,9 +28,10 @@ Task<PagedDto<RentalListingGroupDto>> GetGroupedRentalListings(string? all, stri
Task ConfirmAddressAsync(long rentalListingId);
Task<DssRentalListing> UpdateAddressAsync(UpdateListingAddressDto dto);
DateTime GetLatestRentalListingExportTime();
Task<bool> IsListingUploadProcessRunning();
Task<bool> ListingDataToProcessExists();
Task LinkBizLicence(long rentalListingId, long licenceId);
Task UnLinkBizLicence(long rentalListingId);
Task ResetLgTransferFlag();
}
public class RentalListingRepository : RepositoryBase<DssRentalListingVw>, IRentalListingRepository
{
Expand Down Expand Up @@ -746,7 +747,7 @@ public DateTime GetLatestRentalListingExportTime()
}
}

public async Task<bool> IsListingUploadProcessRunning()
public async Task<bool> ListingDataToProcessExists()
{
return await _dbContext.DssUploadLines
.AnyAsync(x => x.IncludingUploadDelivery.UploadDeliveryType == UploadDeliveryTypes.ListingData && x.IsProcessed == false);
Expand Down Expand Up @@ -780,5 +781,23 @@ public async Task UnLinkBizLicence(long rentalListingId)
listing.EffectiveBusinessLicenceNo = CommonUtils.SanitizeAndUppercaseString(listing.BusinessLicenceNo);
listing.IsChangedBusinessLicence = true;
}

public async Task ResetLgTransferFlag()
{
var sql = "UPDATE dss_rental_listing SET is_lg_transferred = null, lg_transfer_dtm = null WHERE lg_transfer_dtm <= @twomonth";

var parameters = new List<NpgsqlParameter>
{
new NpgsqlParameter("@twomonth", NpgsqlTypes.NpgsqlDbType.Date)
{
Value = DateTime.UtcNow.Date.AddMonths(-2)
},
};

var rowsAffected = await _dbContext.Database.ExecuteSqlRawAsync(sql, parameters.ToArray());

if (rowsAffected > 0)
_logger.LogInformation("{RowsAffected} rental listings had the lg_transfer_dtm and is_lg_transferred fields reset.", rowsAffected);
}
}
}
10 changes: 10 additions & 0 deletions server/StrDss.Data/Repositories/UploadDeliveryRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public interface IUploadDeliveryRepository
Task<bool> IsDuplicateRentalReportUploadAsnyc(DateOnly? periodYm, long orgId, string hashValue);
Task AddUploadDeliveryAsync(DssUploadDelivery upload);
Task<DssUploadDelivery?> GetUploadToProcessAsync(string reportType);
Task<DssUploadDelivery?> GetNonTakedownUploadToProcessAsync();
Task<DssUploadDelivery[]> GetUploadsToProcessAsync(string reportType);
Task<DssUploadDelivery?> GetRentalListingUploadWithErrors(long uploadId);
Task<DssUploadLine?> GetUploadLineAsync(long uploadId, string orgCd, string listingId);
Expand Down Expand Up @@ -55,6 +56,15 @@ public async Task<bool> IsDuplicateRentalReportUploadAsnyc(DateOnly? periodYm, l
.FirstOrDefaultAsync();
}

public async Task<DssUploadDelivery?> GetNonTakedownUploadToProcessAsync()
{
return await _dbSet
.Include(x => x.ProvidingOrganization)
.Where(x => x.UploadDeliveryType != UploadDeliveryTypes.TakedownData && x.DssUploadLines.Any(line => !line.IsProcessed))
.OrderBy(x => x.UpdDtm)
.FirstOrDefaultAsync();
}

public async Task<DssUploadDelivery[]> GetUploadsToProcessAsync(string reportType)
{
return await _dbSet
Expand Down
20 changes: 17 additions & 3 deletions server/StrDss.Hangfire/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Npgsql;
using StrDss.Hangfire;
using Serilog;
using Hangfire.Storage;

var builder = WebApplication.CreateBuilder(args);

Expand Down Expand Up @@ -170,10 +171,23 @@
app.UseHangfireDashboard();

// make sure this is after app.UseHangfireDashboard()
RecurringJob.AddOrUpdate<HangfireJobs>("Process Rental Listing Report", job => job.ProcessRentalListingReports(), "*/2 * * * *");

// Retrieve all recurring jobs
var recurringJobs = JobStorage.Current.GetConnection().GetRecurringJobs();

// Remove each recurring job
foreach (var job in recurringJobs)
{
RecurringJob.RemoveIfExists(job.Id);
}

// process uploads
RecurringJob.AddOrUpdate<HangfireJobs>("Process Uploaded Data", job => job.ProcessUpload(), "*/5 * * * *");

// process nightly job of sending takedown request emails to plaforms
RecurringJob.AddOrUpdate<HangfireJobs>("Process Takedown Request Batch Emails", job => job.ProcessTakedownRequestBatchEmails(), "50 6 * * *");

// daily export
RecurringJob.AddOrUpdate<HangfireJobs>("Create Rental Listing Export Files", job => job.CreateRentalListingExportFiles(), "50 5 * * *");
RecurringJob.AddOrUpdate<HangfireJobs>("Process Takedown Confirmation Report", job => job.ProcessTakedownConfirmation(), "0 * * * *");
RecurringJob.AddOrUpdate<HangfireJobs>("Process Business Licences", job => job.ProcessBusinessLicences(), "*/10 * * * *");

app.Run();
1 change: 1 addition & 0 deletions server/StrDss.Model/OrganizationDtos/OrganizationDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class OrganizationDto
public bool? IsLgParticipating { get; set; }
public bool? IsPrincipalResidenceRequired { get; set; }
public bool? IsBusinessLicenceRequired { get; set; }
public bool? IsStrProhibited { get; set; }
public virtual ICollection<ContactPersonDto> ContactPeople { get; set; } = new List<ContactPersonDto>();

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public class RentalListingViewDto

public string? EffectiveHostNm { get; set; }
public bool? IsChangedBusinessLicence { get; set; }
public DateTime? LgTransferDtm { get; set; }
public bool HasAtLeastOneValidHostEmail { get; set; }
public List<HostInfo> HostsInfo { get; set; } = new List<HostInfo>();
public BizLicenceDto? BizLicenceInfo { get; set; }
Expand Down
20 changes: 4 additions & 16 deletions server/StrDss.Service/BizLicenceService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace StrDss.Service
public interface IBizLicenceService
{
Task<BizLicenceDto?> GetBizLicence(long businessLicenceId);
Task ProcessBizLicenceUploadAsync();
Task ProcessBizLicenceUploadMainAsync(DssUploadDelivery upload);
Task<(long?, string?)> GetMatchingBusinessLicenceIdAndNo(long orgId, string effectiveBizLicNo);
Task<List<BizLicenceSearchDto>> SearchBizLicence(long orgId, string bizLicNo);

Expand Down Expand Up @@ -47,25 +47,13 @@ public BizLicenceService(ICurrentUser currentUser, IFieldValidatorService valida
return await _bizLicenceRepo.GetBizLicence(businessLicenceId);
}

public async Task ProcessBizLicenceUploadAsync()
public async Task ProcessBizLicenceUploadMainAsync(DssUploadDelivery upload)
{
var isListingUploadProcessRunning = await _listingRepo.IsListingUploadProcessRunning();

if (isListingUploadProcessRunning)
{
_logger.LogInformation("Skipping ProcessBizLicenceUploadAsync: Rental Listing Upload Process is running");
return;
}

if (!_validator.CommonCodes.Any())
{
_validator.CommonCodes = await _codeSetRepo.LoadCodeSetAsync();
}

var upload = await _uploadRepo.GetUploadToProcessAsync(UploadDeliveryTypes.LicenceData);

if (upload == null) return;

var processStopwatch = Stopwatch.StartNew();

_logger.LogInformation($"Processing Business Licence Upload Id ({upload.UploadDeliveryId}): {upload.ProvidingOrganization.OrganizationNm}");
Expand All @@ -74,7 +62,7 @@ public async Task ProcessBizLicenceUploadAsync()

await _bizLicenceRepo.CreateBizLicTempTable();

await ProcessBizLicenceUploadAsync(upload);
await ProcessBizLicenceUploadSubAsync(upload);

_unitOfWork.Commit();

Expand All @@ -95,7 +83,7 @@ public async Task ProcessBizLicenceUploadAsync()
_logger.LogInformation($"Finished: Business Licence Upload Id ({upload.UploadDeliveryId}): {upload.ProvidingOrganization.OrganizationNm} - {processStopwatch.Elapsed.TotalSeconds} seconds");
}

private async Task ProcessBizLicenceUploadAsync(DssUploadDelivery upload)
private async Task ProcessBizLicenceUploadSubAsync(DssUploadDelivery upload)
{
var count = 0;

Expand Down
61 changes: 34 additions & 27 deletions server/StrDss.Service/Hangfire/HangfireJobs.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Hangfire;
using StrDss.Common;

namespace StrDss.Service.Hangfire
{
Expand All @@ -9,23 +10,17 @@ public class HangfireJobs
private IRentalListingService _listingService;
private ITakedownConfirmationService _tdcService;
private IBizLicenceService _bizLicService;
private IUploadDeliveryService _uploadService;

public HangfireJobs(IRentalListingReportService listingReportService, IRentalListingService listingService, IDelistingService delistingService,
ITakedownConfirmationService tdcService, IBizLicenceService bizLicService)
ITakedownConfirmationService tdcService, IBizLicenceService bizLicService, IUploadDeliveryService uploadService)
{
_linstingReportService = listingReportService;
_delistingService = delistingService;
_listingService = listingService;
_tdcService = tdcService;
_bizLicService = bizLicService;
}

[Queue("default")]
[SkipSameJob]
[AutomaticRetry(Attempts = 0)]
public async Task ProcessRentalListingReports()
{
await _linstingReportService.ProcessRentalReportUploadAsync();
_uploadService = uploadService;
}

[Queue("default")]
Expand All @@ -36,14 +31,6 @@ public async Task ProcessTakedownRequestBatchEmails()
await _delistingService.ProcessTakedownRequestBatchEmailsAsync();
}

//[Queue("default")]
//[SkipSameJob]
//[AutomaticRetry(Attempts = 0)]
//public async Task CleanUpAddresses()
//{
// await _linstingReportService.CleaupAddressAsync();
//}

[Queue("default")]
[SkipSameJob]
[AutomaticRetry(Attempts = 0)]
Expand All @@ -55,19 +42,39 @@ public async Task CreateRentalListingExportFiles()
[Queue("default")]
[SkipSameJob]
[AutomaticRetry(Attempts = 0)]
public async Task ProcessTakedownConfirmation()
public async Task ProcessUpload()
{
await _tdcService.ProcessTakedownConfrimationAsync();
}
var listingDataToProcessExists = await _listingService.ListingDataToProcessExists();

[Queue("default")]
[SkipSameJob]
[AutomaticRetry(Attempts = 0)]
public async Task ProcessBusinessLicences()
{
await _bizLicService.ProcessBizLicenceUploadAsync();
}
if (!listingDataToProcessExists)
{
await _listingService.ResetLgTransferFlag();
}

var upload = await _uploadService.GetNonTakedownUploadToProcessAsync();

// takedown upload can have not-found listings which never gets processed until the listings exist
// so process it only when there's nothing to process
upload ??= await _uploadService.GetUploadToProcessAsync(UploadDeliveryTypes.TakedownData);

if (upload == null) return;

var reportType = upload.UploadDeliveryType;

switch (reportType)
{
case UploadDeliveryTypes.ListingData:
await _linstingReportService.ProcessRentalReportUploadAsync(upload);
break;
case UploadDeliveryTypes.TakedownData:
await _tdcService.ProcessTakedownConfirmationUploadAsync(upload);
break;
case UploadDeliveryTypes.LicenceData:
await _bizLicService.ProcessBizLicenceUploadMainAsync(upload);
break;
default:
break;
}
}
}
}
Loading

0 comments on commit b37f1a0

Please sign in to comment.