Skip to content

Commit

Permalink
Merge pull request #19 from soat-fiap/create_domain
Browse files Browse the repository at this point in the history
Create initial domain entities
  • Loading branch information
italopessoa committed Apr 20, 2024
2 parents 15cb651 + 136d4b4 commit bf03bd9
Show file tree
Hide file tree
Showing 12 changed files with 705 additions and 6 deletions.
39 changes: 39 additions & 0 deletions src/FIAP.TechChallenge.ByteMeBurger.Domain/Base/ValueObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
namespace FIAP.TechChallenge.ByteMeBurger.Domain.Base;

public abstract class ValueObject
{
protected static bool EqualOperator(ValueObject left, ValueObject right)
{
if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null))
{
return false;
}
return ReferenceEquals(left, right) || left.Equals(right);

Check warning on line 11 in src/FIAP.TechChallenge.ByteMeBurger.Domain/Base/ValueObject.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 11 in src/FIAP.TechChallenge.ByteMeBurger.Domain/Base/ValueObject.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'obj' in 'bool ValueObject.Equals(object obj)'.

Check warning on line 11 in src/FIAP.TechChallenge.ByteMeBurger.Domain/Base/ValueObject.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 11 in src/FIAP.TechChallenge.ByteMeBurger.Domain/Base/ValueObject.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'obj' in 'bool ValueObject.Equals(object obj)'.
}

protected static bool NotEqualOperator(ValueObject left, ValueObject right)
{
return !EqualOperator(left, right);
}

protected abstract IEnumerable<object> GetEqualityComponents();

public override bool Equals(object obj)

Check warning on line 21 in src/FIAP.TechChallenge.ByteMeBurger.Domain/Base/ValueObject.cs

View workflow job for this annotation

GitHub Actions / build

Nullability of type of parameter 'obj' doesn't match overridden member (possibly because of nullability attributes).

Check warning on line 21 in src/FIAP.TechChallenge.ByteMeBurger.Domain/Base/ValueObject.cs

View workflow job for this annotation

GitHub Actions / build

Nullability of type of parameter 'obj' doesn't match overridden member (possibly because of nullability attributes).
{
if (obj is null || obj.GetType() != GetType())
{
return false;
}

var other = (ValueObject)obj;

return this.GetEqualityComponents().SequenceEqual(other.GetEqualityComponents());
}

public override int GetHashCode()
{
return GetEqualityComponents()
.Select(x => x != null ? x.GetHashCode() : 0)
.Aggregate((x, y) => x ^ y);
}
}
103 changes: 103 additions & 0 deletions src/FIAP.TechChallenge.ByteMeBurger.Domain/Entities/Customer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System.Text.RegularExpressions;

namespace FIAP.TechChallenge.ByteMeBurger.Domain.Entities;

public class Customer : Entity<string>
{
public string? Name { get; private set; }

public string? Email { get; private set; }

public Customer()
: base(ValidateId(Guid.NewGuid().ToString()))
{
Name = "Anonymous";
}

public Customer(string cpf)
: base(ValidateId(cpf))
{
}

public Customer(string cpf, string name, string email)
: base(ValidateId(cpf))
{
ArgumentException.ThrowIfNullOrWhiteSpace(name);

Name = name;
Email = ValidateEmail(email);
;
Id = ValidateId(cpf);
}

private static string ValidateEmail(string email)
{
ArgumentException.ThrowIfNullOrWhiteSpace(email);
if (!Regex.IsMatch(email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
throw new ArgumentException($"Invalid email format '{email}'");

return email;
}

private static string SanityseCpf(string cpf) => cpf
.Replace(".", "")
.Replace("-", "")
.Trim();

public static string ValidateId(string cpf)
{
if (Guid.TryParse(cpf, out var validGuid) && Guid.Empty != validGuid)
return cpf;

ArgumentException.ThrowIfNullOrWhiteSpace(cpf);
var isValidCpf = false;

var multiplicador1 = new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2 };
var multiplicador2 = new[] { 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 };

var workingWpf = SanityseCpf(cpf);

if (workingWpf.Length == 11 && workingWpf.Distinct().Count() > 1)
{
var tempCpf = workingWpf.Substring(0, 9);
var soma = 0;

for (int i = 0; i < 9; i++)
soma += int.Parse(tempCpf[i].ToString()) * multiplicador1[i];

var resto = soma % 11;

if (resto < 2)
resto = 0;
else
resto = 11 - resto;

var digito = resto.ToString();

tempCpf += digito;

soma = 0;

for (int i = 0; i < 10; i++)
soma += int.Parse(tempCpf[i].ToString()) * multiplicador2[i];

resto = soma % 11;

if (resto < 2)
resto = 0;
else
resto = 11 - resto;

digito += resto.ToString();

isValidCpf = workingWpf.EndsWith(digito);
}

if (!isValidCpf)
{
throw new ArgumentException($"Invalid CPF value '{cpf}'");
}

return workingWpf;
}
}
6 changes: 6 additions & 0 deletions src/FIAP.TechChallenge.ByteMeBurger.Domain/Entities/Entity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace FIAP.TechChallenge.ByteMeBurger.Domain.Entities;

public abstract class Entity<T>(T id)
{
public T Id { get; protected set; } = id;
}
127 changes: 127 additions & 0 deletions src/FIAP.TechChallenge.ByteMeBurger.Domain/Entities/Order.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using FIAP.TechChallenge.ByteMeBurger.Domain.ValueObjects;

namespace FIAP.TechChallenge.ByteMeBurger.Domain.Entities;

public class Order : Entity<Guid>
{
private List<Product> _products;

public Customer Customer { get; private set; }

public string? TrackingCode { get; private set; }

public OrderStatus Status { get; private set; }

public DateTime CreationDate { get; set; }

public DateTime LastUpdate { get; set; }

public IReadOnlyList<Product> Products => _products.AsReadOnly();

public decimal Total => _products.Sum(p => p.Price);


public Order()
: base(Guid.NewGuid())
{
_products = Enumerable.Empty<Product>().ToList();
Customer = new Customer(Guid.NewGuid().ToString());
}

public Order(string customerId)
: base(Guid.NewGuid())
{
_products = Enumerable.Empty<Product>().ToList();
Customer = new Customer(customerId);
}

public void AddProduct(Product product)
{
_products.Add(product);
}

public void Validate()
{
if (!Products.Any())
{
throw new InvalidOperationException("An Order must have at least one item");
}
}

public void CreateOrder()
{
Validate();
CreationDate = DateTime.UtcNow;
}

public void ConfirmPayment()
{
if (CreationDate == default)
throw new InvalidOperationException("Cannot confirm");

Status = OrderStatus.Received;
TrackingCode = GenerateCode(CreationDate);
}

public void InitiatePrepare()
{
if (Status != OrderStatus.Received)
throw new InvalidOperationException("Cannot start preparing if order isn't confirmed.");

Status = OrderStatus.Preparing;
Update();
}

public void FinishPreparing()
{
if (Status != OrderStatus.Preparing)
throw new InvalidOperationException("Cannot Finish order if it's not Preparing yet.");

Status = OrderStatus.Done;
Update();
}

public void DeliverOrder()
{
if (Status != OrderStatus.Done)
throw new InvalidOperationException("Cannot Deliver order if it's not Finished yet.");

Status = OrderStatus.Finished;
Update();
}

private void Update() => LastUpdate = DateTime.UtcNow;

private bool IsFullCombo() => _products
.Select(p => p.Category)
.Distinct()
.Count() == 4;

private static string GetLetter(int number, string alphabet)
{
var adjustedNumber = number % alphabet.Length;
var letterIndex = adjustedNumber > 0 ? adjustedNumber - 1 : adjustedNumber;

return alphabet.Substring(letterIndex, 1);
}
private string GenerateCode(DateTime confirmationDate)
{
const string lettersOnly = "ABCDEFGHIJKLMNOPQRSTUVXYZ";
const string reversedCharacters = "87654321ZYXVUTSRQPMLKJIHFEDCB";

var hour = confirmationDate.Hour;
var minute = confirmationDate.Minute;
var second = confirmationDate.Second;
var millisecond = confirmationDate.Millisecond;

var partA = GetLetter(hour, lettersOnly);
var partB = millisecond % 2 == 0 ? string.Empty : GetLetter(minute, reversedCharacters);
var partC = GetLetter(second, reversedCharacters);

var key = Guid.NewGuid().ToString()
.Split("-")[2]
.Substring(1, 3);

return $"{partA}{partB}{partC}-{(IsFullCombo() ? "#" : "")}{key}".ToUpper();
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,4 @@
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>

<ItemGroup>
<Folder Include="Base\" />
<Folder Include="Entities\" />
<Folder Include="ValueObjects\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace FIAP.TechChallenge.ByteMeBurger.Domain.ValueObjects;

public enum OrderStatus
{
None = 0,
Received,
Preparing,
Done,
Finished
}
39 changes: 39 additions & 0 deletions src/FIAP.TechChallenge.ByteMeBurger.Domain/ValueObjects/Product.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using FIAP.TechChallenge.ByteMeBurger.Domain.Base;

namespace FIAP.TechChallenge.ByteMeBurger.Domain.ValueObjects;

public class Product : ValueObject
{
public string Name { get; private set; }

public string Description { get; private set; }

public ProductCategory Category { get; private set; }

public decimal Price { get; private set; }

public IReadOnlyList<string> Images { get; private set; }

public Product(string name, string description, ProductCategory category, decimal price,
IReadOnlyList<string> images)
{
ArgumentException.ThrowIfNullOrWhiteSpace(name);
ArgumentException.ThrowIfNullOrWhiteSpace(description);
ArgumentOutOfRangeException.ThrowIfNegative(price);

Name = name.ToUpper();
Description = description.ToUpper();
Category = category;
Price = price;
Images = images;
}

protected override IEnumerable<object> GetEqualityComponents()
{
yield return Name;
yield return Description;
yield return Category;
yield return Price;
yield return Images.GetEnumerator();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace FIAP.TechChallenge.ByteMeBurger.Domain.ValueObjects;

public enum ProductCategory
{
Meal = 0,
FriesAndSides,
Beverage,
SweatsNTreats
}
Loading

0 comments on commit bf03bd9

Please sign in to comment.