diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc9a86a --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*/bin/* +packages/ +bin/ +*.suo +desktop.ini +*.user +**/obj/* +*.mdf +*.ldf diff --git a/CQRS.Base/CQRS.Base.csproj b/CQRS.Base/CQRS.Base.csproj new file mode 100644 index 0000000..b908830 --- /dev/null +++ b/CQRS.Base/CQRS.Base.csproj @@ -0,0 +1,74 @@ + + + + + Debug + AnyCPU + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A} + Library + Properties + CQRS.Base + CQRS.Base + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Iesi.Collections.4.0.0.4000\lib\net40\Iesi.Collections.dll + True + + + ..\packages\NHibernate.4.0.4.4000\lib\net40\NHibernate.dll + True + + + + + + + + + + + + + + + + + + + + {2230C68D-558A-463F-B3ED-427968DECB2E} + PhotoStock.Sales.Domain + + + + + + + + \ No newline at end of file diff --git a/CQRS.Base/Command/ICommandHandler.cs b/CQRS.Base/Command/ICommandHandler.cs new file mode 100644 index 0000000..626cae3 --- /dev/null +++ b/CQRS.Base/Command/ICommandHandler.cs @@ -0,0 +1,7 @@ +namespace CQRS.Base.Command +{ + public interface ICommandHandler + { + void Handle(TCommand command); + } +} \ No newline at end of file diff --git a/CQRS.Base/Command/ICommandSender.cs b/CQRS.Base/Command/ICommandSender.cs new file mode 100644 index 0000000..12e33ae --- /dev/null +++ b/CQRS.Base/Command/ICommandSender.cs @@ -0,0 +1,7 @@ +namespace CQRS.Base.Command +{ + public interface ICommandSender + { + void Send(TCommand command); + } +} \ No newline at end of file diff --git a/CQRS.Base/Events/IEventListener.cs b/CQRS.Base/Events/IEventListener.cs new file mode 100644 index 0000000..6f17241 --- /dev/null +++ b/CQRS.Base/Events/IEventListener.cs @@ -0,0 +1,7 @@ +namespace CQRS.Base.Events +{ + public interface IEventListener + { + void Handle(TEvent eventData); + } +} \ No newline at end of file diff --git a/CQRS.Base/Properties/AssemblyInfo.cs b/CQRS.Base/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..bad425b --- /dev/null +++ b/CQRS.Base/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CQRS.Base")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CQRS.Base")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7d8d2feb-c2e5-4d54-8369-21de2d44984a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CQRS.Base/Query/PaginatedResult.cs b/CQRS.Base/Query/PaginatedResult.cs new file mode 100644 index 0000000..204bbf3 --- /dev/null +++ b/CQRS.Base/Query/PaginatedResult.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; + +namespace CQRS.Base.Query +{ + public class PaginatedResult + { + public List Items { get; private set; } + public int PageSize { get; private set; } + public int PageNumber { get; private set; } + public int PagesCount { get; private set; } + public int TotalItemsCount { get; private set; } + + public PaginatedResult(int pageNumber, int pageSize) + { + PageNumber = pageNumber; + PageSize = pageSize; + Items = new List(); + PagesCount = 0; + TotalItemsCount = 0; + } + + public PaginatedResult(List items, int pageNumber, int pageSize, int totalItemsCount) + { + Items = items; + PageNumber = pageNumber; + PageSize = pageSize; + PagesCount = CountPages(pageSize, totalItemsCount); + TotalItemsCount = totalItemsCount; + } + + private int CountPages(int size, int itemsCount) + { + return (int)Math.Ceiling((double)itemsCount / size); + } + } +} \ No newline at end of file diff --git a/CQRS.Base/packages.config b/CQRS.Base/packages.config new file mode 100644 index 0000000..30a8e96 --- /dev/null +++ b/CQRS.Base/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/DDD.Base/DDD.Base.csproj b/DDD.Base/DDD.Base.csproj new file mode 100644 index 0000000..3750f6a --- /dev/null +++ b/DDD.Base/DDD.Base.csproj @@ -0,0 +1,71 @@ + + + + + Debug + AnyCPU + {F8D43559-8792-498B-AB51-211CA04CB4DF} + Library + Properties + DDD.Base + DDD.Base + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DDD.Base/Domain/AggregateRoot.cs b/DDD.Base/Domain/AggregateRoot.cs new file mode 100644 index 0000000..b69d375 --- /dev/null +++ b/DDD.Base/Domain/AggregateRoot.cs @@ -0,0 +1,44 @@ +using System; + +namespace DDD.Base.Domain +{ + public abstract class AggregateRoot + { + public enum AggregateStatus + { + ACTIVE, ARCHIVE + } + + public AggregateId AggregateId { get; private set; } + + public int Version { get; private set; } + private AggregateStatus _aggregateStatus = AggregateStatus.ACTIVE; + + protected IDomainEventPublisher EventPublisher { get; private set; } + + protected AggregateRoot() + { + Version = 0; + } + + public AggregateRoot(AggregateId aggregateId) + { + AggregateId = aggregateId; + } + + public void MarkAsRemoved() + { + _aggregateStatus = AggregateStatus.ARCHIVE; + } + + public bool IsRemoved() + { + return _aggregateStatus == AggregateStatus.ARCHIVE; + } + + protected void DomainError(string message) + { + throw new DomainOperationException(AggregateId, message); + } + } +} \ No newline at end of file diff --git a/DDD.Base/Domain/AgregateId.cs b/DDD.Base/Domain/AgregateId.cs new file mode 100644 index 0000000..8444a62 --- /dev/null +++ b/DDD.Base/Domain/AgregateId.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace DDD.Base.Domain +{ + public class AggregateId : ValueObject + { + private string _innerId; + + public AggregateId(string value) + { + if (value == null) + { + throw new ArgumentNullException("value"); + } + _innerId = value; + } + + protected AggregateId() + { + } + + public static AggregateId Generate() + { + return new AggregateId(Guid.NewGuid().ToString()); + } + + public static implicit operator AggregateId(string value) + { + return new AggregateId(value); + } + + public static implicit operator string(AggregateId aggregateId) + { + if (aggregateId != null) + { + return aggregateId._innerId; + } + return null; + } + } +} \ No newline at end of file diff --git a/DDD.Base/Domain/DomainOperationException.cs b/DDD.Base/Domain/DomainOperationException.cs new file mode 100644 index 0000000..e5cb39e --- /dev/null +++ b/DDD.Base/Domain/DomainOperationException.cs @@ -0,0 +1,14 @@ +using System; + +namespace DDD.Base.Domain +{ + public class DomainOperationException : Exception + { + public AggregateId AggregateId { get; set; } + + public DomainOperationException(AggregateId aggregateId, string message) : base(message) + { + AggregateId = aggregateId; + } + } +} \ No newline at end of file diff --git a/DDD.Base/Domain/Entity.cs b/DDD.Base/Domain/Entity.cs new file mode 100644 index 0000000..2d8de1a --- /dev/null +++ b/DDD.Base/Domain/Entity.cs @@ -0,0 +1,7 @@ +namespace DDD.Base.Domain +{ + public abstract class Entity + { + public int Id { get; private set; } + } +} \ No newline at end of file diff --git a/DDD.Base/Domain/Exceptions/IllegalStateException.cs b/DDD.Base/Domain/Exceptions/IllegalStateException.cs new file mode 100644 index 0000000..a0e9eda --- /dev/null +++ b/DDD.Base/Domain/Exceptions/IllegalStateException.cs @@ -0,0 +1,15 @@ +using System; + +namespace DDD.Base.Domain.Exceptions +{ + public class IllegalStateException : Exception + { + public IllegalStateException(string message) : base(message) + { + } + + public IllegalStateException() + { + } + } +} \ No newline at end of file diff --git a/DDD.Base/Domain/IDependencyInjector.cs b/DDD.Base/Domain/IDependencyInjector.cs new file mode 100644 index 0000000..74a5317 --- /dev/null +++ b/DDD.Base/Domain/IDependencyInjector.cs @@ -0,0 +1,7 @@ +namespace DDD.Base.Domain +{ + public interface IDependencyInjector + { + void InjectDependencies(AggregateRoot aggregateRoot); + } +} \ No newline at end of file diff --git a/DDD.Base/Domain/IDomainEvent.cs b/DDD.Base/Domain/IDomainEvent.cs new file mode 100644 index 0000000..0b459ef --- /dev/null +++ b/DDD.Base/Domain/IDomainEvent.cs @@ -0,0 +1,8 @@ +namespace DDD.Base.Domain +{ + // Remove marker interface + //[Domain@event] + public interface IDomainEvent + { + } +} \ No newline at end of file diff --git a/DDD.Base/Domain/IDomainEventPublisher.cs b/DDD.Base/Domain/IDomainEventPublisher.cs new file mode 100644 index 0000000..037c93f --- /dev/null +++ b/DDD.Base/Domain/IDomainEventPublisher.cs @@ -0,0 +1,7 @@ +namespace DDD.Base.Domain +{ + public interface IDomainEventPublisher + { + void Publish(T domainEvent) where T : IDomainEvent; + } +} \ No newline at end of file diff --git a/DDD.Base/Domain/IGenericRepository.cs b/DDD.Base/Domain/IGenericRepository.cs new file mode 100644 index 0000000..378c39a --- /dev/null +++ b/DDD.Base/Domain/IGenericRepository.cs @@ -0,0 +1,13 @@ +using System.Collections; + +namespace DDD.Base.Domain +{ + public interface IGenericRepository where T : AggregateRoot + { + T Load(AggregateId id); + + void Delete(AggregateId id); + + void Save(T entity); + } +} \ No newline at end of file diff --git a/DDD.Base/Domain/ValueObject.cs b/DDD.Base/Domain/ValueObject.cs new file mode 100644 index 0000000..e8bd365 --- /dev/null +++ b/DDD.Base/Domain/ValueObject.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace DDD.Base.Domain +{ + public abstract class ValueObject : IEqualityComparer, IEquatable + { + private const int Multiplier = 59; + private const int StartValue = 17; + + public static bool operator ==(ValueObject x, ValueObject y) + { + if (ReferenceEquals(x, null) && ReferenceEquals(y, null)) + { + return true; + } + + if (ReferenceEquals(x, null)) + { + return false; + } + + return x.Equals(y); + } + + public static bool operator !=(ValueObject x, ValueObject y) + { + return !(x == y); + } + + public virtual bool Equals(ValueObject other) + { + if (other == null) + { + return false; + } + + Type t = GetType(); + + Type otherType = other.GetType(); + + if (t != otherType) + { + return false; + } + + FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + + foreach (FieldInfo field in fields) + { + object value1 = field.GetValue(other); + + object value2 = field.GetValue(this); + + if (value1 == null) + { + if (value2 != null) + { + return false; + } + } + else if (!value1.Equals(value2)) + { + return false; + } + } + + return true; + } + + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + + var other = obj as ValueObject; + + return Equals(other); + } + + public override int GetHashCode() + { + IEnumerable fields = GetFields(); + + int startValue = StartValue; + + int multiplier = Multiplier; + + int hashCode = startValue; + + foreach (FieldInfo field in fields) + { + object value = field.GetValue(this); + + if (value != null) + { + hashCode = (hashCode * multiplier) + value.GetHashCode(); + } + } + + return hashCode; + } + + private IEnumerable GetFields() + { + Type t = GetType(); + + var fields = new List(); + + while (t != typeof(object)) + { + fields.AddRange(t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)); + + t = t.BaseType; + } + + return fields; + } + + public bool Equals(object x, object y) + { + if (ReferenceEquals(x, null) && ReferenceEquals(y, null)) + { + return true; + } + + if (ReferenceEquals(x, null)) + { + return false; + } + + return x.Equals(y); + } + + public int GetHashCode(object obj) + { + return obj.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/DDD.Base/Properties/AssemblyInfo.cs b/DDD.Base/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1e198a2 --- /dev/null +++ b/DDD.Base/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DDD.Base")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DDD.Base")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f8d43559-8792-498b-ab51-211ca04cb4df")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DDD.Base/Sagas/ISagaManager.cs b/DDD.Base/Sagas/ISagaManager.cs new file mode 100644 index 0000000..8e61c56 --- /dev/null +++ b/DDD.Base/Sagas/ISagaManager.cs @@ -0,0 +1,7 @@ +namespace DDD.Base.Sagas +{ + public interface ISagaManager + { + void ProcessMessage(T message); + } +} \ No newline at end of file diff --git a/DDD.Base/SharedKernel/Specification/AndSpecification.cs b/DDD.Base/SharedKernel/Specification/AndSpecification.cs new file mode 100644 index 0000000..ae598d1 --- /dev/null +++ b/DDD.Base/SharedKernel/Specification/AndSpecification.cs @@ -0,0 +1,19 @@ +namespace DDD.Base.SharedKernel.Specification +{ + public class AndSpecification : CompositeSpecification + { + private ISpecification _a; + private ISpecification _b; + + public AndSpecification(ISpecification a, ISpecification b) + { + _a = a; + _b = b; + } + + public override bool IsSatisfiedBy(T offer) + { + return _a.IsSatisfiedBy(offer) && _b.IsSatisfiedBy(offer); + } + } +} \ No newline at end of file diff --git a/DDD.Base/SharedKernel/Specification/CompositeSpecification.cs b/DDD.Base/SharedKernel/Specification/CompositeSpecification.cs new file mode 100644 index 0000000..6d3dee1 --- /dev/null +++ b/DDD.Base/SharedKernel/Specification/CompositeSpecification.cs @@ -0,0 +1,22 @@ +namespace DDD.Base.SharedKernel.Specification +{ + public abstract class CompositeSpecification : ISpecification + { + public abstract bool IsSatisfiedBy(T offer); + + public ISpecification And(ISpecification other) + { + return new AndSpecification(this, other); + } + + public ISpecification Or(ISpecification other) + { + return new OrSpecification(this, other); + } + + public ISpecification Not() + { + return new NotSpecification(this); + } + } +} \ No newline at end of file diff --git a/DDD.Base/SharedKernel/Specification/ConjunctionSpecification.cs b/DDD.Base/SharedKernel/Specification/ConjunctionSpecification.cs new file mode 100644 index 0000000..423b498 --- /dev/null +++ b/DDD.Base/SharedKernel/Specification/ConjunctionSpecification.cs @@ -0,0 +1,19 @@ +using System.Linq; + +namespace DDD.Base.SharedKernel.Specification +{ + public class ConjunctionSpecification : CompositeSpecification + { + private readonly ISpecification[] _conjunction; + + public ConjunctionSpecification(params ISpecification[] conjunction) + { + _conjunction = conjunction; + } + + public override bool IsSatisfiedBy(T offer) + { + return _conjunction.All(spec => spec.IsSatisfiedBy(offer)); + } + } +} \ No newline at end of file diff --git a/DDD.Base/SharedKernel/Specification/DisjunctionSpecification.cs b/DDD.Base/SharedKernel/Specification/DisjunctionSpecification.cs new file mode 100644 index 0000000..6d77336 --- /dev/null +++ b/DDD.Base/SharedKernel/Specification/DisjunctionSpecification.cs @@ -0,0 +1,19 @@ +using System.Linq; + +namespace DDD.Base.SharedKernel.Specification +{ + public class DisjunctionSpecification : CompositeSpecification + { + private readonly ISpecification[] _disjunction; + + public DisjunctionSpecification(ISpecification[] disjunction) + { + _disjunction = disjunction; + } + + public override bool IsSatisfiedBy(T offer) + { + return _disjunction.Any(spec => spec.IsSatisfiedBy(offer)); + } + } +} \ No newline at end of file diff --git a/DDD.Base/SharedKernel/Specification/ISpecification.cs b/DDD.Base/SharedKernel/Specification/ISpecification.cs new file mode 100644 index 0000000..02bdfd2 --- /dev/null +++ b/DDD.Base/SharedKernel/Specification/ISpecification.cs @@ -0,0 +1,13 @@ +namespace DDD.Base.SharedKernel.Specification +{ + public interface ISpecification + { + bool IsSatisfiedBy(T offer); + + ISpecification And(ISpecification other); + + ISpecification Or(ISpecification other); + + ISpecification Not(); + } +} \ No newline at end of file diff --git a/DDD.Base/SharedKernel/Specification/NotSpecification.cs b/DDD.Base/SharedKernel/Specification/NotSpecification.cs new file mode 100644 index 0000000..03c7b37 --- /dev/null +++ b/DDD.Base/SharedKernel/Specification/NotSpecification.cs @@ -0,0 +1,17 @@ +namespace DDD.Base.SharedKernel.Specification +{ + public class NotSpecification : CompositeSpecification + { + private ISpecification _wrapped; + + public NotSpecification(ISpecification wrapped) + { + _wrapped = wrapped; + } + + public override bool IsSatisfiedBy(T offer) + { + return !_wrapped.IsSatisfiedBy(offer); + } + } +} \ No newline at end of file diff --git a/DDD.Base/SharedKernel/Specification/OrSpecification.cs b/DDD.Base/SharedKernel/Specification/OrSpecification.cs new file mode 100644 index 0000000..3537ea0 --- /dev/null +++ b/DDD.Base/SharedKernel/Specification/OrSpecification.cs @@ -0,0 +1,19 @@ +namespace DDD.Base.SharedKernel.Specification +{ + public class OrSpecification : CompositeSpecification + { + private ISpecification _a; + private ISpecification _b; + + public OrSpecification(ISpecification a, ISpecification b) + { + _a = a; + _b = b; + } + + public override bool IsSatisfiedBy(T offer) + { + return _a.IsSatisfiedBy(offer) || _b.IsSatisfiedBy(offer); + } + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/DDD.Infrastructure.csproj b/DDD.Infrastructure/DDD.Infrastructure.csproj new file mode 100644 index 0000000..8cf0253 --- /dev/null +++ b/DDD.Infrastructure/DDD.Infrastructure.csproj @@ -0,0 +1,97 @@ + + + + + Debug + AnyCPU + {1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E} + Library + Properties + DDD.Infrastructure + DDD.Infrastructure + v4.5.2 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Automatonymous.3.3.0\lib\net452\Automatonymous.dll + True + + + ..\packages\Castle.Core.3.3.0\lib\net45\Castle.Core.dll + True + + + ..\packages\Castle.Windsor.3.3.0\lib\net45\Castle.Windsor.dll + True + + + ..\packages\Iesi.Collections.4.0.0.4000\lib\net40\Iesi.Collections.dll + True + + + ..\packages\NHibernate.4.0.4.4000\lib\net40\NHibernate.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {7d8d2feb-c2e5-4d54-8369-21de2d44984a} + CQRS.Base + + + {f8d43559-8792-498b-ab51-211ca04cb4df} + DDD.Base + + + + + \ No newline at end of file diff --git a/DDD.Infrastructure/DependencyInjector.cs b/DDD.Infrastructure/DependencyInjector.cs new file mode 100644 index 0000000..6484045 --- /dev/null +++ b/DDD.Infrastructure/DependencyInjector.cs @@ -0,0 +1,29 @@ +using Castle.Windsor; +using DDD.Base.Domain; +using System.Reflection; + +namespace DDD.Infrastructure +{ + public class DependencyInjector : IDependencyInjector + { + private readonly IWindsorContainer _container; + + public DependencyInjector(IWindsorContainer container) + { + _container = container; + } + + public void InjectDependencies(AggregateRoot aggregateRoot) + { + var fields = aggregateRoot.GetType().GetFields(); + foreach (FieldInfo fieldInfo in fields) + { + if (fieldInfo.FieldType.IsInterface) + { + object iface = _container.Resolve(fieldInfo.FieldType); + fieldInfo.SetValue(aggregateRoot, iface); + } + } + } + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/GenericRepository.cs b/DDD.Infrastructure/GenericRepository.cs new file mode 100644 index 0000000..091fb86 --- /dev/null +++ b/DDD.Infrastructure/GenericRepository.cs @@ -0,0 +1,46 @@ +using DDD.Base.Domain; +using NHibernate; + +namespace DDD.Infrastructure +{ + public abstract class GenericRepository : IGenericRepository + where TAggregateRoot : AggregateRoot + { + private readonly IDependencyInjector _dependencyInjector; + private readonly ISession _session; + + public GenericRepository(ISession session, IDependencyInjector dependencyInjector) + { + _session = session; + _dependencyInjector = dependencyInjector; + } + + public TAggregateRoot Load(AggregateId id) + { + var result = _session.Get(id); + if (result == null) + { + return null; + } + if (result.IsRemoved()) + { + return null; + } + _dependencyInjector.InjectDependencies(result); + + return result; + } + + public void Save(TAggregateRoot aggregateRoot) + { + _session.SaveOrUpdate(aggregateRoot); + } + + public void Delete(AggregateId id) + { + var obj = _session.Get(id); + obj.MarkAsRemoved(); + _session.SaveOrUpdate(obj); + } + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/ISystemEvent.cs b/DDD.Infrastructure/ISystemEvent.cs new file mode 100644 index 0000000..0581ccb --- /dev/null +++ b/DDD.Infrastructure/ISystemEvent.cs @@ -0,0 +1,6 @@ +namespace Photostock.Sales.Infrastructure +{ + public interface ISystemEvent + { + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/ISystemEventPublisher.cs b/DDD.Infrastructure/ISystemEventPublisher.cs new file mode 100644 index 0000000..405e930 --- /dev/null +++ b/DDD.Infrastructure/ISystemEventPublisher.cs @@ -0,0 +1,7 @@ +namespace Photostock.Sales.Infrastructure +{ + public interface ISystemEventPublisher + { + void Publish(T @event) where T : ISystemEvent; + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/Properties/AssemblyInfo.cs b/DDD.Infrastructure/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..22d7b5a --- /dev/null +++ b/DDD.Infrastructure/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DDD.Infrastructure")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DDD.Infrastructure")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1f25c4fb-d5ea-46bb-ab2b-ac5582e1aa9e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DDD.Infrastructure/Sagas/ISagaData.cs b/DDD.Infrastructure/Sagas/ISagaData.cs new file mode 100644 index 0000000..d08fbc9 --- /dev/null +++ b/DDD.Infrastructure/Sagas/ISagaData.cs @@ -0,0 +1,9 @@ +using Automatonymous; + +namespace DDD.Infrastructure.Sagas +{ + public interface ISagaData + { + State CurrentState { get; set; } + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/Sagas/ISagaRepository.cs b/DDD.Infrastructure/Sagas/ISagaRepository.cs new file mode 100644 index 0000000..0932129 --- /dev/null +++ b/DDD.Infrastructure/Sagas/ISagaRepository.cs @@ -0,0 +1,9 @@ +namespace DDD.Infrastructure.Sagas +{ + public interface ISagaRepository + { + void Save(string id, TSagaData sagaData); + + TSagaData Load(string id); + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/Sagas/ISerializer.cs b/DDD.Infrastructure/Sagas/ISerializer.cs new file mode 100644 index 0000000..5c89c03 --- /dev/null +++ b/DDD.Infrastructure/Sagas/ISerializer.cs @@ -0,0 +1,9 @@ +namespace DDD.Infrastructure.Sagas +{ + public interface ISerializer + { + T Deserialize(string serializedData) where T : class; + + string Serialize(object sagaData); + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/Sagas/InMemorySagaRepository.cs b/DDD.Infrastructure/Sagas/InMemorySagaRepository.cs new file mode 100644 index 0000000..b21a874 --- /dev/null +++ b/DDD.Infrastructure/Sagas/InMemorySagaRepository.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace DDD.Infrastructure.Sagas +{ + public class InMemorySagaRepository : ISagaRepository where TSagaData : class + { + public Dictionary Values = new Dictionary(); + + public void Save(string id, TSagaData sagaData) + { + Values[id] = sagaData; + } + + public TSagaData Load(string id) + { + if (Values.ContainsKey(id)) + { + return Values[id]; + } + return null; + } + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/Sagas/SagaManager.cs b/DDD.Infrastructure/Sagas/SagaManager.cs new file mode 100644 index 0000000..7b8f34d --- /dev/null +++ b/DDD.Infrastructure/Sagas/SagaManager.cs @@ -0,0 +1,45 @@ +using Automatonymous; +using DDD.Base.Sagas; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace DDD.Infrastructure.Sagas +{ + public class SagaManager : ISagaManager where TSagaMachine : AutomatonymousStateMachine where TSagaData : class, ISagaData, new() + { + private ISagaRepository _sagaRepository; + private Dictionary> _correlationIdFuncs = new Dictionary>(); + public TSagaMachine SagaMachine { get; private set; } + + public SagaManager(TSagaMachine sagaMachine, ISagaRepository sagaRepository) + { + _sagaRepository = sagaRepository; + SagaMachine = sagaMachine; + } + + protected void CorrelateEvent(Func correlationIdFunc) + { + _correlationIdFuncs.Add(typeof(TEvent), e => correlationIdFunc((TEvent)e)); + } + + public void ProcessMessage(TMessage message) + { + Event @event = SagaMachine.Events.OfType>().FirstOrDefault(); + + TMessage eventData = message; + + string correlationId = _correlationIdFuncs[typeof(TMessage)](eventData); + + TSagaData sagaData = _sagaRepository.Load(correlationId); + if (sagaData == null) + { + sagaData = new TSagaData(); + } + + SagaMachine.RaiseEvent(sagaData, @event, eventData); + + _sagaRepository.Save(correlationId, sagaData); + } + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/Sagas/SagaXmlSerilizer.cs b/DDD.Infrastructure/Sagas/SagaXmlSerilizer.cs new file mode 100644 index 0000000..ce2cc14 --- /dev/null +++ b/DDD.Infrastructure/Sagas/SagaXmlSerilizer.cs @@ -0,0 +1,25 @@ +using System.IO; +using System.Xml.Serialization; + +namespace DDD.Infrastructure.Sagas +{ + public class SagaXmlSerilizer : ISerializer + { + public T Deserialize(string serializedData) where T : class + { + using (StringReader sr = new StringReader(serializedData)) + { + return new XmlSerializer(typeof(T)).Deserialize(sr) as T; + } + } + + public string Serialize(object sagaData) + { + using (StringWriter sw = new StringWriter()) + { + new XmlSerializer(sagaData.GetType()).Serialize(sw, sagaData); + return sw.GetStringBuilder().ToString(); + } + } + } +} \ No newline at end of file diff --git a/DDD.Infrastructure/packages.config b/DDD.Infrastructure/packages.config new file mode 100644 index 0000000..2507958 --- /dev/null +++ b/DDD.Infrastructure/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/PhotoStock.BusinessProcess.Tests/OrderSagaManagerTests.cs b/PhotoStock.BusinessProcess.Tests/OrderSagaManagerTests.cs new file mode 100644 index 0000000..9c48cda --- /dev/null +++ b/PhotoStock.BusinessProcess.Tests/OrderSagaManagerTests.cs @@ -0,0 +1,69 @@ +using CQRS.Base.Command; +using DDD.Base.Domain; +using DDD.Infrastructure.Sagas; +using Moq; +using NUnit.Framework; +using PhotoStock.Invoicing.Contract.Events; +using PhotoStock.Sales.Contract.Events; +using PhotoStock.Shipping.Contract.Commands; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PhotoStock.BusinessProcess.Tests +{ + [TestFixture] + public class OrderSagaManagerTests + { + private InMemorySagaRepository _repository; + private Mock _commandSender; + private OrderSagaManager _manager; + + [SetUp] + public void Setup() + { + _repository = new InMemorySagaRepository(); + _commandSender = new Mock(); + _manager = new OrderSagaManager(_repository, _commandSender.Object); + } + + [Test] + public void RaiseEvent_Should_write_to_db_saga_contents() + { + // Arrange + const string orderId = "1"; + var orderConfirmedEvent = new OrderCreatedEvent(orderId); + + // Act + _manager.ProcessMessage(orderConfirmedEvent); + + // Assert + Assert.IsTrue(_repository.Values.ContainsKey(orderConfirmedEvent.OrderId)); + Assert.IsTrue(orderId == _repository.Values[orderId].OrderId); + } + + [Test] + public void OrderInvoicedEvent_Should_write_fill_invoiceNumber_and_send_shipCommand() + { + // Arrange + const string invoiceNumber = "FV/233"; + const string orderId = "12"; + var orderInvoicedEvent = new OrderInvoicedEvent(orderId, invoiceNumber); + + _repository.Values[orderId] = new OrderSagaData() + { + OrderId = orderId, + CurrentState = _manager.SagaMachine.OrderConfirmed + }; + + // Act + _manager.ProcessMessage(orderInvoicedEvent); + + // Assert + _commandSender.Verify(f => f.Send(It.Is(d => d.OrderId == orderId))); + Assert.IsTrue(invoiceNumber == _repository.Values[orderId].InvoiceNumber); + } + } +} \ No newline at end of file diff --git a/PhotoStock.BusinessProcess.Tests/PhotoStock.BusinessProcess.Tests.csproj b/PhotoStock.BusinessProcess.Tests/PhotoStock.BusinessProcess.Tests.csproj new file mode 100644 index 0000000..e57e5ee --- /dev/null +++ b/PhotoStock.BusinessProcess.Tests/PhotoStock.BusinessProcess.Tests.csproj @@ -0,0 +1,102 @@ + + + + + Debug + AnyCPU + {5C0936A5-3185-44C5-9B6B-FEB039CFB6F7} + Library + Properties + PhotoStock.BusinessProcess.Tests + PhotoStock.BusinessProcess.Tests + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Automatonymous.3.3.0\lib\net452\Automatonymous.dll + True + + + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True + + + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll + True + + + + + + + + + + + + + + + + + + + + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A} + CQRS.Base + + + {f8d43559-8792-498b-ab51-211ca04cb4df} + DDD.Base + + + {1f25c4fb-d5ea-46bb-ab2b-ac5582e1aa9e} + DDD.Infrastructure + + + {6B0EA748-FC9A-467B-B3D4-A2A025EEBB29} + PhotoStock.BusinessProcess + + + {265016F3-AE52-4167-926A-52924366E7DD} + PhotoStock.Invoicing.Contract + + + {EA7D831A-03D1-4A08-805C-3E450EA024BC} + PhotoStock.Sales.Contract + + + {1FF64B1A-907E-4056-82A5-67B3EFD45C78} + PhotoStock.Shipping.Contract + + + + + + + + \ No newline at end of file diff --git a/PhotoStock.BusinessProcess.Tests/Properties/AssemblyInfo.cs b/PhotoStock.BusinessProcess.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..230e757 --- /dev/null +++ b/PhotoStock.BusinessProcess.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.BusinessProcess.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.BusinessProcess.Tests")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5c0936a5-3185-44c5-9b6b-feb039cfb6f7")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.BusinessProcess.Tests/packages.config b/PhotoStock.BusinessProcess.Tests/packages.config new file mode 100644 index 0000000..f25d7d2 --- /dev/null +++ b/PhotoStock.BusinessProcess.Tests/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PhotoStock.BusinessProcess/OrderSaga.cs b/PhotoStock.BusinessProcess/OrderSaga.cs new file mode 100644 index 0000000..a1ca3ae --- /dev/null +++ b/PhotoStock.BusinessProcess/OrderSaga.cs @@ -0,0 +1,37 @@ +using Automatonymous; +using CQRS.Base.Command; +using PhotoStock.Invoicing.Contract.Commands; +using PhotoStock.Invoicing.Contract.Events; +using PhotoStock.Sales.Contract.Events; +using PhotoStock.Shipping.Contract.Commands; +using PhotoStock.Shipping.Contract.Events; +using System.Linq; +using OrderItem = PhotoStock.Invoicing.Contract.Commands.OrderItem; + +namespace PhotoStock.BusinessProcess +{ + public class OrderSaga : AutomatonymousStateMachine + { + private ICommandSender _commandSender; + + public OrderSaga(ICommandSender commandSender) + { + _commandSender = commandSender; + + Event(() => OrderCreatedEvent); + Event(() => OrderConfirmedEvent); + Event(() => OrderShippedEvent); + Event(() => OrderInvoicedEvent); + } + + public State OrderCreated { get; set; } + public State OrderShipped { get; set; } + public State OrderConfirmed { get; set; } + public State OrderInvoiced { get; set; } + + public Event OrderCreatedEvent { get; set; } + public Event OrderShippedEvent { get; set; } + public Event OrderConfirmedEvent { get; set; } + public Event OrderInvoicedEvent { get; set; } + } +} \ No newline at end of file diff --git a/PhotoStock.BusinessProcess/OrderSagaData.cs b/PhotoStock.BusinessProcess/OrderSagaData.cs new file mode 100644 index 0000000..1f8f387 --- /dev/null +++ b/PhotoStock.BusinessProcess/OrderSagaData.cs @@ -0,0 +1,14 @@ +using Automatonymous; +using DDD.Base.Domain; +using DDD.Infrastructure.Sagas; + +namespace PhotoStock.BusinessProcess +{ + public class OrderSagaData : ISagaData + { + public State CurrentState { get; set; } + public AggregateId OrderId { get; set; } + public AggregateId InvoiceNumber { get; set; } + public AggregateId ShipementId { get; set; } + } +} \ No newline at end of file diff --git a/PhotoStock.BusinessProcess/PhotoStock.BusinessProcess.csproj b/PhotoStock.BusinessProcess/PhotoStock.BusinessProcess.csproj new file mode 100644 index 0000000..78e743b --- /dev/null +++ b/PhotoStock.BusinessProcess/PhotoStock.BusinessProcess.csproj @@ -0,0 +1,109 @@ + + + + + Debug + AnyCPU + {6B0EA748-FC9A-467B-B3D4-A2A025EEBB29} + Library + Properties + PhotoStock.BusinessProcess + PhotoStock.BusinessProcess + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Automatonymous.3.3.0\lib\net452\Automatonymous.dll + True + + + ..\packages\Automatonymous.NHibernate.3.3.0\lib\net452\Automatonymous.NHibernateIntegration.dll + True + + + ..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll + True + + + ..\packages\NHibernate.4.0.4.4000\lib\net40\NHibernate.dll + True + + + + + + + + + + + + + + + + + + + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A} + CQRS.Base + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + {1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E} + DDD.Infrastructure + + + {265016F3-AE52-4167-926A-52924366E7DD} + PhotoStock.Invoicing.Contract + + + {EA7D831A-03D1-4A08-805C-3E450EA024BC} + PhotoStock.Sales.Contract + + + {266FF480-2B3A-40C5-B01C-721C9A4D79D3} + PhotoStock.SharedKernel + + + {DB22ADE0-E49E-4B7E-9329-5AEA5F82072C} + PhotoStock.Shipping.Application + + + {1FF64B1A-907E-4056-82A5-67B3EFD45C78} + PhotoStock.Shipping.Contract + + + + + + + + \ No newline at end of file diff --git a/PhotoStock.BusinessProcess/Properties/AssemblyInfo.cs b/PhotoStock.BusinessProcess/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..df2bb0e --- /dev/null +++ b/PhotoStock.BusinessProcess/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.BusinnessProcess")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.BusinnessProcess")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6b0ea748-fc9a-467b-b3d4-a2a025eebb29")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.BusinessProcess/SagaManager.cs b/PhotoStock.BusinessProcess/SagaManager.cs new file mode 100644 index 0000000..fe71f1c --- /dev/null +++ b/PhotoStock.BusinessProcess/SagaManager.cs @@ -0,0 +1,20 @@ +using CQRS.Base.Command; +using DDD.Infrastructure.Sagas; +using PhotoStock.Invoicing.Contract.Events; +using PhotoStock.Sales.Contract.Events; +using PhotoStock.Shipping.Contract.Events; + +namespace PhotoStock.BusinessProcess +{ + public class OrderSagaManager : SagaManager + { + public OrderSagaManager(ISagaRepository sagaRepository, ICommandSender commandSender) + : base(new OrderSaga(commandSender), sagaRepository) + { + CorrelateEvent(f => f.OrderId); + CorrelateEvent(f => f.OrderId); + CorrelateEvent(f => f.OrderId); + CorrelateEvent(f => f.OrderId); + } + } +} \ No newline at end of file diff --git a/PhotoStock.BusinessProcess/packages.config b/PhotoStock.BusinessProcess/packages.config new file mode 100644 index 0000000..4c12e27 --- /dev/null +++ b/PhotoStock.BusinessProcess/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/PhotoStock.Invoicing.Application/PhotoStock.Invoicing.Application.csproj b/PhotoStock.Invoicing.Application/PhotoStock.Invoicing.Application.csproj new file mode 100644 index 0000000..dde7706 --- /dev/null +++ b/PhotoStock.Invoicing.Application/PhotoStock.Invoicing.Application.csproj @@ -0,0 +1,87 @@ + + + + + Debug + AnyCPU + {91D4A03B-CCE7-4A9A-AA80-626251967A2B} + Library + Properties + PhotoStock.Invoicing.Application + PhotoStock.Invoicing.Application + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A} + CQRS.Base + + + {f8d43559-8792-498b-ab51-211ca04cb4df} + DDD.Base + + + {1f25c4fb-d5ea-46bb-ab2b-ac5582e1aa9e} + DDD.Infrastructure + + + {265016F3-AE52-4167-926A-52924366E7DD} + PhotoStock.Invoicing.Contract + + + {F686EDF5-2B9C-4DE1-B197-785B38BE4B97} + PhotoStock.Invoicing.Domain + + + {EA7D831A-03D1-4A08-805C-3E450EA024BC} + PhotoStock.Sales.Contract + + + {266ff480-2b3a-40c5-b01c-721c9a4d79d3} + PhotoStock.SharedKernel + + + + + + + + + \ No newline at end of file diff --git a/PhotoStock.Invoicing.Application/Properties/AssemblyInfo.cs b/PhotoStock.Invoicing.Application/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e825632 --- /dev/null +++ b/PhotoStock.Invoicing.Application/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Invoicing.Application")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Invoicing.Application")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("91d4a03b-cce7-4a9a-aa80-626251967a2b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Invoicing.Contract/Commands/InvoiceOrderCommand.cs b/PhotoStock.Invoicing.Contract/Commands/InvoiceOrderCommand.cs new file mode 100644 index 0000000..98c8051 --- /dev/null +++ b/PhotoStock.Invoicing.Contract/Commands/InvoiceOrderCommand.cs @@ -0,0 +1,24 @@ +using DDD.Base.Domain; +using PhotoStock.SharedKernel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PhotoStock.Invoicing.Contract.Commands +{ + public class InvoiceOrderCommand + { + public AggregateId OrderId { get; set; } + public ClientData ClientData { get; set; } + public IEnumerable Items { get; set; } + + public InvoiceOrderCommand(AggregateId orderId, ClientData clientData, IEnumerable items) + { + OrderId = orderId; + ClientData = clientData; + Items = items; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Contract/Commands/OrderItem.cs b/PhotoStock.Invoicing.Contract/Commands/OrderItem.cs new file mode 100644 index 0000000..36747b4 --- /dev/null +++ b/PhotoStock.Invoicing.Contract/Commands/OrderItem.cs @@ -0,0 +1,18 @@ +using PhotoStock.SharedKernel; + +namespace PhotoStock.Invoicing.Contract.Commands +{ + public class OrderItem + { + public OrderItem(ProductData productData, int quantity, Money totalCost) + { + ProductData = productData; + Quantity = quantity; + TotalCost = totalCost; + } + + public Money TotalCost { get; set; } + public ProductData ProductData { get; set; } + public int Quantity { get; set; } + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Contract/Events/OrderInvoicedEvent.cs b/PhotoStock.Invoicing.Contract/Events/OrderInvoicedEvent.cs new file mode 100644 index 0000000..0bda951 --- /dev/null +++ b/PhotoStock.Invoicing.Contract/Events/OrderInvoicedEvent.cs @@ -0,0 +1,16 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Invoicing.Contract.Events +{ + public class OrderInvoicedEvent : IDomainEvent + { + public AggregateId OrderId { get; private set; } + public AggregateId InvoiceNumber { get; private set; } + + public OrderInvoicedEvent(AggregateId orderId, AggregateId invoiceNumber) + { + OrderId = orderId; + InvoiceNumber = invoiceNumber; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Contract/PhotoStock.Invoicing.Contract.csproj b/PhotoStock.Invoicing.Contract/PhotoStock.Invoicing.Contract.csproj new file mode 100644 index 0000000..ff9bde0 --- /dev/null +++ b/PhotoStock.Invoicing.Contract/PhotoStock.Invoicing.Contract.csproj @@ -0,0 +1,70 @@ + + + + + Debug + AnyCPU + {265016F3-AE52-4167-926A-52924366E7DD} + Library + Properties + PhotoStock.Invoicing.Contract + PhotoStock.Invoicing.Contract + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + {EA7D831A-03D1-4A08-805C-3E450EA024BC} + PhotoStock.Sales.Contract + + + {266FF480-2B3A-40C5-B01C-721C9A4D79D3} + PhotoStock.SharedKernel + + + + + \ No newline at end of file diff --git a/PhotoStock.Invoicing.Contract/Properties/AssemblyInfo.cs b/PhotoStock.Invoicing.Contract/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..43c2910 --- /dev/null +++ b/PhotoStock.Invoicing.Contract/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Invoicing.Contract")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Invoicing.Contract")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("265016f3-ae52-4167-926a-52924366e7dd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Invoicing.Domain/IInvoiceFactory.cs b/PhotoStock.Invoicing.Domain/IInvoiceFactory.cs new file mode 100644 index 0000000..fae5506 --- /dev/null +++ b/PhotoStock.Invoicing.Domain/IInvoiceFactory.cs @@ -0,0 +1,10 @@ +using DDD.Base.Domain; +using PhotoStock.SharedKernel; + +namespace PhotoStock.Invoicing.Domain +{ + public interface IInvoiceFactory + { + Invoice Create(AggregateId orderId, ClientData clientData); + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Domain/IInvoiceNumberGenerator.cs b/PhotoStock.Invoicing.Domain/IInvoiceNumberGenerator.cs new file mode 100644 index 0000000..606f922 --- /dev/null +++ b/PhotoStock.Invoicing.Domain/IInvoiceNumberGenerator.cs @@ -0,0 +1,9 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Invoicing.Domain +{ + public interface IInvoiceNumberGenerator + { + AggregateId GenerateNextInvoiceNumber(); + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Domain/ITaxPolicy.cs b/PhotoStock.Invoicing.Domain/ITaxPolicy.cs new file mode 100644 index 0000000..290514b --- /dev/null +++ b/PhotoStock.Invoicing.Domain/ITaxPolicy.cs @@ -0,0 +1,10 @@ +using PhotoStock.Invoicing.Domain.TaxPolicy; +using PhotoStock.SharedKernel; + +namespace PhotoStock.Invoicing.Domain +{ + public interface ITaxPolicy + { + Tax CalculateTax(ProductType productType, Money net); + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Domain/Invoice.cs b/PhotoStock.Invoicing.Domain/Invoice.cs new file mode 100644 index 0000000..68fc927 --- /dev/null +++ b/PhotoStock.Invoicing.Domain/Invoice.cs @@ -0,0 +1,33 @@ +using DDD.Base.Domain; +using PhotoStock.SharedKernel; +using System.Collections.Generic; + +namespace PhotoStock.Invoicing.Domain +{ + public class Invoice : AggregateRoot + { + public ClientData Client { get; private set; } + public Money Net { get; private set; } + public Money Gros { get; private set; } + public List _items = new List(); + + public Invoice(AggregateId invoiceId, ClientData client) : base(invoiceId) + { + Client = client; + Net = Money.ZERO; + Gros = Money.ZERO; + } + + private Invoice() + { + } + + public void AddItem(InvoiceLine item) + { + _items.Add(item); + + Net = Net.Add(item.Net); + Gros = Gros.Add(item.Gros); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Domain/InvoiceFactory.cs b/PhotoStock.Invoicing.Domain/InvoiceFactory.cs new file mode 100644 index 0000000..e73e677 --- /dev/null +++ b/PhotoStock.Invoicing.Domain/InvoiceFactory.cs @@ -0,0 +1,32 @@ +using DDD.Base.Domain; +using PhotoStock.Invoicing.Contract.Events; +using PhotoStock.SharedKernel; +using System; + +namespace PhotoStock.Invoicing.Domain +{ + public class InvoiceFactory : IInvoiceFactory + { + private IInvoiceNumberGenerator _numberGenerator; + private IDomainEventPublisher _eventPublisher; + private IDependencyInjector _dependencyInjector; + + public InvoiceFactory(IDomainEventPublisher eventPublisher, IInvoiceNumberGenerator numberGenerator, IDependencyInjector dependencyInjector) + { + _eventPublisher = eventPublisher; + _numberGenerator = numberGenerator; + _dependencyInjector = dependencyInjector; + } + + public Invoice Create(AggregateId orderId, ClientData clientData) + { + AggregateId number = _numberGenerator.GenerateNextInvoiceNumber(); + _eventPublisher.Publish(new OrderInvoicedEvent(orderId, number)); + + Invoice invoice = new Invoice(number, clientData); + _dependencyInjector.InjectDependencies(invoice); + + return invoice; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Domain/InvoiceLine.cs b/PhotoStock.Invoicing.Domain/InvoiceLine.cs new file mode 100644 index 0000000..15282fd --- /dev/null +++ b/PhotoStock.Invoicing.Domain/InvoiceLine.cs @@ -0,0 +1,27 @@ +using DDD.Base.Domain; +using PhotoStock.SharedKernel; + +namespace PhotoStock.Invoicing.Domain +{ + public class InvoiceLine : Entity + { + public ProductData Product { get; private set; } + public int Quantity { get; private set; } + public Money Net { get; private set; } + public Money Gros { get; private set; } + public Tax Tax { get; private set; } + + public InvoiceLine() + { + } + + public InvoiceLine(ProductData product, int quantity, Money net, Tax tax) + { + Product = product; + Quantity = quantity; + Net = net; + Tax = tax; + Gros = Net.Add(tax.Amount); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Domain/InvoiceRepository.cs b/PhotoStock.Invoicing.Domain/InvoiceRepository.cs new file mode 100644 index 0000000..47aa00d --- /dev/null +++ b/PhotoStock.Invoicing.Domain/InvoiceRepository.cs @@ -0,0 +1,8 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Invoicing.Domain +{ + public interface IInvoiceRepository : IGenericRepository + { + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Domain/PhotoStock.Invoicing.Domain.csproj b/PhotoStock.Invoicing.Domain/PhotoStock.Invoicing.Domain.csproj new file mode 100644 index 0000000..74c7f6b --- /dev/null +++ b/PhotoStock.Invoicing.Domain/PhotoStock.Invoicing.Domain.csproj @@ -0,0 +1,76 @@ + + + + + Debug + AnyCPU + {F686EDF5-2B9C-4DE1-B197-785B38BE4B97} + Library + Properties + PhotoStock.Invoicing.Domain + PhotoStock.Invoicing.Domain + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + {f8d43559-8792-498b-ab51-211ca04cb4df} + DDD.Base + + + {265016F3-AE52-4167-926A-52924366E7DD} + PhotoStock.Invoicing.Contract + + + {266FF480-2B3A-40C5-B01C-721C9A4D79D3} + PhotoStock.SharedKernel + + + + + \ No newline at end of file diff --git a/PhotoStock.Invoicing.Domain/Properties/AssemblyInfo.cs b/PhotoStock.Invoicing.Domain/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..84a945a --- /dev/null +++ b/PhotoStock.Invoicing.Domain/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Invoicing.Domain")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Invoicing.Domain")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f686edf5-2b9c-4de1-b197-785b38be4b97")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Invoicing.Domain/Tax.cs b/PhotoStock.Invoicing.Domain/Tax.cs new file mode 100644 index 0000000..5f87d45 --- /dev/null +++ b/PhotoStock.Invoicing.Domain/Tax.cs @@ -0,0 +1,22 @@ +using DDD.Base.Domain; +using PhotoStock.SharedKernel; +using System; + +namespace PhotoStock.Invoicing.Domain +{ + public class Tax : ValueObject + { + public Money Amount { get; private set; } + public string Description { get; private set; } + + public Tax() + { + } + + public Tax(Money amount, String description) + { + Amount = amount; + Description = description; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Invoicing.Domain/TaxPolicy/DefaultTaxPolicy.cs b/PhotoStock.Invoicing.Domain/TaxPolicy/DefaultTaxPolicy.cs new file mode 100644 index 0000000..86d1dd0 --- /dev/null +++ b/PhotoStock.Invoicing.Domain/TaxPolicy/DefaultTaxPolicy.cs @@ -0,0 +1,34 @@ +using PhotoStock.SharedKernel; +using System; + +namespace PhotoStock.Invoicing.Domain.TaxPolicy +{ + public class DefaultTaxPolicy : ITaxPolicy + { + public Tax CalculateTax(ProductType productType, Money net) + { + decimal ratio; + string desc = null; + + switch (productType) + { + case ProductType.Printed: + ratio = (decimal)0.05; + desc = "5% (D)"; + break; + + case ProductType.Electronic: + ratio = (decimal)0.23; + desc = "23%"; + break; + + default: + throw new ArgumentOutOfRangeException(productType + " not Handled"); + } + + Money tax = net * ratio; + + return new Tax(tax, desc); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Application/PhotoStock.Sales.Application.csproj b/PhotoStock.Sales.Application/PhotoStock.Sales.Application.csproj new file mode 100644 index 0000000..390a690 --- /dev/null +++ b/PhotoStock.Sales.Application/PhotoStock.Sales.Application.csproj @@ -0,0 +1,105 @@ + + + + + Debug + AnyCPU + {502D416A-D97E-46F6-B47F-85AB0BFDCD3A} + Library + Properties + PhotoStock.Sales.Application + PhotoStock.Sales.Application + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + ..\packages\Castle.Core.3.3.0\lib\net45\Castle.Core.dll + True + + + ..\packages\Castle.Windsor.3.3.0\lib\net45\Castle.Windsor.dll + True + + + ..\packages\Iesi.Collections.4.0.0.4000\lib\net40\Iesi.Collections.dll + True + + + + + + + + + + + + + + + + + + + + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A} + CQRS.Base + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + {EA7D831A-03D1-4A08-805C-3E450EA024BC} + PhotoStock.Sales.Contract + + + {2230C68D-558A-463F-B3ED-427968DECB2E} + PhotoStock.Sales.Domain + + + {266ff480-2b3a-40c5-b01c-721c9a4d79d3} + PhotoStock.SharedKernel + + + {2FC58C62-FE65-46C7-989E-180C2B8E41EE} + PhotoStock.System + + + + + + + + + + + \ No newline at end of file diff --git a/PhotoStock.Sales.Application/Properties/AssemblyInfo.cs b/PhotoStock.Sales.Application/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..611ad16 --- /dev/null +++ b/PhotoStock.Sales.Application/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Sales.Application")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Sales.Application")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("502d416a-d97e-46f6-b47f-85ab0bfdcd3a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Sales.Application/Services/OrderingService/IOrderingService.cs b/PhotoStock.Sales.Application/Services/OrderingService/IOrderingService.cs new file mode 100644 index 0000000..034307a --- /dev/null +++ b/PhotoStock.Sales.Application/Services/OrderingService/IOrderingService.cs @@ -0,0 +1,17 @@ +namespace PhotoStock.Sales.Contract +{ + public interface IOrderingService + { + // 1. + //AggregateId CreateOrder(); + + // 2. + //void AddPicture(AggregateId orderId, AggregateId productId); + + // 3. + //Offer CalculateOffer(AggregateId orderId); + + // 4. + //void Confirm(AggregateId orderId, Offer seenOffer); + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Application/Services/OrderingService/OrderingService.cs b/PhotoStock.Sales.Application/Services/OrderingService/OrderingService.cs new file mode 100644 index 0000000..8ac0cbe --- /dev/null +++ b/PhotoStock.Sales.Application/Services/OrderingService/OrderingService.cs @@ -0,0 +1,38 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel.Specification; +using PhotoStock.Sales.Contract; +using PhotoStock.Sales.Domain.Client; +using PhotoStock.Sales.Domain.Offer; +using PhotoStock.Sales.Domain.Offer.Discount; +using PhotoStock.Sales.Domain.ProductsCatalog; +using PhotoStock.Sales.Domain.Purchase; +using PhotoStock.Sales.Domain.Reservation; +using PhotoStock.System; +using System; + +namespace PhotoStock.Sales.Application.Services.OrderingService +{ + public class OrderingService : IOrderingService + { + private ISystemContext _systemContext; + private IClientRepository _clientRepository; + + public OrderingService( + ISystemContext systemContext, + IClientRepository clientRepository) + { + _systemContext = systemContext; + _clientRepository = clientRepository; + } + + public AggregateId CreateOrder() + { + throw new NotImplementedException(); + } + + private Client LoadClient() + { + return _clientRepository.Load(_systemContext.SystemUser.ClientId); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Application/Services/PurchaseService/IPaymentService.cs b/PhotoStock.Sales.Application/Services/PurchaseService/IPaymentService.cs new file mode 100644 index 0000000..2e8c439 --- /dev/null +++ b/PhotoStock.Sales.Application/Services/PurchaseService/IPaymentService.cs @@ -0,0 +1,9 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Sales.Application.Services.PurchaseService +{ + internal interface IPaymentService + { + void ConfirmOrderPayment(AggregateId orderId); + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Application/Services/PurchaseService/PaymentService.cs b/PhotoStock.Sales.Application/Services/PurchaseService/PaymentService.cs new file mode 100644 index 0000000..e6470cd --- /dev/null +++ b/PhotoStock.Sales.Application/Services/PurchaseService/PaymentService.cs @@ -0,0 +1,23 @@ +using DDD.Base.Domain; +using PhotoStock.Sales.Domain.Client; +using PhotoStock.Sales.Domain.Purchase; + +namespace PhotoStock.Sales.Application.Services.PurchaseService +{ + internal class PaymentService : IPaymentService + { + private readonly IPurchaseRepository _purchaseRepository; + + public PaymentService(IPurchaseRepository purchaseRepository) + { + _purchaseRepository = purchaseRepository; + } + + public void ConfirmOrderPayment(AggregateId orderId) + { + Purchase purchase = _purchaseRepository.Load(orderId); + purchase.Confirm(); + _purchaseRepository.Save(purchase); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Application/packages.config b/PhotoStock.Sales.Application/packages.config new file mode 100644 index 0000000..1a32a6a --- /dev/null +++ b/PhotoStock.Sales.Application/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PhotoStock.Sales.Contract/Events/OrderConfirmedEvent.cs b/PhotoStock.Sales.Contract/Events/OrderConfirmedEvent.cs new file mode 100644 index 0000000..8eb5900 --- /dev/null +++ b/PhotoStock.Sales.Contract/Events/OrderConfirmedEvent.cs @@ -0,0 +1,21 @@ +using DDD.Base.Domain; +using Photostock.Sales.Infrastructure; +using PhotoStock.SharedKernel; +using System.Collections.Generic; + +namespace PhotoStock.Sales.Contract.Events +{ + public class OrderConfirmedEvent : ISystemEvent + { + public AggregateId OrderId { get; private set; } + public ClientData ClientData { get; private set; } + public IEnumerable Items { get; private set; } + + public OrderConfirmedEvent(AggregateId orderId, ClientData clientData, IEnumerable items) + { + OrderId = orderId; + ClientData = clientData; + Items = items; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Contract/Events/OrderCreatedEvent.cs b/PhotoStock.Sales.Contract/Events/OrderCreatedEvent.cs new file mode 100644 index 0000000..3b640f1 --- /dev/null +++ b/PhotoStock.Sales.Contract/Events/OrderCreatedEvent.cs @@ -0,0 +1,15 @@ +using DDD.Base.Domain; +using Photostock.Sales.Infrastructure; + +namespace PhotoStock.Sales.Contract.Events +{ + public class OrderCreatedEvent : ISystemEvent + { + public AggregateId OrderId { get; private set; } + + public OrderCreatedEvent(AggregateId orderId) + { + OrderId = orderId; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Contract/Events/OrderItem.cs b/PhotoStock.Sales.Contract/Events/OrderItem.cs new file mode 100644 index 0000000..ab36c05 --- /dev/null +++ b/PhotoStock.Sales.Contract/Events/OrderItem.cs @@ -0,0 +1,10 @@ +using PhotoStock.SharedKernel; + +namespace PhotoStock.Sales.Contract.Events +{ + public class OrderItem + { + public ProductData ProductData { get; set; } + public Money TotalCost { get; set; } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Contract/PhotoStock.Sales.Contract.csproj b/PhotoStock.Sales.Contract/PhotoStock.Sales.Contract.csproj new file mode 100644 index 0000000..f769a30 --- /dev/null +++ b/PhotoStock.Sales.Contract/PhotoStock.Sales.Contract.csproj @@ -0,0 +1,73 @@ + + + + + Debug + AnyCPU + {EA7D831A-03D1-4A08-805C-3E450EA024BC} + Library + Properties + PhotoStock.Sales.Contract + PhotoStock.Sales.Contract + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + {1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E} + DDD.Infrastructure + + + {266FF480-2B3A-40C5-B01C-721C9A4D79D3} + PhotoStock.SharedKernel + + + + + + + + \ No newline at end of file diff --git a/PhotoStock.Sales.Contract/Properties/AssemblyInfo.cs b/PhotoStock.Sales.Contract/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..93c9970 --- /dev/null +++ b/PhotoStock.Sales.Contract/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Sales.Contract")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Sales.Contract")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ea7d831a-03d1-4a08-805c-3e450ea024bc")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Sales.Domain/Client/Client.cs b/PhotoStock.Sales.Domain/Client/Client.cs new file mode 100644 index 0000000..3579af4 --- /dev/null +++ b/PhotoStock.Sales.Domain/Client/Client.cs @@ -0,0 +1,40 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel; +using PhotoStock.SharedKernel; + +namespace PhotoStock.Sales.Domain.Client +{ + public class Client : AggregateRoot + { + private string _name; + + public Client(string name) + { + _name = name; + } + + public ClientData GenerateSnapshot() + { + return new ClientData(AggregateId, _name); + } + + public bool CanAfford(Money amount) + { + return true;//TODO explore domain rules ex: credit limit + } + + public void Charge(Money amount) + { + if (!CanAfford(amount)) + { + DomainError("Can not afford: " + amount); + } + // TODO facade to the payment module + } + + public bool CanMakeReservation() + { + return true; //TODO explore domain rules (ex: cleint's debts, stataus etc) + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Client/IClientRepository.cs b/PhotoStock.Sales.Domain/Client/IClientRepository.cs new file mode 100644 index 0000000..c97827e --- /dev/null +++ b/PhotoStock.Sales.Domain/Client/IClientRepository.cs @@ -0,0 +1,8 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Sales.Domain.Client +{ + public interface IClientRepository : IGenericRepository + { + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Address.cs b/PhotoStock.Sales.Domain/Offer/Address.cs new file mode 100644 index 0000000..66121f4 --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Address.cs @@ -0,0 +1,13 @@ +using PhotoStock.Sales.Domain.Offer.Specification; + +namespace PhotoStock.Sales.Domain.Offer +{ + public class Address + { + public Locale Country { get; set; } + } + + public class Locale + { + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Discount/Discount.cs b/PhotoStock.Sales.Domain/Offer/Discount/Discount.cs new file mode 100644 index 0000000..19f821e --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Discount/Discount.cs @@ -0,0 +1,18 @@ +using DDD.Base.Domain; +using PhotoStock.SharedKernel; + +namespace PhotoStock.Sales.Domain.Offer.Discount +{ + + public class Discount : ValueObject + { + public string Cause { get; set; } + public Money Value { get; set; } + + public Discount(string cause, Money value) + { + Cause = cause; + Value = value; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Discount/DiscountFactory.cs b/PhotoStock.Sales.Domain/Offer/Discount/DiscountFactory.cs new file mode 100644 index 0000000..a4b8a9e --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Discount/DiscountFactory.cs @@ -0,0 +1,13 @@ +using System; + +namespace PhotoStock.Sales.Domain.Offer.Discount +{ + public class DiscountFactory : IDiscountFactory + { + public IDiscountPolicy Create(Client.Client client) + { + IDiscountPolicy result = new DiscountPolicy(); + return result; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Discount/DiscountPolicy.cs b/PhotoStock.Sales.Domain/Offer/Discount/DiscountPolicy.cs new file mode 100644 index 0000000..a4a0c1e --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Discount/DiscountPolicy.cs @@ -0,0 +1,15 @@ +using PhotoStock.Sales.Domain.ProductsCatalog; +using PhotoStock.SharedKernel; +using System; + +namespace PhotoStock.Sales.Domain.Offer.Discount +{ + internal class DiscountPolicy : IDiscountPolicy + { + public Discount ApplyDiscount() + { + //TODO; + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Discount/IDiscountFactory.cs b/PhotoStock.Sales.Domain/Offer/Discount/IDiscountFactory.cs new file mode 100644 index 0000000..91d29c5 --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Discount/IDiscountFactory.cs @@ -0,0 +1,7 @@ +namespace PhotoStock.Sales.Domain.Offer.Discount +{ + public interface IDiscountFactory + { + IDiscountPolicy Create(Client.Client client); + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Discount/IDiscountPolicy.cs b/PhotoStock.Sales.Domain/Offer/Discount/IDiscountPolicy.cs new file mode 100644 index 0000000..56ae28f --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Discount/IDiscountPolicy.cs @@ -0,0 +1,10 @@ +using PhotoStock.Sales.Domain.ProductsCatalog; +using PhotoStock.SharedKernel; + +namespace PhotoStock.Sales.Domain.Offer.Discount +{ + public interface IDiscountPolicy + { + Discount ApplyDiscount(); + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Offer.cs b/PhotoStock.Sales.Domain/Offer/Offer.cs new file mode 100644 index 0000000..ad83dd2 --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Offer.cs @@ -0,0 +1,58 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel; +using PhotoStock.SharedKernel; +using System; +using System.Collections.Generic; + +namespace PhotoStock.Sales.Domain.Offer +{ + public class Offer : ValueObject + { + private List _availableItems = new List(); + + public IEnumerable AvailableItems + { + get { return _availableItems; } + } + + private List _unavailableItems = new List(); + + public IEnumerable UnavailableItems + { + get { return _unavailableItems; } + } + + public Money TotalCost { get; private set;} + public AggregateId ClientId { get; private set; } + public Address ShipingAddress { get; set; } + + public Offer(AggregateId clientId, List availabeItems, List unavailableItems) + { + TotalCost = Money.ZERO; + ClientId = clientId; + _availableItems = availabeItems; + _unavailableItems = unavailableItems; + + foreach (OfferItem offerItem in availabeItems) + { + TotalCost = TotalCost + offerItem.TotalCost; + } + } + + public bool SameAs(Offer seenOffer, double delta) + { + //TODO: + throw new NotImplementedException(); + } + + private OfferItem FindItem(AggregateId productId) + { + foreach (OfferItem item in _availableItems) + { + if (item.ProductData.ProductId.Equals(productId)) + return item; + } + return null; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/OfferItem.cs b/PhotoStock.Sales.Domain/Offer/OfferItem.cs new file mode 100644 index 0000000..e328687 --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/OfferItem.cs @@ -0,0 +1,57 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel; +using PhotoStock.Sales.Domain.ProductsCatalog; +using PhotoStock.SharedKernel; + +namespace PhotoStock.Sales.Domain.Offer +{ + public class OfferItem : ValueObject + { + public ProductData ProductData { get; private set; } + public Discount.Discount Discount { get; private set; } + public Money TotalCost { get; private set; } + + public OfferItem(ProductData productData) : this(productData, null) + { + } + + public OfferItem(ProductData productData, Discount.Discount discount) + { + ProductData = productData; + Discount = discount; + + Money discountValue = Money.ZERO; + if (discount != null) + { + discountValue = discountValue - discount.Value; + } + + TotalCost = productData.Price - discountValue; + } + + public bool SameAs(OfferItem item, double delta) + { + if (!ProductData.Equals(item.ProductData)) + { + return false; + } + + Money max, min; + if (TotalCost > item.TotalCost) + { + max = TotalCost; + min = item.TotalCost; + } + else + { + max = item.TotalCost; + min = TotalCost; + } + + Money difference = max - min; + Money acceptableDelta = max * (delta / 100); + + return acceptableDelta > difference; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Specification/DebtorSpecification.cs b/PhotoStock.Sales.Domain/Offer/Specification/DebtorSpecification.cs new file mode 100644 index 0000000..9706c78 --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Specification/DebtorSpecification.cs @@ -0,0 +1,35 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel.Specification; +using PhotoStock.SharedKernel; +using System; + +namespace PhotoStock.Sales.Domain.Offer.Specification +{ + public class DebtorSpecification : CompositeSpecification + { + private readonly Money _maxDebt; + + public DebtorSpecification(Money maxDebt) + { + _maxDebt = maxDebt; + } + + // No debt is allowed + public DebtorSpecification() + : this(Money.ZERO) + { + } + + public override bool IsSatisfiedBy(Offer offer) + { + //TODO: + throw new NotImplementedException(); + } + + private Money LoadDebt(AggregateId clientId) + { + // TODO load debt using injected Repo/Service to this Spec + return Money.ZERO; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Specification/IOfferSpecificationFactory.cs b/PhotoStock.Sales.Domain/Offer/Specification/IOfferSpecificationFactory.cs new file mode 100644 index 0000000..e3ede1b --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Specification/IOfferSpecificationFactory.cs @@ -0,0 +1,10 @@ +using DDD.Base.SharedKernel.Specification; +using PhotoStock.Sales.Domain.Offer; + +namespace PhotoStock.Sales.Application.Services +{ + public interface IOfferSpecificationFactory + { + ISpecification Create(); + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Offer/Specification/OfferSpecificationFactory.cs b/PhotoStock.Sales.Domain/Offer/Specification/OfferSpecificationFactory.cs new file mode 100644 index 0000000..4017532 --- /dev/null +++ b/PhotoStock.Sales.Domain/Offer/Specification/OfferSpecificationFactory.cs @@ -0,0 +1,17 @@ +using DDD.Base.SharedKernel.Specification; +using PhotoStock.Sales.Domain.Offer; +using PhotoStock.Sales.Domain.Offer.Specification; + +namespace PhotoStock.Sales.Application.Services +{ + internal class OfferSpecificationFactory : IOfferSpecificationFactory + { + public ISpecification Create() + { + ISpecification specification + = new DebtorSpecification(); // not debts or max 1000 => debtors can + + return specification; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/PhotoStock.Sales.Domain.csproj b/PhotoStock.Sales.Domain/PhotoStock.Sales.Domain.csproj new file mode 100644 index 0000000..7267df3 --- /dev/null +++ b/PhotoStock.Sales.Domain/PhotoStock.Sales.Domain.csproj @@ -0,0 +1,90 @@ + + + + + Debug + AnyCPU + {2230C68D-558A-463F-B3ED-427968DECB2E} + Library + Properties + PhotoStock.Sales.Domain + PhotoStock.Sales.Domain + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + {266FF480-2B3A-40C5-B01C-721C9A4D79D3} + PhotoStock.SharedKernel + + + + + \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/ProductsCatalog/IProductRepository.cs b/PhotoStock.Sales.Domain/ProductsCatalog/IProductRepository.cs new file mode 100644 index 0000000..de98280 --- /dev/null +++ b/PhotoStock.Sales.Domain/ProductsCatalog/IProductRepository.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using DDD.Base.Domain; + +namespace PhotoStock.Sales.Domain.ProductsCatalog +{ + public interface IProductRepository : IGenericRepository + { + //TODO : Query to different repository + List FindProductWhereBestBeforeExpiredIn(int days); + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/ProductsCatalog/Product.cs b/PhotoStock.Sales.Domain/ProductsCatalog/Product.cs new file mode 100644 index 0000000..2ecf12d --- /dev/null +++ b/PhotoStock.Sales.Domain/ProductsCatalog/Product.cs @@ -0,0 +1,29 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel; +using PhotoStock.SharedKernel; +using System; + +namespace PhotoStock.Sales.Domain.ProductsCatalog +{ + public class Product : AggregateRoot + { + public Money Price { get; private set; } + + public string Name { get; private set; } + + public ProductType ProductType { get; private set; } + + private Product(AggregateId aggregateId, Money price, String name, ProductType productType) + : base(aggregateId) + { + Price = price; + Name = name; + ProductType = productType; + } + + public ProductData GenerateSnapshot() + { + return new ProductData(AggregateId, Price, Name, ProductType); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Properties/AssemblyInfo.cs b/PhotoStock.Sales.Domain/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..123788b --- /dev/null +++ b/PhotoStock.Sales.Domain/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Sales.Domain")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Sales.Domain")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2230c68d-558a-463f-b3ed-427968decb2e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Sales.Domain/Purchase/IPurchaseFactory.cs b/PhotoStock.Sales.Domain/Purchase/IPurchaseFactory.cs new file mode 100644 index 0000000..98f859a --- /dev/null +++ b/PhotoStock.Sales.Domain/Purchase/IPurchaseFactory.cs @@ -0,0 +1,9 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Sales.Domain.Purchase +{ + public interface IPurchaseFactory + { + Purchase Create(AggregateId orderId, Client.Client client, Offer.Offer offer); + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Purchase/IPurchaseRepository.cs b/PhotoStock.Sales.Domain/Purchase/IPurchaseRepository.cs new file mode 100644 index 0000000..bd53157 --- /dev/null +++ b/PhotoStock.Sales.Domain/Purchase/IPurchaseRepository.cs @@ -0,0 +1,8 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Sales.Domain.Purchase +{ + public interface IPurchaseRepository : IGenericRepository + { + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Purchase/Purchase.cs b/PhotoStock.Sales.Domain/Purchase/Purchase.cs new file mode 100644 index 0000000..c0bfaf9 --- /dev/null +++ b/PhotoStock.Sales.Domain/Purchase/Purchase.cs @@ -0,0 +1,35 @@ +using DDD.Base.Domain; +using PhotoStock.SharedKernel; +using System.Collections.Generic; + +namespace PhotoStock.Sales.Domain.Purchase +{ + public class Purchase : AggregateRoot + { + private readonly IList _items; + public bool IsPaid { get; private set; } + public AggregateId ClientId { get; private set; } + private Date _purchaseDate; + private Money _totalCost; + + protected Purchase() + { + } + + public Purchase(AggregateId purchaseId, AggregateId clientId, IList items, Date purchaseDate, + bool isPaid, Money totalCost) : base(purchaseId) + { + _items = items; + _purchaseDate = purchaseDate; + ClientId = clientId; + IsPaid = isPaid; + _totalCost = totalCost; + } + + public void Confirm() + { + IsPaid = true; + EventPublisher.Publish(new PurchaseConfirmedEvent(AggregateId)); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Purchase/PurchaseConfirmedEvent.cs b/PhotoStock.Sales.Domain/Purchase/PurchaseConfirmedEvent.cs new file mode 100644 index 0000000..4260726 --- /dev/null +++ b/PhotoStock.Sales.Domain/Purchase/PurchaseConfirmedEvent.cs @@ -0,0 +1,14 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Sales.Domain.Purchase +{ + public class PurchaseConfirmedEvent : IDomainEvent + { + public AggregateId PurchaseId { get; set; } + + public PurchaseConfirmedEvent(AggregateId purchaseId) + { + PurchaseId = purchaseId; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Purchase/PurchaseFactory.cs b/PhotoStock.Sales.Domain/Purchase/PurchaseFactory.cs new file mode 100644 index 0000000..f0342be --- /dev/null +++ b/PhotoStock.Sales.Domain/Purchase/PurchaseFactory.cs @@ -0,0 +1,47 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel; +using PhotoStock.Sales.Domain.Offer; +using PhotoStock.SharedKernel; +using System.Collections.Generic; +using System.Linq; + +namespace PhotoStock.Sales.Domain.Purchase +{ + public class PurchaseFactory : IPurchaseFactory + { + private IDependencyInjector _dependencyInjector; + + public PurchaseFactory(IDependencyInjector dependencyInjector) + { + _dependencyInjector = dependencyInjector; + } + + public Purchase Create(AggregateId orderId, Client.Client client, Offer.Offer offer) + { + if (!CanPurchse(client, offer.AvailableItems)) + throw new DomainOperationException(client.AggregateId, "client can not purchase"); + + List items = new List(offer.AvailableItems.Count()); + Money purchaseTotlCost = Money.ZERO; + + foreach (OfferItem item in offer.AvailableItems) + { + PurchaseItem purchaseItem = new PurchaseItem(item.ProductData, item.TotalCost); + items.Add(purchaseItem); + purchaseTotlCost = purchaseTotlCost.Add(purchaseItem.TotalCost); + } + + Purchase purchase = new Purchase(orderId, client.AggregateId, + items, Date.Today(), false, purchaseTotlCost); + + _dependencyInjector.InjectDependencies(purchase); + + return purchase; + } + + private bool CanPurchse(Client.Client client, IEnumerable availabeItems) + { + return true; //TODO explore domain rules + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Purchase/PurchaseItem.cs b/PhotoStock.Sales.Domain/Purchase/PurchaseItem.cs new file mode 100644 index 0000000..7629e07 --- /dev/null +++ b/PhotoStock.Sales.Domain/Purchase/PurchaseItem.cs @@ -0,0 +1,23 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel; +using PhotoStock.Sales.Domain.ProductsCatalog; +using PhotoStock.SharedKernel; + +namespace PhotoStock.Sales.Domain.Purchase +{ + public class PurchaseItem : Entity + { + public ProductData ProductData { get; private set; } + public Money TotalCost { get; private set; } + + private PurchaseItem() + { + } + + public PurchaseItem(ProductData productData, Money totalCost) + { + ProductData = productData; + TotalCost = totalCost; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Reservation/IReservationFactory.cs b/PhotoStock.Sales.Domain/Reservation/IReservationFactory.cs new file mode 100644 index 0000000..40ea54b --- /dev/null +++ b/PhotoStock.Sales.Domain/Reservation/IReservationFactory.cs @@ -0,0 +1,7 @@ +namespace PhotoStock.Sales.Domain.Reservation +{ + public interface IReservationFactory + { + Reservation Create(Client.Client client); + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Reservation/IReservationRepository.cs b/PhotoStock.Sales.Domain/Reservation/IReservationRepository.cs new file mode 100644 index 0000000..96251c4 --- /dev/null +++ b/PhotoStock.Sales.Domain/Reservation/IReservationRepository.cs @@ -0,0 +1,8 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Sales.Domain.Reservation +{ + public interface IReservationRepository : IGenericRepository + { + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Reservation/Reservation.cs b/PhotoStock.Sales.Domain/Reservation/Reservation.cs new file mode 100644 index 0000000..28fb4c1 --- /dev/null +++ b/PhotoStock.Sales.Domain/Reservation/Reservation.cs @@ -0,0 +1,59 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel; +using PhotoStock.Sales.Domain.Offer; +using PhotoStock.Sales.Domain.Offer.Discount; +using PhotoStock.Sales.Domain.ProductsCatalog; +using PhotoStock.SharedKernel; +using System; +using System.Collections.Generic; + +namespace PhotoStock.Sales.Domain.Reservation +{ + public class Reservation : AggregateRoot + { + public enum ReservationStatus + { + OPENED, + CLOSED + }; + + private ReservationStatus _status; + private ISet _items; + private AggregateId _clientId; + private Date _createDate; + + protected Reservation() + { + } + + internal Reservation(AggregateId reservationId, ReservationStatus status, AggregateId clientId, Date createDate) : base(reservationId) + { + _status = status; + _clientId = clientId; + _createDate = createDate; + _items = new HashSet(); + } + + public void Add(Product product) + { + if (IsClosed()) + DomainError("Reservation already closed"); + + //TODO: + } + + public bool IsClosed() + { + return _status == ReservationStatus.CLOSED; + } + + public void Close() + { + if (IsClosed()) + { + DomainError("Reservation is already closed"); + } + _status = ReservationStatus.CLOSED; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Reservation/ReservationCreatedEvent.cs b/PhotoStock.Sales.Domain/Reservation/ReservationCreatedEvent.cs new file mode 100644 index 0000000..1597a9b --- /dev/null +++ b/PhotoStock.Sales.Domain/Reservation/ReservationCreatedEvent.cs @@ -0,0 +1,14 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Sales.Domain.Reservation +{ + public class ReservationCreatedEvent : IDomainEvent + { + public AggregateId AggregateId { get; set; } + + public ReservationCreatedEvent(AggregateId aggregateId) + { + AggregateId = aggregateId; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Domain/Reservation/ReservationFactory.cs b/PhotoStock.Sales.Domain/Reservation/ReservationFactory.cs new file mode 100644 index 0000000..cda8679 --- /dev/null +++ b/PhotoStock.Sales.Domain/Reservation/ReservationFactory.cs @@ -0,0 +1,16 @@ +using DDD.Base.Domain; +using DDD.Base.SharedKernel; +using PhotoStock.SharedKernel; +using System; + +namespace PhotoStock.Sales.Domain.Reservation +{ + public class ReservationFactory : IReservationFactory + { + public Reservation Create(Client.Client client) + { + //TODO: + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Infrastructure/ClientRepository.cs b/PhotoStock.Sales.Infrastructure/ClientRepository.cs new file mode 100644 index 0000000..16ea03f --- /dev/null +++ b/PhotoStock.Sales.Infrastructure/ClientRepository.cs @@ -0,0 +1,13 @@ +using DDD.Base.Domain; +using DDD.Infrastructure; +using NHibernate; + +namespace PhotoStock.Sales.Domain.Client +{ + public class ClientRepository : GenericRepository, IClientRepository + { + public ClientRepository(ISession session, IDependencyInjector dependencyInjector) : base(session, dependencyInjector) + { + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Infrastructure/EventPublisher.cs b/PhotoStock.Sales.Infrastructure/EventPublisher.cs new file mode 100644 index 0000000..b09e2c8 --- /dev/null +++ b/PhotoStock.Sales.Infrastructure/EventPublisher.cs @@ -0,0 +1,50 @@ +using DDD.Base.Domain; +using PhotoStock.Sales.Contract.Events; +using PhotoStock.Sales.Domain.Client; +using PhotoStock.Sales.Domain.Purchase; +using PhotoStock.Sales.Domain.Reservation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Photostock.Sales.Infrastructure +{ + public class EventPublisher : IDomainEventPublisher + { + private ISystemEventPublisher _systemEventPublisher; + private IPurchaseRepository _purchaseRepository; + private IDictionary> _handlers = new Dictionary>(); + private IClientRepository _clientRepository; + + public EventPublisher(ISystemEventPublisher systemEventPublisher, IClientRepository clientRepository, IPurchaseRepository purchaseRepository) + { + _systemEventPublisher = systemEventPublisher; + _clientRepository = clientRepository; + _purchaseRepository = purchaseRepository; + _handlers[typeof(ReservationCreatedEvent)] = f => ReservationCreatedHandler(f as ReservationCreatedEvent); + _handlers[typeof(PurchaseConfirmedEvent)] = f => PurchaseConfirmedHandler(f as PurchaseConfirmedEvent); + } + + private ISystemEvent PurchaseConfirmedHandler(PurchaseConfirmedEvent purchaseConfirmedEvent) + { + Purchase purchase = _purchaseRepository.Load(purchaseConfirmedEvent.PurchaseId); + OrderConfirmedEventBuilder builder = new OrderConfirmedEventBuilder(_clientRepository); + + //TODO: + throw new NotImplementedException(); + } + + private ISystemEvent ReservationCreatedHandler(ReservationCreatedEvent f) + { + return new OrderCreatedEvent(f.AggregateId); + } + + public void Publish(T domainEvent) where T : IDomainEvent + { + ISystemEvent result = _handlers[typeof(T)](domainEvent); + _systemEventPublisher.Publish(result); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Infrastructure/FakeSession.cs b/PhotoStock.Sales.Infrastructure/FakeSession.cs new file mode 100644 index 0000000..3dc5bff --- /dev/null +++ b/PhotoStock.Sales.Infrastructure/FakeSession.cs @@ -0,0 +1,424 @@ +using NHibernate; +using NHibernate.Engine; +using NHibernate.Stat; +using NHibernate.Type; +using System; +using System.Data; +using System.Linq.Expressions; + +namespace PhotoStock.Sales.Application +{ + public class FakeSession : ISession + { + public void Dispose() + { + throw new NotImplementedException(); + } + + public void Flush() + { + throw new NotImplementedException(); + } + + public IDbConnection Disconnect() + { + throw new NotImplementedException(); + } + + public void Reconnect() + { + throw new NotImplementedException(); + } + + public void Reconnect(IDbConnection connection) + { + throw new NotImplementedException(); + } + + public IDbConnection Close() + { + throw new NotImplementedException(); + } + + public void CancelQuery() + { + throw new NotImplementedException(); + } + + public bool IsDirty() + { + throw new NotImplementedException(); + } + + public bool IsReadOnly(object entityOrProxy) + { + throw new NotImplementedException(); + } + + public void SetReadOnly(object entityOrProxy, bool readOnly) + { + throw new NotImplementedException(); + } + + public object GetIdentifier(object obj) + { + throw new NotImplementedException(); + } + + public bool Contains(object obj) + { + throw new NotImplementedException(); + } + + public void Evict(object obj) + { + throw new NotImplementedException(); + } + + public object Load(Type theType, object id, LockMode lockMode) + { + throw new NotImplementedException(); + } + + public object Load(string entityName, object id, LockMode lockMode) + { + throw new NotImplementedException(); + } + + public object Load(Type theType, object id) + { + throw new NotImplementedException(); + } + + public T Load(object id, LockMode lockMode) + { + throw new NotImplementedException(); + } + + public T Load(object id) + { + throw new NotImplementedException(); + } + + public object Load(string entityName, object id) + { + throw new NotImplementedException(); + } + + public void Load(object obj, object id) + { + throw new NotImplementedException(); + } + + public void Replicate(object obj, ReplicationMode replicationMode) + { + throw new NotImplementedException(); + } + + public void Replicate(string entityName, object obj, ReplicationMode replicationMode) + { + throw new NotImplementedException(); + } + + public object Save(object obj) + { + throw new NotImplementedException(); + } + + public void Save(object obj, object id) + { + throw new NotImplementedException(); + } + + public object Save(string entityName, object obj) + { + throw new NotImplementedException(); + } + + public void Save(string entityName, object obj, object id) + { + throw new NotImplementedException(); + } + + public void SaveOrUpdate(object obj) + { + throw new NotImplementedException(); + } + + public void SaveOrUpdate(string entityName, object obj) + { + throw new NotImplementedException(); + } + + public void SaveOrUpdate(string entityName, object obj, object id) + { + throw new NotImplementedException(); + } + + public void Update(object obj) + { + throw new NotImplementedException(); + } + + public void Update(object obj, object id) + { + throw new NotImplementedException(); + } + + public void Update(string entityName, object obj) + { + throw new NotImplementedException(); + } + + public void Update(string entityName, object obj, object id) + { + throw new NotImplementedException(); + } + + public object Merge(object obj) + { + throw new NotImplementedException(); + } + + public object Merge(string entityName, object obj) + { + throw new NotImplementedException(); + } + + public T Merge(T entity) where T : class + { + throw new NotImplementedException(); + } + + public T Merge(string entityName, T entity) where T : class + { + throw new NotImplementedException(); + } + + public void Persist(object obj) + { + throw new NotImplementedException(); + } + + public void Persist(string entityName, object obj) + { + throw new NotImplementedException(); + } + + public void Delete(object obj) + { + throw new NotImplementedException(); + } + + public void Delete(string entityName, object obj) + { + throw new NotImplementedException(); + } + + public int Delete(string query) + { + throw new NotImplementedException(); + } + + public int Delete(string query, object value, IType type) + { + throw new NotImplementedException(); + } + + public int Delete(string query, object[] values, IType[] types) + { + throw new NotImplementedException(); + } + + public void Lock(object obj, LockMode lockMode) + { + throw new NotImplementedException(); + } + + public void Lock(string entityName, object obj, LockMode lockMode) + { + throw new NotImplementedException(); + } + + public void Refresh(object obj) + { + throw new NotImplementedException(); + } + + public void Refresh(object obj, LockMode lockMode) + { + throw new NotImplementedException(); + } + + public LockMode GetCurrentLockMode(object obj) + { + throw new NotImplementedException(); + } + + public ITransaction BeginTransaction() + { + throw new NotImplementedException(); + } + + public ITransaction BeginTransaction(IsolationLevel isolationLevel) + { + throw new NotImplementedException(); + } + + public ICriteria CreateCriteria() where T : class + { + throw new NotImplementedException(); + } + + public ICriteria CreateCriteria(string alias) where T : class + { + throw new NotImplementedException(); + } + + public ICriteria CreateCriteria(Type persistentClass) + { + throw new NotImplementedException(); + } + + public ICriteria CreateCriteria(Type persistentClass, string alias) + { + throw new NotImplementedException(); + } + + public ICriteria CreateCriteria(string entityName) + { + throw new NotImplementedException(); + } + + public ICriteria CreateCriteria(string entityName, string alias) + { + throw new NotImplementedException(); + } + + public IQueryOver QueryOver() where T : class + { + throw new NotImplementedException(); + } + + public IQueryOver QueryOver(Expression> alias) where T : class + { + throw new NotImplementedException(); + } + + public IQueryOver QueryOver(string entityName) where T : class + { + throw new NotImplementedException(); + } + + public IQueryOver QueryOver(string entityName, Expression> alias) where T : class + { + throw new NotImplementedException(); + } + + public IQuery CreateQuery(string queryString) + { + throw new NotImplementedException(); + } + + public IQuery CreateFilter(object collection, string queryString) + { + throw new NotImplementedException(); + } + + public IQuery GetNamedQuery(string queryName) + { + throw new NotImplementedException(); + } + + public ISQLQuery CreateSQLQuery(string queryString) + { + throw new NotImplementedException(); + } + + public void Clear() + { + throw new NotImplementedException(); + } + + public object Get(Type clazz, object id) + { + throw new NotImplementedException(); + } + + public object Get(Type clazz, object id, LockMode lockMode) + { + throw new NotImplementedException(); + } + + public object Get(string entityName, object id) + { + throw new NotImplementedException(); + } + + public T Get(object id) + { + throw new NotImplementedException(); + } + + public T Get(object id, LockMode lockMode) + { + throw new NotImplementedException(); + } + + public string GetEntityName(object obj) + { + throw new NotImplementedException(); + } + + public IFilter EnableFilter(string filterName) + { + throw new NotImplementedException(); + } + + public IFilter GetEnabledFilter(string filterName) + { + throw new NotImplementedException(); + } + + public void DisableFilter(string filterName) + { + throw new NotImplementedException(); + } + + public IMultiQuery CreateMultiQuery() + { + throw new NotImplementedException(); + } + + public ISession SetBatchSize(int batchSize) + { + throw new NotImplementedException(); + } + + public ISessionImplementor GetSessionImplementation() + { + throw new NotImplementedException(); + } + + public IMultiCriteria CreateMultiCriteria() + { + throw new NotImplementedException(); + } + + public ISession GetSession(EntityMode entityMode) + { + throw new NotImplementedException(); + } + + public EntityMode ActiveEntityMode { get; private set; } + public FlushMode FlushMode { get; set; } + public CacheMode CacheMode { get; set; } + public ISessionFactory SessionFactory { get; private set; } + public IDbConnection Connection { get; private set; } + public bool IsOpen { get; private set; } + public bool IsConnected { get; private set; } + public bool DefaultReadOnly { get; set; } + public ITransaction Transaction { get; private set; } + public ISessionStatistics Statistics { get; private set; } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Infrastructure/OrderConfirmedEventBuilder.cs b/PhotoStock.Sales.Infrastructure/OrderConfirmedEventBuilder.cs new file mode 100644 index 0000000..8c94acb --- /dev/null +++ b/PhotoStock.Sales.Infrastructure/OrderConfirmedEventBuilder.cs @@ -0,0 +1,27 @@ +using DDD.Base.Domain; +using PhotoStock.Sales.Contract.Events; +using PhotoStock.Sales.Domain.Client; +using PhotoStock.Sales.Domain.Purchase; +using PhotoStock.SharedKernel; +using System.Collections.Generic; + +namespace Photostock.Sales.Infrastructure +{ + internal class OrderConfirmedEventBuilder + { + private AggregateId _orderId; + private ClientData _clientData; + private IClientRepository _clientRepository; + private List _items = new List(); + + public OrderConfirmedEventBuilder(IClientRepository clientRepository) + { + _clientRepository = clientRepository; + } + + public ISystemEvent Build() + { + return new OrderConfirmedEvent(_orderId, _clientData, _items); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Infrastructure/Photostock.Sales.Infrastructure.csproj b/PhotoStock.Sales.Infrastructure/Photostock.Sales.Infrastructure.csproj new file mode 100644 index 0000000..70e327a --- /dev/null +++ b/PhotoStock.Sales.Infrastructure/Photostock.Sales.Infrastructure.csproj @@ -0,0 +1,94 @@ + + + + + Debug + AnyCPU + {42D9D95B-3F19-46E3-9CCB-B9276A465E13} + Library + Properties + Photostock.Sales.Infrastructure + Photostock.Sales.Infrastructure + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Iesi.Collections.4.0.0.4000\lib\net40\Iesi.Collections.dll + True + + + ..\packages\NHibernate.4.0.4.4000\lib\net40\NHibernate.dll + True + + + ..\packages\NUnit.3.2.1\lib\net45\nunit.framework.dll + True + + + + + + + + + + + + + + + + + + + + + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + {1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E} + DDD.Infrastructure + + + {EA7D831A-03D1-4A08-805C-3E450EA024BC} + PhotoStock.Sales.Contract + + + {2230C68D-558A-463F-B3ED-427968DECB2E} + PhotoStock.Sales.Domain + + + {266FF480-2B3A-40C5-B01C-721C9A4D79D3} + PhotoStock.SharedKernel + + + + + \ No newline at end of file diff --git a/PhotoStock.Sales.Infrastructure/Properties/AssemblyInfo.cs b/PhotoStock.Sales.Infrastructure/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d2c3111 --- /dev/null +++ b/PhotoStock.Sales.Infrastructure/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Photostock.Sales.Infrastructure")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Photostock.Sales.Infrastructure")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("42d9d95b-3f19-46e3-9ccb-b9276a465e13")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Sales.Infrastructure/packages.config b/PhotoStock.Sales.Infrastructure/packages.config new file mode 100644 index 0000000..4d3cf39 --- /dev/null +++ b/PhotoStock.Sales.Infrastructure/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PhotoStock.Sales.Query/Offer/IOfferFinder.cs b/PhotoStock.Sales.Query/Offer/IOfferFinder.cs new file mode 100644 index 0000000..dd0e9b9 --- /dev/null +++ b/PhotoStock.Sales.Query/Offer/IOfferFinder.cs @@ -0,0 +1,10 @@ +using CQRS.Base.Query; +using System.Collections.Generic; + +namespace PhotoStock.Sales.Query.Offer +{ + public interface IProductFinder + { + PaginatedResult GetPage(OfferQuery query); + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Query/Offer/OfferQuery.cs b/PhotoStock.Sales.Query/Offer/OfferQuery.cs new file mode 100644 index 0000000..39086fd --- /dev/null +++ b/PhotoStock.Sales.Query/Offer/OfferQuery.cs @@ -0,0 +1,6 @@ +namespace PhotoStock.Sales.Query.Offer +{ + public class OfferQuery + { + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Query/Offer/OfferedProductDto.cs b/PhotoStock.Sales.Query/Offer/OfferedProductDto.cs new file mode 100644 index 0000000..c96b166 --- /dev/null +++ b/PhotoStock.Sales.Query/Offer/OfferedProductDto.cs @@ -0,0 +1,6 @@ +namespace PhotoStock.Sales.Query.Offer +{ + public class ProductDto + { + } +} \ No newline at end of file diff --git a/PhotoStock.Sales.Query/PhotoStock.Sales.Query.csproj b/PhotoStock.Sales.Query/PhotoStock.Sales.Query.csproj new file mode 100644 index 0000000..2910149 --- /dev/null +++ b/PhotoStock.Sales.Query/PhotoStock.Sales.Query.csproj @@ -0,0 +1,67 @@ + + + + + Debug + AnyCPU + {7BFE16B3-7692-4CE3-8237-1F84CBA62304} + Library + Properties + PhotoStock.Sales.Query + PhotoStock.Sales.Query + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A} + CQRS.Base + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + + + \ No newline at end of file diff --git a/PhotoStock.Sales.Query/Properties/AssemblyInfo.cs b/PhotoStock.Sales.Query/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d30723b --- /dev/null +++ b/PhotoStock.Sales.Query/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Sales.Query")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Sales.Query")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7bfe16b3-7692-4ce3-8237-1f84cba62304")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.SharedKernel/ClientData.cs b/PhotoStock.SharedKernel/ClientData.cs new file mode 100644 index 0000000..67d49e5 --- /dev/null +++ b/PhotoStock.SharedKernel/ClientData.cs @@ -0,0 +1,22 @@ +using DDD.Base.Domain; + +namespace PhotoStock.SharedKernel +{ + public class ClientData : ValueObject + { + public ClientData(AggregateId aggregateId, string name) + { + AggregateId = aggregateId; + Name = name; + } + + public AggregateId AggregateId { get; private set; } + public string Name { get; private set; } + public TaxNumber TaxNumber { get; set; } + public Address Address { get; set; } + } + + public class Address : ValueObject + { + } +} \ No newline at end of file diff --git a/PhotoStock.SharedKernel/Date.cs b/PhotoStock.SharedKernel/Date.cs new file mode 100644 index 0000000..0498497 --- /dev/null +++ b/PhotoStock.SharedKernel/Date.cs @@ -0,0 +1,20 @@ +using System; +using DDD.Base.Domain; + +namespace PhotoStock.SharedKernel +{ + public class Date : ValueObject + { + private readonly DateTime _date; + + private Date(DateTime date) + { + _date = date.Date; + } + + public static Date Today() + { + return new Date(DateTime.Today); + } + } +} \ No newline at end of file diff --git a/PhotoStock.SharedKernel/Money.cs b/PhotoStock.SharedKernel/Money.cs new file mode 100644 index 0000000..e7a5e31 --- /dev/null +++ b/PhotoStock.SharedKernel/Money.cs @@ -0,0 +1,85 @@ +using DDD.Base.Domain; + +namespace PhotoStock.SharedKernel +{ + public class Money : ValueObject + { + private decimal _amount; + public static Money ZERO = 0; + + private Money(decimal amount) + { + _amount = amount; + } + + private Money(double amount) + { + _amount = (decimal)amount; + } + + public static Money operator -(Money x) + { + return new Money(-x._amount); + } + + public static Money operator *(Money money, decimal value) + { + return new Money(money._amount * value); + } + + public static Money operator *(Money money, double value) + { + return new Money((decimal)((double)money._amount * value)); + } + + public static Money operator *(double value, Money money) + { + return new Money((decimal)((double)money._amount * value)); + } + + public static Money operator *(decimal value, Money money) + { + return new Money(money._amount * value); + } + + public static Money operator +(Money money, Money value) + { + return new Money(money._amount + value._amount); + } + + public static Money operator -(Money money, Money value) + { + return new Money(money._amount - value._amount); + } + + public static bool operator >(Money money, Money value) + { + return money._amount > value._amount; + } + + public static bool operator >=(Money money, Money value) + { + return money._amount >= value._amount; + } + + public static bool operator <(Money money, Money value) + { + return money._amount < value._amount; + } + + public static bool operator <=(Money money, Money value) + { + return money._amount <= value._amount; + } + + public static implicit operator Money(decimal value) + { + return new Money(value); + } + + public Money Add(Money net) + { + return new Money(_amount + net._amount); + } + } +} \ No newline at end of file diff --git a/PhotoStock.SharedKernel/PhotoStock.SharedKernel.csproj b/PhotoStock.SharedKernel/PhotoStock.SharedKernel.csproj new file mode 100644 index 0000000..42515b8 --- /dev/null +++ b/PhotoStock.SharedKernel/PhotoStock.SharedKernel.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {266FF480-2B3A-40C5-B01C-721C9A4D79D3} + Library + Properties + PhotoStock.SharedKernel + PhotoStock.SharedKernel + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + + + \ No newline at end of file diff --git a/PhotoStock.SharedKernel/ProductData.cs b/PhotoStock.SharedKernel/ProductData.cs new file mode 100644 index 0000000..2715a6d --- /dev/null +++ b/PhotoStock.SharedKernel/ProductData.cs @@ -0,0 +1,21 @@ +using DDD.Base.Domain; + +namespace PhotoStock.SharedKernel +{ + public class ProductData + { + public ProductData(AggregateId productId, Money price, string name, ProductType productType) + { + ProductId = productId; + Price = price; + Name = name; + ProductType = productType; + } + + public ProductType Type { get; set; } + public AggregateId ProductId { get; set; } + public Money Price { get; set; } + public string Name { get; set; } + public ProductType ProductType { get; set; } + } +} \ No newline at end of file diff --git a/PhotoStock.SharedKernel/ProductType.cs b/PhotoStock.SharedKernel/ProductType.cs new file mode 100644 index 0000000..a20bf7a --- /dev/null +++ b/PhotoStock.SharedKernel/ProductType.cs @@ -0,0 +1,8 @@ +namespace PhotoStock.SharedKernel +{ + public enum ProductType + { + Printed, + Electronic + } +} \ No newline at end of file diff --git a/PhotoStock.SharedKernel/Properties/AssemblyInfo.cs b/PhotoStock.SharedKernel/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..57f7b03 --- /dev/null +++ b/PhotoStock.SharedKernel/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.SharedKernel")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.SharedKernel")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("266ff480-2b3a-40c5-b01c-721c9a4d79d3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.SharedKernel/TaxNumber.cs b/PhotoStock.SharedKernel/TaxNumber.cs new file mode 100644 index 0000000..20d2441 --- /dev/null +++ b/PhotoStock.SharedKernel/TaxNumber.cs @@ -0,0 +1,9 @@ +using DDD.Base.Domain; + +namespace PhotoStock.SharedKernel +{ + public class TaxNumber : ValueObject + { + //TODO: implementation + } +} \ No newline at end of file diff --git a/PhotoStock.Shipping.Application/PhotoStock.Shipping.Application.csproj b/PhotoStock.Shipping.Application/PhotoStock.Shipping.Application.csproj new file mode 100644 index 0000000..447ed50 --- /dev/null +++ b/PhotoStock.Shipping.Application/PhotoStock.Shipping.Application.csproj @@ -0,0 +1,79 @@ + + + + + Debug + AnyCPU + {DB22ADE0-E49E-4B7E-9329-5AEA5F82072C} + Library + Properties + PhotoStock.Shipping.Application + PhotoStock.Shipping.Application + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A} + CQRS.Base + + + {f8d43559-8792-498b-ab51-211ca04cb4df} + DDD.Base + + + {EA7D831A-03D1-4A08-805C-3E450EA024BC} + PhotoStock.Sales.Contract + + + {1FF64B1A-907E-4056-82A5-67B3EFD45C78} + PhotoStock.Shipping.Contract + + + {B49CABB5-36C5-4028-BA42-0F3E0B94E33F} + PhotoStock.Shipping.Domain + + + + + + + + + \ No newline at end of file diff --git a/PhotoStock.Shipping.Application/Properties/AssemblyInfo.cs b/PhotoStock.Shipping.Application/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b596752 --- /dev/null +++ b/PhotoStock.Shipping.Application/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Shipping.Application")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Shipping.Application")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("db22ade0-e49e-4b7e-9329-5aea5f82072c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Shipping.Contract/Commands/DeliverShipmentCommand.cs b/PhotoStock.Shipping.Contract/Commands/DeliverShipmentCommand.cs new file mode 100644 index 0000000..fde7d10 --- /dev/null +++ b/PhotoStock.Shipping.Contract/Commands/DeliverShipmentCommand.cs @@ -0,0 +1,14 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Shipping.Contract.Commands +{ + public class DeliverShipmentCommand + { + public AggregateId ShipmentId { get; private set; } + + public DeliverShipmentCommand(AggregateId shipmentId) + { + ShipmentId = shipmentId; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Shipping.Contract/Commands/SendShipmentCommand.cs b/PhotoStock.Shipping.Contract/Commands/SendShipmentCommand.cs new file mode 100644 index 0000000..9c0c97b --- /dev/null +++ b/PhotoStock.Shipping.Contract/Commands/SendShipmentCommand.cs @@ -0,0 +1,14 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Shipping.Contract.Commands +{ + public class SendShipmentCommand + { + public AggregateId OrderId { get; set; } + + public SendShipmentCommand(AggregateId orderId) + { + OrderId = orderId; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Shipping.Contract/Events/OrderShippedEvent.cs b/PhotoStock.Shipping.Contract/Events/OrderShippedEvent.cs new file mode 100644 index 0000000..1d13277 --- /dev/null +++ b/PhotoStock.Shipping.Contract/Events/OrderShippedEvent.cs @@ -0,0 +1,16 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Shipping.Contract.Events +{ + public class OrderShippedEvent : IDomainEvent + { + public AggregateId OrderId { get; private set; } + public AggregateId ShipmentId { get; private set; } + + public OrderShippedEvent(AggregateId orderId, AggregateId shipmentId) + { + OrderId = orderId; + ShipmentId = shipmentId; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Shipping.Contract/PhotoStock.Shipping.Contract.csproj b/PhotoStock.Shipping.Contract/PhotoStock.Shipping.Contract.csproj new file mode 100644 index 0000000..1868278 --- /dev/null +++ b/PhotoStock.Shipping.Contract/PhotoStock.Shipping.Contract.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {1FF64B1A-907E-4056-82A5-67B3EFD45C78} + Library + Properties + PhotoStock.Shipping.Contract + PhotoStock.Shipping.Contract + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + + + \ No newline at end of file diff --git a/PhotoStock.Shipping.Contract/Properties/AssemblyInfo.cs b/PhotoStock.Shipping.Contract/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c105457 --- /dev/null +++ b/PhotoStock.Shipping.Contract/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Shipping.Contract")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Shipping.Contract")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1ff64b1a-907e-4056-82a5-67b3efd45c78")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Shipping.Domain/IShipmentFactory.cs b/PhotoStock.Shipping.Domain/IShipmentFactory.cs new file mode 100644 index 0000000..a8fb515 --- /dev/null +++ b/PhotoStock.Shipping.Domain/IShipmentFactory.cs @@ -0,0 +1,9 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Shipping.Domain +{ + public interface IShipmentFactory + { + Shipment CreateShipment(AggregateId orderId); + } +} \ No newline at end of file diff --git a/PhotoStock.Shipping.Domain/IShipmentRepository.cs b/PhotoStock.Shipping.Domain/IShipmentRepository.cs new file mode 100644 index 0000000..355a9dc --- /dev/null +++ b/PhotoStock.Shipping.Domain/IShipmentRepository.cs @@ -0,0 +1,8 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Shipping.Domain +{ + public interface IShipmentRepository : IGenericRepository + { + } +} \ No newline at end of file diff --git a/PhotoStock.Shipping.Domain/PhotoStock.Shipping.Domain.csproj b/PhotoStock.Shipping.Domain/PhotoStock.Shipping.Domain.csproj new file mode 100644 index 0000000..570fbee --- /dev/null +++ b/PhotoStock.Shipping.Domain/PhotoStock.Shipping.Domain.csproj @@ -0,0 +1,68 @@ + + + + + Debug + AnyCPU + {B49CABB5-36C5-4028-BA42-0F3E0B94E33F} + Library + Properties + PhotoStock.Shipping.Domain + PhotoStock.Shipping.Domain + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + {1FF64B1A-907E-4056-82A5-67B3EFD45C78} + PhotoStock.Shipping.Contract + + + + + \ No newline at end of file diff --git a/PhotoStock.Shipping.Domain/Properties/AssemblyInfo.cs b/PhotoStock.Shipping.Domain/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2946cc3 --- /dev/null +++ b/PhotoStock.Shipping.Domain/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Shipping.Domain")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Shipping.Domain")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b49cabb5-36c5-4028-ba42-0f3e0b94e33f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Shipping.Domain/Shipment.cs b/PhotoStock.Shipping.Domain/Shipment.cs new file mode 100644 index 0000000..6fe8152 --- /dev/null +++ b/PhotoStock.Shipping.Domain/Shipment.cs @@ -0,0 +1,37 @@ +using DDD.Base.Domain; +using DDD.Base.Domain.Exceptions; +using PhotoStock.Shipping.Contract.Events; + +namespace PhotoStock.Shipping.Domain +{ + public class Shipment : AggregateRoot + { + public AggregateId OrderId { get; private set; } + + public ShippingStatus ShipmentStatus { get; private set; } + + private Shipment() + { + } + + public Shipment(AggregateId orderId) + { + OrderId = orderId; + ShipmentStatus = ShippingStatus.WAITING; + } + + /** + * Shipment has been sent to the customer. + */ + + public void Ship() + { + if (ShipmentStatus != ShippingStatus.WAITING) + { + throw new IllegalStateException("Cannot ship in status " + ShipmentStatus); + } + ShipmentStatus = ShippingStatus.SENT; + EventPublisher.Publish(new OrderShippedEvent(OrderId, AggregateId)); + } + } +} \ No newline at end of file diff --git a/PhotoStock.Shipping.Domain/ShipmentFactory.cs b/PhotoStock.Shipping.Domain/ShipmentFactory.cs new file mode 100644 index 0000000..8c4b63b --- /dev/null +++ b/PhotoStock.Shipping.Domain/ShipmentFactory.cs @@ -0,0 +1,23 @@ +using DDD.Base.Domain; + +namespace PhotoStock.Shipping.Domain +{ + public class ShipmentFactory : IShipmentFactory + { + private IDependencyInjector _dependencyInjector; + + public ShipmentFactory(IDependencyInjector dependencyInjector) + { + _dependencyInjector = dependencyInjector; + } + + public Shipment CreateShipment(AggregateId orderId) + { + Shipment shipment = new Shipment(orderId); + + _dependencyInjector.InjectDependencies(shipment); + + return shipment; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Shipping.Domain/ShippingStatus.cs b/PhotoStock.Shipping.Domain/ShippingStatus.cs new file mode 100644 index 0000000..fc18c10 --- /dev/null +++ b/PhotoStock.Shipping.Domain/ShippingStatus.cs @@ -0,0 +1,10 @@ +namespace PhotoStock.Shipping.Domain +{ + + public enum ShippingStatus + { + WAITING, + SENT, + DELIVERED + } +} diff --git a/PhotoStock.System/ISystemContext.cs b/PhotoStock.System/ISystemContext.cs new file mode 100644 index 0000000..ecff134 --- /dev/null +++ b/PhotoStock.System/ISystemContext.cs @@ -0,0 +1,7 @@ +namespace PhotoStock.System +{ + public interface ISystemContext + { + SystemUser SystemUser { get; } + } +} \ No newline at end of file diff --git a/PhotoStock.System/PhotoStock.System.csproj b/PhotoStock.System/PhotoStock.System.csproj new file mode 100644 index 0000000..da1eabf --- /dev/null +++ b/PhotoStock.System/PhotoStock.System.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {2FC58C62-FE65-46C7-989E-180C2B8E41EE} + Library + Properties + PhotoStock.System + PhotoStock.System + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + {F8D43559-8792-498B-AB51-211CA04CB4DF} + DDD.Base + + + + + \ No newline at end of file diff --git a/PhotoStock.System/Properties/AssemblyInfo.cs b/PhotoStock.System/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1d050ec --- /dev/null +++ b/PhotoStock.System/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.System")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.System")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2fc58c62-fe65-46c7-989e-180c2b8e41ee")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.System/SystemContext.cs b/PhotoStock.System/SystemContext.cs new file mode 100644 index 0000000..7347602 --- /dev/null +++ b/PhotoStock.System/SystemContext.cs @@ -0,0 +1,15 @@ +using DDD.Base.Domain; + +namespace PhotoStock.System +{ + internal class SystemContext : ISystemContext + { + public SystemUser SystemUser + { + get + { + return new SystemUser(new AggregateId("1")); //TODO introduce security integration + } + } + } +} \ No newline at end of file diff --git a/PhotoStock.System/SystemUser.cs b/PhotoStock.System/SystemUser.cs new file mode 100644 index 0000000..b7ec332 --- /dev/null +++ b/PhotoStock.System/SystemUser.cs @@ -0,0 +1,19 @@ +using DDD.Base.Domain; + +namespace PhotoStock.System +{ + public class SystemUser + { + public AggregateId ClientId { get; private set; } + + internal SystemUser(AggregateId clientId) + { + ClientId = clientId; + } + + public bool IsLoogedIn() + { + return ClientId != null; + } + } +} \ No newline at end of file diff --git a/PhotoStock.Tests/Class1.cs b/PhotoStock.Tests/Class1.cs new file mode 100644 index 0000000..076f643 --- /dev/null +++ b/PhotoStock.Tests/Class1.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PhotoStock.Tests +{ + public class OrderingService + { + public void NewOrder(ClientId clientId) + { + Order o = _orderFactory.Create(clientId); + + _historyService.Add + OrderHistory + } + } +} \ No newline at end of file diff --git a/PhotoStock.Tests/PhotoStock.Tests.csproj b/PhotoStock.Tests/PhotoStock.Tests.csproj new file mode 100644 index 0000000..625be74 --- /dev/null +++ b/PhotoStock.Tests/PhotoStock.Tests.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {67F68401-9A9D-48FD-BB9E-A4DAF35CCA65} + Library + Properties + PhotoStock.Tests + PhotoStock.Tests + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PhotoStock.Tests/Properties/AssemblyInfo.cs b/PhotoStock.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..084590e --- /dev/null +++ b/PhotoStock.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhotoStock.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhotoStock.Tests")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("67f68401-9a9d-48fd-bb9e-a4daf35cca65")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PhotoStock.Tests/packages.config b/PhotoStock.Tests/packages.config new file mode 100644 index 0000000..f8429b5 --- /dev/null +++ b/PhotoStock.Tests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/PhotoStock.sln b/PhotoStock.sln new file mode 100644 index 0000000..9f3d45c --- /dev/null +++ b/PhotoStock.sln @@ -0,0 +1,158 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Tests", "PhotoStock.Tests\PhotoStock.Tests.csproj", "{67F68401-9A9D-48FD-BB9E-A4DAF35CCA65}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Sales.Domain", "PhotoStock.Sales.Domain\PhotoStock.Sales.Domain.csproj", "{2230C68D-558A-463F-B3ED-427968DECB2E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Sales.Query", "PhotoStock.Sales.Query\PhotoStock.Sales.Query.csproj", "{7BFE16B3-7692-4CE3-8237-1F84CBA62304}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DDD.Base", "DDD.Base\DDD.Base.csproj", "{F8D43559-8792-498B-AB51-211CA04CB4DF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CQRS.Base", "CQRS.Base\CQRS.Base.csproj", "{7D8D2FEB-C2E5-4D54-8369-21DE2D44984A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DDD.Infrastructure", "DDD.Infrastructure\DDD.Infrastructure.csproj", "{1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Base", "Base", "{A0F7DF3D-4B23-4243-9834-E35FBC15C9A8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sales", "Sales", "{C8607D23-999C-46EE-946A-85C6CF69746F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shipping", "Shipping", "{0D8B3E81-E824-4CE0-A516-87C4ECB59F52}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Sales.Application", "PhotoStock.Sales.Application\PhotoStock.Sales.Application.csproj", "{502D416A-D97E-46F6-B47F-85AB0BFDCD3A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.System", "PhotoStock.System\PhotoStock.System.csproj", "{2FC58C62-FE65-46C7-989E-180C2B8E41EE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Shipping.Application", "PhotoStock.Shipping.Application\PhotoStock.Shipping.Application.csproj", "{DB22ADE0-E49E-4B7E-9329-5AEA5F82072C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Shipping.Domain", "PhotoStock.Shipping.Domain\PhotoStock.Shipping.Domain.csproj", "{B49CABB5-36C5-4028-BA42-0F3E0B94E33F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Shipping.Contract", "PhotoStock.Shipping.Contract\PhotoStock.Shipping.Contract.csproj", "{1FF64B1A-907E-4056-82A5-67B3EFD45C78}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Sales.Contract", "PhotoStock.Sales.Contract\PhotoStock.Sales.Contract.csproj", "{EA7D831A-03D1-4A08-805C-3E450EA024BC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.SharedKernel", "PhotoStock.SharedKernel\PhotoStock.SharedKernel.csproj", "{266FF480-2B3A-40C5-B01C-721C9A4D79D3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Photostock.Sales.Infrastructure", "Photostock.Sales.Infrastructure\Photostock.Sales.Infrastructure.csproj", "{42D9D95B-3F19-46E3-9CCB-B9276A465E13}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Invoicing", "Invoicing", "{80ACDAD5-3FE5-4559-B11F-5F7CF18FF85C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Invoicing.Domain", "PhotoStock.Invoicing.Domain\PhotoStock.Invoicing.Domain.csproj", "{F686EDF5-2B9C-4DE1-B197-785B38BE4B97}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Invoicing.Application", "PhotoStock.Invoicing.Application\PhotoStock.Invoicing.Application.csproj", "{91D4A03B-CCE7-4A9A-AA80-626251967A2B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.Invoicing.Contract", "PhotoStock.Invoicing.Contract\PhotoStock.Invoicing.Contract.csproj", "{265016F3-AE52-4167-926A-52924366E7DD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BusinessProcess", "BusinessProcess", "{EA8DA886-D082-4565-95FA-7E70248260B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.BusinessProcess.Tests", "PhotoStock.BusinessProcess.Tests\PhotoStock.BusinessProcess.Tests.csproj", "{5C0936A5-3185-44C5-9B6B-FEB039CFB6F7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoStock.BusinessProcess", "PhotoStock.BusinessProcess\PhotoStock.BusinessProcess.csproj", "{6B0EA748-FC9A-467B-B3D4-A2A025EEBB29}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {67F68401-9A9D-48FD-BB9E-A4DAF35CCA65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {67F68401-9A9D-48FD-BB9E-A4DAF35CCA65}.Debug|Any CPU.Build.0 = Debug|Any CPU + {67F68401-9A9D-48FD-BB9E-A4DAF35CCA65}.Release|Any CPU.ActiveCfg = Release|Any CPU + {67F68401-9A9D-48FD-BB9E-A4DAF35CCA65}.Release|Any CPU.Build.0 = Release|Any CPU + {2230C68D-558A-463F-B3ED-427968DECB2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2230C68D-558A-463F-B3ED-427968DECB2E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2230C68D-558A-463F-B3ED-427968DECB2E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2230C68D-558A-463F-B3ED-427968DECB2E}.Release|Any CPU.Build.0 = Release|Any CPU + {7BFE16B3-7692-4CE3-8237-1F84CBA62304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BFE16B3-7692-4CE3-8237-1F84CBA62304}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BFE16B3-7692-4CE3-8237-1F84CBA62304}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BFE16B3-7692-4CE3-8237-1F84CBA62304}.Release|Any CPU.Build.0 = Release|Any CPU + {F8D43559-8792-498B-AB51-211CA04CB4DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8D43559-8792-498B-AB51-211CA04CB4DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8D43559-8792-498B-AB51-211CA04CB4DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8D43559-8792-498B-AB51-211CA04CB4DF}.Release|Any CPU.Build.0 = Release|Any CPU + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A}.Release|Any CPU.Build.0 = Release|Any CPU + {1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E}.Release|Any CPU.Build.0 = Release|Any CPU + {502D416A-D97E-46F6-B47F-85AB0BFDCD3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {502D416A-D97E-46F6-B47F-85AB0BFDCD3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {502D416A-D97E-46F6-B47F-85AB0BFDCD3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {502D416A-D97E-46F6-B47F-85AB0BFDCD3A}.Release|Any CPU.Build.0 = Release|Any CPU + {2FC58C62-FE65-46C7-989E-180C2B8E41EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2FC58C62-FE65-46C7-989E-180C2B8E41EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2FC58C62-FE65-46C7-989E-180C2B8E41EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2FC58C62-FE65-46C7-989E-180C2B8E41EE}.Release|Any CPU.Build.0 = Release|Any CPU + {DB22ADE0-E49E-4B7E-9329-5AEA5F82072C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB22ADE0-E49E-4B7E-9329-5AEA5F82072C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB22ADE0-E49E-4B7E-9329-5AEA5F82072C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB22ADE0-E49E-4B7E-9329-5AEA5F82072C}.Release|Any CPU.Build.0 = Release|Any CPU + {B49CABB5-36C5-4028-BA42-0F3E0B94E33F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B49CABB5-36C5-4028-BA42-0F3E0B94E33F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B49CABB5-36C5-4028-BA42-0F3E0B94E33F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B49CABB5-36C5-4028-BA42-0F3E0B94E33F}.Release|Any CPU.Build.0 = Release|Any CPU + {1FF64B1A-907E-4056-82A5-67B3EFD45C78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FF64B1A-907E-4056-82A5-67B3EFD45C78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FF64B1A-907E-4056-82A5-67B3EFD45C78}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FF64B1A-907E-4056-82A5-67B3EFD45C78}.Release|Any CPU.Build.0 = Release|Any CPU + {EA7D831A-03D1-4A08-805C-3E450EA024BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA7D831A-03D1-4A08-805C-3E450EA024BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA7D831A-03D1-4A08-805C-3E450EA024BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA7D831A-03D1-4A08-805C-3E450EA024BC}.Release|Any CPU.Build.0 = Release|Any CPU + {266FF480-2B3A-40C5-B01C-721C9A4D79D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {266FF480-2B3A-40C5-B01C-721C9A4D79D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {266FF480-2B3A-40C5-B01C-721C9A4D79D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {266FF480-2B3A-40C5-B01C-721C9A4D79D3}.Release|Any CPU.Build.0 = Release|Any CPU + {42D9D95B-3F19-46E3-9CCB-B9276A465E13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42D9D95B-3F19-46E3-9CCB-B9276A465E13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42D9D95B-3F19-46E3-9CCB-B9276A465E13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42D9D95B-3F19-46E3-9CCB-B9276A465E13}.Release|Any CPU.Build.0 = Release|Any CPU + {F686EDF5-2B9C-4DE1-B197-785B38BE4B97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F686EDF5-2B9C-4DE1-B197-785B38BE4B97}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F686EDF5-2B9C-4DE1-B197-785B38BE4B97}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F686EDF5-2B9C-4DE1-B197-785B38BE4B97}.Release|Any CPU.Build.0 = Release|Any CPU + {91D4A03B-CCE7-4A9A-AA80-626251967A2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {91D4A03B-CCE7-4A9A-AA80-626251967A2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91D4A03B-CCE7-4A9A-AA80-626251967A2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {91D4A03B-CCE7-4A9A-AA80-626251967A2B}.Release|Any CPU.Build.0 = Release|Any CPU + {265016F3-AE52-4167-926A-52924366E7DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {265016F3-AE52-4167-926A-52924366E7DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {265016F3-AE52-4167-926A-52924366E7DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {265016F3-AE52-4167-926A-52924366E7DD}.Release|Any CPU.Build.0 = Release|Any CPU + {5C0936A5-3185-44C5-9B6B-FEB039CFB6F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C0936A5-3185-44C5-9B6B-FEB039CFB6F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C0936A5-3185-44C5-9B6B-FEB039CFB6F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C0936A5-3185-44C5-9B6B-FEB039CFB6F7}.Release|Any CPU.Build.0 = Release|Any CPU + {6B0EA748-FC9A-467B-B3D4-A2A025EEBB29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B0EA748-FC9A-467B-B3D4-A2A025EEBB29}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B0EA748-FC9A-467B-B3D4-A2A025EEBB29}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B0EA748-FC9A-467B-B3D4-A2A025EEBB29}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {2230C68D-558A-463F-B3ED-427968DECB2E} = {C8607D23-999C-46EE-946A-85C6CF69746F} + {7BFE16B3-7692-4CE3-8237-1F84CBA62304} = {C8607D23-999C-46EE-946A-85C6CF69746F} + {F8D43559-8792-498B-AB51-211CA04CB4DF} = {A0F7DF3D-4B23-4243-9834-E35FBC15C9A8} + {7D8D2FEB-C2E5-4D54-8369-21DE2D44984A} = {A0F7DF3D-4B23-4243-9834-E35FBC15C9A8} + {1F25C4FB-D5EA-46BB-AB2B-AC5582E1AA9E} = {A0F7DF3D-4B23-4243-9834-E35FBC15C9A8} + {502D416A-D97E-46F6-B47F-85AB0BFDCD3A} = {C8607D23-999C-46EE-946A-85C6CF69746F} + {DB22ADE0-E49E-4B7E-9329-5AEA5F82072C} = {0D8B3E81-E824-4CE0-A516-87C4ECB59F52} + {B49CABB5-36C5-4028-BA42-0F3E0B94E33F} = {0D8B3E81-E824-4CE0-A516-87C4ECB59F52} + {1FF64B1A-907E-4056-82A5-67B3EFD45C78} = {0D8B3E81-E824-4CE0-A516-87C4ECB59F52} + {EA7D831A-03D1-4A08-805C-3E450EA024BC} = {C8607D23-999C-46EE-946A-85C6CF69746F} + {42D9D95B-3F19-46E3-9CCB-B9276A465E13} = {C8607D23-999C-46EE-946A-85C6CF69746F} + {F686EDF5-2B9C-4DE1-B197-785B38BE4B97} = {80ACDAD5-3FE5-4559-B11F-5F7CF18FF85C} + {91D4A03B-CCE7-4A9A-AA80-626251967A2B} = {80ACDAD5-3FE5-4559-B11F-5F7CF18FF85C} + {265016F3-AE52-4167-926A-52924366E7DD} = {80ACDAD5-3FE5-4559-B11F-5F7CF18FF85C} + {5C0936A5-3185-44C5-9B6B-FEB039CFB6F7} = {EA8DA886-D082-4565-95FA-7E70248260B7} + {6B0EA748-FC9A-467B-B3D4-A2A025EEBB29} = {EA8DA886-D082-4565-95FA-7E70248260B7} + EndGlobalSection +EndGlobal