public async Task <Interfaces.InvoiceInfo> GenerateInvoiceAsync(string customerId, decimal amount,
                                                                        DateTime releaseDate, string callbackUri, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(customerId))
            {
                throw new ArgumentException(nameof(customerId));
            }
            if (amount < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(amount));
            }

            await InitializeInvoiceNumbersDictionaryAsync();

            Interfaces.InvoiceInfo invoice = null;

            uint   invoiceNumber = 0;
            string yearKey       = releaseDate.Year.ToString();

            using (var tx = this.StateManager.CreateTransaction())
            {
                invoiceNumber = await this.invoiceNumbersDictionary.GetOrAddAsync(tx, yearKey, 0);

                InvoiceActorError creationResult = InvoiceActorError.Ok;
                string            invoiceNumberComplete;
                do
                {
                    invoiceNumber++;

                    invoiceNumberComplete = $"{yearKey}/{invoiceNumber}";

                    var invoiceActor = this.actorFactory.Create <IInvoiceActor>(new ActorId(invoiceNumberComplete),
                                                                                new Uri(UriConstants.InvoiceActorUri));

                    creationResult = await invoiceActor.CreateAsync(customerId, amount, releaseDate,
                                                                    callbackUri, cancellationToken);
                } while ((creationResult == InvoiceActorError.InvoiceAlreadyExists ||
                          creationResult == InvoiceActorError.InvoiceAlreadyPaid ||
                          creationResult == InvoiceActorError.InvoiceNotValid) && !cancellationToken.IsCancellationRequested);

                if (creationResult == InvoiceActorError.Ok)
                {
                    await this.invoiceNumbersDictionary.SetAsync(tx, yearKey, invoiceNumber);

                    invoice = new Interfaces.InvoiceInfo()
                    {
                        Amount        = amount,
                        Customer      = customerId,
                        InvoiceNumber = invoiceNumberComplete,
                        ReleaseDate   = releaseDate,
                        State         = Interfaces.InvoiceState.NotPaid
                    };
                    await tx.CommitAsync();
                }
            }
            return(invoice);
        }
        public async Task <IActionResult> Post()
        {
            var body = await this.Request.GetRawBodyStringAsync();

            var paymentData = await this.paymentAdapter.ParseAsync(body);

            if (paymentData == null)
            {
                return(BadRequest());
            }

            InvoiceActorError invoiceResponse = InvoiceActorError.GenericError;

            if (paymentData.PaymentResult == PaymentResult.Paid)
            {
                var invoiceProxy = this.actorFactory.Create <IInvoiceActor>(new ActorId(paymentData.InvoiceNumber),
                                                                            new Uri(UriConstants.InvoiceActorUri));
                try
                {
                    invoiceResponse = await invoiceProxy.PaidAsync(paymentData.PaymentDate, default(CancellationToken));
                }
                catch (Exception)
                {
                    return(BadRequest());
                }

                switch (invoiceResponse)
                {
                case InvoiceActorError.InvoiceAlreadyPaid:
                    return(Ok());

                case InvoiceActorError.InvoiceNotValid:
                    return(NotFound());

                case InvoiceActorError.PaymentDateNotCorrect:
                    return(BadRequest());

                case InvoiceActorError.GenericError:
                    return(BadRequest());

                case InvoiceActorError.Ok:
                    return(Ok());
                }
            }
            return(Ok());
        }