/// <summary>
        /// Creates the contract.
        /// </summary>
        /// <param name="contractId">The contract identifier.</param>
        /// <param name="estateId">The estate identifier.</param>
        /// <param name="operatorId">The operator identifier.</param>
        /// <param name="description">The description.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <exception cref="System.InvalidOperationException">
        /// Unable to create a contract for an estate that is not created
        /// or
        /// Unable to create a contract for an operator that is not setup on estate [{estate.Name}]
        /// or
        /// Contract Id [{contractId}] already created for estate [{estate.Name}]
        /// </exception>
        public async Task CreateContract(Guid contractId,
                                         Guid estateId,
                                         Guid operatorId,
                                         String description,
                                         CancellationToken cancellationToken)
        {
            // Validate the estate
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            if (estateAggregate.IsCreated == false)
            {
                throw new InvalidOperationException("Unable to create a contract for an estate that is not created");
            }

            // Validate the operator
            Estate estate = estateAggregate.GetEstate();

            if (estate.Operators == null || estate.Operators.Any(o => o.OperatorId == operatorId) == false)
            {
                throw new InvalidOperationException($"Unable to create a contract for an operator that is not setup on estate [{estate.Name}]");
            }

            // Get the contract aggregate
            ContractAggregate contractAggregate = await this.ContractAggregateRepository.GetLatestVersion(contractId, cancellationToken);

            // Check for a duplicate
            if (contractAggregate.IsCreated)
            {
                throw new InvalidOperationException($"Contract Id [{contractId}] already created for estate [{estate.Name}]");
            }

            contractAggregate.Create(estateId, operatorId, description);

            await this.ContractAggregateRepository.SaveChanges(contractAggregate, cancellationToken);
        }
示例#2
0
        public void EstateAggregate_AddSecurityUserToEstate_SecurityUserIsAdded()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            aggregate.Create(TestData.EstateName);
            aggregate.AddSecurityUser(TestData.SecurityUserId, TestData.EstateUserEmailAddress);
        }
示例#3
0
        /// <summary>
        /// Adds the device to merchant.
        /// </summary>
        /// <param name="estateId">The estate identifier.</param>
        /// <param name="merchantId">The merchant identifier.</param>
        /// <param name="deviceId">The device identifier.</param>
        /// <param name="deviceIdentifier">The device identifier.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        public async Task AddDeviceToMerchant(Guid estateId,
                                              Guid merchantId,
                                              Guid deviceId,
                                              String deviceIdentifier,
                                              CancellationToken cancellationToken)
        {
            MerchantAggregate merchantAggregate = await this.MerchantAggregateRepository.GetLatestVersion(merchantId, cancellationToken);

            // Check merchant has been created
            if (merchantAggregate.IsCreated == false)
            {
                throw new InvalidOperationException($"Merchant Id {merchantId} has not been created");
            }

            // Estate Id is a valid estate
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            if (estateAggregate.IsCreated == false)
            {
                throw new InvalidOperationException($"Estate Id {estateId} has not been created");
            }

            merchantAggregate.AddDevice(deviceId, deviceIdentifier);

            await this.MerchantAggregateRepository.SaveChanges(merchantAggregate, cancellationToken);
        }
示例#4
0
        public void EstateAggregate_AddOperatorToEstate_OperatorIsAdded()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            aggregate.Create(TestData.EstateName);

            aggregate.AddOperator(TestData.OperatorId, TestData.OperatorName, TestData.RequireCustomMerchantNumberFalse, TestData.RequireCustomTerminalNumberFalse);
        }
示例#5
0
        public async Task AssignOperatorToMerchant(Guid estateId,
                                                   Guid merchantId,
                                                   Guid operatorId,
                                                   String merchantNumber,
                                                   String terminalNumber,
                                                   CancellationToken cancellationToken)
        {
            MerchantAggregate merchantAggregate = await this.MerchantAggregateRepository.GetLatestVersion(merchantId, cancellationToken);

            // Check merchant has been created
            if (merchantAggregate.IsCreated == false)
            {
                throw new InvalidOperationException($"Merchant Id {merchantId} has not been created");
            }

            // Estate Id is a valid estate
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            if (estateAggregate.IsCreated == false)
            {
                throw new InvalidOperationException($"Estate Id {estateId} has not been created");
            }

            // Is the operator valid for this estate
            Estate   estate    = estateAggregate.GetEstate();
            Operator @operator = estate.Operators?.SingleOrDefault(o => o.OperatorId == operatorId);

            if (@operator == null)
            {
                throw new InvalidOperationException($"Operator Id {operatorId} is not supported on Estate [{estate.Name}]");
            }

            // Operator has been validated, now check the rules of the operator against the passed in data
            if (@operator.RequireCustomMerchantNumber)
            {
                // requested addition must have a merchant number supplied
                if (String.IsNullOrEmpty(merchantNumber))
                {
                    throw new InvalidOperationException($"Operator Id {operatorId} requires that a merchant number is provided");
                }
            }

            if (@operator.RequireCustomTerminalNumber)
            {
                // requested addition must have a terminal number supplied
                if (String.IsNullOrEmpty(terminalNumber))
                {
                    throw new InvalidOperationException($"Operator Id {operatorId} requires that a terminal number is provided");
                }
            }

            // Assign the operator
            merchantAggregate.AssignOperator(operatorId, @operator.Name, merchantNumber, terminalNumber);

            await this.MerchantAggregateRepository.SaveChanges(merchantAggregate, cancellationToken);
        }
示例#6
0
        /// <summary>
        /// Creates the estate.
        /// </summary>
        /// <param name="estateId">The estate identifier.</param>
        /// <param name="estateName">Name of the estate.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        public async Task CreateEstate(Guid estateId,
                                       String estateName,
                                       CancellationToken cancellationToken)
        {
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            estateAggregate.Create(estateName);

            await this.EstateAggregateRepository.SaveChanges(estateAggregate, cancellationToken);
        }
示例#7
0
        public void EstateAggregate_Create_InvalidEstateName_ErrorThrown(String estateName)
        {
            EstateAggregate       aggregate = EstateAggregate.Create(TestData.EstateId);
            ArgumentNullException exception = Should.Throw <ArgumentNullException>(() =>
            {
                aggregate.Create(estateName);
            });

            exception.Message.ShouldContain("Estate name must be provided when registering a new estate");
        }
示例#8
0
        public void EstateAggregate_Create_IsCreated()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            aggregate.Create(TestData.EstateName);

            aggregate.AggregateId.ShouldBe(TestData.EstateId);
            aggregate.EstateName.ShouldBe(TestData.EstateName);
            aggregate.IsCreated.ShouldBeTrue();
        }
示例#9
0
        public void EstateAggregate_AddSecurityUserToEstate_EstateNotCreated_ErrorThrown()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            InvalidOperationException exception = Should.Throw <InvalidOperationException>(() =>
            {
                aggregate.AddSecurityUser(TestData.SecurityUserId, TestData.EstateUserEmailAddress);
            });

            exception.Message.ShouldContain("Estate has not been created");
        }
示例#10
0
        public void EstateAggregate_AddOperatorToEstate_EstateNotCreated_ErrorThrown()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            InvalidOperationException exception = Should.Throw <InvalidOperationException>(() =>
            {
                aggregate.AddOperator(TestData.OperatorId, TestData.OperatorName, TestData.RequireCustomMerchantNumberFalse, TestData.RequireCustomTerminalNumberFalse);
            });

            exception.Message.ShouldContain("Estate has not been created");
        }
示例#11
0
        public async Task <Guid> CreateMerchantUser(Guid estateId,
                                                    Guid merchantId,
                                                    String emailAddress,
                                                    String password,
                                                    String givenName,
                                                    String middleName,
                                                    String familyName,
                                                    CancellationToken cancellationToken)
        {
            MerchantAggregate merchantAggregate = await this.MerchantAggregateRepository.GetLatestVersion(merchantId, cancellationToken);

            // Check merchant has been created
            if (merchantAggregate.IsCreated == false)
            {
                throw new InvalidOperationException($"Merchant Id {merchantId} has not been created");
            }

            // Estate Id is a valid estate
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            if (estateAggregate.IsCreated == false)
            {
                throw new InvalidOperationException($"Estate Id {estateId} has not been created");
            }

            CreateUserRequest createUserRequest = new CreateUserRequest
            {
                EmailAddress = emailAddress,
                FamilyName   = familyName,
                GivenName    = givenName,
                MiddleName   = middleName,
                Password     = password,
                PhoneNumber  = "123456",                                      // Is this really needed :|
                Roles        = new List <String>(),
                Claims       = new Dictionary <String, String>()
            };

            String merchantRoleName = Environment.GetEnvironmentVariable("MerchantRoleName");

            createUserRequest.Roles.Add(String.IsNullOrEmpty(merchantRoleName) ? "Merchant" : merchantRoleName);
            createUserRequest.Claims.Add("estateId", estateId.ToString());
            createUserRequest.Claims.Add("merchantId", merchantId.ToString());

            CreateUserResponse createUserResponse = await this.SecurityServiceClient.CreateUser(createUserRequest, cancellationToken);

            // Add the user to the aggregate
            merchantAggregate.AddSecurityUser(createUserResponse.UserId, emailAddress);

            // TODO: add a delete user here in case the aggregate add fails...

            await this.MerchantAggregateRepository.SaveChanges(merchantAggregate, cancellationToken);

            return(createUserResponse.UserId);
        }
示例#12
0
        public void EstateAggregate_GetEstate_NoOperators_EstateIsReturned()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            aggregate.Create(TestData.EstateName);

            Estate model = aggregate.GetEstate();

            model.EstateId.ShouldBe(TestData.EstateId);
            model.Name.ShouldBe(TestData.EstateName);
            model.Operators.ShouldBeNull();
        }
示例#13
0
        /// <summary>
        /// Creates the operator.
        /// </summary>
        /// <param name="estateId">The estate identifier.</param>
        /// <param name="operatorId">The operator identifier.</param>
        /// <param name="operatorName">Name of the operator.</param>
        /// <param name="requireCustomMerchantNumber">if set to <c>true</c> [require custom merchant number].</param>
        /// <param name="requireCustomTerminalNumber">if set to <c>true</c> [require custom terminal number].</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        public async Task AddOperatorToEstate(Guid estateId,
                                              Guid operatorId,
                                              String operatorName,
                                              Boolean requireCustomMerchantNumber,
                                              Boolean requireCustomTerminalNumber,
                                              CancellationToken cancellationToken)
        {
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            estateAggregate.AddOperator(operatorId, operatorName, requireCustomMerchantNumber, requireCustomTerminalNumber);

            await this.EstateAggregateRepository.SaveChanges(estateAggregate, cancellationToken);
        }
示例#14
0
        public void EstateAggregate_Create_EstateAlreadyCreated_ErrorThrown()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            aggregate.Create(TestData.EstateName);

            InvalidOperationException exception = Should.Throw <InvalidOperationException>(() =>
            {
                aggregate.Create(TestData.EstateName);
            });

            exception.Message.ShouldContain($"Estate with name {TestData.EstateName} has already been created");
        }
示例#15
0
        public void EstateAggregate_AddOperatorToEstate_OperatorWithNameAlreadyAdded_ErrorThrown()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            aggregate.Create(TestData.EstateName);
            aggregate.AddOperator(TestData.OperatorId, TestData.OperatorName, TestData.RequireCustomMerchantNumberFalse, TestData.RequireCustomTerminalNumberFalse);

            InvalidOperationException exception = Should.Throw <InvalidOperationException>(() =>
            {
                aggregate.AddOperator(TestData.OperatorId2, TestData.OperatorName, TestData.RequireCustomMerchantNumberFalse, TestData.RequireCustomTerminalNumberFalse);
            });

            exception.Message.ShouldContain($"Duplicate operator details are not allowed, an operator already exists on this estate with Name [{TestData.OperatorName}]");
        }
示例#16
0
        /// <summary>
        /// Gets the estate.
        /// </summary>
        /// <param name="estateId">The estate identifier.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        /// <exception cref="NotFoundException">No estate found with Id [{estateId}]</exception>
        public async Task <Estate> GetEstate(Guid estateId,
                                             CancellationToken cancellationToken)
        {
            // Get the estate from the aggregate repository
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            if (estateAggregate.IsCreated == false)
            {
                throw new NotFoundException($"No estate found with Id [{estateId}]");
            }

            Estate estateModel = await this.EstateManagementRepository.GetEstate(estateId, cancellationToken);

            return(estateModel);
        }
示例#17
0
        public void EstateAggregate_GetEstate_WithASecurityUser_EstateIsReturned()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            aggregate.Create(TestData.EstateName);
            aggregate.AddSecurityUser(TestData.SecurityUserId, TestData.EstateUserEmailAddress);

            Estate model = aggregate.GetEstate();

            model.EstateId.ShouldBe(TestData.EstateId);
            model.Name.ShouldBe(TestData.EstateName);
            model.SecurityUsers.ShouldHaveSingleItem();

            SecurityUser securityUser = model.SecurityUsers.Single();

            securityUser.SecurityUserId.ShouldBe(TestData.SecurityUserId);
            securityUser.EmailAddress.ShouldBe(TestData.EstateUserEmailAddress);
        }
示例#18
0
        public void EstateAggregate_GetEstate_WithAnOperator_EstateIsReturned()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            aggregate.Create(TestData.EstateName);
            aggregate.AddOperator(TestData.OperatorId, TestData.OperatorName, TestData.RequireCustomMerchantNumberFalse, TestData.RequireCustomTerminalNumberFalse);

            Estate model = aggregate.GetEstate();

            model.EstateId.ShouldBe(TestData.EstateId);
            model.Name.ShouldBe(TestData.EstateName);
            model.Operators.ShouldHaveSingleItem();

            Operator @operator = model.Operators.Single();

            @operator.OperatorId.ShouldBe(TestData.OperatorId);
            @operator.Name.ShouldBe(TestData.OperatorName);
            @operator.RequireCustomMerchantNumber.ShouldBe(TestData.RequireCustomMerchantNumberFalse);
            @operator.RequireCustomTerminalNumber.ShouldBe(TestData.RequireCustomTerminalNumberFalse);
        }
示例#19
0
        /// <summary>
        /// Creates the merchant.
        /// </summary>
        /// <param name="estateId">The estate identifier.</param>
        /// <param name="merchantId">The merchant identifier.</param>
        /// <param name="name">The name.</param>
        /// <param name="addressId">The address identifier.</param>
        /// <param name="addressLine1">The address line1.</param>
        /// <param name="addressLine2">The address line2.</param>
        /// <param name="addressLine3">The address line3.</param>
        /// <param name="addressLine4">The address line4.</param>
        /// <param name="town">The town.</param>
        /// <param name="region">The region.</param>
        /// <param name="postalCode">The postal code.</param>
        /// <param name="country">The country.</param>
        /// <param name="contactId">The contact identifier.</param>
        /// <param name="contactName">Name of the contact.</param>
        /// <param name="contactPhoneNumber">The contact phone number.</param>
        /// <param name="contactEmailAddress">The contact email address.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <exception cref="System.InvalidOperationException">Estate Id {estateId} has not been created</exception>
        public async Task CreateMerchant(Guid estateId,
                                         Guid merchantId,
                                         String name,
                                         Guid addressId,
                                         String addressLine1,
                                         String addressLine2,
                                         String addressLine3,
                                         String addressLine4,
                                         String town,
                                         String region,
                                         String postalCode,
                                         String country,
                                         Guid contactId,
                                         String contactName,
                                         String contactPhoneNumber,
                                         String contactEmailAddress,
                                         CancellationToken cancellationToken)
        {
            MerchantAggregate merchantAggregate = await this.MerchantAggregateRepository.GetLatestVersion(merchantId, cancellationToken);

            // Estate Id is a valid estate
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            if (estateAggregate.IsCreated == false)
            {
                throw new InvalidOperationException($"Estate Id {estateId} has not been created");
            }

            // Reject Duplicate Merchant Names... is this needed ?

            // Create the merchant
            merchantAggregate.Create(estateId, name, DateTime.Now);

            // Add the address
            merchantAggregate.AddAddress(addressId, addressLine1, addressLine2, addressLine3, addressLine4, town, region, postalCode, country);

            // Add the contact
            merchantAggregate.AddContact(contactId, contactName, contactPhoneNumber, contactEmailAddress);

            await this.MerchantAggregateRepository.SaveChanges(merchantAggregate, cancellationToken);
        }
示例#20
0
        /// <summary>
        /// Creates the estate user.
        /// </summary>
        /// <param name="estateId">The estate identifier.</param>
        /// <param name="emailAddress">The email address.</param>
        /// <param name="password">The password.</param>
        /// <param name="givenName">Name of the given.</param>
        /// <param name="middleName">Name of the middle.</param>
        /// <param name="familyName">Name of the family.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        public async Task <Guid> CreateEstateUser(Guid estateId,
                                                  String emailAddress,
                                                  String password,
                                                  String givenName,
                                                  String middleName,
                                                  String familyName,
                                                  CancellationToken cancellationToken)
        {
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            CreateUserRequest createUserRequest = new CreateUserRequest
            {
                EmailAddress = emailAddress,
                FamilyName   = familyName,
                GivenName    = givenName,
                MiddleName   = middleName,
                Password     = password,
                PhoneNumber  = "123456",                                      // Is this really needed :|
                Roles        = new List <String>(),
                Claims       = new Dictionary <String, String>()
            };

            // Check if role has been overridden
            String estateRoleName = Environment.GetEnvironmentVariable("EstateRoleName");

            createUserRequest.Roles.Add(String.IsNullOrEmpty(estateRoleName) ? "Estate" : estateRoleName);
            createUserRequest.Claims.Add("estateId", estateId.ToString());

            CreateUserResponse createUserResponse = await this.SecurityServiceClient.CreateUser(createUserRequest, cancellationToken);

            // Add the user to the aggregate
            estateAggregate.AddSecurityUser(createUserResponse.UserId, emailAddress);

            // TODO: add a delete user here in case the aggregate add fails...

            await this.EstateAggregateRepository.SaveChanges(estateAggregate, cancellationToken);

            return(createUserResponse.UserId);
        }
示例#21
0
        /// <summary>
        /// Makes the merchant deposit.
        /// </summary>
        /// <param name="estateId">The estate identifier.</param>
        /// <param name="merchantId">The merchant identifier.</param>
        /// <param name="source">The source.</param>
        /// <param name="reference">The reference.</param>
        /// <param name="depositDateTime">The deposit date time.</param>
        /// <param name="amount">The amount.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException">
        /// Merchant Id {merchantId} has not been created
        /// or
        /// Estate Id {estateId} has not been created
        /// </exception>
        public async Task <Guid> MakeMerchantDeposit(Guid estateId,
                                                     Guid merchantId,
                                                     Models.MerchantDepositSource source,
                                                     String reference,
                                                     DateTime depositDateTime,
                                                     Decimal amount,
                                                     CancellationToken cancellationToken)
        {
            MerchantAggregate merchantAggregate = await this.MerchantAggregateRepository.GetLatestVersion(merchantId, cancellationToken);

            // Check merchant has been created
            if (merchantAggregate.IsCreated == false)
            {
                throw new InvalidOperationException($"Merchant Id {merchantId} has not been created");
            }

            // Estate Id is a valid estate
            EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);

            if (estateAggregate.IsCreated == false)
            {
                throw new InvalidOperationException($"Estate Id {estateId} has not been created");
            }

            merchantAggregate.MakeDeposit(source, reference, depositDateTime, amount);

            await this.MerchantAggregateRepository.SaveChanges(merchantAggregate, cancellationToken);

            Merchant merchant = merchantAggregate.GetMerchant();

            // Find the deposit
            Deposit deposit = merchant.Deposits.Single(d => d.Reference == reference && d.DepositDateTime == depositDateTime && d.Source == source &&
                                                       d.Amount == amount);

            return(deposit.DepositId);
        }
示例#22
0
        public void EstateAggregate_CanBeCreated_IsCreated()
        {
            EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId);

            aggregate.AggregateId.ShouldBe(TestData.EstateId);
        }