public async Task <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 EnsurePartitionCount();

            InvoiceInfo invoice = null;

            try
            {
                var proxy = CreateServiceProxy();
                invoice = await proxy.GenerateInvoiceAsync(customerId, amount, releaseDate, callbackUri, cancellationToken);
            }
            catch (Exception)
            {
                throw;
            }
            return(invoice);
        }
        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);
        }
        internal static InvoiceData ToInvoiceData(this InvoicesServiceInterfaces.InvoiceInfo info)
        {
            if (info == null)
            {
                throw new NullReferenceException(nameof(info));
            }

            return(new InvoiceData()
            {
                Amount = info.Amount,
                Number = info.InvoiceNumber,
                ReleaseDate = info.ReleaseDate,
                State = info.State == InvoicesServiceInterfaces.InvoiceState.Paid ?
                        InvoiceState.Paid : InvoiceState.NotPaid,
            });
        }