Skip to content

Commit

Permalink
Agreement update (#537)
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 20, 2024
1 parent a5b0333 commit c64da86
Show file tree
Hide file tree
Showing 17 changed files with 1,313 additions and 255 deletions.
145 changes: 131 additions & 14 deletions backend/Api/Projects/AgreementController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Core.Agreements;
using Core.Customers;
using Core.Engagements;
using Core.Organizations;
using Infrastructure.DatabaseContext;
using Microsoft.AspNetCore.Authorization;
Expand Down Expand Up @@ -30,8 +32,10 @@ public async Task<ActionResult<AgreementReadModel>> GetAgreement([FromRoute] str
if (agreement is null) return NotFound();

var responseModel = new AgreementReadModel(
Name: agreement.Name,
AgreementId: agreement.Id,
EngagementId: agreement.EngagementId,
CustomerId: agreement.CustomerId,
StartDate: agreement.StartDate,
EndDate: agreement.EndDate,
NextPriceAdjustmentDate: agreement.NextPriceAdjustmentDate,
Expand All @@ -50,19 +54,21 @@ public async Task<ActionResult<AgreementReadModel>> GetAgreement([FromRoute] str

[HttpGet]
[Route("get/engagement/{engagementId}")]
public async Task<ActionResult<AgreementReadModel>> GetAgreementByEngagement([FromRoute] string orgUrlKey,
public async Task<ActionResult<List<AgreementReadModel>>> GetAgreementsByEngagement([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);
var agreements = await agreementsRepository.GetAgreementsByEngagementId(engagementId, ct);

if (agreement is null) return NotFound();
if (agreements is null || !agreements.Any()) return NotFound();

var responseModel = new AgreementReadModel(
var responseModels = agreements.Select(agreement => new AgreementReadModel(
AgreementId: agreement.Id,
Name: agreement.Name,
EngagementId: agreement.EngagementId,
CustomerId: agreement.CustomerId,
StartDate: agreement.StartDate,
EndDate: agreement.EndDate,
NextPriceAdjustmentDate: agreement.NextPriceAdjustmentDate,
Expand All @@ -75,24 +81,86 @@ public async Task<ActionResult<AgreementReadModel>> GetAgreementByEngagement([Fr
BlobName: f.BlobName,
UploadedOn: f.UploadedOn
)).ToList()
);
return Ok(responseModel);
)).ToList();

return Ok(responseModels);
}

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

var agreements = await agreementsRepository.GetAgreementsByCustomerId(customerId, ct);

if (agreements is null || !agreements.Any()) return NotFound();

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

return Ok(responseModels);
}

[HttpPost]
[Route("create")]
public async Task<ActionResult<AgreementWriteModel>> Post([FromRoute] string orgUrlKey,
public async Task<ActionResult<AgreementReadModel>> Post([FromRoute] string orgUrlKey,
[FromBody] AgreementWriteModel body, CancellationToken ct)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

if (body.CustomerId is null && body.EngagementId is null)
{
ModelState.AddModelError("", "At least one of CustomerId or EngagementId must be provided.");
return BadRequest(ModelState);
}

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

Customer? customer = null;
if (body.CustomerId != null)
{
customer = await context.Customer.FindAsync(body.CustomerId.Value);
if (customer == null)
return BadRequest("Customer not found");
}

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

var agreement = new Agreement
{
Name = body.Name,
CustomerId = body.CustomerId,
Customer = customer,
EngagementId = body.EngagementId,
Engagement = engagement,
StartDate = body.StartDate,
Expand All @@ -113,7 +181,9 @@ public async Task<ActionResult<AgreementWriteModel>> Post([FromRoute] string org
await agreementsRepository.AddAgreementAsync(agreement, ct);

var responseModel = new AgreementReadModel(
Name: agreement.Name,
AgreementId: agreement.Id,
CustomerId: agreement.CustomerId,
EngagementId: agreement.EngagementId,
StartDate: agreement.StartDate,
EndDate: agreement.EndDate,
Expand All @@ -137,13 +207,58 @@ public async Task<ActionResult<AgreementWriteModel>> Post([FromRoute] string org
public async Task<ActionResult<AgreementReadModel>> Put([FromRoute] string orgUrlKey,
[FromRoute] int agreementId, [FromBody] AgreementWriteModel body, CancellationToken ct)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

if (body.CustomerId is null && body.EngagementId is null)
{
ModelState.AddModelError("", "At least one of CustomerId or EngagementId must be provided.");
return BadRequest(ModelState);
}

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

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

Customer? customer = null;
if (body.CustomerId is not null)
{
customer = await context.Customer.FindAsync(body.CustomerId);
if (customer is null)
return BadRequest("Customer not found");

agreement.CustomerId = body.CustomerId;
agreement.Customer = customer;
}
else
{
agreement.CustomerId = null;
agreement.Customer = null;
}

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

agreement.EngagementId = body.EngagementId;
agreement.Engagement = engagement;
}
else
{
agreement.EngagementId = null;
agreement.Engagement = null;
}

agreement.EngagementId = body.EngagementId;
agreement.Name = body.Name;
agreement.StartDate = body.StartDate;
agreement.EndDate = body.EndDate;
agreement.NextPriceAdjustmentDate = body.NextPriceAdjustmentDate;
Expand All @@ -162,6 +277,8 @@ public async Task<ActionResult<AgreementReadModel>> Put([FromRoute] string orgUr

var responseModel = new AgreementReadModel(
AgreementId: agreement.Id,
Name: agreement.Name,
CustomerId: agreement.CustomerId,
EngagementId: agreement.EngagementId,
StartDate: agreement.StartDate,
EndDate: agreement.EndDate,
Expand Down Expand Up @@ -192,7 +309,7 @@ public async Task<ActionResult> Delete([FromRoute] string orgUrlKey, [FromRoute]

await agreementsRepository.DeleteAgreementAsync(agreementId, ct);

return Ok();
return Ok("Deleted");
}

[HttpGet]
Expand Down
23 changes: 19 additions & 4 deletions backend/Api/Projects/AgreementModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

public record AgreementReadModel(
int AgreementId,
int EngagementId,
string? Name,
int? CustomerId,
int? EngagementId,
DateTime? StartDate,
DateTime EndDate,
DateTime? NextPriceAdjustmentDate,
Expand All @@ -14,15 +16,16 @@ public record AgreementReadModel(
string? PriceAdjustmentProcess,
List<FileReferenceReadModel> Files
);

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

public record AgreementWriteModel(
int EngagementId,
string? Name,
int? CustomerId,
int? EngagementId,
DateTime? StartDate,
DateTime EndDate,
DateTime? NextPriceAdjustmentDate,
Expand All @@ -31,7 +34,19 @@ public record AgreementWriteModel(
string? Options,
string? PriceAdjustmentProcess,
List<FileReferenceWriteModel> Files
);
): IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (CustomerId == null && EngagementId == null)
{
yield return new ValidationResult(
"At least one of CustomerId or EngagementId must be provided.",
new[] { nameof(CustomerId), nameof(EngagementId) });
}
}
}


public record FileReferenceWriteModel(
string FileName,
Expand Down
34 changes: 18 additions & 16 deletions backend/Core/Agreements/Agreement.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
using System.ComponentModel.DataAnnotations.Schema;
using Core.Customers;
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; }
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string? Name { get; set; } = string.Empty;
public int? CustomerId { get; set; }
public Customer? Customer { get; set; }

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

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

public required DateTime EndDate { get; set; }
public DateTime? StartDate { get; set; }
public required DateTime EndDate { get; set; }

public DateTime? NextPriceAdjustmentDate { get; set; }
public DateTime? NextPriceAdjustmentDate { get; set; }

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

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

public class FileReference
{
Expand Down
4 changes: 2 additions & 2 deletions backend/Core/Agreements/IAgreementRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ public interface IAgreementsRepository
{
public Task<Agreement?> GetAgreementById(int id, CancellationToken cancellationToken);

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

public Task<List<Agreement>> GetAgreementsByEngagementId(int engagementId, CancellationToken cancellationToken);
public Task<List<Agreement>> GetAgreementsByCustomerId(int customerId, CancellationToken cancellationToken);
public Task AddAgreementAsync(Agreement agreement, CancellationToken cancellationToken);

public Task UpdateAgreementAsync(Agreement agreement, CancellationToken cancellationToken);
Expand Down
3 changes: 2 additions & 1 deletion backend/Core/Customers/Customer.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.Engagements;
using Core.Organizations;

Expand All @@ -10,7 +11,7 @@ public class Customer
public int Id { get; set; }

public string? OrganizationId { get; set; }

public ICollection<Agreement> Agreements { get; set; } = new List<Agreement>();
public required string Name { get; set; }
public required Organization Organization { get; set; }
public required List<Engagement> Projects { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion backend/Core/Engagements/Engagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class Engagement

public required Customer Customer { get; set; }

public Agreement? Agreement { get; set; }
public ICollection<Agreement> Agreements { get; set; } = new List<Agreement>();

public required EngagementState State { get; set; }

Expand Down
22 changes: 14 additions & 8 deletions backend/Infrastructure/DatabaseContext/ApplicationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,16 +167,22 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

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.Customer)
.WithMany(c => c.Agreements)
.HasForeignKey(a => a.CustomerId)
.OnDelete(DeleteBehavior.Restrict);

entity.HasOne(a => a.Engagement)
.WithOne(e => e.Agreement)
.HasForeignKey<Agreement>(a => a.EngagementId);
.WithMany(e => e.Agreements)
.HasForeignKey(a => a.EngagementId)
.OnDelete(DeleteBehavior.Restrict);

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

modelBuilder.Entity<Organization>()
Expand Down
Loading

0 comments on commit c64da86

Please sign in to comment.