예제 #1
0
        public async Task <DisperseFundsResult> TransferCreated(Transfer transfer)
        {
            _logger.LogInformation(GetLogMessage("Transfer ID: {0}"), transfer.Id);
            var retVal = new DisperseFundsResult()
            {
                TransferId = transfer.Id,
                Amount     = 0,
            };

            if (transfer.Metadata.ContainsKey("invoice-id"))
            {
                string invoiceId = transfer.Metadata["invoice-id"];
                _logger.LogDebug(GetLogMessage("Invoice Id: {0}"), invoiceId);

                retVal.InvoiceId = invoiceId;

                var stripeTransfer = new StripeTransfer
                {
                    ObjectState     = ObjectState.Added,
                    Id              = transfer.Id,
                    Amount          = transfer.Amount / 100m,
                    Created         = transfer.Created,
                    DestinationId   = transfer.DestinationId,
                    AmountReversed  = transfer.AmountReversed / 100m,
                    Description     = transfer.Description,
                    InvoiceTransfer = new InvoiceTransfer()
                    {
                        ObjectState = ObjectState.Added,
                        InvoiceId   = invoiceId,
                        TransferId  = transfer.Id,
                    }
                };
                stripeTransfer.InjectFrom(transfer);

                var firstUpdate = _transfers.InsertOrUpdateGraph(stripeTransfer, true);
                _logger.LogDebug(GetLogMessage("{0} Transfer Records Created"), firstUpdate);

                if (firstUpdate > 0)
                {
                    stripeTransfer.ObjectState = ObjectState.Modified;
                    if (transfer.Metadata.ContainsKey("individual-payout-ids"))
                    {
                        if (Guid.TryParse(transfer.Metadata["person-id"], out var personId))
                        {
                            _logger.LogInformation(GetLogMessage("This is an individual payout transaction request"));

                            var payoutIds = transfer.Metadata["individual-payout-ids"].Split(",")
                                            .Select(Guid.Parse).ToArray();

                            _logger.LogDebug(GetLogMessage("Person Payout Ids: {0}"), payoutIds);

                            var payouts = await _individualPayoutIntents.Queryable()
                                          .Where(x => payoutIds.Contains(x.Id) && x.InvoiceTransferId == null)
                                          .ToListAsync();

                            _logger.LogDebug(GetLogMessage("{0} Individual Payouts to process"), payouts.Count);

                            foreach (var x in payouts)
                            {
                                _logger.LogInformation(GetLogMessage("Intent Id: {0}; Transfer Id: {1}"), x.Id, transfer.Id);

                                x.InvoiceTransferId = transfer.Id;
                                x.ObjectState       = ObjectState.Modified;

                                _individualPayoutIntents.InsertOrUpdateGraph(x);
                            }

                            var updatedPayouts = _individualPayoutIntents.Commit();
                            _logger.LogDebug(GetLogMessage("{0} Individual Payouts records updated"), updatedPayouts);

                            if (updatedPayouts > 0)
                            {
                                retVal.Succeeded = true;
                                retVal.Amount    = stripeTransfer.Amount;

                                await Task.Run(() =>
                                {
                                    RaiseEvent(new FundsDispersedToPersonEvent()
                                    {
                                        InvoiceId = invoiceId,
                                        PersonId  = personId,
                                        Amount    = stripeTransfer.Amount
                                    });
                                });
                            }
                        }
                    }

                    var organizationPayouts = 0;
                    if (transfer.Metadata.ContainsKey("organization-payout-ids"))
                    {
                        if (Guid.TryParse(transfer.Metadata["organization-id"], out var organizationId))
                        {
                            _logger.LogInformation(GetLogMessage("Processing Organization Payouts"));

                            var payoutIds = transfer.Metadata["organization-payout-ids"].Split(",").Select(Guid.Parse).ToArray();
                            var payouts   = await _organizationPayoutIntents.Queryable()
                                            .Where(x => payoutIds.Contains(x.Id) && x.OrganizationId == organizationId && x.InvoiceTransferId == null)
                                            .ToListAsync();

                            _logger.LogDebug(GetLogMessage("PayoutIds:{0}"), payoutIds);

                            foreach (var x in payouts)
                            {
                                _logger.LogInformation(GetLogMessage("Intent Id: {0}; Transfer Id: {1}"), x.Id, x.InvoiceTransferId);

                                x.InvoiceTransferId = transfer.Id;
                                x.ObjectState       = ObjectState.Modified;

                                _organizationPayoutIntents.InsertOrUpdateGraph(x);
                            }


                            var records = _organizationPayoutIntents.Commit();

                            _logger.LogDebug(GetLogMessage("{0} Organization Payout records updated"), records);

                            if (records > 0)
                            {
                                organizationPayouts++;
                            }

                            _logger.LogDebug(GetLogMessage("{0} Organization payouts updated"), organizationPayouts);

                            if (organizationPayouts > 0)
                            {
                                retVal.Succeeded = true;
                                retVal.Amount    = stripeTransfer.Amount;

                                await Task.Run(() =>
                                {
                                    RaiseEvent(new FundsDispersedToOrganizationEvent()
                                    {
                                        InvoiceId      = invoiceId,
                                        OrganizationId = organizationId,
                                        Amount         = stripeTransfer.Amount
                                    });
                                });
                            }
                        }
                        ;
                    }
                }
                else
                {
                    _logger.LogDebug(GetLogMessage("First update failed"));
                }
            }
            else
            {
                _logger.LogDebug(GetLogMessage("Not an invoice transfer"));
            }


            return(retVal);
        }
        private async Task <DisperseFundsResult> DisperseFundsToOrganization(IProviderAgencyOwner ao, string invoiceId)
        {
            _logger.LogInformation(GetLogMessage("Dispersing Funds for invoice: {0}"), invoiceId);
            var retVal = new DisperseFundsResult {
                InvoiceId = invoiceId
            };

            var organizationPayouts = await _organizationPayoutIntents
                                      .Queryable()
                                      .Include(x => x.InvoiceTransfer)
                                      .Include(x => x.InvoiceItem)
                                      .ThenInclude(x => x.Contract)
                                      .Include(x => x.InvoiceItem)
                                      .ThenInclude(x => x.TimeEntries)
                                      .Include(x => x.Organization)
                                      .ThenInclude(x => x.OrganizationFinancialAccount)
                                      .ThenInclude(x => x.FinancialAccount)
                                      .Where(x => x.InvoiceItem.InvoiceId == invoiceId &&
                                             x.Organization.OrganizationFinancialAccount.FinancialAccount != null &&
                                             x.Organization.OrganizationFinancialAccount.FinancialAccount.PayoutsEnabled &&
                                             x.InvoiceTransfer == null)
                                      .ToListAsync();

            _logger.LogDebug(GetLogMessage("Payouts ready for payment: {0}"), organizationPayouts.Count);


            var totalTransfersMade     = 0;
            var totalAmountTransferred = 0m;


            if (organizationPayouts.Count > 0)
            {
                var transfersToMake = new List <TransferCreateOptions>();

                var organizations = organizationPayouts.Select(x => x.Organization).Distinct().ToList();

                _logger.LogDebug(GetLogMessage("Unique Organizations: {0}"), organizations.Count);

                foreach (var organization in organizations)
                {
                    _logger.LogDebug(GetLogMessage("Processing Payouts for Organization: {0}"), organization.Id);

                    var orgPayouts = organizationPayouts
                                     .Where(x => x.OrganizationId == organization.Id)
                                     .ToList();

                    _logger.LogDebug(GetLogMessage("Number of Payouts: {0}"), orgPayouts.Count);

                    if (orgPayouts.Count > 0)
                    {
                        var orgPayoutIds = orgPayouts
                                           .Select(x => x.Id)
                                           .ToArray();

                        var payoutIdString = string.Join(",", orgPayoutIds);

                        var sb = new StringBuilder();
                        foreach (var payout in orgPayouts)
                        {
                            sb.AppendLine($@"{payout.Type.GetDescription()}: {payout.Amount:C}");
                        }

                        transfersToMake.Add(new TransferCreateOptions()
                        {
                            Amount        = Convert.ToInt64(orgPayouts.Sum(x => x.Amount) * 100),
                            Currency      = "usd",
                            Description   = sb.ToString(),
                            Destination   = organization.OrganizationFinancialAccount.FinancialAccountId,
                            TransferGroup = invoiceId,
                            Metadata      = new Dictionary <string, string>()
                            {
                                { "invoice-id", invoiceId },
                                { "organization-payout-ids", payoutIdString },
                                { "organization-id", organization.Id.ToString() }
                            }
                        });
                    }
                    else
                    {
                        _logger.LogDebug(GetLogMessage("Skipping payouts"));
                    }
                }

                _logger.LogDebug(GetLogMessage("{0} Transfers to make"), transfersToMake.Count);

                foreach (var tran in transfersToMake)
                {
                    _logger.LogDebug(GetLogMessage("Transfer Amount: {0}"), tran.Amount);

                    var transfer = _transferService.Create(tran);

                    var transferResult = await TransferCreated(transfer);

                    _logger.LogDebug(GetLogMessage("Transfer Result: {@0}"), transferResult);
                    if (transferResult.Succeeded)
                    {
                        _logger.LogDebug(GetLogMessage("Transfer Creation Succeeded: {@result}"), transferResult);
                        totalAmountTransferred += transferResult.Amount;
                        totalTransfersMade     += 1;
                    }

                    else
                    {
                        _logger.LogDebug(GetLogMessage("Transfer Creation Failed"));
                    }
                }

                if (totalTransfersMade > 0)
                {
                    retVal.Succeeded          = true;
                    retVal.Amount             = totalAmountTransferred;
                    retVal.TotalTransfersMade = totalTransfersMade;

                    await Task.Run(() =>
                    {
                        RaiseEvent(new FundsDispersedEvent()
                        {
                            InvoiceId          = invoiceId,
                            TotalTransfersMade = totalTransfersMade
                        });
                    });
                }
            }


            return(await Task.FromResult(retVal));
        }