Skip to content

Commit

Permalink
added agreeemnts for projects with file upload (#535)
Browse files Browse the repository at this point in the history
Co-authored-by: md <[email protected]>
  • Loading branch information
Dahly96 and md authored Nov 14, 2024
1 parent 909ee96 commit fc154fc
Show file tree
Hide file tree
Showing 23 changed files with 2,049 additions and 80 deletions.
193 changes: 193 additions & 0 deletions backend/Api/Projects/AgreementController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
using Api.Common;
using Api.StaffingController;
using Core.Agreements;
using Core.Consultants;
using Core.DomainModels;
using Core.Organizations;
using Core.Staffings;
using Infrastructure.DatabaseContext;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;

namespace Api.Projects;

[Authorize]
[Route("/v0/{orgUrlKey}/agreements")]
[ApiController]
public class AgreementController(
ApplicationContext context,
IMemoryCache cache,
IOrganisationRepository organisationRepository,
IAgreementsRepository agreementsRepository) : ControllerBase
{

[HttpGet]
[Route("get/{agreementId}")]
public async Task<ActionResult<AgreementReadModel>> GetAgreement([FromRoute] string orgUrlKey,
[FromRoute] int agreementId, CancellationToken ct)
{
var selectedOrg = await organisationRepository.GetOrganizationByUrlKey(orgUrlKey, ct);
if (selectedOrg is null) return BadRequest("Selected org not found");

var agreement = await agreementsRepository.GetAgreementById(agreementId, ct);

if (agreement is null) return NotFound();

var responseModel = new AgreementReadModel(
AgreementId: agreement.Id,
EngagementId: agreement.EngagementId,
StartDate: agreement.StartDate,
EndDate: agreement.EndDate,
NextPriceAdjustmentDate: agreement.NextPriceAdjustmentDate,
PriceAdjustmentIndex: agreement.PriceAdjustmentIndex,
Notes: agreement.Notes,
Files: agreement.Files.Select(f => new FileReferenceReadModel(
FileName: f.FileName,
BlobName: f.BlobName,
UploadedOn: f.UploadedOn
)).ToList()
);
return Ok(responseModel);
}

[HttpGet]
[Route("get/engagement/{engagementId}")]
public async Task<ActionResult<AgreementReadModel>> GetAgreementByEngagement([FromRoute] string orgUrlKey,
[FromRoute] int engagementId, CancellationToken ct)
{
var selectedOrg = await organisationRepository.GetOrganizationByUrlKey(orgUrlKey, ct);
if (selectedOrg is null) return BadRequest("Selected org not found");

var agreement = await agreementsRepository.GetAgreementByEngagementId(engagementId, ct);

if (agreement is null) return NotFound();

var responseModel = new AgreementReadModel(
AgreementId: agreement.Id,
EngagementId: agreement.EngagementId,
StartDate: agreement.StartDate,
EndDate: agreement.EndDate,
NextPriceAdjustmentDate: agreement.NextPriceAdjustmentDate,
PriceAdjustmentIndex: agreement.PriceAdjustmentIndex,
Notes: agreement.Notes,
Files: agreement.Files.Select(f => new FileReferenceReadModel(
FileName: f.FileName,
BlobName: f.BlobName,
UploadedOn: f.UploadedOn
)).ToList()
);
return Ok(responseModel);
}

[HttpPost]
[Route("create")]
public async Task<ActionResult<AgreementWriteModel>> Post([FromRoute] string orgUrlKey,
[FromBody] AgreementWriteModel body, CancellationToken ct)
{

Console.WriteLine(body);

var selectedOrg = await organisationRepository.GetOrganizationByUrlKey(orgUrlKey, ct);
if (selectedOrg is null) return BadRequest("Selected org not found");

var engagement = await context.Project.FindAsync(body.EngagementId);
if (engagement is null) return BadRequest("Engagement not found");

var agreement = new Agreement
{
EngagementId = body.EngagementId,
Engagement = engagement,
StartDate = body.StartDate,
EndDate = body.EndDate,
NextPriceAdjustmentDate = body.NextPriceAdjustmentDate,
PriceAdjustmentIndex = body.PriceAdjustmentIndex,
Notes = body.Notes,
Files = body.Files.Select(f => new FileReference
{
FileName = f.FileName,
BlobName = f.BlobName,
UploadedOn = f.UploadedOn
}).ToList()
};

await agreementsRepository.AddAgreementAsync(agreement, ct);

var responseModel = new AgreementReadModel(
AgreementId: agreement.Id,
EngagementId: agreement.EngagementId,
StartDate: agreement.StartDate,
EndDate: agreement.EndDate,
NextPriceAdjustmentDate: agreement.NextPriceAdjustmentDate,
PriceAdjustmentIndex: agreement.PriceAdjustmentIndex,
Notes: agreement.Notes,
Files: agreement.Files.Select(f => new FileReferenceReadModel(
FileName: f.FileName,
BlobName: f.BlobName,
UploadedOn: f.UploadedOn
)).ToList()
);

return Ok(responseModel);
}

[HttpPut]
[Route("update/{agreementId}")]
public async Task<ActionResult<AgreementReadModel>> Put([FromRoute] string orgUrlKey,
[FromRoute] int agreementId, [FromBody] AgreementWriteModel body, CancellationToken ct)
{
var selectedOrg = await organisationRepository.GetOrganizationByUrlKey(orgUrlKey, ct);
if (selectedOrg is null) return BadRequest("Selected org not found");

var agreement = await agreementsRepository.GetAgreementById(agreementId, ct);
if (agreement is null) return NotFound();

agreement.EngagementId = body.EngagementId;
agreement.StartDate = body.StartDate;
agreement.EndDate = body.EndDate;
agreement.NextPriceAdjustmentDate = body.NextPriceAdjustmentDate;
agreement.PriceAdjustmentIndex = body.PriceAdjustmentIndex;
agreement.Notes = body.Notes;
agreement.Files = body.Files.Select(f => new FileReference
{
FileName = f.FileName,
BlobName = f.BlobName,
UploadedOn = f.UploadedOn
}).ToList();

await agreementsRepository.UpdateAgreementAsync(agreement, ct);

var responseModel = new AgreementReadModel(
AgreementId: agreement.Id,
EngagementId: agreement.EngagementId,
StartDate: agreement.StartDate,
EndDate: agreement.EndDate,
NextPriceAdjustmentDate: agreement.NextPriceAdjustmentDate,
PriceAdjustmentIndex: agreement.PriceAdjustmentIndex,
Notes: agreement.Notes,
Files: agreement.Files.Select(f => new FileReferenceReadModel(
FileName: f.FileName,
BlobName: f.BlobName,
UploadedOn: f.UploadedOn
)).ToList()
);

return Ok(responseModel);
}

[HttpDelete]
[Route("delete/{agreementId}")]
public async Task<ActionResult> Delete([FromRoute] string orgUrlKey, [FromRoute] int agreementId, CancellationToken ct)
{
var selectedOrg = await organisationRepository.GetOrganizationByUrlKey(orgUrlKey, ct);
if (selectedOrg is null) return BadRequest("Selected org not found");

var agreement = await agreementsRepository.GetAgreementById(agreementId, ct);
if (agreement is null) return NotFound();

await agreementsRepository.DeleteAgreementAsync(agreementId, ct);

return Ok();
}
}
37 changes: 37 additions & 0 deletions backend/Api/Projects/AgreementModels.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

public record AgreementReadModel(
int AgreementId,
int EngagementId,
DateTime? StartDate,
DateTime EndDate,
DateTime? NextPriceAdjustmentDate,
string? PriceAdjustmentIndex,
string? Notes,
List<FileReferenceReadModel> Files
);

public record FileReferenceReadModel(
string FileName,
string BlobName,
DateTime UploadedOn
);

public record AgreementWriteModel(
int EngagementId,
DateTime? StartDate,
DateTime EndDate,
DateTime? NextPriceAdjustmentDate,
string? PriceAdjustmentIndex,
string? Notes,
List<FileReferenceWriteModel> Files
);

public record FileReferenceWriteModel(
string FileName,
string BlobName,
DateTime UploadedOn
);

34 changes: 34 additions & 0 deletions backend/Core/Agreements/Agreement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.ComponentModel.DataAnnotations.Schema;
using Core.Engagements;

namespace Core.Agreements
{
public class Agreement
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }

public int EngagementId { get; set; }

public required Engagement Engagement { get; set; }

public ICollection<FileReference> Files { get; set; } = new List<FileReference>();

public DateTime? StartDate { get; set; }

public required DateTime EndDate { get; set; }

public DateTime? NextPriceAdjustmentDate { get; set; }

public string? PriceAdjustmentIndex { get; set; }

public string? Notes { get; set; } = string.Empty;
}

public class FileReference
{
public string FileName { get; set; } = string.Empty;
public string BlobName { get; set; } = string.Empty; // URI to the blob storage
public DateTime UploadedOn { get; set; }
}
}
15 changes: 15 additions & 0 deletions backend/Core/Agreements/IAgreementRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Core.Agreements;

public interface IAgreementsRepository
{
public Task<Agreement?> GetAgreementById(int id, CancellationToken cancellationToken);

public Task<Agreement?> GetAgreementByEngagementId(int engagementId, CancellationToken cancellationToken);

public Task AddAgreementAsync(Agreement agreement, CancellationToken cancellationToken);

public Task UpdateAgreementAsync(Agreement agreement, CancellationToken cancellationToken);

public Task DeleteAgreementAsync(int id, CancellationToken cancellationToken);

}
3 changes: 3 additions & 0 deletions backend/Core/Engagements/Engagement.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations.Schema;
using Core.Agreements;
using Core.Consultants;
using Core.Customers;
using Core.Staffings;
Expand All @@ -14,6 +15,8 @@ public class Engagement

public required Customer Customer { get; set; }

public Agreement? Agreement { get; set; }

public required EngagementState State { get; set; }

public List<Consultant> Consultants { get; set; } = new();
Expand Down
18 changes: 18 additions & 0 deletions backend/Infrastructure/DatabaseContext/ApplicationContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Core.Absences;
using Core.Agreements;
using Core.Consultants;
using Core.Customers;
using Core.DomainModels;
Expand Down Expand Up @@ -30,6 +31,7 @@ public ApplicationContext(DbContextOptions options) : base(options)
public DbSet<Customer> Customer { get; set; } = null!;
public DbSet<Engagement> Project { get; set; } = null!;
public DbSet<Staffing> Staffing { get; set; } = null!;
public DbSet<Agreement> Agreements { get; set; } = null!;


protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
Expand Down Expand Up @@ -163,6 +165,20 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
new() { Id = "development", Name = "Utvikling" }
});

modelBuilder.Entity<Agreement>(entity =>
{
entity.OwnsMany(e => e.Files, a =>
{
a.WithOwner().HasForeignKey("AgreementId");
a.Property<int>("Id");
a.HasKey("Id");
});

entity.HasOne(a => a.Engagement)
.WithOne(e => e.Agreement)
.HasForeignKey<Agreement>(a => a.EngagementId);
});

modelBuilder.Entity<Organization>()
.HasData(new
{
Expand All @@ -189,6 +205,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
GraduationYear = 2019
});



base.OnModelCreating(modelBuilder);
}
}
Loading

0 comments on commit fc154fc

Please sign in to comment.