/// <summary> /// Refreshes the list. Public method...can be called from other blocks. /// </summary> public void RefreshList() { var contextEntity = this.ContextEntity(); if ( contextEntity != null ) { if ( contextEntity is FinancialBatch ) { var batchId = PageParameter( "financialBatchId" ); var batch = new FinancialBatchService( new RockContext() ).Get( int.Parse( batchId ) ); _batch = batch; BindGrid(); } } }
/// <summary> /// Shows the detail. /// </summary> /// <param name="itemKey">The item key.</param> /// <param name="itemKeyValue">The item key value.</param> public void ShowDetail( string itemKey, int itemKeyValue ) { if ( !itemKey.Equals( "financialBatchId" ) ) { return; } FinancialBatch financialBatch = null; if ( !itemKeyValue.Equals( 0 ) ) { financialBatch = new FinancialBatchService( new RockContext() ).Get( itemKeyValue ); } else { financialBatch = new FinancialBatch { Id = 0 }; } bool readOnly = false; if ( !IsUserAuthorized( Authorization.EDIT ) ) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( FinancialBatch.FriendlyTypeName ); } if ( !readOnly ) { lbEdit.Visible = true; if ( financialBatch.Id > 0 ) { ShowSummary( financialBatch ); } else { ShowEdit( financialBatch ); } } else { lbEdit.Visible = false; ShowSummary( financialBatch ); } lbSave.Visible = !readOnly; }
/// <summary> /// Handles the Click event of the btnSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param> private void btnSave_Click( object sender, RoutedEventArgs e ) { try { RockConfig rockConfig = RockConfig.Load(); RockRestClient client = new RockRestClient( rockConfig.RockBaseUrl ); client.Login( rockConfig.Username, rockConfig.Password ); FinancialBatch financialBatch = null; if ( SelectedFinancialBatch == null || SelectedFinancialBatch.Id == 0) { financialBatch = new FinancialBatch { Id = 0, Guid = Guid.NewGuid(), Status = BatchStatus.Pending, CreatedByPersonAliasId = LoggedInPerson.PrimaryAlias.Id }; } else { financialBatch = client.GetData<FinancialBatch>( string.Format( "api/FinancialBatches/{0}", SelectedFinancialBatch.Id ) ); } txtBatchName.Text = txtBatchName.Text.Trim(); financialBatch.Name = txtBatchName.Text; Campus selectedCampus = cbCampus.SelectedItem as Campus; if ( selectedCampus.Id > 0 ) { financialBatch.CampusId = selectedCampus.Id; } else { financialBatch.CampusId = null; } financialBatch.BatchStartDateTime = dpBatchDate.SelectedDate; if ( !string.IsNullOrWhiteSpace( txtControlAmount.Text ) ) { financialBatch.ControlAmount = decimal.Parse( txtControlAmount.Text.Replace( "$", string.Empty ) ); } else { financialBatch.ControlAmount = 0.00M; } if ( financialBatch.Id == 0 ) { client.PostData<FinancialBatch>( "api/FinancialBatches/", financialBatch ); } else { client.PutData<FinancialBatch>( "api/FinancialBatches/", financialBatch ); } if ( SelectedFinancialBatch == null || SelectedFinancialBatch.Id == 0 ) { // refetch the batch to get the Id if it was just Inserted financialBatch = client.GetDataByGuid<FinancialBatch>( "api/FinancialBatches", financialBatch.Guid ); SelectedFinancialBatch = financialBatch; } LoadFinancialBatchesGrid(); ShowBatch( false ); } catch ( Exception ex ) { MessageBox.Show( ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation ); } }
/// <summary> /// Maps the batch data. /// </summary> /// <param name="csvData">The table data.</param> /// <exception cref="System.NotImplementedException"></exception> private int MapBatch(CSVInstance csvData) { var newBatches = new List <FinancialBatch>(); var earliestBatchDate = ImportDateTime; var completed = 0; ReportProgress(0, $"Verifying batch import ({ImportedBatches.Count:N0} already exist)."); string[] row; // Uses a look-ahead enumerator: this call will move to the next record immediately while ((row = csvData.Database.FirstOrDefault()) != null) { var batchIdKey = row[BatchID]; var batchId = batchIdKey.AsType <int?>(); if (batchId != null && !ImportedBatches.ContainsKey((int)batchId)) { var batch = new FinancialBatch { CreatedByPersonAliasId = ImportPersonAliasId, ForeignKey = batchId.ToString(), ForeignId = batchId, Note = string.Empty, Status = BatchStatus.Closed, AccountingSystemCode = string.Empty }; var name = row[BatchName] as string; if (!string.IsNullOrWhiteSpace(name)) { name = name.Trim(); batch.Name = name.Left(50); batch.CampusId = CampusList.Where(c => name.StartsWith(c.Name) || name.StartsWith(c.ShortCode)) .Select(c => (int?)c.Id).FirstOrDefault(); } var batchDate = ParseDateOrDefault(row[BatchDate], null); if (batchDate.HasValue) { batch.BatchStartDateTime = batchDate; batch.BatchEndDateTime = batchDate; if (earliestBatchDate > batchDate) { earliestBatchDate = (DateTime)batchDate; } } var amountKey = row[BatchAmount]; var amount = amountKey.AsType <decimal?>(); if (amount != null) { batch.ControlAmount = amount.HasValue ? amount.Value : new decimal(); } newBatches.Add(batch); completed++; if (completed % (ReportingNumber * 10) < 1) { ReportProgress(0, $"{completed:N0} batches imported."); } else if (completed % ReportingNumber < 1) { SaveFinancialBatches(newBatches); foreach (var b in newBatches) { if (!ImportedBatches.ContainsKey((int)b.ForeignId)) { ImportedBatches.Add((int)b.ForeignId, b.Id); } else { LogException("Duplicate Batch", string.Format("Batch #{0} is a duplicate and will be skipped. Please check the source data.", b.ForeignId)); } } newBatches.Clear(); ReportPartialProgress(); } } } // add a default batch to use with contributions if (!ImportedBatches.ContainsKey(0)) { var defaultBatch = new FinancialBatch { CreatedDateTime = ImportDateTime, CreatedByPersonAliasId = ImportPersonAliasId, Status = BatchStatus.Closed, BatchStartDateTime = earliestBatchDate, Name = $"Default Batch {ImportDateTime}", ControlAmount = 0.0m, ForeignKey = "0", ForeignId = 0 }; newBatches.Add(defaultBatch); } if (newBatches.Any()) { SaveFinancialBatches(newBatches); newBatches.ForEach(b => ImportedBatches.Add((int)b.ForeignId, (int?)b.Id)); } ReportProgress(100, $"Finished batch import: {completed:N0} batches imported."); return(completed); }
/// <summary> /// Creates the giving records for the given parameters. /// </summary> /// <param name="personGuid">The person unique identifier.</param> /// <param name="startingDate">The starting date.</param> /// <param name="endDate">The end date.</param> /// <param name="frequency">The frequency (onetime, weekly, monthly).</param> /// <param name="percentGive">The percent give.</param> /// <param name="growRatePercent">The grow rate percent.</param> /// <param name="growFrequencyWeeks">The grow frequency weeks.</param> /// <param name="specialGiftPercent">The special gift percent.</param> /// <param name="accountAmountDict">The account amount dictionary.</param> /// <param name="circularImageList">A circular linked list of imageUrls to use for the fake contribution checks.</param> /// <param name="rockContexe">A rock context.</param> private void CreateGiving( Guid personGuid, DateTime startingDate, DateTime endDate, Frequency frequency, int percentGive, int growRatePercent, int growFrequencyWeeks, int specialGiftPercent, Dictionary<int, decimal> accountAmountDict, LinkedList<string> circularImageList, RockContext rockContext ) { int weekNumber = 0; DateTime monthly = startingDate; var currencyTypeCheck = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK.AsGuid() ); var imageUrlNode = circularImageList.First ?? null; // foreach weekend or monthly between the starting and ending date... for ( DateTime date = startingDate; date <= endDate; date = frequency == Frequency.weekly ? date.AddDays( 7 ) : frequency == Frequency.monthly ? date.AddMonths( 1 ) : endDate.AddDays(1) ) { weekNumber = (int)(date - startingDate).TotalDays / 7; // increase by growRatePercent every growFrequencyWeeks if ( growFrequencyWeeks != 0 && growRatePercent != 0 && weekNumber !=0 && weekNumber % growFrequencyWeeks == 0 ) { var copy = accountAmountDict.ToDictionary( entry => entry.Key, entry => entry.Value ); foreach ( var item in accountAmountDict ) { decimal amount = Math.Round( ( item.Value * 0.01M ) + item.Value, 0 ); copy[item.Key] = amount; } accountAmountDict = copy; } // randomized skip/missed weeks int summerFactor = ( 7 <= date.Month && date.Month <= 9 ) ? summerPercentFactor : 0; if ( _random.Next( 0, 100 ) > percentGive - summerFactor ) { continue; // skip this week } FinancialBatch batch; if ( _contributionBatches.ContainsKey( date ) ) { batch = _contributionBatches[date]; } else { batch = new FinancialBatch { Id = 0, Guid = Guid.NewGuid(), BatchStartDateTime = date, BatchEndDateTime = date, Status = BatchStatus.Closed, ControlAmount = 0, Name = string.Format( "SampleData{0}", date.ToJavascriptMilliseconds() ), CreatedByPersonAliasId = CurrentPerson.PrimaryAliasId }; _contributionBatches.Add( date, batch ); } // Set up the new transaction FinancialTransaction financialTransaction = new FinancialTransaction { TransactionTypeValueId = _transactionTypeContributionId, Guid = Guid.NewGuid(), TransactionDateTime = date, AuthorizedPersonAliasId = _peopleAliasDictionary[personGuid] }; financialTransaction.FinancialPaymentDetail = new FinancialPaymentDetail(); financialTransaction.FinancialPaymentDetail.CurrencyTypeValueId = currencyTypeCheck.Id; financialTransaction.FinancialPaymentDetail.Guid = Guid.NewGuid(); // Add a transaction detail record for each account they're donating to foreach ( var item in accountAmountDict ) { FinancialTransactionDetail transactionDetail = new FinancialTransactionDetail { AccountId = item.Key, Amount = item.Value, Guid = Guid.NewGuid() }; financialTransaction.TransactionDetails.Add( transactionDetail ); } // Add the image to the transaction (if any) if ( imageUrlNode != null ) { FinancialTransactionImage transactionImage = new FinancialTransactionImage { BinaryFile = SaveImage( imageUrlNode.Value, _checkImageBinaryFileType, _checkImageBinaryFileTypeSettings, rockContext ), Guid = Guid.NewGuid(), }; financialTransaction.Images.Add( transactionImage ); imageUrlNode = imageUrlNode.Next ?? imageUrlNode.List.First; } // Update the batch with the new control amount batch.ControlAmount += financialTransaction.TotalAmount; batch.Transactions.Add( financialTransaction ); } }
/// <summary> /// Shows the detail. /// </summary> /// <param name="batchId">The financial batch identifier.</param> public void ShowDetail( int batchId ) { FinancialBatch batch = null; bool editAllowed = true; if ( !batchId.Equals( 0 ) ) { batch = GetBatch( batchId ); if ( batch != null ) { editAllowed = batch.IsAuthorized( Authorization.EDIT, CurrentPerson ); pdAuditDetails.SetEntity( batch, ResolveRockUrl( "~" ) ); } } if ( batch == null ) { batch = new FinancialBatch { Id = 0, Status = BatchStatus.Open }; // hide the panel drawer that show created and last modified dates pdAuditDetails.Visible = false; } hfBatchId.Value = batch.Id.ToString(); bool readOnly = false; nbEditModeMessage.Text = string.Empty; if ( !editAllowed || !IsUserAuthorized( Authorization.EDIT ) ) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( FinancialBatch.FriendlyTypeName ); } if ( readOnly ) { lbEdit.Visible = false; ShowReadonlyDetails( batch ); } else { lbEdit.Visible = true; if ( batch.Id > 0 ) { ShowReadonlyDetails( batch ); } else { ShowEditDetails( batch ); } } lbSave.Visible = !readOnly; }
/// <summary> /// Shows the edit details. /// </summary> /// <param name="batch">The financial batch.</param> protected void ShowEditDetails( FinancialBatch batch ) { if ( batch != null ) { hfBatchId.Value = batch.Id.ToString(); string title = batch.Id > 0 ? ActionTitle.Edit( FinancialBatch.FriendlyTypeName ) : ActionTitle.Add( FinancialBatch.FriendlyTypeName ); SetHeadingInfo( batch, title ); SetEditMode( true ); tbName.Text = batch.Name; ddlStatus.BindToEnum<BatchStatus>(); ddlStatus.SelectedIndex = (int)(BatchStatus)batch.Status; campCampus.Campuses = CampusCache.All(); if ( batch.CampusId.HasValue ) { campCampus.SetValue( batch.CampusId.Value ); } tbControlAmount.Text = batch.ControlAmount.ToString( "N2" ); dtpStart.SelectedDateTime = batch.BatchStartDateTime; dtpEnd.SelectedDateTime = batch.BatchEndDateTime; tbAccountingCode.Text = batch.AccountingSystemCode; tbNote.Text = batch.Note; } }
/// <summary> /// Shows the financial batch summary. /// </summary> /// <param name="batch">The financial batch.</param> private void ShowReadonlyDetails(FinancialBatch batch) { SetEditMode(false); if (batch != null) { hfBatchId.SetValue(batch.Id); SetHeadingInfo(batch, batch.Name); string campus = string.Empty; if (batch.Campus != null) { campus = batch.Campus.ToString(); } decimal txnTotal = batch.Transactions.Sum(t => (decimal?)(t.TransactionDetails.Sum(d => (decimal?)d.Amount) ?? 0.0M)) ?? 0.0M; decimal variance = txnTotal - batch.ControlAmount; string amountFormat = string.Format("{0} / {1} / " + (variance == 0.0M ? "{2}" : "<span class='label label-danger'>{2}</span>"), txnTotal.ToString("C2"), batch.ControlAmount.ToString("C2"), variance.ToString("C2")); lDetails.Text = new DescriptionList() .Add("Date Range", new DateRange(batch.BatchStartDateTime, batch.BatchEndDateTime).ToString("g")) .Add("Transaction / Control / Variance", amountFormat) .Add("Accounting Code", batch.AccountingSystemCode) .Html; //Account Summary gAccounts.DataSource = batch.Transactions .SelectMany(t => t.TransactionDetails) .GroupBy(d => new { AccountId = d.AccountId, AccountName = d.Account.Name }) .Select(s => new { Id = s.Key.AccountId, Name = s.Key.AccountName, Amount = s.Sum(a => (decimal?)a.Amount) ?? 0.0M }) .OrderBy(s => s.Name) .ToList(); gAccounts.DataBind(); //Currency Summary gCurrencyTypes.DataSource = batch.Transactions .Select(t => new { CurrencyId = t.CurrencyTypeValue != null ? t.CurrencyTypeValue.Id : 0, CurrencyName = t.CurrencyTypeValue != null ? t.CurrencyTypeValue.Value : "None", TotalAmount = t.TotalAmount }) .GroupBy(c => new { c.CurrencyId, c.CurrencyName }) .Select(s => new { Id = s.Key.CurrencyId, Name = s.Key.CurrencyName, Amount = s.Sum(a => (decimal?)a.TotalAmount) ?? 0.0M }) .OrderBy(s => s.Name) .ToList(); gCurrencyTypes.DataBind(); } }
/// <summary> /// Handles the Click event of the lbSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbSave_Click(object sender, EventArgs e) { var rockContext = new RockContext(); var batchService = new FinancialBatchService(rockContext); FinancialBatch batch = null; var changes = new List <string>(); int batchId = hfBatchId.Value.AsInteger(); if (batchId == 0) { batch = new FinancialBatch(); batchService.Add(batch); changes.Add("Created the batch"); } else { batch = batchService.Get(batchId); } if (batch != null) { if (ddlBatchName.Visible) { History.EvaluateChange(changes, "Batch Name", batch.Name, ddlBatchName.SelectedItem.Text); batch.Name = ddlBatchName.SelectedItem.Text; } else { History.EvaluateChange(changes, "Batch Name", batch.Name, tbName.Text); batch.Name = tbName.Text; } BatchStatus batchStatus = (BatchStatus)ddlStatus.SelectedIndex; string errorMessage; if (!batch.IsValidBatchStatusChange(batch.Status, batchStatus, this.CurrentPerson, out errorMessage)) { cvBatch.IsValid = false; cvBatch.ErrorMessage = errorMessage; return; } History.EvaluateChange(changes, "Status", batch.Status, batchStatus); batch.Status = batchStatus; CampusCache oldCampus = null; if (batch.CampusId.HasValue) { oldCampus = CampusCache.Read(batch.CampusId.Value); } CampusCache newCampus = null; if (campCampus.SelectedCampusId.HasValue) { newCampus = CampusCache.Read(campCampus.SelectedCampusId.Value); } History.EvaluateChange(changes, "Campus", oldCampus != null ? oldCampus.Name : "None", newCampus != null ? newCampus.Name : "None"); batch.CampusId = campCampus.SelectedCampusId; DateTime?startDateTime = dtpStart.SelectedDateTimeIsBlank ? null : dtpStart.SelectedDateTime; History.EvaluateChange(changes, "Start Date/Time", batch.BatchStartDateTime, startDateTime); batch.BatchStartDateTime = startDateTime; DateTime?endDateTime; if (dtpEnd.SelectedDateTimeIsBlank && batch.BatchStartDateTime.HasValue) { endDateTime = batch.BatchStartDateTime.Value.AddDays(1); } else { endDateTime = dtpEnd.SelectedDateTimeIsBlank ? null : dtpEnd.SelectedDateTime; } History.EvaluateChange(changes, "End Date/Time", batch.BatchEndDateTime, endDateTime); batch.BatchEndDateTime = endDateTime; decimal controlAmount = tbControlAmount.Text.AsDecimal(); History.EvaluateChange(changes, "Control Amount", batch.ControlAmount.FormatAsCurrency(), controlAmount.FormatAsCurrency()); batch.ControlAmount = controlAmount; History.EvaluateChange(changes, "Accounting System Code", batch.AccountingSystemCode, tbAccountingCode.Text); batch.AccountingSystemCode = tbAccountingCode.Text; History.EvaluateChange(changes, "Notes", batch.Note, tbNote.Text); batch.Note = tbNote.Text; cvBatch.IsValid = batch.IsValid; if (!Page.IsValid || !batch.IsValid) { cvBatch.ErrorMessage = batch.ValidationResults.Select(a => a.ErrorMessage).ToList().AsDelimited("<br />"); return; } batch.LoadAttributes(rockContext); Rock.Attribute.Helper.GetEditValues(phAttributes, batch); rockContext.WrapTransaction(() => { if (rockContext.SaveChanges() > 0) { if (changes.Any()) { pdAuditDetails.SetEntity(batch, ResolveRockUrl("~")); HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, changes); } } }); batch.SaveAttributeValues(rockContext); if (batchId == 0) { // If created a new batch, navigate to same page so that transaction list displays correctly var pageReference = CurrentPageReference; pageReference.Parameters.AddOrReplace("batchId", batch.Id.ToString()); NavigateToPage(pageReference); } else { hfBatchId.SetValue(batch.Id); // Requery the batch to support EF navigation properties var savedBatch = GetBatch(batch.Id); ShowReadonlyDetails(savedBatch); // If there is a batch context item, update the context's properties with new values var contextObjects = new Dictionary <string, object>(); foreach (var contextEntityType in RockPage.GetContextEntityTypes()) { var contextEntity = RockPage.GetCurrentContext(contextEntityType); if (contextEntity is FinancialBatch) { var contextBatch = contextEntity as FinancialBatch; contextBatch.CopyPropertiesFrom(batch); } } // Then refresh transaction list RockPage.UpdateBlocks("~/Blocks/Finance/TransactionList.ascx"); } } }
/// <summary> /// Maps the batch data. /// </summary> /// <param name="tableData">The table data.</param> /// <exception cref="System.NotImplementedException"></exception> private void MapBatch( IQueryable<Row> tableData ) { var batchAttribute = AttributeCache.Read( BatchAttributeId ); var batchStatusClosed = Rock.Model.BatchStatus.Closed; var newBatches = new List<FinancialBatch>(); int completed = 0; int totalRows = tableData.Count(); int percentage = ( totalRows - 1 ) / 100 + 1; ReportProgress( 0, string.Format( "Checking batch import ({0:N0} found, {1:N0} already exist).", totalRows, ImportedBatches.Count() ) ); foreach ( var row in tableData ) { int? batchId = row["BatchID"] as int?; if ( batchId != null && !ImportedBatches.ContainsKey( batchId ) ) { var batch = new FinancialBatch(); batch.CreatedByPersonAliasId = ImportPersonAlias.Id; batch.Status = batchStatusClosed; string name = row["BatchName"] as string; if ( name != null ) { name = name.Trim(); batch.Name = name.Left( 50 ); batch.CampusId = CampusList.Where( c => name.StartsWith( c.Name ) || name.StartsWith( c.ShortCode ) ) .Select( c => (int?)c.Id ).FirstOrDefault(); } DateTime? batchDate = row["BatchDate"] as DateTime?; if ( batchDate != null ) { batch.BatchStartDateTime = batchDate; batch.BatchEndDateTime = batchDate; } decimal? amount = row["BatchAmount"] as decimal?; if ( amount != null ) { batch.ControlAmount = amount.HasValue ? amount.Value : new decimal(); } batch.Attributes = new Dictionary<string, AttributeCache>(); batch.AttributeValues = new Dictionary<string, List<AttributeValue>>(); batch.Attributes.Add( batchAttribute.Key, batchAttribute ); batch.AttributeValues.Add( batchAttribute.Key, new List<AttributeValue>() ); batch.AttributeValues[batchAttribute.Key].Add( new AttributeValue() { AttributeId = batchAttribute.Id, Value = batchId.ToString(), Order = 0 } ); newBatches.Add( batch ); completed++; if ( completed % percentage < 1 ) { int percentComplete = completed / percentage; ReportProgress( percentComplete, string.Format( "{0:N0} batches imported ({1}% complete).", completed, percentComplete ) ); } else if ( completed % ReportingNumber < 1 ) { RockTransactionScope.WrapTransaction( () => { var batchService = new FinancialBatchService(); batchService.RockContext.FinancialBatches.AddRange( newBatches ); batchService.RockContext.SaveChanges(); var attributeValueService = new AttributeValueService(); foreach ( var newBatch in newBatches.Where( b => b.Attributes.Any() ) ) { var attributeValue = newBatch.AttributeValues[batchAttribute.Key].FirstOrDefault(); if ( attributeValue != null ) { attributeValue.EntityId = newBatch.Id; attributeValueService.RockContext.AttributeValues.Add( attributeValue ); } } attributeValueService.RockContext.SaveChanges(); } ); newBatches.Clear(); ReportPartialProgress(); } } } if ( newBatches.Any() ) { RockTransactionScope.WrapTransaction( () => { var batchService = new FinancialBatchService(); batchService.RockContext.FinancialBatches.AddRange( newBatches ); batchService.RockContext.SaveChanges(); var attributeValueService = new AttributeValueService(); foreach ( var newBatch in newBatches.Where( b => b.Attributes.Any() ) ) { var attributeValue = newBatch.AttributeValues[batchAttribute.Key].FirstOrDefault(); if ( attributeValue != null ) { attributeValue.EntityId = newBatch.Id; attributeValueService.RockContext.AttributeValues.Add( attributeValue ); } } attributeValueService.RockContext.SaveChanges(); } ); } ReportProgress( 100, string.Format( "Finished batch import: {0:N0} batches imported.", completed ) ); }
/// <summary> /// Updates the batch UI. /// </summary> /// <param name="selectedBatch">The selected batch.</param> private void UpdateBatchUI( FinancialBatch selectedBatch ) { if ( selectedBatch == null ) { HideBatch(); return; } else { ShowBatch( false ); } RockConfig rockConfig = RockConfig.Load(); RockRestClient client = new RockRestClient( rockConfig.RockBaseUrl ); client.Login( rockConfig.Username, rockConfig.Password ); SelectedFinancialBatch = selectedBatch; lblBatchNameReadOnly.Content = selectedBatch.Name; lblBatchCampusReadOnly.Content = selectedBatch.CampusId.HasValue ? client.GetData<Campus>( string.Format( "api/Campus/{0}", selectedBatch.CampusId ) ).Name : None.Text; lblBatchDateReadOnly.Content = selectedBatch.BatchStartDateTime.Value.ToString( "d" ); lblBatchCreatedByReadOnly.Content = client.GetData<Person>( string.Format( "api/People/GetByPersonAliasId/{0}", selectedBatch.CreatedByPersonAliasId ) ).FullName; lblBatchControlAmountReadOnly.Content = selectedBatch.ControlAmount.ToString( "F" ); txtBatchName.Text = selectedBatch.Name; if ( selectedBatch.CampusId.HasValue ) { cbCampus.SelectedValue = selectedBatch.CampusId; } else { cbCampus.SelectedValue = 0; } dpBatchDate.SelectedDate = selectedBatch.BatchStartDateTime; lblCreatedBy.Content = lblBatchCreatedByReadOnly.Content as string; txtControlAmount.Text = selectedBatch.ControlAmount.ToString( "F" ); List<FinancialTransaction> transactions = client.GetData<List<FinancialTransaction>>( "api/FinancialTransactions/", string.Format( "BatchId eq {0}", selectedBatch.Id ) ); foreach ( var transaction in transactions ) { transaction.CurrencyTypeValue = this.CurrencyValueList.FirstOrDefault( a => a.Id == transaction.CurrencyTypeValueId ); } // include CheckNumber for checks that we scanned in this session var scannedCheckList = ScannedDocList.Where( a => a.IsCheck ).ToList(); var gridList = transactions.OrderByDescending( a => a.CreatedDateTime ).Select( a => new { FinancialTransaction = a, CheckNumber = a.CurrencyTypeValue.Guid == Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK.AsGuid() ? scannedCheckList.FirstOrDefault( s => s.TransactionId == a.Id ) != null ? scannedCheckList.FirstOrDefault( s => s.TransactionId == a.Id ).CheckNumber : "****" : "-" } ); grdBatchItems.DataContext = gridList; }
public static FinancialTransaction Translate(IDictionary <string, object> record, List <FinancialAccount> accounts, List <FinancialBatch> batches) { if (record == null || !record.Keys.Any()) { return(null); } var accountName = CsvFieldTranslators.GetString("Fund(s)", record); var account = accounts.FirstOrDefault(a => a.Name == accountName); if (account == null) { account = new FinancialAccount { // CampusId Id = accounts.Count + 1, Name = accountName }; accounts.Add(account); } // Map the properties of Person Note class to known CSV headers // Maybe this could be configurable to the user in the UI if the need arises var transactionPropertyToCsvFieldNameMap = new Dictionary <string, string> { { "Id", "Payment ID" }, { "BatchId", "Batch" }, { "AuthorizedPersonId", "Person ID" }, { "TransactionDate", "Date" }, //{ "TransactionType", "" } { "TransactionSource", "Method ID" }, { "CurrencyType", "Method ID" }, { "Summary", "Note" }, { "TransactionCode", "Payment ID" }, { "CreatedDateTime", "Date" } // ModifiedByPersonId // ModifiedDateTime }; var detailPropertyToCsvFieldNameMap = new Dictionary <string, string> { { "Id", "Payment ID" }, { "TransactionId", "Payment ID" }, // AccountId { "Amount", "Amount" }, { "Summary", "Note" }, // CreatedByPersonId { "CreatedDateTime", "Date" } // ModifiedByPersonId // ModifiedDateTime }; // Create a person note object. Using the map, read values from the CSV record and // set the associated properties of the person with those values var transaction = new FinancialTransaction(); var transactionType = transaction.GetType(); foreach (var kvp in transactionPropertyToCsvFieldNameMap) { var propertyName = kvp.Key; var csvFieldName = kvp.Value; var property = transactionType.GetProperty(propertyName); var value = CsvFieldTranslators.GetValue(property.PropertyType, csvFieldName, record); property.SetValue(transaction, value); } var detail = new FinancialTransactionDetail { AccountId = account.Id }; var detailType = detail.GetType(); transaction.FinancialTransactionDetails.Add(detail); foreach (var kvp in detailPropertyToCsvFieldNameMap) { var propertyName = kvp.Key; var csvFieldName = kvp.Value; var property = detailType.GetProperty(propertyName); var value = CsvFieldTranslators.GetValue(property.PropertyType, csvFieldName, record); property.SetValue(detail, value); } var existingBatch = batches.FirstOrDefault(b => b.Id == transaction.BatchId); if (existingBatch == null) { existingBatch = new FinancialBatch { Id = transaction.BatchId, Name = "Breeze Transactions", Status = BatchStatus.Closed }; batches.Add(existingBatch); } existingBatch.FinancialTransactions.Add(transaction); // Batch doesn't have a start date or this transaction is before the start date if (!existingBatch.StartDate.HasValue || (transaction.TransactionDate.HasValue && transaction.TransactionDate.Value < existingBatch.StartDate.Value)) { existingBatch.StartDate = transaction.TransactionDate; } // TODO store unused values, like checknumber, as attributes when slingshot supports it return(transaction); }
public static List <GLTransaction> GetTransactionSummary(FinancialBatch financialBatch, RockContext rockContext, out List <RegistrationInstance> registrationLinks, out List <GroupMember> groupMemberLinks) { // // Group/Sum Transactions by Debit/Bank Account and Project since Project can come from Account or Transaction Details // var batchTransactions = new List <GLTransaction>(); registrationLinks = new List <RegistrationInstance>(); groupMemberLinks = new List <GroupMember>(); foreach (var transaction in financialBatch.Transactions) { transaction.LoadAttributes(); var gateway = transaction.FinancialGateway; var gatewayDefaultFeeAccount = string.Empty; var processTransactionFees = 0; if (gateway != null) { gateway.LoadAttributes(); gatewayDefaultFeeAccount = transaction.FinancialGateway.GetAttributeValue("rocks.kfs.Intacct.DEFAULTFEEACCOUNTNO"); var gatewayFeeProcessing = transaction.FinancialGateway.GetAttributeValue("rocks.kfs.Intacct.FEEPROCESSING").AsIntegerOrNull(); if (gatewayFeeProcessing != null) { processTransactionFees = gatewayFeeProcessing.Value; } } foreach (var transactionDetail in transaction.TransactionDetails) { transactionDetail.LoadAttributes(); transactionDetail.Account.LoadAttributes(); var detailProject = transactionDetail.GetAttributeValue("rocks.kfs.Intacct.PROJECTID").AsGuidOrNull(); var accountProject = transactionDetail.Account.GetAttributeValue("rocks.kfs.Intacct.PROJECTID").AsGuidOrNull(); var transactionFeeAccount = transactionDetail.Account.GetAttributeValue("rocks.kfs.Intacct.FEEACCOUNTNO"); if (string.IsNullOrWhiteSpace(transactionFeeAccount)) { transactionFeeAccount = gatewayDefaultFeeAccount; } var projectCode = string.Empty; if (detailProject != null) { projectCode = DefinedValueCache.Get(( Guid )detailProject).Value; } else if (accountProject != null) { projectCode = DefinedValueCache.Get(( Guid )accountProject).Value; } if (transactionDetail.EntityTypeId.HasValue) { var registrationEntityType = EntityTypeCache.Get(typeof(Rock.Model.Registration)); var groupMemberEntityType = EntityTypeCache.Get(typeof(Rock.Model.GroupMember)); if (transactionDetail.EntityId.HasValue && transactionDetail.EntityTypeId == registrationEntityType.Id) { foreach (var registration in new RegistrationService(rockContext) .Queryable().AsNoTracking() .Where(r => r.RegistrationInstance != null && r.RegistrationInstance.RegistrationTemplate != null && r.Id == transactionDetail.EntityId)) { registrationLinks.Add(registration.RegistrationInstance); } } if (transactionDetail.EntityId.HasValue && transactionDetail.EntityTypeId == groupMemberEntityType.Id) { foreach (var groupMember in new GroupMemberService(rockContext) .Queryable().AsNoTracking() .Where(gm => gm.Group != null && gm.Id == transactionDetail.EntityId)) { groupMemberLinks.Add(groupMember); } } } var transactionItem = new GLTransaction() { Payer = transaction.AuthorizedPersonAlias.Person.FullName, Amount = transactionDetail.Amount, FinancialAccountId = transactionDetail.AccountId, Project = projectCode, TransactionFeeAmount = transactionDetail.FeeAmount != null && transactionDetail.FeeAmount.Value > 0 ? transactionDetail.FeeAmount.Value : 0.0M, TransactionFeeAccount = transactionFeeAccount, ProcessTransactionFees = processTransactionFees }; batchTransactions.Add(transactionItem); } } var batchTransactionList = batchTransactions .GroupBy(d => new { d.FinancialAccountId, d.Project, d.TransactionFeeAccount, d.ProcessTransactionFees }) .Select(s => new GLTransaction { Payer = "Rock Import", FinancialAccountId = s.Key.FinancialAccountId, Project = s.Key.Project, Amount = s.Sum(f => ( decimal? )f.Amount) ?? 0.0M, TransactionFeeAmount = s.Sum(f => ( decimal? )f.TransactionFeeAmount) ?? 0.0M, TransactionFeeAccount = s.Key.TransactionFeeAccount, ProcessTransactionFees = s.Key.ProcessTransactionFees }) .ToList(); return(batchTransactionList); }
/// <summary> /// Raises the <see cref="E:System.Web.UI.Control.Load" /> event. /// </summary> /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnLoad(EventArgs e) { base.OnLoad(e); bool promptWithFilter = true; var contextEntity = this.ContextEntity(); if (contextEntity != null) { if (contextEntity is Person) { _person = contextEntity as Person; promptWithFilter = false; } else if (contextEntity is FinancialBatch) { _batch = contextEntity as FinancialBatch; gfTransactions.Visible = false; promptWithFilter = false; } else if (contextEntity is FinancialScheduledTransaction) { _scheduledTxn = contextEntity as FinancialScheduledTransaction; gfTransactions.Visible = false; promptWithFilter = false; } } if (!Page.IsPostBack) { BindFilter(); if (promptWithFilter && gfTransactions.Visible) { //// NOTE: Special Case for this List Block since there could be a very large number of transactions: //// If the filter is shown and we aren't filtering by anything else, don't automatically populate the grid. Wait for them to hit apply on the filter gfTransactions.Show(); } else { BindGrid(); } } if (_canEdit && _batch != null) { string script = string.Format(@" $('#{0}').change(function( e ){{ var count = $(""#{1} input[id$='_cbSelect_0']:checked"").length; if (count == 0) {{ eval({2}); }} else {{ var $ddl = $(this); if ($ddl.val() != '') {{ Rock.dialogs.confirm('Are you sure you want to move the selected transactions to a new batch (the control amounts on each batch will be updated to reflect the moved transaction\'s amounts)?', function (result) {{ if (result) {{ eval({2}); }} $ddl.val(''); }}); }} }} }}); ", _ddlMove.ClientID, gTransactions.ClientID, Page.ClientScript.GetPostBackEventReference(this, "MoveTransactions")); ScriptManager.RegisterStartupScript(_ddlMove, _ddlMove.GetType(), "moveTransaction", script, true); } }
private OtherReceipt BuildOtherReceipt(FinancialBatch financialBatch, ref string debugLava, PaymentMethod paymentMethod, string bankAccountId = null, string unDepGLAccountId = null, string DescriptionLava = "") { if (string.IsNullOrWhiteSpace(DescriptionLava)) { DescriptionLava = "{{ Batch.Id }}: {{ Batch.Name }}"; } var rockContext = new RockContext(); var batchDate = financialBatch.BatchStartDateTime == null ? RockDateTime.Now : ((System.DateTime)financialBatch.BatchStartDateTime); var otherReceipt = new OtherReceipt { Payer = "Rock Batch Import", PaymentDate = batchDate, ReceivedDate = batchDate, PaymentMethod = paymentMethod, BankAccountId = bankAccountId, UnDepGLAccountNo = unDepGLAccountId, DepositDate = batchDate, Description = string.Format("Imported From Rock batch {0}: {1}", financialBatch.Id, financialBatch.Name), RefId = financialBatch.Id.ToString(), ReceiptItems = new List <ReceiptLineItem>() }; List <RegistrationInstance> registrationLinks; List <GroupMember> groupMemberLinks; var receiptTransactions = TransactionHelpers.GetTransactionSummary(financialBatch, rockContext, out registrationLinks, out groupMemberLinks); // // Get the Dimensions from the Account since the Transaction Details have been Grouped already // var customDimensions = TransactionHelpers.GetCustomDimensions(); // Create Receipt Item for each entry within a grouping foreach (var bTran in receiptTransactions) { var account = new FinancialAccountService(rockContext).Get(bTran.FinancialAccountId); var customDimensionValues = new Dictionary <string, dynamic>(); account.LoadAttributes(); var mergeFieldObjects = new MergeFieldObjects { Account = account, Batch = financialBatch, Registrations = registrationLinks, GroupMembers = groupMemberLinks, Summary = bTran, CustomDimensions = customDimensions }; Dictionary <string, object> mergeFields = TransactionHelpers.GetMergeFieldsAndDimensions(ref debugLava, customDimensionValues, mergeFieldObjects); var classId = account.GetAttributeValue("rocks.kfs.Intacct.CLASSID"); var departmentId = account.GetAttributeValue("rocks.kfs.Intacct.DEPARTMENT"); var locationId = account.GetAttributeValue("rocks.kfs.Intacct.LOCATION"); var receiptItem = new ReceiptLineItem { GlAccountNo = account.GetAttributeValue("rocks.kfs.Intacct.ACCOUNTNO"), Amount = bTran.ProcessTransactionFees == 1 ? bTran.Amount - bTran.TransactionFeeAmount : bTran.Amount, Memo = DescriptionLava.ResolveMergeFields(mergeFields), LocationId = locationId, DepartmentId = departmentId, ProjectId = bTran.Project, ClassId = classId, CustomFields = customDimensionValues }; otherReceipt.ReceiptItems.Add(receiptItem); if (bTran.ProcessTransactionFees == 2) { var feeLineItem = new ReceiptLineItem { GlAccountNo = bTran.TransactionFeeAccount, Amount = bTran.TransactionFeeAmount * -1, Memo = "Transaction Fees", LocationId = locationId, DepartmentId = departmentId, ProjectId = bTran.Project, ClassId = classId }; otherReceipt.ReceiptItems.Add(feeLineItem); } } return(otherReceipt); }
/// <summary> /// Handles the Click event of the lbSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbSave_Click(object sender, EventArgs e) { var rockContext = new RockContext(); var batchService = new FinancialBatchService(rockContext); FinancialBatch batch = null; var changes = new List <string>(); int batchId = hfBatchId.Value.AsInteger(); if (batchId == 0) { batch = new FinancialBatch(); batchService.Add(batch); changes.Add("Created the batch"); } else { batch = batchService.Get(batchId); } if (batch != null) { History.EvaluateChange(changes, "Batch Name", batch.Name, tbName.Text); batch.Name = tbName.Text; BatchStatus batchStatus = (BatchStatus)ddlStatus.SelectedIndex; History.EvaluateChange(changes, "Status", batch.Status, batchStatus); batch.Status = batchStatus; CampusCache oldCampus = null; if (batch.CampusId.HasValue) { oldCampus = CampusCache.Read(batch.CampusId.Value); } CampusCache newCampus = null; if (campCampus.SelectedCampusId.HasValue) { newCampus = CampusCache.Read(campCampus.SelectedCampusId.Value); } History.EvaluateChange(changes, "Campus", oldCampus != null ? oldCampus.Name : "None", newCampus != null ? newCampus.Name : "None"); batch.CampusId = campCampus.SelectedCampusId; DateTime?startDateTime = dtpStart.SelectedDateTimeIsBlank ? null : dtpStart.SelectedDateTime; History.EvaluateChange(changes, "Start Date/Time", batch.BatchStartDateTime, startDateTime); batch.BatchStartDateTime = startDateTime; DateTime?endDateTime; if (dtpEnd.SelectedDateTimeIsBlank && batch.BatchStartDateTime.HasValue) { endDateTime = batch.BatchStartDateTime.Value.AddDays(1); } else { endDateTime = dtpEnd.SelectedDateTimeIsBlank ? null : dtpEnd.SelectedDateTime; } History.EvaluateChange(changes, "End Date/Time", batch.BatchEndDateTime, endDateTime); batch.BatchEndDateTime = endDateTime; decimal controlAmount = tbControlAmount.Text.AsDecimal(); History.EvaluateChange(changes, "Control Amount", batch.ControlAmount.FormatAsCurrency(), controlAmount.FormatAsCurrency()); batch.ControlAmount = controlAmount; History.EvaluateChange(changes, "Accounting System Code", batch.AccountingSystemCode, tbAccountingCode.Text); batch.AccountingSystemCode = tbAccountingCode.Text; History.EvaluateChange(changes, "Notes", batch.Note, tbNote.Text); batch.Note = tbNote.Text; cvBatch.IsValid = batch.IsValid; if (!Page.IsValid || !batch.IsValid) { cvBatch.ErrorMessage = batch.ValidationResults.Select(a => a.ErrorMessage).ToList().AsDelimited("<br />"); return; } rockContext.WrapTransaction(() => { if (rockContext.SaveChanges() > 0) { if (changes.Any()) { HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, changes); } } }); if (batchId == 0) { // If created a new batch, navigate to same page so that transaction list displays correctly var pageReference = CurrentPageReference; pageReference.Parameters.AddOrReplace("batchId", batch.Id.ToString()); NavigateToPage(pageReference); } else { hfBatchId.SetValue(batch.Id); // Requery the batch to support EF navigation properties var savedBatch = GetBatch(batch.Id); ShowReadonlyDetails(savedBatch); } } }
/// <summary> /// Maps the batch data. /// </summary> /// <param name="csvData">The table data.</param> /// <exception cref="System.NotImplementedException"></exception> private int MapBatch( CSVInstance csvData ) { var batchStatusClosed = Rock.Model.BatchStatus.Closed; var newBatches = new List<FinancialBatch>(); int completed = 0; ReportProgress( 0, string.Format( "Verifying batch import ({0:N0} already exist).", ImportedBatches.Count ) ); string[] row; // Uses a look-ahead enumerator: this call will move to the next record immediately while ( (row = csvData.Database.FirstOrDefault()) != null ) { string batchIdKey = row[BatchID]; int? batchId = batchIdKey.AsType<int?>(); if ( batchId != null && !ImportedBatches.ContainsKey( ( int )batchId ) ) { var batch = new FinancialBatch(); batch.CreatedByPersonAliasId = ImportPersonAliasId; batch.ForeignKey = batchId.ToString(); batch.ForeignId = batchId; batch.Note = string.Empty; batch.Status = batchStatusClosed; batch.AccountingSystemCode = string.Empty; string name = row[BatchName] as string; if ( !String.IsNullOrWhiteSpace( name ) ) { name = name.Trim(); batch.Name = name.Left( 50 ); batch.CampusId = CampusList.Where( c => name.StartsWith( c.Name ) || name.StartsWith( c.ShortCode ) ) .Select( c => ( int? )c.Id ).FirstOrDefault(); } string batchDateKey = row[BatchDate]; DateTime? batchDate = batchDateKey.AsType<DateTime?>(); if ( batchDate != null ) { batch.BatchStartDateTime = batchDate; batch.BatchEndDateTime = batchDate; } string amountKey = row[BatchAmount]; decimal? amount = amountKey.AsType<decimal?>(); if ( amount != null ) { batch.ControlAmount = amount.HasValue ? amount.Value : new decimal(); } newBatches.Add( batch ); completed++; if ( completed % (ReportingNumber * 10) < 1 ) { ReportProgress( 0, string.Format( "{0:N0} batches imported.", completed ) ); } else if ( completed % ReportingNumber < 1 ) { SaveFinancialBatches( newBatches ); newBatches.ForEach( b => ImportedBatches.Add( ( int )b.ForeignId, ( int? )b.Id ) ); newBatches.Clear(); ReportPartialProgress(); } } } // add a default batch to use with contributions if ( !ImportedBatches.ContainsKey( 0 ) ) { var defaultBatch = new FinancialBatch(); defaultBatch.CreatedDateTime = ImportDateTime; defaultBatch.CreatedByPersonAliasId = ImportPersonAliasId; defaultBatch.Status = Rock.Model.BatchStatus.Closed; defaultBatch.Name = string.Format( "Default Batch (Imported {0})", ImportDateTime ); defaultBatch.ControlAmount = 0.0m; defaultBatch.ForeignKey = "0"; defaultBatch.ForeignId = 0; newBatches.Add( defaultBatch ); } if ( newBatches.Any() ) { SaveFinancialBatches( newBatches ); newBatches.ForEach( b => ImportedBatches.Add( ( int )b.ForeignId, ( int? )b.Id ) ); } ReportProgress( 100, string.Format( "Finished batch import: {0:N0} batches imported.", completed ) ); return completed; }
private List <JournalEntryLine> GetGlEntries(RockContext rockContext, FinancialBatch financialBatch, string journalCode, int period, ref string debugLava, string DescriptionLava = "") { if (string.IsNullOrWhiteSpace(DescriptionLava)) { DescriptionLava = "{{ Batch.Id }}: {{ Batch.Name }}"; } // // Group/Sum Transactions by Account and Project since Project can come from Account or Transaction Details // var batchTransactions = new List <GLTransaction>(); var registrationLinks = new List <RegistrationInstance>(); var groupMemberLinks = new List <GroupMember>(); foreach (var transaction in financialBatch.Transactions) { transaction.LoadAttributes(); foreach (var transactionDetail in transaction.TransactionDetails) { transactionDetail.LoadAttributes(); transactionDetail.Account.LoadAttributes(); var detailProject = transactionDetail.GetAttributeValue("rocks.kfs.ShelbyFinancials.Project").AsGuidOrNull(); var transactionProject = transaction.GetAttributeValue("rocks.kfs.ShelbyFinancials.Project").AsGuidOrNull(); var accountProject = transactionDetail.Account.GetAttributeValue("rocks.kfs.ShelbyFinancials.Project").AsGuidOrNull(); var projectCode = string.Empty; if (detailProject != null) { projectCode = DefinedValueCache.Get(( Guid )detailProject).Value; } else if (transactionProject != null) { projectCode = DefinedValueCache.Get(( Guid )transactionProject).Value; } else if (accountProject != null) { projectCode = DefinedValueCache.Get(( Guid )accountProject).Value; } if (transactionDetail.EntityTypeId.HasValue) { var registrationEntityType = EntityTypeCache.Get(typeof(Rock.Model.Registration)); var groupMemberEntityType = EntityTypeCache.Get(typeof(Rock.Model.GroupMember)); if (transactionDetail.EntityId.HasValue && transactionDetail.EntityTypeId == registrationEntityType.Id) { foreach (var registration in new RegistrationService(rockContext) .Queryable().AsNoTracking() .Where(r => r.RegistrationInstance != null && r.RegistrationInstance.RegistrationTemplate != null && r.Id == transactionDetail.EntityId)) { registrationLinks.Add(registration.RegistrationInstance); } } if (transactionDetail.EntityId.HasValue && transactionDetail.EntityTypeId == groupMemberEntityType.Id) { foreach (var groupMember in new GroupMemberService(rockContext) .Queryable().AsNoTracking() .Where(gm => gm.Group != null && gm.Id == transactionDetail.EntityId)) { groupMemberLinks.Add(groupMember); } } } var transactionItem = new GLTransaction() { Amount = transactionDetail.Amount, FinancialAccountId = transactionDetail.AccountId, Project = projectCode }; batchTransactions.Add(transactionItem); } } var batchTransactionsSummary = batchTransactions .GroupBy(d => new { d.FinancialAccountId, d.Project }) .Select(s => new GLTransaction { FinancialAccountId = s.Key.FinancialAccountId, Project = s.Key.Project, Amount = s.Sum(f => ( decimal? )f.Amount) ?? 0.0M }) .ToList(); var batchSummary = new List <GLBatchTotals>(); foreach (var summary in batchTransactionsSummary) { var account = new FinancialAccountService(rockContext).Get(summary.FinancialAccountId); account.LoadAttributes(); var mergeFields = new Dictionary <string, object>(); mergeFields.Add("Account", account); mergeFields.Add("Summary", summary); mergeFields.Add("Batch", financialBatch); mergeFields.Add("Registrations", registrationLinks); mergeFields.Add("GroupMembers", groupMemberLinks); mergeFields.Add("JournalCode", journalCode); mergeFields.Add("Period", period); var batchSummaryItem = new GLBatchTotals() { CompanyNumber = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.Company"), RegionNumber = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.Region"), SuperFundNumber = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.SuperFund"), FundNumber = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.Fund"), LocationNumber = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.Location"), CostCenterNumber = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.CostCenter"), DepartmentNumber = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.Department"), CreditAccountNumber = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.CreditAccount"), DebitAccountNumber = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.DebitAccount"), AccountSub = account.GetAttributeValue("rocks.kfs.ShelbyFinancials.AccountSub"), Amount = summary.Amount, Project = summary.Project, JournalNumber = financialBatch.Id, JournalDescription = DescriptionLava.ResolveMergeFields(mergeFields), Date = financialBatch.BatchStartDateTime ?? RockDateTime.Now, Note = financialBatch.Note }; if (debugLava.Length < 6 && debugLava.AsBoolean()) { debugLava = mergeFields.lavaDebugInfo(); } batchSummary.Add(batchSummaryItem); } return(GenerateLineItems(batchSummary)); }
/// <summary> /// Gets the warnings. /// </summary> /// <returns></returns> private List<string> GetWarnings( FinancialBatch batch ) { var warningList = new List<string>(); if ( batch.Status == BatchStatus.Open ) { var transactionService = new FinancialTransactionService( new RockContext() ); var transactionList = transactionService.Queryable().Where( trans => trans.BatchId == batch.Id && trans.AuthorizedPersonId == null ).ToList(); if ( transactionList.Count > 0 ) { warningList.Add( "UNTIED" ); } } return warningList; }
/// <summary> /// Processes the confirmation. /// </summary> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessConfirmation( out string errorMessage ) { if ( string.IsNullOrWhiteSpace( TransactionCode ) ) { GatewayComponent gateway = hfPaymentTab.Value == "ACH" ? _achGateway : _ccGateway; if ( gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } Person person = GetPerson( true ); if ( person == null ) { errorMessage = "There was a problem creating the person information"; return false; } PaymentInfo paymentInfo = GetPaymentInfo(); if ( paymentInfo == null ) { errorMessage = "There was a problem creating the payment information"; return false; } else { paymentInfo.FirstName = person.FirstName; paymentInfo.LastName = person.LastName; } if ( paymentInfo.CreditCardTypeValue != null ) { CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id; } PaymentSchedule schedule = GetSchedule(); if ( schedule != null ) { schedule.PersonId = person.Id; var scheduledTransaction = gateway.AddScheduledPayment( schedule, paymentInfo, out errorMessage ); if ( scheduledTransaction != null ) { scheduledTransaction.TransactionFrequencyValueId = schedule.TransactionFrequencyValue.Id; scheduledTransaction.AuthorizedPersonId = person.Id; scheduledTransaction.GatewayEntityTypeId = EntityTypeCache.Read( gateway.TypeGuid ).Id; foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialScheduledTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; scheduledTransaction.ScheduledTransactionDetails.Add( transactionDetail ); } var transactionService = new FinancialScheduledTransactionService(); transactionService.Add( scheduledTransaction, CurrentPersonId ); transactionService.Save( scheduledTransaction, CurrentPersonId ); ScheduleId = scheduledTransaction.GatewayScheduleId; TransactionCode = scheduledTransaction.TransactionCode; } else { return false; } } else { var transaction = gateway.Charge( paymentInfo, out errorMessage ); if ( transaction != null ) { transaction.TransactionDateTime = DateTime.Now; transaction.AuthorizedPersonId = person.Id; transaction.GatewayEntityTypeId = gateway.TypeId; transaction.Amount = paymentInfo.Amount; transaction.TransactionTypeValueId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION)).Id; transaction.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id; transaction.CreditCardTypeValueId = CreditCardTypeValueId; Guid sourceGuid = Guid.Empty; if (Guid.TryParse(GetAttributeValue("Source"), out sourceGuid)) { transaction.SourceTypeValueId = DefinedValueCache.Read(sourceGuid).Id; } foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; transaction.TransactionDetails.Add( transactionDetail ); } // Get the batch name string ccSuffix = string.Empty; if ( paymentInfo.CreditCardTypeValue != null ) { ccSuffix = paymentInfo.CreditCardTypeValue.GetAttributeValue( "BatchNameSuffix" ); } if ( string.IsNullOrWhiteSpace( ccSuffix ) ) { ccSuffix = paymentInfo.CurrencyTypeValue.Name; } string batchName = GetAttributeValue( "BatchNamePrefix" ).Trim() + " " + ccSuffix; using ( new UnitOfWorkScope() ) { var batchService = new FinancialBatchService(); var batch = batchService.Queryable() .Where( b => b.Status == BatchStatus.Open && b.BatchStartDateTime <= transaction.TransactionDateTime && b.BatchEndDateTime > transaction.TransactionDateTime && b.Name == batchName ) .FirstOrDefault(); if ( batch == null ) { batch = new FinancialBatch(); batch.Name = batchName; batch.Status = BatchStatus.Open; batch.BatchStartDateTime = transaction.TransactionDateTime.Value.Date.Add( gateway.BatchTimeOffset ); if ( batch.BatchStartDateTime > transaction.TransactionDateTime ) { batch.BatchStartDateTime.Value.AddDays( -1 ); } batch.BatchEndDateTime = batch.BatchStartDateTime.Value.AddDays( 1 ).AddMilliseconds( -1 ); batch.CreatedByPersonId = person.Id; batchService.Add( batch, CurrentPersonId ); batchService.Save( batch, CurrentPersonId ); batch = batchService.Get( batch.Id ); } batch.ControlAmount += transaction.Amount; batchService.Save( batch, CurrentPersonId ); var transactionService = new FinancialTransactionService(); transaction.BatchId = batch.Id; transactionService.Add( transaction, CurrentPersonId ); transactionService.Save( transaction, CurrentPersonId ); } TransactionCode = transaction.TransactionCode; } else { return false; } } tdTransactionCode.Description = TransactionCode; tdTransactionCode.Visible = !string.IsNullOrWhiteSpace( TransactionCode ); tdScheduleId.Description = ScheduleId; tdScheduleId.Visible = !string.IsNullOrWhiteSpace( ScheduleId ); // If there was a transaction code returned and this was not already created from a previous saved account, // show the option to save the account. if ( !( paymentInfo is ReferencePaymentInfo ) && !string.IsNullOrWhiteSpace( TransactionCode ) ) { cbSaveAccount.Visible = true; pnlSaveAccount.Visible = true; txtSaveAccount.Visible = true; // If current person does not have a login, have them create a username and password phCreateLogin.Visible = !new UserLoginService().GetByPersonId( person.Id ).Any(); } else { pnlSaveAccount.Visible = false; } return true; } else { pnlDupWarning.Visible = true; errorMessage = string.Empty; return false; } }
/// <summary> /// Shows the edit details. /// </summary> /// <param name="batch">The financial batch.</param> protected void ShowEditDetails( FinancialBatch batch ) { if ( batch != null ) { hfBatchId.Value = batch.Id.ToString(); string title = batch.Id > 0 ? ActionTitle.Edit( FinancialBatch.FriendlyTypeName ) : ActionTitle.Add( FinancialBatch.FriendlyTypeName ); SetHeadingInfo( batch, title ); SetEditMode( true ); tbName.Text = batch.Name; ddlStatus.BindToEnum( typeof( BatchStatus ) ); ddlStatus.SelectedIndex = (int)(BatchStatus)batch.Status; campCampus.Campuses = new CampusService( new RockContext() ).Queryable().OrderBy( a => a.Name ).ToList(); if ( batch.CampusId.HasValue ) { campCampus.SetValue( batch.CampusId.Value ); } tbControlAmount.Text = batch.ControlAmount.ToString( "N2" ); dtpStart.SelectedDateTime = batch.BatchStartDateTime; dtpEnd.SelectedDateTime = batch.BatchEndDateTime; tbAccountingCode.Text = batch.AccountingSystemCode; } }
/// <summary> /// Shows the detail. /// </summary> /// <param name="batchId">The financial batch identifier.</param> public void ShowDetail(int batchId) { FinancialBatch batch = null; bool editAllowed = true; if (!batchId.Equals(0)) { batch = GetBatch(batchId); if (batch != null) { editAllowed = batch.IsAuthorized(Authorization.EDIT, CurrentPerson); pdAuditDetails.SetEntity(batch, ResolveRockUrl("~")); } } if (batch == null) { batch = new FinancialBatch { Id = 0, Status = BatchStatus.Open }; // hide the panel drawer that show created and last modified dates pdAuditDetails.Visible = false; } else { string quickReturnLava = "{{ Batch.Name | AddQuickReturn:'Batches', 50 }}"; var quickReturnMergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(this.RockPage, this.CurrentPerson, new Rock.Lava.CommonMergeFieldsOptions { GetLegacyGlobalMergeFields = false }); quickReturnMergeFields.Add("Batch", batch); quickReturnLava.ResolveMergeFields(quickReturnMergeFields); } hfBatchId.Value = batch.Id.ToString(); bool readOnly = false; nbEditModeMessage.Text = string.Empty; if (!editAllowed || !IsUserAuthorized(Authorization.EDIT)) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed(FinancialBatch.FriendlyTypeName); } else if (batch.Status == BatchStatus.Closed) { if (!batch.IsAuthorized("ReopenBatch", this.CurrentPerson)) { readOnly = true; nbEditModeMessage.Text = "Batch is closed and requires authorization to re-open before editing."; } } if (readOnly) { lbEdit.Visible = false; ShowReadonlyDetails(batch); } else { lbEdit.Visible = true; if (batch.Id > 0) { ShowReadonlyDetails(batch); } else { ShowEditDetails(batch); } } lbSave.Visible = !readOnly; }
/// <summary> /// Shows the financial batch summary. /// </summary> /// <param name="batch">The financial batch.</param> private void ShowReadonlyDetails(FinancialBatch batch) { SetEditMode(false); if (batch != null) { hfBatchId.SetValue(batch.Id); SetHeadingInfo(batch, batch.Name); string campusName = string.Empty; if (batch.CampusId.HasValue) { var campus = CampusCache.Read(batch.CampusId.Value); if (campus != null) { campusName = campus.ToString(); } } var rockContext = new RockContext(); var financialTransactionService = new FinancialTransactionService(rockContext); var batchTransactions = financialTransactionService.Queryable().Where(a => a.BatchId.HasValue && a.BatchId.Value == batch.Id); var financialTransactionDetailService = new FinancialTransactionDetailService(rockContext); var qryTransactionDetails = financialTransactionDetailService.Queryable().Where(a => a.Transaction.BatchId == batch.Id); decimal txnTotal = qryTransactionDetails.Select(a => (decimal?)a.Amount).Sum() ?? 0; decimal variance = txnTotal - batch.ControlAmount; string amountFormat = string.Format( "{0} / {1} / " + (variance == 0.0M ? "{2}" : "<span class='label label-danger'>{2}</span>"), txnTotal.FormatAsCurrency(), batch.ControlAmount.FormatAsCurrency(), variance.FormatAsCurrency()); lDetails.Text = new DescriptionList() .Add("Date Range", new DateRange(batch.BatchStartDateTime, batch.BatchEndDateTime).ToString("g")) .Add("Transaction / Control / Variance", amountFormat) .Add("Accounting Code", batch.AccountingSystemCode) .Add("Notes", batch.Note) .Html; batch.LoadAttributes(); var attributes = batch.Attributes.Select(a => a.Value).OrderBy(a => a.Order).ThenBy(a => a.Name).ToList(); var attributeCategories = Helper.GetAttributeCategories(attributes); Rock.Attribute.Helper.AddDisplayControls(batch, attributeCategories, phReadonlyAttributes, null, false); // Account Summary gAccounts.DataSource = qryTransactionDetails .GroupBy(d => new { AccountId = d.AccountId, AccountName = d.Account.Name }) .Select(s => new { Id = s.Key.AccountId, Name = s.Key.AccountName, Amount = s.Sum(a => (decimal?)a.Amount) ?? 0.0M }) .OrderBy(s => s.Name) .ToList(); gAccounts.DataBind(); // Currency Summary gCurrencyTypes.DataSource = batchTransactions .GroupBy(c => new { CurrencyTypeValueId = c.FinancialPaymentDetailId.HasValue ? c.FinancialPaymentDetail.CurrencyTypeValueId : 0, }) .Select(s => new { CurrencyTypeValueId = s.Key.CurrencyTypeValueId, Amount = s.Sum(a => (decimal?)a.TransactionDetails.Sum(t => t.Amount)) ?? 0.0M }) .ToList() .Select(s => new { Id = s.CurrencyTypeValueId, Name = DefinedValueCache.GetName(s.CurrencyTypeValueId), Amount = s.Amount }).OrderBy(a => a.Name).ToList(); gCurrencyTypes.DataBind(); } }
/// <summary> /// Exports any contributions. /// </summary> public static void ExportContributions() { try { // Retrieve & Output the Fund Accounts using (var dtFunds = GetTableData(SQL_FINANCIAL_ACCOUNTS)) { foreach (DataRow row in dtFunds.Rows) { FinancialAccount account = SkFinancialAccount.Translate(row); if (account is null) { continue; } ImportPackage.WriteToPackage(account); } } // Retrieve & Output the Batches using (var dtBatches = GetTableData(SQL_FINANCIAL_BATCHES)) { foreach (DataRow row in dtBatches.Rows) { FinancialBatch batch = SkFinancialBatch.Translate(row); if (batch is null) { continue; } ImportPackage.WriteToPackage(batch); } } // Retrieve & Output the Contributions using (var dtContributions = GetTableData(SQL_FINANCIAL_CONTRIBUTIONS)) { foreach (DataRow row in dtContributions.Rows) { FinancialTransaction transaction = SkFinancialContribution.Translate(row); if (transaction is null) { continue; } ImportPackage.WriteToPackage(transaction); } } // Retrieve & Output the Contribution Details using (var dtContributionDetails = GetTableData(SQL_FINANCIAL_CONTRIBUTIONDETAILS)) { foreach (DataRow row in dtContributionDetails.Rows) { FinancialTransactionDetail details = SkFinancialContributionDetail.Translate(row); if (details is null) { continue; } ImportPackage.WriteToPackage(details); } } } catch (Exception ex) { ErrorMessage = ex.Message; } }
/// <summary> /// Maps the batch data. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="totalRows">The total rows.</param> /// <exception cref="System.NotImplementedException"></exception> private void MapBatch(IQueryable <Row> tableData, long totalRows = 0) { var newBatches = new List <FinancialBatch>(); if (totalRows == 0) { totalRows = tableData.Count(); } var earliestBatchDate = ImportDateTime; var completedItems = 0; var percentage = (totalRows - 1) / 100 + 1; ReportProgress(0, $"Verifying batch import ({totalRows:N0} found, {ImportedBatches.Count:N0} already exist)."); foreach (var row in tableData.Where(r => r != null)) { var batchId = row["BatchID"] as int?; if (batchId.HasValue && !ImportedBatches.ContainsKey(( int )batchId)) { var batch = new FinancialBatch { CreatedByPersonAliasId = ImportPersonAliasId, ForeignKey = batchId.ToString(), ForeignId = batchId, Note = string.Empty, Status = BatchStatus.Closed, AccountingSystemCode = string.Empty }; var name = row["BatchName"] as string; if (!string.IsNullOrWhiteSpace(name)) { name = name.Trim(); batch.Name = name.Truncate(50); batch.CampusId = GetCampusId(name); } var batchDate = row["BatchDate"] as DateTime?; if (batchDate.HasValue) { batch.BatchStartDateTime = batchDate; batch.BatchEndDateTime = batchDate; if (batchDate < earliestBatchDate) { earliestBatchDate = ( DateTime )batchDate; } } var amount = row["BatchAmount"] as decimal?; if (amount.HasValue) { batch.ControlAmount = amount.Value; } newBatches.Add(batch); completedItems++; if (completedItems % percentage < 1) { var percentComplete = completedItems / percentage; ReportProgress(percentComplete, $"{completedItems:N0} batches imported ({percentComplete}% complete)."); } if (completedItems % ReportingNumber < 1) { SaveFinancialBatches(newBatches); newBatches.ForEach(b => ImportedBatches.Add(( int )b.ForeignId, ( int? )b.Id)); newBatches.Clear(); ReportPartialProgress(); } } } // add a default batch to use with contributions if (!ImportedBatches.ContainsKey(0)) { var defaultBatch = new FinancialBatch { CreatedDateTime = ImportDateTime, CreatedByPersonAliasId = ImportPersonAliasId, BatchStartDateTime = earliestBatchDate, Status = BatchStatus.Closed, Name = $"Default Batch (Imported {ImportDateTime})", ControlAmount = 0.0m, ForeignKey = "0", ForeignId = 0 }; newBatches.Add(defaultBatch); } if (newBatches.Any()) { SaveFinancialBatches(newBatches); newBatches.ForEach(b => ImportedBatches.Add(( int )b.ForeignId, ( int? )b.Id)); } ImportedBatches = new FinancialBatchService(new RockContext()).Queryable().AsNoTracking() .Where(b => b.ForeignId.HasValue) .ToDictionary(t => ( int )t.ForeignId, t => ( int? )t.Id); ReportProgress(100, $"Finished batch import: {completedItems:N0} batches imported."); }
public List <JournalEntryLine> GetGlEntries(RockContext rockContext, FinancialBatch financialBatch, string journal, string encumbranceStatus = "Regular") { // // Group/Sum Transactions by Account and Project since Project can come from Account or Transaction Details // var batchTransactions = new List <GLTransaction>(); foreach (var transaction in financialBatch.Transactions) { transaction.LoadAttributes(); foreach (var transactionDetail in transaction.TransactionDetails) { transactionDetail.LoadAttributes(); transactionDetail.Account.LoadAttributes(); var detailProject = transactionDetail.GetAttributeValue("rocks.kfs.FinancialEdge.PROJECTID").AsGuidOrNull(); var accountProject = transactionDetail.Account.GetAttributeValue("rocks.kfs.FinancialEdge.PROJECTID").AsGuidOrNull(); var projectCode = string.Empty; if (detailProject != null) { projectCode = detailProject.ToString(); } else if (accountProject != null) { projectCode = accountProject.ToString(); } var transactionItem = new GLTransaction() { Amount = transactionDetail.Amount, CreditAccount = transactionDetail.Account.GetAttributeValue("rocks.kfs.FinancialEdge.ACCOUNTNO"), DebitAccount = transactionDetail.Account.GetAttributeValue("rocks.kfs.FinancialEdge.DEBITACCOUNTNO"), Project = projectCode, FinancialAccountId = transactionDetail.Account.Id, DebitProject = transactionDetail.Account.GetAttributeValue("rocks.kfs.FinancialEdge.DEBITPROJECTID"), }; batchTransactions.Add(transactionItem); } } var creditLines = batchTransactions .GroupBy(d => new { d.CreditAccount, d.Project }) .Select(s => new GLTransactionLine { Account = s.Key.CreditAccount, Project = s.Key.Project, Amount = s.Sum(f => ( decimal? )f.Amount) ?? 0.0M }) .ToList(); var debitLines = batchTransactions .GroupBy(d => new { d.DebitAccount, d.DebitProject }) .Select(s => new GLTransactionLine { Account = s.Key.DebitAccount, Project = s.Key.DebitProject, Amount = s.Sum(f => ( decimal? )f.Amount) ?? 0.0M, }) .ToList(); var batchName = string.Format("{0} ({1})", financialBatch.Name, financialBatch.Id); return(GenerateLineItems(rockContext, creditLines, debitLines, financialBatch.BatchStartDateTime, journal, batchName, encumbranceStatus)); }
/// <summary> /// Shows the financial batch summary. /// </summary> /// <param name="batch">The financial batch.</param> private void ShowReadonlyDetails( FinancialBatch batch ) { SetEditMode( false ); if ( batch != null ) { hfBatchId.SetValue( batch.Id ); SetHeadingInfo( batch, batch.Name ); string campusName = string.Empty; if ( batch.CampusId.HasValue ) { var campus = CampusCache.Read( batch.CampusId.Value ); if ( campus != null ) { campusName = campus.ToString(); } } var rockContext = new RockContext(); var financialTransactionService = new FinancialTransactionService( rockContext ); var batchTransactions = financialTransactionService.Queryable().Where( a => a.BatchId.HasValue && a.BatchId.Value == batch.Id ); var financialTransactionDetailService = new FinancialTransactionDetailService( rockContext ); var qryTransactionDetails = financialTransactionDetailService.Queryable().Where( a => a.Transaction.BatchId == batch.Id ); decimal txnTotal = qryTransactionDetails.Select( a => (decimal?)a.Amount ).Sum() ?? 0; decimal variance = txnTotal - batch.ControlAmount; string amountFormat = string.Format( "{0} / {1} / " + ( variance == 0.0M ? "{2}" : "<span class='label label-danger'>{2}</span>" ), txnTotal.FormatAsCurrency(), batch.ControlAmount.FormatAsCurrency(), variance.FormatAsCurrency() ); lDetails.Text = new DescriptionList() .Add( "Date Range", new DateRange( batch.BatchStartDateTime, batch.BatchEndDateTime ).ToString( "g" ) ) .Add( "Transaction / Control / Variance", amountFormat ) .Add( "Accounting Code", batch.AccountingSystemCode ) .Add( "Notes", batch.Note ) .Html; // Account Summary gAccounts.DataSource = qryTransactionDetails .GroupBy( d => new { AccountId = d.AccountId, AccountName = d.Account.Name } ) .Select( s => new { Id = s.Key.AccountId, Name = s.Key.AccountName, Amount = s.Sum( a => (decimal?)a.Amount ) ?? 0.0M } ) .OrderBy( s => s.Name ) .ToList(); gAccounts.DataBind(); // Currency Summary gCurrencyTypes.DataSource = batchTransactions .GroupBy( c => new { CurrencyTypeValueId = c.FinancialPaymentDetailId.HasValue ? c.FinancialPaymentDetail.CurrencyTypeValueId : 0, } ) .Select( s => new { CurrencyTypeValueId = s.Key.CurrencyTypeValueId, Amount = s.Sum( a => (decimal?)a.TransactionDetails.Sum( t => t.Amount ) ) ?? 0.0M } ) .ToList() .Select( s => new { Id = s.CurrencyTypeValueId, Name = DefinedValueCache.GetName( s.CurrencyTypeValueId ), Amount = s.Amount } ).OrderBy( a => a.Name ).ToList(); gCurrencyTypes.DataBind(); } }
/// <summary> /// Raises the <see cref="E:System.Web.UI.Control.Load" /> event. /// </summary> /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnLoad( EventArgs e ) { base.OnLoad( e ); var contextEntity = this.ContextEntity(); if ( contextEntity != null ) { if ( contextEntity is Person ) { _person = contextEntity as Person; } else if ( contextEntity is FinancialBatch ) { _batch = contextEntity as FinancialBatch; gfTransactions.Visible = false; } } if ( !Page.IsPostBack ) { BindFilter(); BindGrid(); } }
/// <summary> /// Updates the batch UI. /// </summary> /// <param name="selectedBatch">The selected batch.</param> private void UpdateBatchUI(FinancialBatch selectedBatch) { if (selectedBatch == null) { grdBatchItems.DataContext = null; DisplayTransactionCount(); HideBatch(); return; } else { ShowBatch(false); } RockConfig rockConfig = RockConfig.Load(); RockRestClient client = new RockRestClient(rockConfig.RockBaseUrl); client.Login(rockConfig.Username, rockConfig.Password); SelectedFinancialBatch = selectedBatch; lblBatchNameReadOnly.Content = selectedBatch.Name; lblBatchIdReadOnly.Content = string.Format("Batch Id: {0}", selectedBatch.Id); lblBatchCampusReadOnly.Content = selectedBatch.CampusId.HasValue ? client.GetData <Campus>(string.Format("api/Campuses/{0}", selectedBatch.CampusId ?? 0)).Name : string.Empty; lblBatchDateReadOnly.Content = selectedBatch.BatchStartDateTime.Value.ToString("d"); var createdByPerson = client.GetData <Person>(string.Format("api/People/GetByPersonAliasId/{0}", selectedBatch.CreatedByPersonAliasId ?? 0)); if (createdByPerson != null) { lblBatchCreatedByReadOnly.Content = string.Format("{0} {1}", createdByPerson.NickName, createdByPerson.LastName); } else { lblBatchCreatedByReadOnly.Content = string.Empty; } lblBatchControlAmountReadOnly.Content = selectedBatch.ControlAmount.ToString("F"); txtBatchName.Text = selectedBatch.Name; if (selectedBatch.CampusId.HasValue) { cbCampus.SelectedValue = selectedBatch.CampusId; } else { cbCampus.SelectedValue = 0; } dpBatchDate.SelectedDate = selectedBatch.BatchStartDateTime; lblCreatedBy.Content = lblBatchCreatedByReadOnly.Content as string; txtControlAmount.Text = selectedBatch.ControlAmount.ToString("F"); txtNote.Text = selectedBatch.Note; // start a background thread to download transactions since this could take a little while and we want a Wait cursor BackgroundWorker bw = new BackgroundWorker(); Rock.Wpf.WpfHelper.FadeOut(lblCount, 0); lblCount.Content = "Loading..."; Rock.Wpf.WpfHelper.FadeIn(lblCount, 300); List <FinancialTransaction> transactions = null; grdBatchItems.DataContext = null; bw.DoWork += delegate(object s, DoWorkEventArgs ee) { ee.Result = null; transactions = client.GetData <List <FinancialTransaction> >("api/FinancialTransactions/", string.Format("BatchId eq {0}", selectedBatch.Id)); }; bw.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs ee) { this.Cursor = null; foreach (var transaction in transactions) { if (transaction.FinancialPaymentDetailId.HasValue) { transaction.FinancialPaymentDetail = transaction.FinancialPaymentDetail ?? client.GetData <FinancialPaymentDetail>(string.Format("api/FinancialPaymentDetails/{0}", transaction.FinancialPaymentDetailId ?? 0)); if (transaction.FinancialPaymentDetail != null) { transaction.FinancialPaymentDetail.CurrencyTypeValue = this.CurrencyValueList.FirstOrDefault(a => a.Id == transaction.FinancialPaymentDetail.CurrencyTypeValueId); } } } // sort starting with most recent first var bindingList = new BindingList <FinancialTransaction>(transactions.OrderByDescending(a => a.CreatedDateTime).ToList()); bindingList.RaiseListChangedEvents = true; bindingList.ListChanged += bindingList_ListChanged; grdBatchItems.DataContext = bindingList; DisplayTransactionCount(); }; this.Cursor = Cursors.Wait; bw.RunWorkerAsync(); }
/// <summary> /// Handles the Click event of the btnAddBatch control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param> private void btnAddBatch_Click( object sender, RoutedEventArgs e ) { var financialBatch = new FinancialBatch { Id = 0, BatchStartDateTime = DateTime.Now.Date, CreatedByPersonAliasId = LoggedInPerson.PrimaryAlias.Id }; UpdateBatchUI( financialBatch ); ShowBatch( true ); }
private static void CreateFinancialTransactions( int personAliasId, int count, FinancialAccount account, FinancialBatch batch) { var currencyTypeGuid = string.Empty; for (var i = 0; i < count; i++) { int? currencyTypeId = 0; int? cardTypeId = null; string checkMicrEncrypted = null; string checkMicrHash = null; string checkMicrParts = null; var transactionDateTime = RockDateTime.Now.AddDays(i * -1); if (i == 0) { _endDate = _startDate = transactionDateTime.AddDays(1); } // Dates are going backwards in time, adjuect start if (transactionDateTime < _startDate) { _startDate = transactionDateTime; } if (i % 5 == 0) { // Checks currencyTypeId = _checkValue.Id; cardTypeId = null; checkMicrEncrypted = $"{Guid.NewGuid().ToString().Replace( "-", "" )}{Guid.NewGuid().ToString().Replace( "-", "" )}{Guid.NewGuid().ToString().Replace( "-", "" )}"; checkMicrHash = null; checkMicrParts = null; } else if (i % 6 == 0) { // Cash currencyTypeId = _cashValue.Id; cardTypeId = null; checkMicrEncrypted = null; checkMicrHash = null; checkMicrParts = null; } else { // Credit Cards currencyTypeId = _creditCardValue.Id; cardTypeId = _visaValue.Id; checkMicrEncrypted = null; checkMicrHash = null; checkMicrParts = null; } var payment = CreateFinancialPaymentDetail(currencyTypeId, cardTypeId, transactionDateTime); var transaction = CreateFinancialTransaction(personAliasId, batch.Id, payment.Id, i, transactionDateTime, checkMicrEncrypted, checkMicrHash, checkMicrParts); var transactionDetail = CreateFinancialTransactionDetail(account.Id, transaction.Id, i, transactionDateTime); } _startDate = _startDate.AddDays(-1); _rockContext.SaveChanges(true); }
/// <summary> /// Maps the batch data. /// </summary> /// <param name="tableData">The table data.</param> /// <exception cref="System.NotImplementedException"></exception> private void MapBatch(IQueryable <Row> tableData) { var batchStatusClosed = Rock.Model.BatchStatus.Closed; var newBatches = new List <FinancialBatch>(); int completed = 0; int totalRows = tableData.Count(); int percentage = (totalRows - 1) / 100 + 1; ReportProgress(0, string.Format("Verifying batch import ({0:N0} found, {1:N0} already exist).", totalRows, ImportedBatches.Count)); foreach (var row in tableData.Where(r => r != null)) { int?batchId = row["BatchID"] as int?; if (batchId != null && !ImportedBatches.ContainsKey((int)batchId)) { var batch = new FinancialBatch(); batch.CreatedByPersonAliasId = ImportPersonAliasId; batch.ForeignKey = batchId.ToString(); batch.ForeignId = batchId; batch.Note = string.Empty; batch.Status = batchStatusClosed; batch.AccountingSystemCode = string.Empty; string name = row["BatchName"] as string; if (name != null) { name = name.Trim(); batch.Name = name.Left(50); batch.CampusId = CampusList.Where(c => name.StartsWith(c.Name) || name.StartsWith(c.ShortCode)) .Select(c => (int?)c.Id).FirstOrDefault(); } DateTime?batchDate = row["BatchDate"] as DateTime?; if (batchDate != null) { batch.BatchStartDateTime = batchDate; batch.BatchEndDateTime = batchDate; } decimal?amount = row["BatchAmount"] as decimal?; if (amount != null) { batch.ControlAmount = amount.HasValue ? amount.Value : new decimal(); } newBatches.Add(batch); completed++; if (completed % percentage < 1) { int percentComplete = completed / percentage; ReportProgress(percentComplete, string.Format("{0:N0} batches imported ({1}% complete).", completed, percentComplete)); } else if (completed % ReportingNumber < 1) { SaveFinancialBatches(newBatches); newBatches.ForEach(b => ImportedBatches.Add((int)b.ForeignId, (int?)b.Id)); newBatches.Clear(); ReportPartialProgress(); } } } // add a default batch to use with contributions if (!ImportedBatches.ContainsKey(0)) { var defaultBatch = new FinancialBatch(); defaultBatch.CreatedDateTime = ImportDateTime; defaultBatch.CreatedByPersonAliasId = ImportPersonAliasId; defaultBatch.Status = Rock.Model.BatchStatus.Closed; defaultBatch.Name = string.Format("Default Batch (Imported {0})", ImportDateTime); defaultBatch.ControlAmount = 0.0m; defaultBatch.ForeignKey = "0"; defaultBatch.ForeignId = 0; newBatches.Add(defaultBatch); } if (newBatches.Any()) { SaveFinancialBatches(newBatches); newBatches.ForEach(b => ImportedBatches.Add((int)b.ForeignId, (int?)b.Id)); } ReportProgress(100, string.Format("Finished batch import: {0:N0} batches imported.", completed)); }
/// <summary> /// Updates the batch UI. /// </summary> /// <param name="selectedBatch">The selected batch.</param> private void UpdateBatchUI( FinancialBatch selectedBatch ) { if ( selectedBatch == null ) { HideBatch(); return; } else { ShowBatch( false ); } RockConfig rockConfig = RockConfig.Load(); RockRestClient client = new RockRestClient( rockConfig.RockBaseUrl ); client.Login( rockConfig.Username, rockConfig.Password ); SelectedFinancialBatch = selectedBatch; lblBatchNameReadOnly.Content = selectedBatch.Name; lblBatchCampusReadOnly.Content = selectedBatch.CampusId.HasValue ? client.GetData<Campus>( string.Format( "api/Campus/{0}", selectedBatch.CampusId ) ).Name : None.Text; lblBatchDateReadOnly.Content = selectedBatch.BatchStartDateTime.Value.ToString( "d" ); lblBatchCreatedByReadOnly.Content = client.GetData<Person>( string.Format( "api/People/GetByPersonAliasId/{0}", selectedBatch.CreatedByPersonAliasId ) ).FullName; lblBatchControlAmountReadOnly.Content = selectedBatch.ControlAmount.ToString( "F" ); txtBatchName.Text = selectedBatch.Name; if ( selectedBatch.CampusId.HasValue ) { cbCampus.SelectedValue = selectedBatch.CampusId; } else { cbCampus.SelectedValue = 0; } dpBatchDate.SelectedDate = selectedBatch.BatchStartDateTime; lblCreatedBy.Content = lblBatchCreatedByReadOnly.Content as string; txtControlAmount.Text = selectedBatch.ControlAmount.ToString( "F" ); List<FinancialTransaction> transactions = client.GetData<List<FinancialTransaction>>( "api/FinancialTransactions/", string.Format( "BatchId eq {0}", selectedBatch.Id ) ); foreach (var transaction in transactions) { transaction.TransactionDetails = client.GetData<List<FinancialTransactionDetail>>( "api/FinancialTransactionDetails/", string.Format( "TransactionId eq {0}", transaction.Id ) ); } grdBatchItems.DataContext = transactions.OrderByDescending( a => a.CreatedDateTime ); }
/// <summary> /// Get the GLRecords for the given batch, with the appropriate information about /// the export data. /// </summary> /// <param name="batch">Batch to be exported.</param> /// <param name="date">The date of this deposit.</param> /// <param name="accountingPeriod">Accounting period as defined in the GL system.</param> /// <param name="journalType">The type of journal entry to create as defined in the GL system.</param> /// <returns>A collection of GLRecord objects to be imported into the GL system.</returns> List <GLRecord> GLRecordsForBatch(FinancialBatch batch, DateTime date, string accountingPeriod, string journalType) { List <GLRecord> records = new List <GLRecord>(); // // Load all the transaction details, load their attributes and then group // by the account attributes, GLBankAccount+GLCompany+GLFund. // var transactions = batch.Transactions .SelectMany(t => t.TransactionDetails) .ToList(); foreach (var d in transactions) { d.LoadAttributes(); d.Account.LoadAttributes(); } var accounts = transactions.GroupBy(d => new { GLBankAccount = d.Account.GetAttributeValue("GLBankAccount"), GLCompany = d.Account.GetAttributeValue("GLCompany"), GLFund = d.Account.GetAttributeValue("GLFund") }, d => d).OrderBy(g => g.Key.GLBankAccount); // // Go through each group and build the line items. // foreach (var grp in accounts) { GLRecord record = new GLRecord(); // // Build the bank account deposit line item. // record.AccountingPeriod = accountingPeriod; record.AccountNumber = grp.Key.GLBankAccount; record.Amount = grp.Sum(d => d.Amount); record.Company = grp.Key.GLCompany; record.Date = date; record.Department = string.Empty; record.Description1 = batch.Name + " (" + batch.Id.ToString() + ")"; record.Description2 = string.Empty; record.Fund = grp.Key.GLFund; record.Journal = "0"; record.JournalType = journalType; record.Project = string.Empty; records.Add(record); // // Build each of the revenue fund withdrawls. // foreach (var grpTransactions in grp.GroupBy(t => t.AccountId, t => t)) { record = new GLRecord(); record.AccountingPeriod = accountingPeriod; record.AccountNumber = grpTransactions.First().Account.GetAttributeValue("GLRevenueAccount"); record.Amount = -(grpTransactions.Sum(t => t.Amount)); record.Company = grp.Key.GLCompany; record.Date = date; record.Department = grpTransactions.First().Account.GetAttributeValue("GLRevenueDepartment"); record.Description1 = grpTransactions.First().Account.Name; record.Description2 = string.Empty; record.Fund = grp.Key.GLFund; record.Journal = "0"; record.JournalType = journalType; record.Project = string.Empty; records.Add(record); } } return(records); }
/// <summary> /// Handles the Click event of the btnConfirm control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void btnConfirm_Click(object sender, EventArgs e) { // send signalR message to start progress indicator int progress = 0; _hubContext.Clients.All.receiveNotification(signalREventName, "0"); XDocument xml = null; int? total = null; int? batchId = null; string batchName = string.Empty; int?attributeId = null; int?binaryFileTypeId = null; using (var rockContext = new RockContext()) { // Get the XML var binaryFile = new BinaryFileService(rockContext).Get(_binaryFileId.Value); if (binaryFile != null) { using (var stream = binaryFile.ContentStream) { xml = XDocument.Load(stream); } } // Get the number of transactions if (xml != null) { total = xml.Root.Descendants().Where(n => n.Name == "Gift").Count(); } if (xml != null && total.HasValue && total.Value > 0) { var batchService = new FinancialBatchService(rockContext); FinancialBatch batch = null; // Load (or create) the batch batchId = ddlBatch.SelectedValueAsInt(); if (batchId.HasValue) { batch = batchService.Get(batchId.Value); } if (batch == null) { batch = new FinancialBatch(); batch.Guid = Guid.NewGuid(); batch.Name = Path.GetFileNameWithoutExtension(binaryFile.FileName); batch.Status = BatchStatus.Open; batch.BatchStartDateTime = RockDateTime.Today; batch.BatchEndDateTime = batch.BatchStartDateTime.Value.AddDays(1); batch.ControlAmount = 0; batchService.Add(batch); rockContext.SaveChanges(); batchId = batch.Id; } batchName = batch.Name; // Get the attribute id for the envelop number attribute int?personEntityTypeId = EntityTypeCache.GetId <Rock.Model.Person>(); attributeId = new AttributeService(rockContext) .Queryable().AsNoTracking() .Where(a => a.EntityTypeId == personEntityTypeId && a.Key == "GivingEnvelopeNumber") .Select(a => a.Id) .FirstOrDefault(); // Get the binary file type for contribution images var binaryFileType = new BinaryFileTypeService(rockContext).Get(Rock.SystemGuid.BinaryFiletype.CONTRIBUTION_IMAGE.AsGuid()); if (binaryFileType != null) { binaryFileTypeId = binaryFileType.Id; } } } // Initialize the status variables int matchCount = 0; int unmatchCount = 0; int errorCount = 0; var allErrorMessages = new List <string>(); // Process each transaction foreach (var node in xml.Root.Descendants().Where(n => n.Name == "Gift")) { var errorMessages = new List <string>(); var status = ProcessTransaction(node, batchId, attributeId, binaryFileTypeId, out errorMessages); switch (status) { case ProcessStatus.Matched: matchCount++; break; case ProcessStatus.Unmatched: unmatchCount++; break; case ProcessStatus.Error: errorCount++; break; } allErrorMessages.AddRange(errorMessages); // Update progress using signalR progress++; int percentage = (progress * 100) / total.Value; _hubContext.Clients.All.receiveNotification(signalREventName, percentage.ToString("N0")); } // update success message to indicate the txns that were updated StringBuilder sb = new StringBuilder(); sb.AppendFormat("<li>{0:N0} {1} processed.</li>", total.Value, "transaction".PluralizeIf(total.Value > 1)); sb.AppendFormat("<li>{0:N0} {1} matched to an existing person.</li>", matchCount, (matchCount == 1 ? "transaction was" : "transactions were")); sb.AppendFormat("<li>{0:N0} {1} NOT matched to an existing person.</li>", unmatchCount, (unmatchCount == 1 ? "transaction was" : "transactions were")); if (errorCount > 0) { sb.AppendFormat("<li>{0:N0} {1} NOT imported due to error during import (see errors below).</li>", errorCount, (errorCount == 1 ? "transaction was" : "transactions were")); } using (var rockContext = new RockContext()) { var batch = new FinancialBatchService(rockContext).Get(batchId.Value); if (batch != null) { // update batch control amount batch.ControlAmount += _totalAmount; rockContext.SaveChanges(); // Add link to batch var qryParam = new Dictionary <string, string>(); qryParam.Add("batchId", batchId.ToString()); string batchUrl = LinkedPageUrl("BatchDetailPage", qryParam); string batchLink = string.Format("<a href='{0}'>{1}</a>", batchUrl, batch.Name); int totalTransactions = matchCount + unmatchCount; string summaryformat = totalTransactions == 1 ? "<li>{0} transaction of {1} was added to the {2} batch.</li>" : "<li>{0} transactions totaling {1} were added to the {2} batch</li>"; sb.AppendFormat(summaryformat, totalTransactions.ToString("N0"), _totalAmount.FormatAsCurrency(), batchLink); } } nbSuccess.Text = string.Format("<ul>{0}</ul>", sb.ToString()); // Display any errors that occurred if (allErrorMessages.Any()) { StringBuilder sbErrors = new StringBuilder(); foreach (var errorMsg in allErrorMessages) { sbErrors.AppendFormat("<li>{0}</li>", errorMsg); } nbErrors.Text = string.Format("<ul>{0}</ul>", sbErrors.ToString()); nbErrors.Visible = true; } else { nbErrors.Visible = false; } ShowResults(); }
/// <summary> /// Shows the edit details. /// </summary> /// <param name="financialBatch">The financial batch.</param> protected void ShowEdit( FinancialBatch financialBatch ) { if ( financialBatch.Id > 0 ) { lTitle.Text = ActionTitle.Edit( FinancialBatch.FriendlyTypeName ).FormatAsHtmlTitle(); } else { lTitle.Text = ActionTitle.Add( FinancialBatch.FriendlyTypeName ).FormatAsHtmlTitle(); } SetEditMode( true ); ddlStatus.BindToEnum( typeof( BatchStatus ) ); hfBatchId.Value = financialBatch.Id.ToString(); tbName.Text = financialBatch.Name; tbControlAmount.Text = financialBatch.ControlAmount.ToString(); ddlStatus.SelectedIndex = (int)(BatchStatus)financialBatch.Status; campCampus.Campuses = new CampusService( new RockContext() ).Queryable().OrderBy( a => a.Name ).ToList(); if ( financialBatch.CampusId.HasValue ) { campCampus.SelectedCampusId = financialBatch.CampusId; } drpBatchDate.LowerValue = financialBatch.BatchStartDateTime; drpBatchDate.UpperValue = financialBatch.BatchEndDateTime; }
protected void ShowDetail(bool setSelectControlValues = true) { var rockContext = new RockContext(); var isExported = false; var debugEnabled = GetAttributeValue(AttributeKey.EnableDebug).AsBoolean(); var exportMode = GetAttributeValue(AttributeKey.ExportMode); _financialBatch = new FinancialBatchService(rockContext).Get(_batchId); DateTime?dateExported = null; _variance = 0; if (_financialBatch != null) { var financialTransactionDetailService = new FinancialTransactionDetailService(rockContext); var qryTransactionDetails = financialTransactionDetailService.Queryable().Where(a => a.Transaction.BatchId == _financialBatch.Id); decimal txnTotal = qryTransactionDetails.Select(a => ( decimal? )a.Amount).Sum() ?? 0; _variance = txnTotal - _financialBatch.ControlAmount; _financialBatch.LoadAttributes(); dateExported = ( DateTime? )_financialBatch.GetAttributeValueAsType("rocks.kfs.Intacct.DateExported"); if (dateExported != null && dateExported > DateTime.MinValue) { isExported = true; } if (debugEnabled) { var debugLava = Session["IntacctDebugLava"].ToStringSafe(); if (!string.IsNullOrWhiteSpace(debugLava)) { lDebug.Visible = true; lDebug.Text += debugLava; Session["IntacctDebugLava"] = string.Empty; } } } if (ValidSettings() && !isExported) { btnExportToIntacct.Text = GetAttributeValue(AttributeKey.ButtonText); btnExportToIntacct.Visible = true; if (exportMode == "JournalEntry") { pnlOtherReceipt.Visible = false; } else { SetupOtherReceipts(setSelectControlValues); } SetExportButtonVisibility(); } else if (isExported) { litDateExported.Text = string.Format("<div class=\"small\">Exported: {0}</div>", dateExported.ToRelativeDateString()); litDateExported.Visible = true; pnlExportedDetails.Visible = true; if (UserCanEdit) { btnRemoveDate.Visible = true; } } }
/// <summary> /// Shows the financial batch summary. /// </summary> /// <param name="financialBatch">The financial batch.</param> private void ShowSummary( FinancialBatch financialBatch ) { string batchDate = string.Empty; if ( financialBatch.BatchStartDateTime != null ) { batchDate = financialBatch.BatchStartDateTime.Value.ToShortDateString(); } lTitle.Text = string.Format( "{0} <small>{1}</small>", financialBatch.Name.FormatAsHtmlTitle(), batchDate ); SetEditMode( false ); string campus = string.Empty; if ( financialBatch.CampusId.HasValue ) { campus = financialBatch.Campus.ToString(); } hfBatchId.SetValue( financialBatch.Id ); lDetailsLeft.Text = new DescriptionList() .Add( "Title", financialBatch.Name ) .Add( "Status", financialBatch.Status.ToString() ) .Add( "Batch Start Date", Convert.ToDateTime( financialBatch.BatchStartDateTime ).ToString( "MM/dd/yyyy" ) ) .Html; lDetailsRight.Text = new DescriptionList() .Add( "Control Amount", financialBatch.ControlAmount.ToString() ) .Add( "Campus", campus ) .Add( "Batch End Date", Convert.ToDateTime( financialBatch.BatchEndDateTime ).ToString( "MM/dd/yyyy" ) ) .Html; }
/// <summary> /// Handles the Click event of the lbSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbSave_Click(object sender, EventArgs e) { var rockContext = new RockContext(); var batchService = new FinancialBatchService(rockContext); FinancialBatch batch = null; int batchId = hfBatchId.Value.AsInteger(); if (batchId == 0) { batch = new FinancialBatch(); batchService.Add(batch); } else { batch = batchService.Get(batchId); } if (batch != null) { batch.Name = tbName.Text; batch.Status = (BatchStatus)ddlStatus.SelectedIndex; batch.CampusId = campCampus.SelectedCampusId; batch.BatchStartDateTime = dtpStart.SelectedDateTimeIsBlank ? null : dtpStart.SelectedDateTime; if (dtpEnd.SelectedDateTimeIsBlank && batch.BatchStartDateTime.HasValue) { batch.BatchEndDateTime = batch.BatchStartDateTime.Value.AddDays(1); } else { batch.BatchEndDateTime = dtpEnd.SelectedDateTimeIsBlank ? null : dtpEnd.SelectedDateTime; } batch.ControlAmount = tbControlAmount.Text.AsDecimal(); batch.AccountingSystemCode = tbAccountingCode.Text; if (!Page.IsValid || !batch.IsValid) { // Controls will render the error messages return; } rockContext.SaveChanges(); if (batchId == 0) { // If created a new batch, navigate to same page so that transaction list displays correctly var pageReference = CurrentPageReference; pageReference.Parameters.AddOrReplace("batchId", batch.Id.ToString()); NavigateToPage(pageReference); } else { hfBatchId.SetValue(batch.Id); // Requery the batch to support EF navigation properties var savedBatch = GetBatch(batch.Id); ShowReadonlyDetails(savedBatch); } } }
/// <summary> /// Maps the batch data. /// </summary> /// <param name="csvData">The table data.</param> /// <exception cref="System.NotImplementedException"></exception> private int MapBatch(CSVInstance csvData) { var batchStatusClosed = Rock.Model.BatchStatus.Closed; var newBatches = new List <FinancialBatch>(); int completed = 0; ReportProgress(0, string.Format("Verifying batch import ({0:N0} already exist).", ImportedBatches.Count)); string[] row; // Uses a look-ahead enumerator: this call will move to the next record immediately while ((row = csvData.Database.FirstOrDefault()) != null) { string batchIdKey = row[BatchID]; int? batchId = batchIdKey.AsType <int?>(); if (batchId != null && !ImportedBatches.ContainsKey((int)batchId)) { var batch = new FinancialBatch(); batch.CreatedByPersonAliasId = ImportPersonAliasId; batch.ForeignKey = batchId.ToString(); batch.ForeignId = batchId; batch.Note = string.Empty; batch.Status = batchStatusClosed; batch.AccountingSystemCode = string.Empty; string name = row[BatchName] as string; if (name != null) { name = name.Trim(); batch.Name = name.Left(50); batch.CampusId = CampusList.Where(c => name.StartsWith(c.Name) || name.StartsWith(c.ShortCode)) .Select(c => (int?)c.Id).FirstOrDefault(); } string batchDateKey = row[BatchDate]; DateTime?batchDate = batchDateKey.AsType <DateTime?>(); if (batchDate != null) { batch.BatchStartDateTime = batchDate; batch.BatchEndDateTime = batchDate; } string amountKey = row[BatchAmount]; decimal?amount = amountKey.AsType <decimal?>(); if (amount != null) { batch.ControlAmount = amount.HasValue ? amount.Value : new decimal(); } newBatches.Add(batch); completed++; if (completed % (ReportingNumber * 10) < 1) { ReportProgress(0, string.Format("{0:N0} batches imported.", completed)); } else if (completed % ReportingNumber < 1) { SaveFinancialBatches(newBatches); newBatches.ForEach(b => ImportedBatches.Add((int)b.ForeignId, (int?)b.Id)); newBatches.Clear(); ReportPartialProgress(); } } } // add a default batch to use with contributions if (!ImportedBatches.ContainsKey(0)) { var defaultBatch = new FinancialBatch(); defaultBatch.CreatedDateTime = ImportDateTime; defaultBatch.CreatedByPersonAliasId = ImportPersonAliasId; defaultBatch.Status = Rock.Model.BatchStatus.Closed; defaultBatch.Name = string.Format("Default Batch (Imported {0})", ImportDateTime); defaultBatch.ControlAmount = 0.0m; defaultBatch.ForeignKey = "0"; defaultBatch.ForeignId = 0; newBatches.Add(defaultBatch); } if (newBatches.Any()) { SaveFinancialBatches(newBatches); newBatches.ForEach(b => ImportedBatches.Add((int)b.ForeignId, (int?)b.Id)); } ReportProgress(100, string.Format("Finished batch import: {0:N0} batches imported.", completed)); return(completed); }
/// <summary> /// Handles the Click event of the lbSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbSave_Click( object sender, EventArgs e ) { var rockContext = new RockContext(); var batchService = new FinancialBatchService( rockContext ); FinancialBatch batch = null; int batchId = hfBatchId.Value.AsInteger(); if ( batchId == 0 ) { batch = new FinancialBatch(); batchService.Add( batch ); } else { batch = batchService.Get( batchId ); } if ( batch != null ) { batch.Name = tbName.Text; batch.Status = (BatchStatus)ddlStatus.SelectedIndex; batch.CampusId = campCampus.SelectedCampusId; batch.BatchStartDateTime = dtpStart.SelectedDateTimeIsBlank ? null : dtpStart.SelectedDateTime; if ( dtpEnd.SelectedDateTimeIsBlank && batch.BatchStartDateTime.HasValue ) { batch.BatchEndDateTime = batch.BatchStartDateTime.Value.AddDays( 1 ); } else { batch.BatchEndDateTime = dtpEnd.SelectedDateTimeIsBlank ? null : dtpEnd.SelectedDateTime; } batch.ControlAmount = tbControlAmount.Text.AsDecimal(); batch.AccountingSystemCode = tbAccountingCode.Text; if ( !Page.IsValid || !batch.IsValid ) { // Controls will render the error messages return; } rockContext.SaveChanges(); hfBatchId.SetValue( batch.Id ); // Requery the batch to support EF navigation properties var savedBatch = GetBatch( batch.Id ); ShowReadonlyDetails( savedBatch ); } }
/// <summary> /// Gets the specified name prefix. /// </summary> /// <param name="namePrefix">The name prefix.</param> /// <param name="currencyType">Type of the currency.</param> /// <param name="creditCardType">Type of the credit card.</param> /// <param name="transactionDate">The transaction date.</param> /// <param name="batchTimeOffset">The batch time offset.</param> /// <param name="batches">The batches.</param> /// <returns></returns> public FinancialBatch Get( string namePrefix, DefinedValueCache currencyType, DefinedValueCache creditCardType, DateTime transactionDate, TimeSpan batchTimeOffset, List<FinancialBatch> batches = null ) { // Use the credit card type's batch name suffix, or if that doesn't exist, use the currency type value string ccSuffix = string.Empty; if (creditCardType != null ) { ccSuffix = creditCardType.GetAttributeValue( "BatchNameSuffix" ); if ( string.IsNullOrWhiteSpace( ccSuffix ) ) { ccSuffix = creditCardType.Value; } } if ( string.IsNullOrWhiteSpace( ccSuffix ) && currencyType != null ) { ccSuffix = currencyType.Value; } string batchName = namePrefix.Trim() + ( string.IsNullOrWhiteSpace( ccSuffix ) ? "" : " " + ccSuffix ); FinancialBatch batch = null; // If a list of batches was passed, search those first if ( batches != null ) { batch = batches .Where( b => b.Status == BatchStatus.Open && b.BatchStartDateTime <= transactionDate && b.BatchEndDateTime > transactionDate && b.Name == batchName ) .OrderByDescending( b => b.BatchStartDateTime ) .FirstOrDefault(); if ( batch != null ) { return batch; } } // If batch was not found in existing list, search database batch = Queryable() .Where( b => b.Status == BatchStatus.Open && b.BatchStartDateTime <= transactionDate && b.BatchEndDateTime > transactionDate && b.Name == batchName ) .OrderByDescending( b => b.BatchStartDateTime ) .FirstOrDefault(); // If still no batch, create a new one if ( batch == null ) { batch = new FinancialBatch(); batch.Guid = Guid.NewGuid(); batch.Name = batchName; batch.Status = BatchStatus.Open; batch.BatchStartDateTime = transactionDate.Date.Add( batchTimeOffset ); if ( batch.BatchStartDateTime > transactionDate ) { batch.BatchStartDateTime.Value.AddDays( -1 ); } batch.BatchEndDateTime = batch.BatchStartDateTime.Value.AddDays( 1 ); batch.ControlAmount = 0; Add( batch ); } // Add the batch to the list if ( batches != null ) { batches.Add( batch ); } return batch; }
/// <summary> /// Shows the financial batch summary. /// </summary> /// <param name="batch">The financial batch.</param> private void ShowReadonlyDetails( FinancialBatch batch ) { SetEditMode( false ); if ( batch != null ) { hfBatchId.SetValue( batch.Id ); SetHeadingInfo( batch, batch.Name ); string campus = string.Empty; if ( batch.Campus != null ) { campus = batch.Campus.ToString(); } decimal txnTotal = batch.Transactions.Sum( t => (decimal?)( t.TransactionDetails.Sum( d => (decimal?)d.Amount ) ?? 0.0M ) ) ?? 0.0M; decimal variance = txnTotal - batch.ControlAmount; string amountFormat = string.Format( "{0} / {1} / " + ( variance == 0.0M ? "{2}" : "<span class='label label-danger'>{2}</span>" ), txnTotal.ToString( "C2" ), batch.ControlAmount.ToString( "C2" ), variance.ToString( "C2" ) ); lDetails.Text = new DescriptionList() .Add( "Date Range", new DateRange( batch.BatchStartDateTime, batch.BatchEndDateTime ).ToString( "g" ) ) .Add( "Transaction / Control / Variance", amountFormat ) .Add( "Accounting Code", batch.AccountingSystemCode ) .Add( "Notes", batch.Note ) .Html; //Account Summary gAccounts.DataSource = batch.Transactions .SelectMany( t => t.TransactionDetails ) .GroupBy( d => new { AccountId = d.AccountId, AccountName = d.Account.Name } ) .Select( s => new { Id = s.Key.AccountId, Name = s.Key.AccountName, Amount = s.Sum( a => (decimal?)a.Amount ) ?? 0.0M } ) .OrderBy( s => s.Name ) .ToList(); gAccounts.DataBind(); //Currency Summary gCurrencyTypes.DataSource = batch.Transactions .Select( t => new { CurrencyId = t.FinancialPaymentDetail != null && t.FinancialPaymentDetail.CurrencyTypeValue != null ? t.FinancialPaymentDetail.CurrencyTypeValue.Id : 0, CurrencyName = t.FinancialPaymentDetail != null && t.FinancialPaymentDetail.CurrencyTypeValue != null ? t.FinancialPaymentDetail.CurrencyTypeValue.Value : "None", TotalAmount = t.TotalAmount } ) .GroupBy( c => new { c.CurrencyId, c.CurrencyName } ) .Select( s => new { Id = s.Key.CurrencyId, Name = s.Key.CurrencyName, Amount = s.Sum( a => (decimal?)a.TotalAmount ) ?? 0.0M } ) .OrderBy( s => s.Name ) .ToList(); gCurrencyTypes.DataBind(); } }
/// <summary>Process all transactions (payments) from Service Reef.</summary> /// <param name="message">The message that is returned depending on the result.</param> /// <param name="state">The state of the process.</param> /// <returns><see cref="WorkerResultStatus"/></returns> public void Execute(IJobExecutionContext context) { RockContext dbContext = new RockContext(); FinancialBatchService financialBatchService = new FinancialBatchService(dbContext); PersonService personService = new PersonService(dbContext); PersonAliasService personAliasService = new PersonAliasService(dbContext); FinancialAccountService financialAccountService = new FinancialAccountService(dbContext); FinancialAccountService accountService = new FinancialAccountService(dbContext); FinancialTransactionService financialTransactionService = new FinancialTransactionService(dbContext); FinancialGatewayService financialGatewayService = new FinancialGatewayService(dbContext); DefinedValueService definedValueService = new DefinedValueService(dbContext); DefinedTypeService definedTypeService = new DefinedTypeService(dbContext); TransactionService transactionService = new TransactionService(new PayPalReporting.Data.PayPalReportingContext()); // Get the datamap for loading attributes JobDataMap dataMap = context.JobDetail.JobDataMap; String warnings = string.Empty; FinancialBatch batch = null; Double totalAmount = 0; var total = 1; var processed = 0; try { DateRange dateRange = Rock.Web.UI.Controls.SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues(dataMap.GetString("DateRange") ?? "-1||"); String SRApiKey = Encryption.DecryptString(dataMap.GetString("ServiceReefAPIKey")); String SRApiSecret = Encryption.DecryptString(dataMap.GetString("ServiceReefAPISecret")); String SRApiUrl = dataMap.GetString("ServiceReefAPIURL"); DefinedValueCache transactionSource = DefinedValueCache.Read(dataMap.GetString("TransactionSource").AsGuid(), dbContext); DefinedValueCache connectionStatus = DefinedValueCache.Read(dataMap.GetString("ConnectionStatus").AsGuid(), dbContext); DefinedValueCache contribution = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION); // Setup some lookups DefinedTypeCache creditCards = DefinedTypeCache.Read(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE.AsGuid(), dbContext); DefinedTypeCache tenderType = DefinedTypeCache.Get(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE.AsGuid(), dbContext); FinancialAccount specialFund = accountService.Get(dataMap.GetString("Account").AsGuid()); FinancialGateway gateway = financialGatewayService.Get(dataMap.GetString("FinancialGateway").AsGuid()); List <FinancialAccount> trips = financialAccountService.Queryable().Where(fa => fa.ParentAccountId == specialFund.Id).OrderBy(fa => fa.Order).ToList(); // Get the trips DefinedValueCache serviceReefAccountType = DefinedValueCache.Get(dataMap.Get("ServiceReefAccountType").ToString().AsGuid()); // Setup the ServiceReef API Client var client = new RestClient(SRApiUrl); client.Authenticator = new HMACAuthenticator(SRApiKey, SRApiSecret); // Get all payments from ServiceReef var request = new RestRequest("v1/payments", Method.GET); request.AddParameter("pageSize", 100); if (dateRange.Start.HasValue) { request.AddParameter("startDate", dateRange.Start.Value.ToString("o")); } if (dateRange.End.HasValue) { request.AddParameter("endDate", dateRange.End.Value.ToString("o")); } request.AddParameter("page", 1); while (total > processed) { var response = client.Execute <Contracts.Payments>(request); if (response.StatusCode != System.Net.HttpStatusCode.OK) { throw new Exception("ServiceReef API Response: " + response.StatusDescription + " Content Length: " + response.ContentLength); } if (response.Data != null && response.Data.PageInfo != null) { total = response.Data.PageInfo.TotalRecords; foreach (Contracts.Payments.Result result in response.Data.Results) { // Process the transaction if (result.PaymentProcessorTransactionId != null) { if (result.FirstName == null || result.LastName == null) { warnings += "Missing Firstname/Lastname for ServiceReef transaction Id: " + result.TransactionId + Environment.NewLine; processed++; continue; } FinancialAccount trip = null; // Make sure we have a sub-account to go with this transaction if (result.EventId > 0) { trip = trips.Where(t => t.GlCode == result.EventCode && t.Url == result.EventUrl).FirstOrDefault(); } if (trip == null) { if (result.EventCode == null) { warnings += "Event Code is missing on the Service Reef Trip for ServiceReef transaction Id: " + result.TransactionId + Environment.NewLine; processed++; continue; } // Create the trip subaccount FinancialAccount tripFA = new FinancialAccount(); tripFA.Name = result.EventName; // Name is limited to 50 if (tripFA.Name.Length > 50) { tripFA.Name = tripFA.Name.Substring(0, 50); } tripFA.Description = "Service Reef Event. Name: " + result.EventName + " ID: " + result.EventId; tripFA.GlCode = result.EventCode; tripFA.Url = result.EventUrl; tripFA.PublicName = result.EventName; // Public Name is limited to 50 if (tripFA.PublicName.Length > 50) { tripFA.PublicName = tripFA.PublicName.Substring(0, 50); } tripFA.IsTaxDeductible = true; tripFA.IsPublic = false; tripFA.ParentAccountId = specialFund.Id; tripFA.Order = specialFund.Order + 1; tripFA.AccountTypeValueId = serviceReefAccountType.Id; // Figure out what order it should be; foreach (FinancialAccount tmpTrip in trips) { if (tmpTrip.Name.CompareTo(tripFA.Name) < 0) { tripFA.Order++; } } financialAccountService.Add(tripFA); // Now save the trip dbContext.SaveChanges(); // Increment all the rest of the Orders financialAccountService.Queryable().Where(fa => fa.Order >= tripFA.Order && fa.Id != tripFA.Id).ToList().ForEach(c => c.Order++); dbContext.SaveChanges(); trips = financialAccountService.Queryable().Where(fa => fa.ParentAccountId == specialFund.Id).OrderBy(fa => fa.Order).ToList(); trip = tripFA; } FinancialTransaction tran = financialTransactionService.Queryable().Where(tx => tx.TransactionCode == result.PaymentProcessorTransactionId).FirstOrDefault(); // We haven't processed this before so get busy! if (tran == null) { tran = new FinancialTransaction(); tran.FinancialPaymentDetail = new FinancialPaymentDetail(); if (result.Type == "CreditCard") { tran.FinancialPaymentDetail.CurrencyTypeValueId = tenderType.DefinedValues.Where(t => t.Value == "Credit Card").FirstOrDefault().Id; } else { tran.TransactionTypeValueId = tenderType.DefinedValues.Where(t => t.Value == "Credit Card").FirstOrDefault().Id; } Person person = null; // Find the person this transaction belongs to // 1. First start by determining whether this was a person // paying their application fee or contributing to themselves // because then we can just use their member info if (result.UserId > 0 && result.DonatedToUserId == result.UserId && result.DonatedToFirstName == result.FirstName && result.DonatedToLastName == result.LastName) { var memberRequest = new RestRequest("v1/members/{userId}", Method.GET); memberRequest.AddUrlSegment("userId", result.UserId.ToString()); var memberResult = client.Execute <Contracts.Member>(memberRequest); if (memberResult.Data != null && memberResult.Data.ArenaId > 0) { try { Person personMatch = personAliasService.Queryable().Where(pa => pa.AliasPersonId == memberResult.Data.ArenaId).Select(pa => pa.Person).FirstOrDefault(); if (personMatch == null) { throw new Exception("Person not found: " + memberResult.Data.ArenaId); } person = personMatch; } catch (Exception e) { warnings += "Loading the person failed transaction id " + result.TransactionId + " for " + result.FirstName + " " + result.LastName + " with the following error: " + e.Message + Environment.NewLine; processed++; continue; } } } // 2. If we didn't get a person match via their Alias Id // then just use the standard person match logic if (person == null) { String street1 = null; String postalCode = null; if (result.Address != null) { street1 = result.Address.Address1; postalCode = result.Address.Zip; } List <Person> matches = personService.GetByMatch(result.FirstName.Trim(), result.LastName.Trim(), null, result.Email, null, street1, postalCode).ToList(); if (matches.Count > 1) { // Find the oldest member record in the list person = matches.Where(p => p.ConnectionStatusValue.Value == "Member").OrderBy(p => p.Id).FirstOrDefault(); if (person == null) { // Find the oldest attendee record in the list person = matches.Where(p => p.ConnectionStatusValue.Value == "Attendee").OrderBy(p => p.Id).FirstOrDefault(); if (person == null) { person = matches.OrderBy(p => p.Id).First(); } } } else if (matches.Count == 1) { person = matches.First(); } else { // Create the person person = new Person(); person.FirstName = result.FirstName.Trim(); person.LastName = result.LastName.Trim(); if (result.Email.IsValidEmail()) { person.Email = result.Email.Trim(); } person.RecordTypeValueId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_RECORD_TYPE_PERSON.AsGuid()).Id; person.ConnectionStatusValueId = connectionStatus.Id; person.RecordStatusValueId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_ACTIVE.AsGuid()).Id; Group family = PersonService.SaveNewPerson(person, dbContext); GroupLocation location = new GroupLocation(); location.GroupLocationTypeValueId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.GROUP_LOCATION_TYPE_HOME).Id; location.Location = new Location() { Street1 = result.Address.Address1, Street2 = result.Address.Address2, City = result.Address.City, State = result.Address.State, PostalCode = result.Address.Zip, Country = result.Address.Country }; family.CampusId = CampusCache.All().FirstOrDefault().Id; family.GroupLocations.Add(location); dbContext.SaveChanges(); } } // Get details about the transaction from our PayPal report table Transaction tx = transactionService.Get(result.PaymentProcessorTransactionId); if (tx != null) { if (tx.TenderType.Contains("ACH")) { result.Type = "ACH"; result.Method = null; } else { result.Type = "Credit Card"; result.Method = tx.TenderType; } } else { // Defaults result.Type = "Credit Card"; result.Method = "Visa"; warnings += "Unable to find transaction in _org_secc_PaypalReporting_Transaction table: " + result.TransactionId + Environment.NewLine; } // If we don't have a batch, create one if (batch == null) { batch = new FinancialBatch(); batch.BatchStartDateTime = result.Date; batch.BatchEndDateTime = DateTime.Now; batch.Name = "Service Reef Payments"; batch.Status = BatchStatus.Open; financialBatchService.Add(batch); dbContext.SaveChanges(); } // Complete the FinancialTransaction tran.AuthorizedPersonAliasId = person.PrimaryAliasId; tran.BatchId = batch.Id; tran.Summary = "F" + specialFund.Id + ":$" + result.Amount.ToString(); tran.TransactionDateTime = result.Date; tran.FinancialGatewayId = gateway.Id; FinancialTransactionDetail financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.AccountId = trip.Id; financialTransactionDetail.Amount = result.Amount.ToString().AsDecimal(); tran.TransactionDetails.Add(financialTransactionDetail); tran.TransactionTypeValueId = contribution.Id; tran.FinancialPaymentDetail = new FinancialPaymentDetail(); tran.FinancialPaymentDetail.CurrencyTypeValueId = tenderType.DefinedValues.Where(type => type.Value.ToLower() == result.Type.ToLower()).FirstOrDefault().Id; if (result.Method != null) { tran.FinancialPaymentDetail.CreditCardTypeValueId = creditCards.DefinedValues.Where(card => card.Value.ToLower() == result.Method.ToLower()).FirstOrDefault().Id; } tran.TransactionCode = result.PaymentProcessorTransactionId; tran.SourceTypeValueId = transactionSource.Id; financialTransactionService.Add(tran); dbContext.SaveChanges(); totalAmount += result.Amount; } } processed++; } } else { total = 0; } // Update the page number for the next request var pageParam = request.Parameters.Where(p => p.Name == "page").FirstOrDefault(); pageParam.Value = (int)pageParam.Value + 1; } } catch (Exception ex) { throw new Exception("ServiceReef Job Failed", ex); } finally { if (batch != null && totalAmount > 0) { batch.ControlAmount = (Decimal)totalAmount; } dbContext.SaveChanges(); } if (warnings.Length > 0) { throw new Exception(warnings); } context.Result = "Successfully imported " + processed + " transactions."; }
/// <summary> /// Shows the detail. /// </summary> /// <param name="batchId">The financial batch identifier.</param> public void ShowDetail(int batchId) { FinancialBatch batch = null; bool editAllowed = true; if (!batchId.Equals(0)) { batch = GetBatch(batchId); if (batch != null) { editAllowed = batch.IsAuthorized(Authorization.EDIT, CurrentPerson); pdAuditDetails.SetEntity(batch, ResolveRockUrl("~")); } } if (batch == null) { batch = new FinancialBatch { Id = 0, Status = BatchStatus.Open }; // hide the panel drawer that show created and last modified dates pdAuditDetails.Visible = false; } hfBatchId.Value = batch.Id.ToString(); bool readOnly = false; nbEditModeMessage.Text = string.Empty; if (!editAllowed || !IsUserAuthorized(Authorization.EDIT)) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed(FinancialBatch.FriendlyTypeName); } else if (batch.Status == BatchStatus.Closed) { if (!batch.IsAuthorized("ReopenBatch", this.CurrentPerson)) { readOnly = true; nbEditModeMessage.Text = "Batch is closed and requires authorization to re-open before editing."; } } if (readOnly) { lbEdit.Visible = false; ShowReadonlyDetails(batch); } else { lbEdit.Visible = true; if (batch.Id > 0) { ShowReadonlyDetails(batch); } else { ShowEditDetails(batch); } } lbSave.Visible = !readOnly; }
/// <summary> /// Raises the <see cref="E:System.Web.UI.Control.Load" /> event. /// </summary> /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnLoad( EventArgs e ) { base.OnLoad( e ); bool promptWithFilter = true; var contextEntity = this.ContextEntity(); if ( contextEntity != null ) { if ( contextEntity is Person ) { _person = contextEntity as Person; promptWithFilter = false; } else if ( contextEntity is FinancialBatch ) { _batch = contextEntity as FinancialBatch; gfTransactions.Visible = false; promptWithFilter = false; } else if ( contextEntity is FinancialScheduledTransaction ) { _scheduledTxn = contextEntity as FinancialScheduledTransaction; gfTransactions.Visible = false; promptWithFilter = false; } } if ( !Page.IsPostBack ) { BindFilter(); if ( promptWithFilter && gfTransactions.Visible ) { //// NOTE: Special Case for this List Block since there could be a very large number of transactions: //// If the filter is shown and we aren't filtering by anything else, don't automatically populate the grid. Wait for them to hit apply on the filter gfTransactions.Show(); } else { BindGrid(); } } if ( _canEdit && _batch != null ) { string script = string.Format( @" $('#{0}').change(function( e ){{ var count = $(""#{1} input[id$='_cbSelect_0']:checked"").length; if (count == 0) {{ eval({2}); }} else {{ var $ddl = $(this); if ($ddl.val() != '') {{ Rock.dialogs.confirm('Are you sure you want to move the selected transactions to a new batch (the control amounts on each batch will be updated to reflect the moved transaction\'s amounts)?', function (result) {{ if (result) {{ eval({2}); }} $ddl.val(''); }}); }} }} }}); ", _ddlMove.ClientID, gTransactions.ClientID, Page.ClientScript.GetPostBackEventReference( this, "MoveTransactions" ) ); ScriptManager.RegisterStartupScript( _ddlMove, _ddlMove.GetType(), "moveTransaction", script, true ); } }
/// <summary> /// Shows the edit details. /// </summary> /// <param name="batch">The financial batch.</param> protected void ShowEditDetails(FinancialBatch batch) { if (batch == null || batch.Id == 0) { // if the "BatchNames" configuration setting is set, and this is a new batch present a DropDown of BatchNames instead of a text box var batchNamesDefinedTypeGuid = this.GetAttributeValue("BatchNames").AsGuidOrNull(); ddlBatchName.Visible = false; tbName.Visible = true; if (batchNamesDefinedTypeGuid.HasValue) { var batchNamesDefinedType = DefinedTypeCache.Read(batchNamesDefinedTypeGuid.Value); if (batchNamesDefinedType != null) { ddlBatchName.BindToDefinedType(batchNamesDefinedType, true, false); if (batchNamesDefinedType.DefinedValues.Any(a => !string.IsNullOrWhiteSpace(a.Value))) { ddlBatchName.Visible = true; tbName.Visible = false; } } } } if (batch != null) { hfBatchId.Value = batch.Id.ToString(); string title = batch.Id > 0 ? ActionTitle.Edit(FinancialBatch.FriendlyTypeName) : ActionTitle.Add(FinancialBatch.FriendlyTypeName); SetHeadingInfo(batch, title); SetEditMode(true); tbName.Text = batch.Name; ddlStatus.BindToEnum <BatchStatus>(); ddlStatus.SelectedIndex = (int)(BatchStatus)batch.Status; ddlStatus.Enabled = true; if (batch.Status == BatchStatus.Closed) { if (!batch.IsAuthorized("ReopenBatch", this.CurrentPerson)) { ddlStatus.Enabled = false; } } if (batch.IsAutomated == true && batch.Status == BatchStatus.Pending) { ddlStatus.Enabled = false; } campCampus.Campuses = CampusCache.All(); if (batch.CampusId.HasValue) { campCampus.SetValue(batch.CampusId.Value); } tbControlAmount.Text = batch.ControlAmount.ToString("N2"); dtpStart.SelectedDateTime = batch.BatchStartDateTime; dtpEnd.SelectedDateTime = batch.BatchEndDateTime; tbAccountingCode.Text = batch.AccountingSystemCode; tbNote.Text = batch.Note; SetEditableForBatchStatus(ddlStatus.SelectedValueAsEnum <BatchStatus>()); } }
/// <summary> /// Handles the Click event of the btnSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param> private void btnSave_Click(object sender, RoutedEventArgs e) { try { RockConfig rockConfig = RockConfig.Load(); RockRestClient client = new RockRestClient(rockConfig.RockBaseUrl); client.Login(rockConfig.Username, rockConfig.Password); FinancialBatch financialBatch = null; if (SelectedFinancialBatchId.Equals(0)) { financialBatch = new FinancialBatch { Id = 0, Guid = Guid.NewGuid(), Status = BatchStatus.Pending, CreatedByPersonId = LoggedInPerson.Id }; } else { financialBatch = client.GetData <FinancialBatch>(string.Format("api/FinancialBatches/{0}", SelectedFinancialBatchId)); } txtBatchName.Text = txtBatchName.Text.Trim(); financialBatch.Name = txtBatchName.Text; Campus selectedCampus = cbCampus.SelectedItem as Campus; if (selectedCampus.Id > 0) { financialBatch.CampusId = selectedCampus.Id; } else { financialBatch.CampusId = null; } financialBatch.BatchStartDateTime = dpBatchDate.SelectedDate; if (!string.IsNullOrWhiteSpace(txtControlAmount.Text)) { financialBatch.ControlAmount = decimal.Parse(txtControlAmount.Text.Replace("$", string.Empty)); } else { financialBatch.ControlAmount = 0.00M; } if (financialBatch.Id == 0) { client.PostData <FinancialBatch>("api/FinancialBatches/", financialBatch); } else { client.PutData <FinancialBatch>("api/FinancialBatches/", financialBatch); } if (SelectedFinancialBatchId.Equals(0)) { // refetch the batch to get the Id if it was just Inserted financialBatch = client.GetDataByGuid <FinancialBatch>("api/FinancialBatches", financialBatch.Guid); SelectedFinancialBatchId = financialBatch.Id; } LoadFinancialBatchesGrid(); ShowBatch(false); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation); } }
/// <summary> /// Raises the <see cref="E:System.Web.UI.Control.Load" /> event. /// </summary> /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnLoad( EventArgs e ) { base.OnLoad( e ); nbClosedWarning.Visible = false; nbResult.Visible = false; var contextEntity = this.ContextEntity(); if ( contextEntity != null ) { if ( contextEntity is Person ) { _person = contextEntity as Person; } else if ( contextEntity is FinancialBatch ) { _batch = contextEntity as FinancialBatch; gfTransactions.Visible = false; } else if ( contextEntity is FinancialScheduledTransaction ) { _scheduledTxn = contextEntity as FinancialScheduledTransaction; gfTransactions.Visible = false; } else if ( contextEntity is Registration ) { _registration = contextEntity as Registration; gfTransactions.Visible = false; } } if ( !Page.IsPostBack ) { BindFilter(); BindGrid(); } else { ShowDialog(); } if ( _canEdit && _batch != null ) { string script = string.Format( @" $('#{0}').change(function( e ){{ var count = $(""#{1} input[id$='_cbSelect_0']:checked"").length; if (count == 0) {{ {2}; }} else {{ var $ddl = $(this); if ($ddl.val() != '') {{ Rock.dialogs.confirm('Are you sure you want to move the selected transactions to a new batch (the control amounts on each batch will be updated to reflect the moved transaction\'s amounts)?', function (result) {{ if (result) {{ {2}; }} $ddl.val(''); }}); }} }} }}); ", _ddlMove.ClientID, gTransactions.ClientID, Page.ClientScript.GetPostBackEventReference( this, "MoveTransactions" ) ); ScriptManager.RegisterStartupScript( _ddlMove, _ddlMove.GetType(), "moveTransaction", script, true ); } }
/// <summary> /// Maps the batch data. /// </summary> /// <param name="tableData">The table data.</param> /// <exception cref="System.NotImplementedException"></exception> private void MapBatch( IQueryable<Row> tableData ) { var batchStatusClosed = Rock.Model.BatchStatus.Closed; var newBatches = new List<FinancialBatch>(); int completed = 0; int totalRows = tableData.Count(); int percentage = ( totalRows - 1 ) / 100 + 1; ReportProgress( 0, string.Format( "Verifying batch import ({0:N0} found, {1:N0} already exist).", totalRows, ImportedBatches.Count ) ); foreach ( var row in tableData.Where( r => r != null ) ) { int? batchId = row["BatchID"] as int?; if ( batchId != null && !ImportedBatches.ContainsKey( (int)batchId ) ) { var batch = new FinancialBatch(); batch.CreatedByPersonAliasId = ImportPersonAliasId; batch.ForeignKey = batchId.ToString(); batch.ForeignId = batchId; batch.Note = string.Empty; batch.Status = batchStatusClosed; batch.AccountingSystemCode = string.Empty; string name = row["BatchName"] as string; if ( name != null ) { name = name.Trim(); batch.Name = name.Left( 50 ); batch.CampusId = CampusList.Where( c => name.StartsWith( c.Name ) || name.StartsWith( c.ShortCode ) ) .Select( c => (int?)c.Id ).FirstOrDefault(); } DateTime? batchDate = row["BatchDate"] as DateTime?; if ( batchDate != null ) { batch.BatchStartDateTime = batchDate; batch.BatchEndDateTime = batchDate; } decimal? amount = row["BatchAmount"] as decimal?; if ( amount != null ) { batch.ControlAmount = amount.HasValue ? amount.Value : new decimal(); } newBatches.Add( batch ); completed++; if ( completed % percentage < 1 ) { int percentComplete = completed / percentage; ReportProgress( percentComplete, string.Format( "{0:N0} batches imported ({1}% complete).", completed, percentComplete ) ); } else if ( completed % ReportingNumber < 1 ) { SaveFinancialBatches( newBatches ); newBatches.ForEach( b => ImportedBatches.Add( (int)b.ForeignId, (int?)b.Id ) ); newBatches.Clear(); ReportPartialProgress(); } } } // add a default batch to use with contributions if ( !ImportedBatches.ContainsKey( 0 ) ) { var defaultBatch = new FinancialBatch(); defaultBatch.CreatedDateTime = ImportDateTime; defaultBatch.CreatedByPersonAliasId = ImportPersonAliasId; defaultBatch.Status = Rock.Model.BatchStatus.Closed; defaultBatch.Name = string.Format( "Default Batch (Imported {0})", ImportDateTime ); defaultBatch.ControlAmount = 0.0m; defaultBatch.ForeignKey = "0"; defaultBatch.ForeignId = 0; newBatches.Add( defaultBatch ); } if ( newBatches.Any() ) { SaveFinancialBatches( newBatches ); newBatches.ForEach( b => ImportedBatches.Add( (int)b.ForeignId, (int?)b.Id ) ); } ReportProgress( 100, string.Format( "Finished batch import: {0:N0} batches imported.", completed ) ); }
/// <summary> /// Handles the Click event of the lbSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbSave_Click( object sender, EventArgs e ) { var rockContext = new RockContext(); var batchService = new FinancialBatchService( rockContext ); FinancialBatch batch = null; var changes = new List<string>(); int batchId = hfBatchId.Value.AsInteger(); if ( batchId == 0 ) { batch = new FinancialBatch(); batchService.Add( batch ); changes.Add( "Created the batch" ); } else { batch = batchService.Get( batchId ); } if ( batch != null ) { History.EvaluateChange( changes, "Batch Name", batch.Name, tbName.Text ); batch.Name = tbName.Text; BatchStatus batchStatus = (BatchStatus)ddlStatus.SelectedIndex; History.EvaluateChange( changes, "Status", batch.Status, batchStatus ); batch.Status = batchStatus; CampusCache oldCampus = null; if ( batch.CampusId.HasValue ) { oldCampus = CampusCache.Read( batch.CampusId.Value ); } CampusCache newCampus = null; if ( campCampus.SelectedCampusId.HasValue ) { newCampus = CampusCache.Read( campCampus.SelectedCampusId.Value ); } History.EvaluateChange( changes, "Campus", oldCampus != null ? oldCampus.Name : "None", newCampus != null ? newCampus.Name : "None" ); batch.CampusId = campCampus.SelectedCampusId; DateTime? startDateTime = dtpStart.SelectedDateTimeIsBlank ? null : dtpStart.SelectedDateTime; History.EvaluateChange( changes, "Start Date/Time", batch.BatchStartDateTime, startDateTime ); batch.BatchStartDateTime = startDateTime; DateTime? endDateTime; if ( dtpEnd.SelectedDateTimeIsBlank && batch.BatchStartDateTime.HasValue ) { endDateTime = batch.BatchStartDateTime.Value.AddDays( 1 ); } else { endDateTime = dtpEnd.SelectedDateTimeIsBlank ? null : dtpEnd.SelectedDateTime; } History.EvaluateChange( changes, "End Date/Time", batch.BatchEndDateTime, endDateTime ); batch.BatchEndDateTime = endDateTime; decimal controlAmount = tbControlAmount.Text.AsDecimal(); History.EvaluateChange( changes, "Control Amount", batch.ControlAmount.FormatAsCurrency(), controlAmount.FormatAsCurrency() ); batch.ControlAmount = controlAmount; History.EvaluateChange( changes, "Accounting System Code", batch.AccountingSystemCode, tbAccountingCode.Text ); batch.AccountingSystemCode = tbAccountingCode.Text; History.EvaluateChange( changes, "Notes", batch.Note, tbNote.Text ); batch.Note = tbNote.Text; cvBatch.IsValid = batch.IsValid; if ( !Page.IsValid || !batch.IsValid ) { cvBatch.ErrorMessage = batch.ValidationResults.Select( a => a.ErrorMessage ).ToList().AsDelimited( "<br />" ); return; } rockContext.WrapTransaction( () => { if ( rockContext.SaveChanges() > 0 ) { if ( changes.Any() ) { HistoryService.SaveChanges( rockContext, typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, changes ); } } } ); if ( batchId == 0 ) { // If created a new batch, navigate to same page so that transaction list displays correctly var pageReference = CurrentPageReference; pageReference.Parameters.AddOrReplace( "batchId", batch.Id.ToString() ); NavigateToPage( pageReference ); } else { hfBatchId.SetValue( batch.Id ); // Requery the batch to support EF navigation properties var savedBatch = GetBatch( batch.Id ); ShowReadonlyDetails( savedBatch ); // If there is a batch context item, update the context's properties with new values var contextObjects = new Dictionary<string, object>(); foreach ( var contextEntityType in RockPage.GetContextEntityTypes() ) { var contextEntity = RockPage.GetCurrentContext( contextEntityType ); if ( contextEntity is FinancialBatch ) { var contextBatch = contextEntity as FinancialBatch; contextBatch.CopyPropertiesFrom( batch ); } } // Then refresh transaction list RockPage.UpdateBlocks( "~/Blocks/Finance/TransactionList.ascx" ); } } }
/// <summary> /// Handles the Click event of the btnSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param> private void btnSave_Click(object sender, RoutedEventArgs e) { try { RockConfig rockConfig = RockConfig.Load(); RockRestClient client = new RockRestClient(rockConfig.RockBaseUrl); client.Login(rockConfig.Username, rockConfig.Password); FinancialBatch financialBatch = null; if (SelectedFinancialBatch == null || SelectedFinancialBatch.Id == 0) { financialBatch = new FinancialBatch { Id = 0, Guid = Guid.NewGuid(), Status = BatchStatus.Pending, CreatedByPersonAliasId = LoggedInPerson.PrimaryAliasId }; } else { financialBatch = client.GetData <FinancialBatch>(string.Format("api/FinancialBatches/{0}", SelectedFinancialBatch.Id)); } txtBatchName.Text = txtBatchName.Text.Trim(); if (string.IsNullOrWhiteSpace(txtBatchName.Text)) { txtBatchName.Style = this.FindResource("textboxStyleError") as Style; return; } else { txtBatchName.Style = this.FindResource("textboxStyle") as Style; } financialBatch.Name = txtBatchName.Text; Campus selectedCampus = cbCampus.SelectedItem as Campus; if (selectedCampus.Id > 0) { financialBatch.CampusId = selectedCampus.Id; } else { financialBatch.CampusId = null; } financialBatch.BatchStartDateTime = dpBatchDate.SelectedDate; if (!string.IsNullOrWhiteSpace(txtControlAmount.Text)) { financialBatch.ControlAmount = decimal.Parse(txtControlAmount.Text.Replace("$", string.Empty)); } else { financialBatch.ControlAmount = 0.00M; } txtNote.Text = txtNote.Text.Trim(); financialBatch.Note = txtNote.Text; if (financialBatch.Id == 0) { client.PostData <FinancialBatch>("api/FinancialBatches/", financialBatch); } else { client.PutData <FinancialBatch>("api/FinancialBatches/", financialBatch, financialBatch.Id); } if (SelectedFinancialBatch == null || SelectedFinancialBatch.Id == 0) { // refetch the batch to get the Id if it was just Inserted financialBatch = client.GetDataByGuid <FinancialBatch>("api/FinancialBatches", financialBatch.Guid); SelectedFinancialBatch = financialBatch; } LoadFinancialBatchesGrid(); UpdateBatchUI(financialBatch); ShowBatch(false); } catch (Exception ex) { ShowException(ex); } }
/// <summary> /// Sets the heading information. /// </summary> /// <param name="batch">The batch.</param> /// <param name="title">The title.</param> private void SetHeadingInfo( FinancialBatch batch, string title ) { lTitle.Text = title.FormatAsHtmlTitle(); hlStatus.Text = batch.Status.ConvertToString(); switch ( batch.Status ) { case BatchStatus.Pending: hlStatus.LabelType = LabelType.Danger; break; case BatchStatus.Open: hlStatus.LabelType = LabelType.Warning; break; case BatchStatus.Closed: hlStatus.LabelType = LabelType.Default; break; } if ( batch.Campus != null ) { hlCampus.Visible = true; hlCampus.Text = batch.Campus.Name; } else { hlCampus.Visible = false; } hlBatchId.Text = string.Format( "Batch #{0}", batch.Id.ToString() ); hlBatchId.Visible = batch.Id != 0; }
/// <summary> /// Handles the SelectionChanged event of the grdBatches control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="SelectionChangedEventArgs"/> instance containing the event data.</param> private void grdBatches_SelectionChanged(object sender, SelectionChangedEventArgs e) { FinancialBatch selectedBatch = grdBatches.SelectedValue as FinancialBatch; UpdateBatchUI(selectedBatch); }
/// <summary> /// Shows the detail. /// </summary> /// <param name="batchId">The financial batch identifier.</param> public void ShowDetail( int batchId ) { FinancialBatch batch = null; bool editAllowed = true; if ( !batchId.Equals( 0 ) ) { batch = GetBatch( batchId ); if ( batch != null ) { editAllowed = batch.IsAuthorized( Authorization.EDIT, CurrentPerson ); } } if ( batch == null ) { batch = new FinancialBatch { Id = 0 }; } hfBatchId.Value = batch.Id.ToString(); bool readOnly = false; nbEditModeMessage.Text = string.Empty; if ( !editAllowed || !IsUserAuthorized( Authorization.EDIT ) ) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( FinancialBatch.FriendlyTypeName ); } if ( readOnly ) { lbEdit.Visible = false; ShowReadonlyDetails( batch ); } else { lbEdit.Visible = true; if ( batch.Id > 0 ) { ShowReadonlyDetails( batch ); } else { ShowEditDetails( batch ); } } lbSave.Visible = !readOnly; }
/// <summary> /// Gets the by name and date. /// </summary> /// <param name="batchName">Name of the batch.</param> /// <param name="transactionDate">The transaction date.</param> /// <param name="batchTimeOffset">The batch time offset.</param> /// <param name="batches">The batches.</param> /// <returns></returns> public FinancialBatch GetByNameAndDate( string batchName, DateTime transactionDate, TimeSpan batchTimeOffset, List<FinancialBatch> batches = null ) { FinancialBatch batch = null; // If a list of batches was passed, search those first if ( batches != null ) { batch = batches .Where( b => b.Status == BatchStatus.Open && b.BatchStartDateTime <= transactionDate && b.BatchEndDateTime > transactionDate && b.Name == batchName ) .OrderByDescending( b => b.BatchStartDateTime ) .FirstOrDefault(); if ( batch != null ) { return batch; } } // If batch was not found in existing list, search database batch = Queryable() .Where( b => b.Status == BatchStatus.Open && b.BatchStartDateTime <= transactionDate && b.BatchEndDateTime > transactionDate && b.Name == batchName ) .OrderByDescending( b => b.BatchStartDateTime ) .FirstOrDefault(); // If still no batch, create a new one if ( batch == null ) { batch = new FinancialBatch(); batch.Guid = Guid.NewGuid(); batch.Name = batchName; batch.Status = BatchStatus.Open; var batchStartDateTime = transactionDate.Date.Add( batchTimeOffset ); if ( batchStartDateTime > transactionDate ) { batchStartDateTime = batchStartDateTime.AddDays( -1 ); } batch.BatchStartDateTime = batchStartDateTime; batch.BatchEndDateTime = batchStartDateTime.AddDays( 1 ); batch.ControlAmount = 0; Add( batch ); } // Add the batch to the list if ( batches != null ) { batches.Add( batch ); } return batch; }