// Bank Run Process Notes: /* * 1. User clicks the generate list on the bank run. This uses the query to get the records from SQL DB. * 2. With these records we attempt to create Bank Run Schedule records in SQL DB. * 3. Those records are synced back to Dynamics via the data sync process. * 4. Those records are used for the Report generation (taken from SQL DB). * 5. After the report is generated the user confirms the list changing the bank run status to List Confirmed. * - This generates the child transactions (links them to the bank run) and updates all the payment schedules. */ public static void GetPaymentSchedulesForBankRun(BankRun bankRunEntity, PaymentContext dataContext, ILogger logger) { logger.LogInformation("----------Entering GetPaymentSchedulesForBankRun()----------"); try { var paymentSchedules = dataContext.PaymentSchedule.Where(ps => (ps.Deleted == null || ps.Deleted == false) && ps.StatusCode == StatusCode.Active && // Active ps.PaymentMethodId != null && // Has a payment method ps.PaymentTypeCode == PaymentTypeCode.BankAccount && (ps.NextPaymentDate.Value.Date <= bankRunEntity.EndDate.Value.Date && ps.NextPaymentDate.Value.Date >= bankRunEntity.StartDate.Value.Date) // If it is within the start-end range ).ToList(); //Local debugging: var paymentSchedules = DataContext.PaymentSchedule.Where(ps => ps.PaymentScheduleId == new Guid("3e5fec3c-f96d-ea11-a811-000d3a0c8a65")); logger.LogInformation("Payment Schedules to associate = " + paymentSchedules.Count()); logger.LogInformation("Bank Run Start Date = " + bankRunEntity.StartDate.Value.Date); logger.LogInformation("Bank Run End Date = " + bankRunEntity.EndDate.Value.Date); // Now that we have the payment schedules, attach them to this bank run: foreach (PaymentSchedule ps in paymentSchedules) { logger.LogInformation("Adding Payment Schedule: " + ps.Name + " (" + ps.PaymentScheduleId + ")"); // Create the bank run schedule in SQL DB: try { bool duplicate = false; if (dataContext.BankRunSchedule.Count() > 0) { // We make sure to not add a duplicate for the same bank run: if (dataContext.BankRunSchedule.Where(brs => brs.PaymentScheduleId == ps.PaymentScheduleId && brs.BankRunId == bankRunEntity.BankRunId && (brs.Deleted == null || brs.Deleted == false)).Count() > 0) { // Duplicate, ignore. duplicate = true; } } if (!duplicate) { BankRunSchedule newBRS = new BankRunSchedule(); newBRS.BankRunId = bankRunEntity.BankRunId; newBRS.PaymentScheduleId = ps.PaymentScheduleId; newBRS.CreatedOn = DateTime.UtcNow; newBRS.StateCode = 0; // Active state newBRS.StatusCode = StatusCode.Active; // Active status reason code (default status reason) dataContext.BankRunSchedule.Add(newBRS); } } catch (Exception e) { // It may already exist, so ignore and move on. logger.LogError("Issue with adding new bank run schedule record for payment schedule " + ps.Name + " (" + ps.PaymentScheduleId + "): " + e.Message); } } try { if (bankRunEntity.BankRunStatus == 844060000 || bankRunEntity.BankRunStatus == 844060004) { logger.LogInformation("Setting Bank Run Status to 'Gift List Retrieved'."); bankRunEntity.BankRunStatus = 844060003; // Gift List Retrieved bankRunEntity.SyncDate = null; // Sync this change back to Dynamics. } logger.LogInformation("Saving new Bank Run Schedules to DB."); dataContext.SaveChanges(); logger.LogInformation("Save Complete."); } catch (Exception e) { // It may already exist, so ignore and move on. logger.LogError("Issue saving Bank Run Schedules: " + e.Message); if (e.InnerException != null) { logger.LogError("Inner exception: " + e.InnerException.ToString()); } } } catch (Exception ex) { Console.WriteLine("An error has occured in GetPaymentSchedulesForBankRun(): " + ex.Message); if (ex.InnerException != null) { Console.WriteLine("Inner exception: " + ex.InnerException.ToString()); } throw; } Console.WriteLine("----------Exiting GetPaymentSchedulesForBankRun()----------"); }
public AbaFileReport(BankRun bankRun, PaymentProcessor paymentProcessor, PaymentMethod paymentMethod, PaymentContext dataContext, ILogger logger) : base(bankRun, paymentProcessor, paymentMethod, dataContext, logger) { Debits = new List <PaymentSchedule>(); Credits = new List <PaymentSchedule>(); fileExtension = "aba"; }
private static Transaction GenerateChildTransactionForPaymentSchedule(PaymentSchedule parentPaymentSchedule, BankRun paymentSchedulesAssociatedRun) { Transaction newChildTransaction = new Transaction(); // Get all the same fields and copy them to the new child record: newChildTransaction = parentPaymentSchedule.CopyCommonFieldsTo(newChildTransaction); // Some fields are named different or have different states for the child vs parent, so we fix those here: newChildTransaction.TransactionId = Guid.NewGuid(); newChildTransaction.StatusCode = StatusCode.Completed; // Completed newChildTransaction.TransactionPaymentScheduleId = parentPaymentSchedule.PaymentScheduleId; newChildTransaction.BookDate = DateTime.UtcNow; newChildTransaction.CreatedOn = DateTime.UtcNow; newChildTransaction.Amount = parentPaymentSchedule.RecurringAmount; // Total Header newChildTransaction.AmountMembership = parentPaymentSchedule.AmountMembership; newChildTransaction.AmountNonReceiptable = parentPaymentSchedule.AmountNonReceiptable; newChildTransaction.AmountReceipted = parentPaymentSchedule.AmountReceipted; newChildTransaction.TransactionPaymentMethodId = parentPaymentSchedule.PaymentMethodId; newChildTransaction.DepositDate = paymentSchedulesAssociatedRun.DateToBeProcessed; newChildTransaction.TransactionResult = "Bank Run ID: " + paymentSchedulesAssociatedRun.BankRunId.ToString(); newChildTransaction.DesignationId = parentPaymentSchedule.DesignationId; newChildTransaction.AppealId = parentPaymentSchedule.AppealId; newChildTransaction.TransactionCurrencyId = parentPaymentSchedule.TransactionCurrencyId; newChildTransaction.MembershipInstanceId = parentPaymentSchedule.MembershipId; newChildTransaction.MembershipId = parentPaymentSchedule.MembershipCategoryId; newChildTransaction.SyncDate = null; newChildTransaction.ReceivedDate = paymentSchedulesAssociatedRun.DateToBeProcessed; return(newChildTransaction); }
public static void GenerateBankRunRecurringDonations(BankRun bankRunEntity, PaymentContext dataContext, ILogger logger) { logger.LogInformation("----------Entering GenerateBankRunRecurringDonations()----------"); // Get all of the payment schedules from the bank runs: List <BankRunSchedule> bankRunSchedules = dataContext.BankRunSchedule.Where(brs => brs.BankRunId == bankRunEntity.BankRunId && brs.StatusCode == StatusCode.Active && (brs.Deleted == null || brs.Deleted == false)).ToList(); // Active and not deleted. if (bankRunSchedules.Count() < 1) { logger.LogInformation("No Bank Run Schedules found for this bank run (" + bankRunEntity.BankRunId + "). Exiting webjob."); return; } logger.LogInformation("Bank Run Schedules meeting the criteria for this bank run (" + bankRunEntity.BankRunId + "): " + bankRunSchedules.Count()); int numberOfFailedPaymentSchedules = 0; int currentPaymentScheduleNumber = 0; // Used for visual counting, not for code operations. List <Guid> paymentSchedulesProcessed = new List <Guid>(); foreach (BankRunSchedule brs in bankRunSchedules) { try { bool generateTransaction = false; PaymentSchedule paymentSchedule = dataContext.PaymentSchedule.Where(ps => ps.PaymentScheduleId == brs.PaymentScheduleId).FirstOrDefault(); BankRun paymentSchedulesAssociatedRun = dataContext.BankRun.Where(br => br.BankRunId == brs.BankRunId).FirstOrDefault(); currentPaymentScheduleNumber++; // Make sure we don't process anything twice (just in case): if (!paymentSchedulesProcessed.Contains(paymentSchedule.PaymentScheduleId)) { generateTransaction = true; } else { logger.LogInformation("Skipping potential duplicate: " + paymentSchedule.PaymentScheduleId); } if (generateTransaction) { logger.LogInformation("--PS-" + currentPaymentScheduleNumber.ToString() + "--"); logger.LogInformation("Processing Payment Schedule = " + paymentSchedule.Name + " (" + paymentSchedule.PaymentScheduleId.ToString() + ")"); logger.LogInformation("Previous Next Donation Date = " + paymentSchedule.NextPaymentDate.ToString()); // Set the last donation date: paymentSchedule.LastPaymentDate = paymentSchedulesAssociatedRun.DateToBeProcessed; // If so, we process it (create the child transaction, update next donation date) and move on to the next one: paymentSchedule.NextPaymentDate = paymentSchedule.GetNextDonationDate(); logger.LogInformation("New Next Donation Date = " + paymentSchedule.NextPaymentDate.ToString()); paymentSchedule.SyncDate = null; Transaction newChildTransaction = GenerateChildTransactionForPaymentSchedule(paymentSchedule, paymentSchedulesAssociatedRun); // Add to DB changes: logger.LogInformation("Created new transaction (" + newChildTransaction.TransactionId.ToString() + ") adding to transaction list."); dataContext.Transaction.Add(newChildTransaction); // Update the bank run schedule to status to "Completed": brs.StatusCode = StatusCode.Completed; brs.SyncDate = null; // Update the bank run: paymentSchedulesAssociatedRun.BankRunStatus = 844060001; // Processed paymentSchedulesAssociatedRun.SyncDate = null; paymentSchedulesProcessed.Add(paymentSchedule.PaymentScheduleId); logger.LogInformation("----"); } } catch (Exception e) { numberOfFailedPaymentSchedules++; logger.LogError("Error with processing payment schedule (" + brs.PaymentScheduleId + "): " + e.Message); if (e.InnerException != null) { logger.LogError("Inner exception: " + e.InnerException.ToString()); } } } logger.LogInformation("Processed all payment schedules (" + currentPaymentScheduleNumber + " total, " + numberOfFailedPaymentSchedules.ToString() + " failed payment schedules)."); logger.LogInformation("Saving all payment schedules and new transactions to the DB."); dataContext.SaveChanges(); logger.LogInformation("Save Complete."); logger.LogInformation("----------Exiting GenerateBankRunRecurringDonations()----------"); }
public async Task BankRunAppSelector(string selectedProcess, Guid?bankRunGUID, Guid?entityId, string entityName) { logger.LogInformation("----------Entering BankRunAppSelector()----------"); try { #region Bank Run Generate List // ----------Bank Run Generate List---------- if (selectedProcess.Equals("List")) { BankRun bankRunEntity = BankRunFileReport.GetBankRunEntityFromId(bankRunGUID, this.context); if (bankRunEntity == null) { logger.LogInformation("Exiting web job."); return; } // Assign the payment schedules to the bank run: BankRunGenerateList.GetPaymentSchedulesForBankRun(bankRunEntity, context, this.logger); // Now do the same for one off transactions (TODO in future sprint). try { // Update the Bankrun Status to "Report Available" (844060004): BankRun bankRunToUpdate = new BankRun(); bankRunToUpdate.BankRunId = bankRunEntity.BankRunId; bankRunToUpdate.BankRunStatus = 844060004; logger.LogInformation("Updating BankRun Status."); await this.xrmService.UpdateAsync(bankRunToUpdate); logger.LogInformation("Updated BankRun Status to \"Report Available\" successfully."); } catch (Exception ex) { logger.LogError("Could not Update Bank Run Status. Exception:" + ex.Message); } } #endregion #region Bank Run Generate File // ----------Bank Run Generate File---------- else if (selectedProcess.Equals("File")) { BankRun bankRunEntity = BankRunFileReport.GetBankRunEntityFromId(bankRunGUID, this.context); //Configuration configEntity = Common.GetConfigurationEntityFromId(configGuid, this.DataContext); PaymentProcessor paymentProcessorEntity = BankRunFileReport.GetPaymentProcessorEntityFromBankRun(bankRunEntity, this.context, this.logger); PaymentMethod paymentMethodEntity = BankRunFileReport.GetPaymentMethodEntityFromBankRun(bankRunEntity, this.context, this.logger); int?bankRunFileFormat = paymentProcessorEntity.BankRunFileFormat; logger.LogInformation("Requested Bank Run File Format:" + bankRunFileFormat); BankRunFileReport bankRunFileReport; switch (bankRunFileFormat) { case (int)BankRunFileFormat.ABA: bankRunFileReport = new AbaFileReport(bankRunEntity, paymentProcessorEntity, paymentMethodEntity, this.context, this.logger); break; case (int)BankRunFileFormat.BMO: bankRunFileReport = new BMOFileReport(bankRunEntity, paymentProcessorEntity, paymentMethodEntity, this.context, this.logger); break; case (int)BankRunFileFormat.ScotiaBank: bankRunFileReport = new ScotiaBankFileReport(bankRunEntity, paymentProcessorEntity, paymentMethodEntity, this.context, this.logger); break; case null: throw new Exception("No Bank Run File Format set on the Payment Processor with ID:" + paymentProcessorEntity.PaymentProcessorId); default: throw new Exception("Can't find Bank Run File Format for provided value:" + bankRunFileFormat); } await bankRunFileReport.GenerateFileReport(); await bankRunFileReport.SaveReport(); } #endregion #region Bank Run Generate Recurring Donation Records else if (selectedProcess.Equals("GenerateTransactions")) { BankRun bankRunEntity = BankRunFileReport.GetBankRunEntityFromId(bankRunGUID, this.context); BankRunRecurringDonations.GenerateBankRunRecurringDonations(bankRunEntity, this.context, this.logger); } #endregion #region Event Receipting else if (selectedProcess.Equals("EventReceipting") && entityId.HasValue) { List <EventPackage> eventPackages = new List <EventPackage>(); switch (entityName) { case EventReceipting.EventTicket: EventTicket eventTicket = EventReceipting.GetEventTicketFromId(entityId.Value, this.context); EventReceipting.UpdateTicketsFromEventTicket(eventTicket, this.context); eventPackages = EventReceipting.GetEventPackagesFromEventTicket(eventTicket, this.context); break; case EventReceipting.EventProduct: EventProduct eventProduct = EventReceipting.GetEventProductFromId(entityId.Value, this.context); EventReceipting.UpdateProductsFromEventProduct(eventProduct, this.context); eventPackages = EventReceipting.GetEventPackagesFromEventProduct(eventProduct, this.context); break; case EventReceipting.EventSponsorship: EventSponsorship eventSponsorship = EventReceipting.GetEventSponsorshipFromId(entityId.Value, this.context); EventReceipting.UpdateSponsorshipsFromEventSponsorship(eventSponsorship, this.context); eventPackages = EventReceipting.GetEventPackagesFromEventSponsorship(eventSponsorship, this.context); break; default: throw new Exception("Unknown Entity for Event Receipting: " + entityName + ". Exiting."); } EventReceipting.UpdateEventPackages(eventPackages, this.context); } #endregion } catch (Exception e) { logger.LogError("Error in BankRunAppSelector(): " + e.Message); if (e.InnerException != null) { logger.LogError("Inner exception: " + e.InnerException.ToString()); } } logger.LogInformation("----------Exiting BankRunAppSelector()----------"); logger.LogInformation("----------Exiting Web Job----------"); }
public ScotiaBankFileReport(BankRun bankRun, PaymentProcessor paymentProcessor, PaymentMethod paymentMethod, PaymentContext dataContext, ILogger logger) : base(bankRun, paymentProcessor, paymentMethod, dataContext, logger) { Debits = new List <PaymentSchedule>(); Credits = new List <PaymentSchedule>(); }