/// <summary> /// Looks for gifts where the donor is anoymous but the gift is not marked as confidential and asks the user if they want to continue. /// (Make sure GetDataFromControls is called before this method so that AMainDS is up-to-date.) /// </summary> /// <param name="AMainDS"></param> public static bool CanContinueWithAnyAnonymousDonors(GiftBatchTDS AMainDS) { GiftBatchTDSAGiftDetailTable UnConfidentialGiftsWithAnonymousDonors = new GiftBatchTDSAGiftDetailTable(); foreach (GiftBatchTDSAGiftDetailRow Row in AMainDS.AGiftDetail.Rows) { if (!Row.ConfidentialGiftFlag) { PPartnerRow PartnerRow = (PPartnerRow)AMainDS.DonorPartners.Rows.Find(Row.DonorKey); if ((PartnerRow != null) && PartnerRow.AnonymousDonor) { UnConfidentialGiftsWithAnonymousDonors.Rows.Add((object[])Row.ItemArray.Clone()); } } } if (UnConfidentialGiftsWithAnonymousDonors.Rows.Count > 0) { string Message = string.Empty; DataView dv = UnConfidentialGiftsWithAnonymousDonors.DefaultView; dv.Sort = GiftBatchTDSAGiftDetailTable.GetGiftTransactionNumberDBName() + " ASC"; DataTable sortedDT = dv.ToTable(); if (UnConfidentialGiftsWithAnonymousDonors.Rows.Count == 1) { Message = Catalog.GetString( "The gift listed below in this batch is not marked as confidential but the donor has asked to remain anonymous."); } else { Message = Catalog.GetString( "The gifts listed below in this batch are not marked as confidential but the donors have asked to remain anonymous."); } Message += "\n\n"; foreach (DataRow UnConfidentialGifts in sortedDT.Rows) { Message += Catalog.GetString("Batch: ") + UnConfidentialGifts[GiftBatchTDSAGiftDetailTable.GetBatchNumberDBName()] + "; " + Catalog.GetString("Gift: ") + UnConfidentialGifts[GiftBatchTDSAGiftDetailTable.GetGiftTransactionNumberDBName()] + "; " + Catalog.GetString("Donor: ") + UnConfidentialGifts[GiftBatchTDSAGiftDetailTable.GetDonorNameDBName()] + " (" + UnConfidentialGifts[GiftBatchTDSAGiftDetailTable.GetDonorKeyDBName()] + ")\n"; } Message += "\n" + Catalog.GetString("Do you want to continue with posting anyway?"); if (MessageBox.Show( Message, Catalog.GetString("Anonymous Donor Warning"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) { return(false); } } return(true); }
public void SpeedTestLoadIntoTypedTable() { TDBTransaction ReadTransaction = null; DateTime before = DateTime.Now; DateTime after = DateTime.Now; GiftBatchTDS ds = new GiftBatchTDS(); DBAccess.GDBAccessObj.GetNewOrExistingAutoReadTransaction( IsolationLevel.ReadCommitted, TEnforceIsolationLevel.eilMinimum, ref ReadTransaction, delegate { string sql = "SELECT PUB_a_gift_detail.*, false AS AlreadyMatched, PUB_a_gift_batch.a_batch_status_c AS BatchStatus " + "FROM PUB_a_gift_batch, PUB_a_gift_detail " + "WHERE PUB_a_gift_detail.a_ledger_number_i = PUB_a_gift_batch.a_ledger_number_i AND PUB_a_gift_detail.a_batch_number_i = PUB_a_gift_batch.a_batch_number_i"; before = DateTime.Now; DataTable untyped = DBAccess.GDBAccessObj.SelectDT(sql, "test", ReadTransaction); after = DateTime.Now; TLogging.Log(String.Format("loading all {0} gift details into an untyped table took {1} milliseconds", untyped.Rows.Count, (after.Subtract(before)).TotalMilliseconds)); GiftBatchTDSAGiftDetailTable typed = new GiftBatchTDSAGiftDetailTable(); before = DateTime.Now; DBAccess.GDBAccessObj.SelectDT(typed, sql, ReadTransaction, new OdbcParameter[0], 0, 0); after = DateTime.Now; TLogging.Log(String.Format("loading all {0} gift details into a typed table took {1} milliseconds", typed.Rows.Count, (after.Subtract(before)).TotalMilliseconds)); AMotivationDetailAccess.LoadAll(ds, ReadTransaction); before = DateTime.Now; DBAccess.GDBAccessObj.Select(ds, sql, ds.AGiftDetail.TableName, ReadTransaction); after = DateTime.Now; }); TLogging.Log(String.Format("loading all {0} gift details into a typed dataset took {1} milliseconds", ds.AGiftDetail.Rows.Count, (after.Subtract(before)).TotalMilliseconds)); before = DateTime.Now; GiftBatchTDS ds2 = new GiftBatchTDS(); ds2.Merge(ds.AGiftDetail); after = DateTime.Now; TLogging.Log(String.Format("merging typed table into other dataset took {0} milliseconds", (after.Subtract(before)).TotalMilliseconds)); }
private static string GetExWorkersString(GiftBatchAction?AAction, string AExWorkerSpecialType, DataTable AExWorkers) { string ReturnValue = string.Empty; if (AExWorkers.Rows.Count == 0) { return(ReturnValue); } DataView dv = AExWorkers.DefaultView; dv.Sort = GiftBatchTDSAGiftDetailTable.GetGiftTransactionNumberDBName() + " ASC"; DataTable sortedDT = dv.ToTable(); if ((AAction == GiftBatchAction.POSTING) || (AAction == GiftBatchAction.SUBMITTING)) { if (AExWorkers.Rows.Count == 1) { ReturnValue = string.Format(Catalog.GetString( "The gift listed below has a recipient who has a Special Type beginning with {0}:"), AExWorkerSpecialType); } else { ReturnValue = string.Format(Catalog.GetString( "The gifts listed below have recipients who have a Special Type beginning with {0}:"), AExWorkerSpecialType); } } else { if (AExWorkers.Rows.Count == 1) { ReturnValue = string.Format(Catalog.GetString( "The unsaved gift listed below is for a recipient who has Special Type beginning with {0}:"), AExWorkerSpecialType); } else { ReturnValue = string.Format(Catalog.GetString( "The unsaved gifts listed below are for recipients who have Special Type beginning with {0}:"), AExWorkerSpecialType); } } ReturnValue += "\n\n"; foreach (DataRow Row in sortedDT.Rows) { ReturnValue += Catalog.GetString("Batch: ") + Row[GiftBatchTDSAGiftDetailTable.GetBatchNumberDBName()] + "; " + Catalog.GetString("Gift: ") + Row[GiftBatchTDSAGiftDetailTable.GetGiftTransactionNumberDBName()] + "; " + Catalog.GetString("Recipient: ") + Row[GiftBatchTDSAGiftDetailTable.GetRecipientDescriptionDBName()] + " (" + Row[GiftBatchTDSAGiftDetailTable.GetRecipientKeyDBName()] + ")\n"; } return(ReturnValue += "\n"); }
/// <summary> /// Wrapper method to handle returned bool value from remoting call to ImportGiftBatches /// </summary> /// <param name="ARequestParams"></param> /// <param name="AImportString"></param> /// <param name="AMessages"></param> /// <param name="ok"></param> /// <param name="AGUIRefreshRequired"></param> /// <param name="ANeedRecipientLedgerNumber"></param> private void ImportGiftBatches(Hashtable ARequestParams, string AImportString, out TVerificationResultCollection AMessages, out bool ok, out bool AGUIRefreshRequired, out GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber) { TVerificationResultCollection AResultMessages; bool ImportIsSuccessful; ImportIsSuccessful = TRemote.MFinance.Gift.WebConnectors.ImportGiftBatches( ARequestParams, AImportString, out ANeedRecipientLedgerNumber, out AGUIRefreshRequired, out AResultMessages); ok = ImportIsSuccessful; AMessages = AResultMessages; }
private static string GetExWorkersString(GiftBatchAction?AAction, string AExWorkerSpecialType, DataTable AExWorkers) { string ReturnValue = string.Empty; if (AExWorkers.Rows.Count == 0) { return(ReturnValue); } DataView dv = AExWorkers.DefaultView; dv.Sort = string.Format("{0} ASC, {1} ASC", GiftBatchTDSAGiftDetailTable.GetGiftTransactionNumberDBName(), GiftBatchTDSAGiftDetailTable.GetDetailNumberDBName()); DataTable sortedDT = dv.ToTable(); ReturnValue = String.Format(Catalog.GetString("The {0}gift(s) listed below have recipient(s) with a Special Type beginning with {1}:{2}{2}"), ((AAction == GiftBatchAction.POSTING) || (AAction == GiftBatchAction.SUBMITTING)) ? "" : "unsaved ", AExWorkerSpecialType, Environment.NewLine); ReturnValue += new String('-', 86) + Environment.NewLine; foreach (DataRow Row in sortedDT.Rows) { ReturnValue += Catalog.GetString("Batch: ") + Row[GiftBatchTDSAGiftDetailTable.GetBatchNumberDBName()] + "; " + Catalog.GetString("Gift: ") + Row[GiftBatchTDSAGiftDetailTable.GetGiftTransactionNumberDBName()] + "; " + Catalog.GetString("Detail: ") + Row[GiftBatchTDSAGiftDetailTable.GetDetailNumberDBName()] + "; " + Catalog.GetString("Recipient: ") + Row[GiftBatchTDSAGiftDetailTable.GetRecipientDescriptionDBName()] + " (" + Row[GiftBatchTDSAGiftDetailTable.GetRecipientKeyDBName()] + ")" + Environment.NewLine; } ReturnValue += new String('-', 86); return(ReturnValue); }
/// <summary> /// this supports the batch export files from Petra 2.x. /// Each line starts with a type specifier, B for batch, J for journal, T for transaction /// </summary> public void ImportBatches(TGiftImportDataSourceEnum AImportSource) { bool ok = false; String importString; String impOptions; OpenFileDialog dialog = null; if (FPetraUtilsObject.HasChanges) { // saving failed, therefore do not try to post MessageBox.Show(Catalog.GetString("Please save before calling this function!"), Catalog.GetString( "Failure"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } FdlgSeparator = new TDlgSelectCSVSeparator(false); if (AImportSource == TGiftImportDataSourceEnum.FromClipboard) { importString = Clipboard.GetText(TextDataFormat.UnicodeText); if ((importString == null) || (importString.Length == 0)) { MessageBox.Show(Catalog.GetString("Please first copy data from your spreadsheet application!"), Catalog.GetString("Failure"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } impOptions = TUserDefaults.GetStringDefault("Imp Options", ";American"); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator = new TDlgSelectCSVSeparator(false); FdlgSeparator.SelectedSeparator = "\t"; FdlgSeparator.CSVData = importString; FdlgSeparator.DateFormat = dateFormatString; if (impOptions.Length > 1) { FdlgSeparator.NumberFormat = impOptions.Substring(1); } } else if (AImportSource == TGiftImportDataSourceEnum.FromFile) { dialog = new OpenFileDialog(); string exportPath = TClientSettings.GetExportPath(); string fullPath = TUserDefaults.GetStringDefault("Imp Filename", exportPath + Path.DirectorySeparatorChar + "import.csv"); TImportExportDialogs.SetOpenFileDialogFilePathAndName(dialog, fullPath, exportPath); dialog.Title = Catalog.GetString("Import Batches from CSV File"); dialog.Filter = Catalog.GetString("Gift Batches files (*.csv)|*.csv"); impOptions = TUserDefaults.GetStringDefault("Imp Options", ";" + TDlgSelectCSVSeparator.NUMBERFORMAT_AMERICAN); // This call fixes Windows7 Open File Dialogs. It must be the line before ShowDialog() TWin7FileOpenSaveDialog.PrepareDialog(Path.GetFileName(fullPath)); if (dialog.ShowDialog() == DialogResult.OK) { Boolean fileCanOpen = FdlgSeparator.OpenCsvFile(dialog.FileName); if (!fileCanOpen) { MessageBox.Show(Catalog.GetString("Unable to open file."), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Stop); return; } importString = File.ReadAllText(dialog.FileName, Encoding.Default); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator.DateFormat = dateFormatString; if (impOptions.Length > 1) { FdlgSeparator.NumberFormat = impOptions.Substring(1); } FdlgSeparator.SelectedSeparator = impOptions.Substring(0, 1); } else { return; } } else { // unknown source!! The following need a value... impOptions = String.Empty; importString = String.Empty; } if (FdlgSeparator.ShowDialog() == DialogResult.OK) { Hashtable requestParams = new Hashtable(); requestParams.Add("ALedgerNumber", FLedgerNumber); requestParams.Add("Delimiter", FdlgSeparator.SelectedSeparator); requestParams.Add("DateFormatString", FdlgSeparator.DateFormat); requestParams.Add("NumberFormat", FdlgSeparator.NumberFormat); requestParams.Add("NewLine", Environment.NewLine); bool Repeat = true; while (Repeat) { Repeat = false; TVerificationResultCollection AMessages = new TVerificationResultCollection(); GiftBatchTDSAGiftDetailTable NeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); Thread ImportThread = new Thread(() => ImportGiftBatches( requestParams, importString, out AMessages, out ok, out NeedRecipientLedgerNumber)); using (TProgressDialog ImportDialog = new TProgressDialog(ImportThread)) { ImportDialog.ShowDialog(); } // If NeedRecipientLedgerNumber contains data then AMessages will only ever contain // one message alerting the user that no data has been imported. // We do not want to show this as we will be displaying another more detailed message. if (NeedRecipientLedgerNumber.Rows.Count == 0) { ShowMessages(AMessages); } // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination // then the import will have failed and we need to alert the user if (NeedRecipientLedgerNumber.Rows.Count > 0) { bool OfferToRunImportAgain = true; bool DoNotShowMessageBoxEverytime = false; TFrmExtendedMessageBox.TResult Result = TFrmExtendedMessageBox.TResult.embrUndefined; int count = 1; // for each gift in which the recipient needs a Git Destination foreach (GiftBatchTDSAGiftDetailRow Row in NeedRecipientLedgerNumber.Rows) { if (!DoNotShowMessageBoxEverytime) { string CheckboxText = string.Empty; // only show checkbox if there is at least one more occurance of this error if (NeedRecipientLedgerNumber.Rows.Count - count > 0) { CheckboxText = string.Format( Catalog.GetString("Do this for all further occurances ({0})?"), NeedRecipientLedgerNumber.Rows.Count - count); } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FPetraUtilsObject.GetForm()); extendedMessageBox.ShowDialog(string.Format( Catalog.GetString( "Gift Import has been cancelled as the recipient '{0}' ({1}) has no Gift Destination assigned."), Row.RecipientDescription, Row.RecipientKey) + "\n\r\n\r\n\r" + Catalog.GetString("Do you want to assign a Gift Destination to this partner now?"), Catalog.GetString("Import Errors"), CheckboxText, TFrmExtendedMessageBox.TButtons.embbYesNo, TFrmExtendedMessageBox.TIcon.embiWarning); Result = extendedMessageBox.GetResult(out DoNotShowMessageBoxEverytime); } if (Result == TFrmExtendedMessageBox.TResult.embrYes) { // allow the user to assign a Gift Destingation TFrmGiftDestination GiftDestinationForm = new TFrmGiftDestination(FPetraUtilsObject.GetForm(), Row.RecipientKey); GiftDestinationForm.ShowDialog(); } else { OfferToRunImportAgain = false; if (DoNotShowMessageBoxEverytime) { break; } } count++; } // if the user has clicked yes to assigning Gift Destinations then offer to restart the import if (OfferToRunImportAgain && (MessageBox.Show(Catalog.GetString("Would you like to import this Gift Batch again?"), Catalog.GetString("Gift Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)) { Repeat = true; } } } // We save the defaults even if ok is false - because the client will probably want to try and import // the same file again after correcting any errors SaveUserDefaults(dialog, impOptions); } if (ok) { MessageBox.Show(Catalog.GetString("Your data was imported successfully!"), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Information); FMyUserControl.LoadBatchesForCurrentYear(); FPetraUtilsObject.DisableSaveButton(); } }
private void FPetraUtilsObject_DataSavingStarted_NewDonorWarning() { GetDataFromControls(); FGiftDetailTable = FMainDS.AGiftDetail.GetChangesTyped(); }
/// <summary> /// Main method to post a specified batch /// </summary> /// <param name="ACurrentBatchRow">The batch row to post</param> /// <param name="APostingAlreadyConfirmed">True means ask user if they want to post</param> /// <param name="AWarnOfInactiveValues">True means user is warned if inactive values exist</param> /// <param name="ADonorZeroIsValid"></param> /// <param name="ARecipientZeroIsValid"></param> /// <returns>True if the batch was successfully posted</returns> public bool PostBatch(AGiftBatchRow ACurrentBatchRow, bool APostingAlreadyConfirmed = false, bool AWarnOfInactiveValues = true, bool ADonorZeroIsValid = false, bool ARecipientZeroIsValid = false) { //This assumes that all gift data etc is loaded into the batch before arriving here bool RetVal = false; if ((ACurrentBatchRow == null) || (ACurrentBatchRow.BatchStatus != MFinanceConstants.BATCH_UNPOSTED)) { return(RetVal); } FSelectedBatchNumber = ACurrentBatchRow.BatchNumber; TVerificationResultCollection Verifications; try { //Make sure that all control data is in dataset FMyForm.GetControlDataForPosting(); GiftBatchTDSAGiftDetailTable batchGiftDetails = new GiftBatchTDSAGiftDetailTable(); DataView batchGiftDetailsDV = new DataView(FMainDS.AGiftDetail); batchGiftDetailsDV.RowFilter = string.Format("{0}={1}", AGiftDetailTable.GetBatchNumberDBName(), FSelectedBatchNumber); batchGiftDetailsDV.Sort = string.Format("{0} ASC, {1} ASC, {2} ASC", AGiftDetailTable.GetBatchNumberDBName(), AGiftDetailTable.GetGiftTransactionNumberDBName(), AGiftDetailTable.GetDetailNumberDBName()); foreach (DataRowView drv in batchGiftDetailsDV) { GiftBatchTDSAGiftDetailRow gBRow = (GiftBatchTDSAGiftDetailRow)drv.Row; batchGiftDetails.Rows.Add((object[])gBRow.ItemArray.Clone()); } bool CancelledDueToExWorkerOrAnonDonor; // save first, then post if (!FMyForm.SaveChangesForPosting(batchGiftDetails, out CancelledDueToExWorkerOrAnonDonor)) { FMyForm.Cursor = Cursors.Default; if (!CancelledDueToExWorkerOrAnonDonor) { // saving failed, therefore do not try to post MessageBox.Show(Catalog.GetString("The batch was not posted due to problems during saving; ") + Environment.NewLine + Catalog.GetString("Please first correct and save the batch, and then post it!")); } return(RetVal); } } catch (Exception ex) { TLogging.LogException(ex, Utilities.GetMethodSignature()); throw; } //Check for missing international exchange rate bool IsTransactionInIntlCurrency = false; FMyForm.WarnAboutMissingIntlExchangeRate = true; if (FMyForm.InternationalCurrencyExchangeRate(ACurrentBatchRow, out IsTransactionInIntlCurrency, true) == 0) { return(RetVal); } //Check for zero Donors or Recipients if (!ADonorZeroIsValid) { DataView batchGiftDV = new DataView(FMainDS.AGift); batchGiftDV.RowFilter = string.Format("{0}={1} And {2}=0", AGiftTable.GetBatchNumberDBName(), FSelectedBatchNumber, AGiftTable.GetDonorKeyDBName()); int numDonorZeros = batchGiftDV.Count; if (numDonorZeros > 0) { string messageListOfOffendingGifts = String.Format(Catalog.GetString( "Gift Batch {0} contains {1} gift detail(s) with Donor 0000000. Please fix before posting!{2}{2}"), FSelectedBatchNumber, numDonorZeros, Environment.NewLine); string listOfOffendingRows = string.Empty; listOfOffendingRows += "Gift" + Environment.NewLine; listOfOffendingRows += "------------"; foreach (DataRowView drv in batchGiftDV) { AGiftRow giftRow = (AGiftRow)drv.Row; listOfOffendingRows += String.Format("{0}{1:0000}", Environment.NewLine, giftRow.GiftTransactionNumber); } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FMyForm); extendedMessageBox.ShowDialog((messageListOfOffendingGifts + listOfOffendingRows), Catalog.GetString("Post Batch Error"), string.Empty, TFrmExtendedMessageBox.TButtons.embbOK, TFrmExtendedMessageBox.TIcon.embiWarning); return(RetVal); } } if (!ARecipientZeroIsValid) { DataView batchGiftDetailsDV = new DataView(FMainDS.AGiftDetail); batchGiftDetailsDV.RowFilter = string.Format("{0}={1} And {2}=0", AGiftDetailTable.GetBatchNumberDBName(), FSelectedBatchNumber, AGiftDetailTable.GetRecipientKeyDBName()); int numRecipientZeros = batchGiftDetailsDV.Count; if (numRecipientZeros > 0) { string messageListOfOffendingGifts = String.Format(Catalog.GetString( "Gift Batch {0} contains {1} gift detail(s) with Recipient 0000000. Please fix before posting!{2}{2}"), FSelectedBatchNumber, numRecipientZeros, Environment.NewLine); string listOfOffendingRows = string.Empty; listOfOffendingRows += "Gift Detail" + Environment.NewLine; listOfOffendingRows += "-------------------"; foreach (DataRowView drv in batchGiftDetailsDV) { AGiftDetailRow giftDetailRow = (AGiftDetailRow)drv.Row; listOfOffendingRows += String.Format("{0}{1:0000} {2:00}", Environment.NewLine, giftDetailRow.GiftTransactionNumber, giftDetailRow.DetailNumber); } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FMyForm); extendedMessageBox.ShowDialog((messageListOfOffendingGifts + listOfOffendingRows), Catalog.GetString("Post Batch Error"), string.Empty, TFrmExtendedMessageBox.TButtons.embbOK, TFrmExtendedMessageBox.TIcon.embiWarning); return(RetVal); } } //Check for inactive KeyMinistries DataTable GiftsWithInactiveKeyMinistries; bool ModifiedDetails = false; if (AWarnOfInactiveValues && TRemote.MFinance.Gift.WebConnectors.InactiveKeyMinistriesFoundInBatch(FLedgerNumber, FSelectedBatchNumber, out GiftsWithInactiveKeyMinistries, false)) { int numInactiveValues = GiftsWithInactiveKeyMinistries.Rows.Count; string messageNonModifiedBatch = String.Format(Catalog.GetString("Gift Batch {0} contains {1} inactive key ministries. Please fix before posting!{2}{2}"), FSelectedBatchNumber, numInactiveValues, Environment.NewLine); string messageModifiedBatch = String.Format(Catalog.GetString( "Reversal/Adjustment Gift Batch {0} contains {1} inactive key ministries. Do you still want to post?{2}{2}"), FSelectedBatchNumber, numInactiveValues, Environment.NewLine); string listOfOffendingRows = string.Empty; listOfOffendingRows += "Gift Detail Recipient KeyMinistry" + Environment.NewLine; listOfOffendingRows += "-------------------------------------------------------------------------------"; foreach (DataRow dr in GiftsWithInactiveKeyMinistries.Rows) { listOfOffendingRows += String.Format("{0}{1:0000} {2:00} {3:00000000000} {4}", Environment.NewLine, dr[0], dr[1], dr[2], dr[3]); bool isModified = Convert.ToBoolean(dr[4]); if (isModified) { ModifiedDetails = true; } } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FMyForm); if (ModifiedDetails) { if (extendedMessageBox.ShowDialog((messageModifiedBatch + listOfOffendingRows), Catalog.GetString("Post Batch"), string.Empty, TFrmExtendedMessageBox.TButtons.embbYesNo, TFrmExtendedMessageBox.TIcon.embiWarning) == TFrmExtendedMessageBox.TResult.embrYes) { APostingAlreadyConfirmed = true; } else { return(RetVal); } } else { extendedMessageBox.ShowDialog((messageNonModifiedBatch + listOfOffendingRows), Catalog.GetString("Post Batch Error"), string.Empty, TFrmExtendedMessageBox.TButtons.embbOK, TFrmExtendedMessageBox.TIcon.embiWarning); return(RetVal); } } // ask if the user really wants to post the batch if (!APostingAlreadyConfirmed && (MessageBox.Show(String.Format(Catalog.GetString("Do you really want to post gift batch {0}?"), FSelectedBatchNumber), Catalog.GetString("Confirm posting of Gift Batch"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)) { return(RetVal); } Verifications = new TVerificationResultCollection(); try { FPostingInProgress = true; Thread postingThread = new Thread(() => PostGiftBatch(out Verifications)); using (TProgressDialog dialog = new TProgressDialog(postingThread)) { dialog.ShowDialog(); } if (!TVerificationHelper.IsNullOrOnlyNonCritical(Verifications)) { TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FMyForm); StringBuilder errorMessages = new StringBuilder(); int counter = 0; errorMessages.AppendLine(Catalog.GetString("________________________Gift Posting Errors________________________")); errorMessages.AppendLine(); foreach (TVerificationResult verif in Verifications) { counter++; errorMessages.AppendLine(counter.ToString("000") + " - " + verif.ResultText); errorMessages.AppendLine(); } extendedMessageBox.ShowDialog(errorMessages.ToString(), Catalog.GetString("Post Batch Error"), string.Empty, TFrmExtendedMessageBox.TButtons.embbOK, TFrmExtendedMessageBox.TIcon.embiWarning); } else { MessageBox.Show(Catalog.GetString("The batch has been posted successfully!")); RetVal = true; } } catch (Exception ex) { TLogging.LogException(ex, Utilities.GetMethodSignature()); throw; } finally { FPostingInProgress = false; } return(RetVal); }
public static bool ImportGiftTransactions( Hashtable requestParams, String importString, Int32 AGiftBatchNumber, out GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber, out TVerificationResultCollection AMessages ) { TGiftImporting Importing = new TGiftImporting(); return Importing.ImportGiftTransactions(requestParams, importString, AGiftBatchNumber, out ANeedRecipientLedgerNumber, out AMessages); }
private void ParseTransactionLine(AGiftRow AGift, AGiftBatchRow AGiftBatch, ref AGiftRow APreviousGift, int ANumberOfColumns, ref decimal ATotalBatchAmount, ref string AImportMessage, int ARowNumber, decimal AIntlRateFromBase, TVerificationResultCollection AMessages, AMotivationDetailTable AMotivationDetailTable, // TValidationControlsDict AValidationControlsDictGift, // TValidationControlsDict AValidationControlsDictGiftDetail, // ACostCentreTable AValidationCostCentreTable, // AAccountTable AValidationAccountTable, // AMotivationGroupTable AValidationMotivationGroupTable, // AMethodOfGivingTable AValidationMethodOfGivingTable, // AMethodOfPaymentTable AValidationMethodOfPaymentTable, // PMailingTable AValidationMailingTable, GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber, AGiftDetailRow AGiftDetails) { // Start parsing int preParseMessageCount = AMessages.Count; // Is this the format with extra columns? // Actually if it has the extra columns but does not have the optional final 8 columns we cannot distiguish using this test... // A file without extra columns will have between 13 and 21 columns - depending on whether some of the optional ones at the end are included. // A file with extra columns will be between 19 and 27. // So any count between 19 and 21 is ambiguous. We will assume that if the file has extra columns it also has // at least enough of the optional ones to exceed 21. bool HasExtraColumns = (ANumberOfColumns > 21); AImportMessage = Catalog.GetString("Importing the gift data"); AGift.DonorKey = TCommonImport.ImportInt64(ref FImportLine, FDelimiter, Catalog.GetString("Donor key"), FMainDS.AGift.ColumnDonorKey, ARowNumber, AMessages, null); TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString( "short name of donor (unused)"), null, ARowNumber, AMessages, null); // unused // This group is optional and database NULL's are allowed AGift.MethodOfGivingCode = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Method of giving Code"), FMainDS.AGift.ColumnMethodOfGivingCode, ARowNumber, AMessages, null, false); AGift.MethodOfPaymentCode = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Method Of Payment Code"), FMainDS.AGift.ColumnMethodOfPaymentCode, ARowNumber, AMessages, null, false); AGift.Reference = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Reference"), FMainDS.AGift.ColumnReference, ARowNumber, AMessages, null, false); AGift.ReceiptLetterCode = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Receipt letter code"), FMainDS.AGift.ColumnReceiptLetterCode, ARowNumber, AMessages, null, false); if (AGift.MethodOfGivingCode != null) { AGift.MethodOfGivingCode = AGift.MethodOfGivingCode.ToUpper(); } if (AGift.MethodOfPaymentCode != null) { AGift.MethodOfPaymentCode = AGift.MethodOfPaymentCode.ToUpper(); } if (AGift.ReceiptLetterCode != null) { AGift.ReceiptLetterCode = AGift.ReceiptLetterCode.ToUpper(); } if (HasExtraColumns) { TCommonImport.ImportInt32(ref FImportLine, FDelimiter, Catalog.GetString("Receipt number"), FMainDS.AGift.ColumnReceiptNumber, ARowNumber, AMessages, null); TCommonImport.ImportBoolean(ref FImportLine, FDelimiter, Catalog.GetString("First time gift"), FMainDS.AGift.ColumnFirstTimeGift, ARowNumber, AMessages, null); TCommonImport.ImportBoolean(ref FImportLine, FDelimiter, Catalog.GetString("Receipt printed"), FMainDS.AGift.ColumnReceiptPrinted, ARowNumber, AMessages, null); } AImportMessage = Catalog.GetString("Importing the gift details"); if ((APreviousGift != null) && (AGift.DonorKey == APreviousGift.DonorKey) && (AGift.MethodOfGivingCode == APreviousGift.MethodOfGivingCode) && (AGift.MethodOfPaymentCode == APreviousGift.MethodOfPaymentCode) && (AGift.Reference == APreviousGift.Reference) && (AGift.ReceiptLetterCode == APreviousGift.ReceiptLetterCode) && (AGift.ReceiptNumber == APreviousGift.ReceiptNumber) && (AGift.FirstTimeGift == APreviousGift.FirstTimeGift) && (AGift.ReceiptPrinted == APreviousGift.ReceiptPrinted)) { // this row is a new detail for the previousGift AGift = APreviousGift; AGift.LastDetailNumber++; AGiftDetails.DetailNumber = AGift.LastDetailNumber; } else { APreviousGift = AGift; AGift.LedgerNumber = AGiftBatch.LedgerNumber; AGift.BatchNumber = AGiftBatch.BatchNumber; AGift.GiftTransactionNumber = AGiftBatch.LastGiftNumber + 1; AGiftBatch.LastGiftNumber++; AGift.LastDetailNumber = 1; FMainDS.AGift.Rows.Add(AGift); AGiftDetails.DetailNumber = 1; } AGiftDetails.LedgerNumber = AGift.LedgerNumber; AGiftDetails.BatchNumber = AGiftBatch.BatchNumber; AGiftDetails.GiftTransactionNumber = AGift.GiftTransactionNumber; FMainDS.AGiftDetail.Rows.Add(AGiftDetails); AGiftDetails.RecipientKey = TCommonImport.ImportInt64(ref FImportLine, FDelimiter, Catalog.GetString("Recipient key"), FMainDS.AGiftDetail.ColumnRecipientKey, ARowNumber, AMessages, null); TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString( "short name of recipient (unused)"), null, ARowNumber, AMessages, null); // unused if (HasExtraColumns) { TCommonImport.ImportInt32(ref FImportLine, FDelimiter, Catalog.GetString("Recipient ledger number"), FMainDS.AGiftDetail.ColumnRecipientLedgerNumber, ARowNumber, AMessages, null); } // we always calculate RecipientLedgerNumber AGiftDetails.RecipientLedgerNumber = TGiftTransactionWebConnector.GetRecipientFundNumber( AGiftDetails.RecipientKey, AGiftBatch.GlEffectiveDate); decimal currentGiftAmount = TCommonImport.ImportDecimal(ref FImportLine, FDelimiter, FCultureInfoNumberFormat, Catalog.GetString("Gift amount"), FMainDS.AGiftDetail.ColumnGiftTransactionAmount, ARowNumber, AMessages, null); AGiftDetails.GiftTransactionAmount = currentGiftAmount; // amount in batch currency ATotalBatchAmount += currentGiftAmount; AGiftDetails.GiftAmount = GLRoutines.Divide(currentGiftAmount, AGiftBatch.ExchangeRateToBase); // amount in ledger currency if (HasExtraColumns) { // amount in international currency TCommonImport.ImportDecimal(ref FImportLine, FDelimiter, FCultureInfoNumberFormat, Catalog.GetString("Gift amount intl"), FMainDS.AGiftDetail.ColumnGiftAmountIntl, ARowNumber, AMessages, null); } else if (AIntlRateFromBase > 0.0m) { AGiftDetails.GiftAmountIntl = GLRoutines.Divide(AGiftDetails.GiftAmount, AIntlRateFromBase, 2); } AGiftDetails.ConfidentialGiftFlag = TCommonImport.ImportBoolean(ref FImportLine, FDelimiter, Catalog.GetString("Confidential gift"), FMainDS.AGiftDetail.ColumnConfidentialGiftFlag, ARowNumber, AMessages, null); AGiftDetails.MotivationGroupCode = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Motivation group code"), FMainDS.AGiftDetail.ColumnMotivationGroupCode, ARowNumber, AMessages, null).ToUpper(); AGiftDetails.MotivationDetailCode = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Motivation detail"), FMainDS.AGiftDetail.ColumnMotivationDetailCode, ARowNumber, AMessages, null).ToUpper(); if (HasExtraColumns) { TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Cost centre code"), FMainDS.AGiftDetail.ColumnCostCentreCode, ARowNumber, AMessages, null); } // "In Petra Cost Centre is always inferred from recipient field and motivation detail so is not needed in the import." AGiftDetails.CostCentreCode = TGiftTransactionWebConnector.RetrieveCostCentreCodeForRecipient( AGiftDetails.LedgerNumber, AGiftDetails.RecipientKey, AGiftDetails.RecipientLedgerNumber, AGift.DateEntered, AGiftDetails.MotivationGroupCode, AGiftDetails.MotivationDetailCode); // All the remaining columns are optional and can contain database NULL AGiftDetails.GiftCommentOne = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Gift comment one"), FMainDS.AGiftDetail.ColumnGiftCommentOne, ARowNumber, AMessages, null, false); string commentOneType = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Comment one type"), FMainDS.AGiftDetail.ColumnCommentOneType, ARowNumber, AMessages, null, false); AGiftDetails.MailingCode = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Mailing code"), FMainDS.AGiftDetail.ColumnMailingCode, ARowNumber, AMessages, null, false); AGiftDetails.GiftCommentTwo = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Gift comment two"), FMainDS.AGiftDetail.ColumnGiftCommentTwo, ARowNumber, AMessages, null, false); string commentTwoType = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Comment two type"), FMainDS.AGiftDetail.ColumnCommentTwoType, ARowNumber, AMessages, null, false); AGiftDetails.GiftCommentThree = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Gift comment three"), FMainDS.AGiftDetail.ColumnGiftCommentThree, ARowNumber, AMessages, null, false); string commentThreeType = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("Comment three type"), FMainDS.AGiftDetail.ColumnCommentThreeType, ARowNumber, AMessages, null, false); SetCommentTypeCase(ref commentOneType); AGiftDetails.CommentOneType = commentOneType; SetCommentTypeCase(ref commentTwoType); AGiftDetails.CommentTwoType = commentTwoType; SetCommentTypeCase(ref commentThreeType); AGiftDetails.CommentThreeType = commentThreeType; if (AGiftDetails.MailingCode != null) { AGiftDetails.MailingCode = AGiftDetails.MailingCode.ToUpper(); } // Find the default Tax deductabilty from the motivation detail. This ensures that the column can be missing. AMotivationDetailRow motivationDetailRow = (AMotivationDetailRow)AMotivationDetailTable.Rows.Find( new object[] { FLedgerNumber, AGiftDetails.MotivationGroupCode, AGiftDetails.MotivationDetailCode }); string defaultTaxDeductible = ((motivationDetailRow != null) && !motivationDetailRow.IsTaxDeductibleAccountCodeNull() && motivationDetailRow.TaxDeductible) ? "yes" : "no"; AGiftDetails.TaxDeductible = TCommonImport.ImportBoolean(ref FImportLine, FDelimiter, Catalog.GetString("Tax deductible"), FMainDS.AGiftDetail.ColumnTaxDeductible, ARowNumber, AMessages, null, defaultTaxDeductible); // Account Codes are always inferred from the motivation detail and so is not needed in the import. string NewAccountCode = null; string NewTaxDeductibleAccountCode = null; // get up-to-date account codes if (motivationDetailRow != null) { NewAccountCode = motivationDetailRow.AccountCode; NewTaxDeductibleAccountCode = motivationDetailRow.TaxDeductibleAccountCode; } AGiftDetails.AccountCode = NewAccountCode; AGiftDetails.TaxDeductibleAccountCode = NewTaxDeductibleAccountCode; // Date entered cannot be imported although it can be modified in the GUI. // This is because it would have to be the last column in the import for compatibility // but it belongs with the gift and not the detail so it would need to go in an earlier column. // For now the import date entered is the effective date. AGift.DateEntered = AGiftBatch.GlEffectiveDate; // Enforce the correct case for our GIFT constant if (String.Compare(AGiftDetails.MotivationGroupCode, MFinanceConstants.MOTIVATION_GROUP_GIFT, true) == 0) { AGiftDetails.MotivationGroupCode = MFinanceConstants.MOTIVATION_GROUP_GIFT; } } // Parse TransactionLine
/// <summary> /// this supports the batch export files from Petra 2.x. /// Each line starts with a type specifier, B for batch, J for journal, T for transaction /// </summary> public void ImportBatches(TGiftImportDataSourceEnum AImportSource) { bool ok = false; String importString; String impOptions; OpenFileDialog dialog = null; if (FPetraUtilsObject.HasChanges) { // saving failed, therefore do not try to post MessageBox.Show(Catalog.GetString("Please save before calling this function!"), Catalog.GetString( "Failure"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } FdlgSeparator = new TDlgSelectCSVSeparator(false); if (AImportSource == TGiftImportDataSourceEnum.FromClipboard) { importString = Clipboard.GetText(TextDataFormat.UnicodeText); if ((importString == null) || (importString.Length == 0)) { MessageBox.Show(Catalog.GetString("Please first copy data from your spreadsheet application!"), Catalog.GetString("Failure"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } impOptions = TUserDefaults.GetStringDefault("Imp Options", ";American"); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator = new TDlgSelectCSVSeparator(false); FdlgSeparator.SelectedSeparator = "\t"; FdlgSeparator.CSVData = importString; FdlgSeparator.DateFormat = dateFormatString; if (impOptions.Length > 1) { FdlgSeparator.NumberFormat = impOptions.Substring(1); } } else if (AImportSource == TGiftImportDataSourceEnum.FromFile) { dialog = new OpenFileDialog(); dialog.FileName = TUserDefaults.GetStringDefault("Imp Filename", TClientSettings.GetExportPath() + Path.DirectorySeparatorChar + "import.csv"); dialog.Title = Catalog.GetString("Import Batches from CSV File"); dialog.Filter = Catalog.GetString("Gift Batches files (*.csv)|*.csv"); impOptions = TUserDefaults.GetStringDefault("Imp Options", ";" + TDlgSelectCSVSeparator.NUMBERFORMAT_AMERICAN); if (dialog.ShowDialog() == DialogResult.OK) { Boolean fileCanOpen = FdlgSeparator.OpenCsvFile(dialog.FileName); if (!fileCanOpen) { MessageBox.Show(Catalog.GetString("Unable to open file."), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Stop); return; } importString = File.ReadAllText(dialog.FileName); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator.DateFormat = dateFormatString; if (impOptions.Length > 1) { FdlgSeparator.NumberFormat = impOptions.Substring(1); } FdlgSeparator.SelectedSeparator = impOptions.Substring(0, 1); } else { return; } } else { // unknown source!! The following need a value... impOptions = String.Empty; importString = String.Empty; } if (FdlgSeparator.ShowDialog() == DialogResult.OK) { Hashtable requestParams = new Hashtable(); requestParams.Add("ALedgerNumber", FLedgerNumber); requestParams.Add("Delimiter", FdlgSeparator.SelectedSeparator); requestParams.Add("DateFormatString", FdlgSeparator.DateFormat); requestParams.Add("NumberFormat", FdlgSeparator.NumberFormat); requestParams.Add("NewLine", Environment.NewLine); bool Repeat = true; while (Repeat) { Repeat = false; TVerificationResultCollection AMessages = new TVerificationResultCollection(); GiftBatchTDSAGiftDetailTable NeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); Thread ImportThread = new Thread(() => ImportGiftBatches( requestParams, importString, out AMessages, out ok, out NeedRecipientLedgerNumber)); using (TProgressDialog ImportDialog = new TProgressDialog(ImportThread)) { ImportDialog.ShowDialog(); } // If NeedRecipientLedgerNumber contains data then AMessages will only ever contain // one message alerting the user that no data has been imported. // We do not want to show this as we will be displaying another more detailed message. if (NeedRecipientLedgerNumber.Rows.Count == 0) { ShowMessages(AMessages); } // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination // then the import will have failed and we need to alert the user if (NeedRecipientLedgerNumber.Rows.Count > 0) { bool OfferToRunImportAgain = true; bool DoNotShowMessageBoxEverytime = false; TFrmExtendedMessageBox.TResult Result = TFrmExtendedMessageBox.TResult.embrUndefined; int count = 1; // for each gift in which the recipient needs a Git Destination foreach (GiftBatchTDSAGiftDetailRow Row in NeedRecipientLedgerNumber.Rows) { if (!DoNotShowMessageBoxEverytime) { string CheckboxText = string.Empty; // only show checkbox if there is at least one more occurance of this error if (NeedRecipientLedgerNumber.Rows.Count - count > 0) { CheckboxText = string.Format( Catalog.GetString("Do this for all further occurances ({0})?"), NeedRecipientLedgerNumber.Rows.Count - count); } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FPetraUtilsObject.GetForm()); extendedMessageBox.ShowDialog(string.Format( Catalog.GetString( "Gift Import has been cancelled as the recipient '{0}' ({1}) has no Gift Destination assigned."), Row.RecipientDescription, Row.RecipientKey) + "\n\r\n\r\n\r" + Catalog.GetString("Do you want to assign a Gift Destination to this partner now?"), Catalog.GetString("Import Errors"), CheckboxText, TFrmExtendedMessageBox.TButtons.embbYesNo, TFrmExtendedMessageBox.TIcon.embiWarning); Result = extendedMessageBox.GetResult(out DoNotShowMessageBoxEverytime); } if (Result == TFrmExtendedMessageBox.TResult.embrYes) { // allow the user to assign a Gift Destingation TFrmGiftDestination GiftDestinationForm = new TFrmGiftDestination(FPetraUtilsObject.GetForm(), Row.RecipientKey); GiftDestinationForm.ShowDialog(); } else { OfferToRunImportAgain = false; if (DoNotShowMessageBoxEverytime) { break; } } count++; } // if the user has clicked yes to assigning Gift Destinations then offer to restart the import if (OfferToRunImportAgain && (MessageBox.Show(Catalog.GetString("Would you like to import this Gift Batch again?"), Catalog.GetString("Gift Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)) { Repeat = true; } } } } if (ok) { MessageBox.Show(Catalog.GetString("Your data was imported successfully!"), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Information); SaveUserDefaults(dialog, impOptions); FMyUserControl.LoadBatchesForCurrentYear(); FPetraUtilsObject.DisableSaveButton(); } }
/// <summary> /// Main method to post a specified batch /// </summary> /// <param name="ACurrentBatchRow">The batch row to post</param> /// <param name="ARefreshGUIAfterPosting">Will be set to true if the GUI should be updated. Can be true even if Posting fails /// <param name="AWarnOfInactiveValues">True means user is warned if inactive values exist</param> /// <param name="ADonorZeroIsValid"></param> /// <param name="ARecipientZeroIsValid"></param> /// <param name="APostingAlreadyConfirmed">True means ask user if they want to post</param> /// if the server gets a SerializableTransactionException</param> /// <returns>True if the batch was successfully posted</returns> public bool PostBatch(AGiftBatchRow ACurrentBatchRow, out bool ARefreshGUIAfterPosting, bool AWarnOfInactiveValues = true, bool ADonorZeroIsValid = false, bool ARecipientZeroIsValid = false, bool APostingAlreadyConfirmed = false) { ARefreshGUIAfterPosting = false; if ((ACurrentBatchRow == null) || (ACurrentBatchRow.BatchStatus != MFinanceConstants.BATCH_UNPOSTED)) { return(false); } FSelectedBatchNumber = ACurrentBatchRow.BatchNumber; //Make sure that all control data is in dataset FMyForm.GetLatestControlData(); //Copy all batch data to new table GiftBatchTDSAGiftDetailTable BatchGiftDetails = new GiftBatchTDSAGiftDetailTable(); DataView BatchGiftDetailsDV = new DataView(FMainDS.AGiftDetail); BatchGiftDetailsDV.RowFilter = string.Format("{0}={1}", AGiftDetailTable.GetBatchNumberDBName(), FSelectedBatchNumber); BatchGiftDetailsDV.Sort = string.Format("{0} ASC, {1} ASC, {2} ASC", AGiftDetailTable.GetBatchNumberDBName(), AGiftDetailTable.GetGiftTransactionNumberDBName(), AGiftDetailTable.GetDetailNumberDBName()); foreach (DataRowView drv in BatchGiftDetailsDV) { GiftBatchTDSAGiftDetailRow gBRow = (GiftBatchTDSAGiftDetailRow)drv.Row; BatchGiftDetails.Rows.Add((object[])gBRow.ItemArray.Clone()); } //Save and check for inactive values and ex-workers and anonymous gifts if (FPetraUtilsObject.HasChanges) { //Keep this conditional check separate from the one above so that it only gets called // when necessary and doesn't result in the executon of the same method if (!FMyForm.SaveChangesForPosting(BatchGiftDetails)) { return(false); } else { APostingAlreadyConfirmed = true; } } else { //This has to be called here because if there are no changes then the DataSavingValidating // method which calls the method below, will not run. if (!FMyForm.GetBatchControl().AllowInactiveFieldValues(ref APostingAlreadyConfirmed, TExtraGiftBatchChecks.GiftBatchAction.POSTING) || FMyForm.GiftHasExWorkerOrAnon(BatchGiftDetails) ) { return(false); } } //Check hash total validity if ((ACurrentBatchRow.HashTotal != 0) && (ACurrentBatchRow.BatchTotal != ACurrentBatchRow.HashTotal)) { MessageBox.Show(String.Format(Catalog.GetString( "The gift batch total ({0}) for batch {1} does not equal the hash total ({2})!"), StringHelper.FormatUsingCurrencyCode(ACurrentBatchRow.BatchTotal, ACurrentBatchRow.CurrencyCode), ACurrentBatchRow.BatchNumber, StringHelper.FormatUsingCurrencyCode(ACurrentBatchRow.HashTotal, ACurrentBatchRow.CurrencyCode)), "Post Gift Batch"); return(false); } //Check for missing international exchange rate bool IsTransactionInIntlCurrency = false; FMyForm.WarnAboutMissingIntlExchangeRate = true; if (FMyForm.InternationalCurrencyExchangeRate(ACurrentBatchRow, out IsTransactionInIntlCurrency, true) == 0) { return(false); } //Check for zero Donors or Recipients if (!ADonorZeroIsValid) { DataView batchGiftDV = new DataView(FMainDS.AGift); batchGiftDV.RowFilter = string.Format("{0}={1} And {2}=0", AGiftTable.GetBatchNumberDBName(), FSelectedBatchNumber, AGiftTable.GetDonorKeyDBName()); int numDonorZeros = batchGiftDV.Count; if (numDonorZeros > 0) { string messageListOfOffendingGifts = String.Format(Catalog.GetString( "Gift Batch {0} contains {1} gift detail(s) with Donor 0000000. Please fix before posting!{2}{2}"), FSelectedBatchNumber, numDonorZeros, Environment.NewLine); string listOfOffendingRows = string.Empty; listOfOffendingRows += "Gift" + Environment.NewLine; listOfOffendingRows += "------------"; foreach (DataRowView drv in batchGiftDV) { AGiftRow giftRow = (AGiftRow)drv.Row; listOfOffendingRows += String.Format("{0}{1:0000}", Environment.NewLine, giftRow.GiftTransactionNumber); } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FMyForm); extendedMessageBox.ShowDialog((messageListOfOffendingGifts + listOfOffendingRows), Catalog.GetString("Post Batch Error"), string.Empty, TFrmExtendedMessageBox.TButtons.embbOK, TFrmExtendedMessageBox.TIcon.embiWarning); return(false); } } if (!ARecipientZeroIsValid) { DataView batchGiftDetailsDV = new DataView(FMainDS.AGiftDetail); batchGiftDetailsDV.RowFilter = string.Format("{0}={1} And {2}=0", AGiftDetailTable.GetBatchNumberDBName(), FSelectedBatchNumber, AGiftDetailTable.GetRecipientKeyDBName()); int numRecipientZeros = batchGiftDetailsDV.Count; if (numRecipientZeros > 0) { string messageListOfOffendingGifts = String.Format(Catalog.GetString( "Gift Batch {0} contains {1} gift detail(s) with Recipient 0000000. Please fix before posting!{2}{2}"), FSelectedBatchNumber, numRecipientZeros, Environment.NewLine); string listOfOffendingRows = string.Empty; listOfOffendingRows += "Gift Detail" + Environment.NewLine; listOfOffendingRows += "-------------------"; foreach (DataRowView drv in batchGiftDetailsDV) { AGiftDetailRow giftDetailRow = (AGiftDetailRow)drv.Row; listOfOffendingRows += String.Format("{0}{1:0000} {2:00}", Environment.NewLine, giftDetailRow.GiftTransactionNumber, giftDetailRow.DetailNumber); } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FMyForm); extendedMessageBox.ShowDialog((messageListOfOffendingGifts + listOfOffendingRows), Catalog.GetString("Post Batch Error"), string.Empty, TFrmExtendedMessageBox.TButtons.embbOK, TFrmExtendedMessageBox.TIcon.embiWarning); return(false); } } //Check for inactive KeyMinistries DataTable GiftsWithInactiveKeyMinistries; bool ModifiedDetails = false; if (AWarnOfInactiveValues && TRemote.MFinance.Gift.WebConnectors.InactiveKeyMinistriesFoundInBatch(FLedgerNumber, FSelectedBatchNumber, out GiftsWithInactiveKeyMinistries, false)) { int numInactiveValues = GiftsWithInactiveKeyMinistries.Rows.Count; string messageNonModifiedBatch = String.Format(Catalog.GetString("Gift Batch {0} contains {1} inactive key ministries. Please fix before posting!{2}{2}"), FSelectedBatchNumber, numInactiveValues, Environment.NewLine); string messageModifiedBatch = String.Format(Catalog.GetString( "Reversal/Adjustment Gift Batch {0} contains {1} inactive key ministries. Do you still want to post?{2}{2}"), FSelectedBatchNumber, numInactiveValues, Environment.NewLine); string listOfOffendingRows = string.Empty; listOfOffendingRows += "Gift Detail Recipient KeyMinistry" + Environment.NewLine; listOfOffendingRows += "-------------------------------------------------------------------------------"; foreach (DataRow dr in GiftsWithInactiveKeyMinistries.Rows) { listOfOffendingRows += String.Format("{0}{1:0000} {2:00} {3:00000000000} {4}", Environment.NewLine, dr[0], dr[1], dr[2], dr[3]); bool isModified = Convert.ToBoolean(dr[4]); if (isModified) { ModifiedDetails = true; } } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FMyForm); if (ModifiedDetails) { if (extendedMessageBox.ShowDialog((messageModifiedBatch + listOfOffendingRows), Catalog.GetString("Post Batch"), string.Empty, TFrmExtendedMessageBox.TButtons.embbYesNo, TFrmExtendedMessageBox.TIcon.embiWarning) == TFrmExtendedMessageBox.TResult.embrYes) { APostingAlreadyConfirmed = true; } else { return(false); } } else { extendedMessageBox.ShowDialog((messageNonModifiedBatch + listOfOffendingRows), Catalog.GetString("Post Batch Error"), string.Empty, TFrmExtendedMessageBox.TButtons.embbOK, TFrmExtendedMessageBox.TIcon.embiWarning); return(false); } } // ask if the user really wants to post the batch if (!APostingAlreadyConfirmed && (MessageBox.Show(String.Format(Catalog.GetString("Do you really want to post gift batch {0}?"), FSelectedBatchNumber), Catalog.GetString("Confirm posting of Gift Batch"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)) { return(false); } TVerificationResultCollection Verifications = new TVerificationResultCollection(); try { FPostingInProgress = true; Thread postingThread = new Thread(() => PostGiftBatch(out Verifications)); postingThread.SetApartmentState(ApartmentState.STA); using (TProgressDialog dialog = new TProgressDialog(postingThread)) { dialog.ShowDialog(); } if (TVerificationHelper.ResultsContainErrorCode(Verifications, PetraErrorCodes.ERR_DB_SERIALIZATION_EXCEPTION)) { TConcurrentServerTransactions.ShowTransactionSerializationExceptionDialog(); ARefreshGUIAfterPosting = true; return(false); } else if (!TVerificationHelper.IsNullOrOnlyNonCritical(Verifications)) { TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FMyForm); StringBuilder errorMessages = new StringBuilder(); int counter = 0; errorMessages.AppendLine(Catalog.GetString("________________________Gift Posting Errors________________________")); errorMessages.AppendLine(); foreach (TVerificationResult verif in Verifications) { counter++; errorMessages.AppendLine(counter.ToString("000") + " - " + verif.ResultText); errorMessages.AppendLine(); } extendedMessageBox.ShowDialog(errorMessages.ToString(), Catalog.GetString("Post Batch Error"), string.Empty, TFrmExtendedMessageBox.TButtons.embbOK, TFrmExtendedMessageBox.TIcon.embiWarning); } else { MessageBox.Show(Catalog.GetString("The batch has been posted successfully!")); ARefreshGUIAfterPosting = true; } } catch (Exception ex) { TLogging.LogException(ex, Utilities.GetMethodSignature()); throw; } finally { FPostingInProgress = false; } return(true); }
/// <summary> /// Looks for gifts where the recipient is an ExWorker and asks the user if they want to continue. /// (Make sure GetDataFromControls is called before this method so that AMainDS is up-to-date.) /// </summary> /// <param name="AAction">Why this method is being called</param> /// <param name="AMainDS"></param> /// <param name="APetraUtilsObject"></param> /// <param name="APostingGiftDetails">Only used when being called in order to carry out a batch posting</param> /// <returns>Returns true if saving/posting can continue</returns> public static bool CanContinueWithAnyExWorkers(GiftBatchAction AAction, GiftBatchTDS AMainDS, TFrmPetraEditUtils APetraUtilsObject, DataTable APostingGiftDetails = null) { DataTable ExWorkers = null; string Msg = string.Empty; int BatchNumber = -1; int ExWorkerGifts = 0; string ExWorkerSpecialType = TSystemDefaults.GetSystemDefault(SharedConstants.SYSDEFAULT_EXWORKERSPECIALTYPE, "EX-WORKER"); // first check for Ex-Workers in the batch that is being posted/submitted (if a batch is being posted/submitted) if ((APostingGiftDetails != null) && (APostingGiftDetails.Rows.Count > 0)) { ExWorkers = TRemote.MFinance.Gift.WebConnectors.FindGiftRecipientExWorker(APostingGiftDetails, BatchNumber); ExWorkerGifts += ExWorkers.Rows.Count; Msg = GetExWorkersString(AAction, ExWorkerSpecialType, ExWorkers); if (ExWorkers.Rows.Count > 0) { BatchNumber = (int)APostingGiftDetails.Rows[0][GiftBatchTDSAGiftDetailTable.GetBatchNumberDBName()]; } } // check for Ex-Workers in all added and modified data if (APetraUtilsObject.HasChanges) { DataTable Changes = new DataTable(); if (AMainDS.AGiftDetail.GetChangesTyped() != null) { Changes.Merge(AMainDS.AGiftDetail.GetChangesTyped()); } else if (AMainDS.ARecurringGiftDetail.GetChangesTyped() != null) { Changes.Merge(AMainDS.ARecurringGiftDetail.GetChangesTyped()); } if ((Changes != null) && (Changes.Rows.Count > 0)) { ExWorkers = TRemote.MFinance.Gift.WebConnectors.FindGiftRecipientExWorker(Changes, BatchNumber); ExWorkerGifts += ExWorkers.Rows.Count; Msg += GetExWorkersString(null, ExWorkerSpecialType, ExWorkers); } } // alert the user to any recipients who are Ex-Workers if (Msg != string.Empty) { if (AAction == GiftBatchAction.SAVING) { Msg += Catalog.GetString("Do you want to continue with saving anyway?"); } else { // singular if (ExWorkerGifts == 1) { if (AAction == GiftBatchAction.POSTING) { Msg += Catalog.GetString("This gift will need to be saved before this batch can be posted."); } else if (AAction == GiftBatchAction.NEWBATCH) { Msg += Catalog.GetString("This gift will need to be saved before a new batch can be created."); } else if (AAction == GiftBatchAction.CANCELLING) { Msg += Catalog.GetString("This gift will need to be saved before this batch can be cancelled."); } else if (AAction == GiftBatchAction.SUBMITTING) { Msg += Catalog.GetString("This gift will need to be saved before this batch can be submitted."); } else if (AAction == GiftBatchAction.DELETING) { Msg += Catalog.GetString("This gift will need to be saved before this batch can be deleted."); } } // plural else { if (AAction == GiftBatchAction.POSTING) { Msg += Catalog.GetString("These gifts will need to be saved before this batch can be posted."); } else if (AAction == GiftBatchAction.NEWBATCH) { Msg += Catalog.GetString("These gifts will need to be saved before a new batch can be created."); } else if (AAction == GiftBatchAction.CANCELLING) { Msg += Catalog.GetString("These gifts will need to be saved before this batch can be cancelled."); } else if (AAction == GiftBatchAction.SUBMITTING) { Msg += Catalog.GetString("These gifts will need to be saved before this batch can be submitted."); } else if (AAction == GiftBatchAction.DELETING) { Msg += Catalog.GetString("These gifts will need to be saved before this batch can be deleted."); } } Msg += " " + Catalog.GetString("Do you want to continue?"); } if (MessageBox.Show( Msg, string.Format(Catalog.GetString("{0} Warning"), ExWorkerSpecialType), MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) { return(false); } } return(true); }
/// <summary> /// Import Gift Transactions from a file /// </summary> /// <param name="ARequestParams"></param> /// <param name="AImportString"></param> /// <param name="AGiftBatchNumber"></param> /// <param name="ANeedRecipientLedgerNumber"></param> /// <param name="AMessages"></param> /// <returns></returns> public bool ImportGiftTransactions( Hashtable ARequestParams, String AImportString, Int32 AGiftBatchNumber, out GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber, out TVerificationResultCollection AMessages ) { TProgressTracker.InitProgressTracker(DomainManager.GClientID.ToString(), Catalog.GetString("Importing Gift Batches"), 100); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Initialising"), 5); GiftBatchTDSAGiftDetailTable NeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); TVerificationResultCollection Messages = new TVerificationResultCollection(); // fix for Mono issue with out parameter: https://bugzilla.xamarin.com/show_bug.cgi?id=28196 AMessages = Messages; FMainDS = new GiftBatchTDS(); StringReader sr = new StringReader(AImportString); // Parse the supplied parameters FDelimiter = (String)ARequestParams["Delimiter"]; FLedgerNumber = (Int32)ARequestParams["ALedgerNumber"]; FDateFormatString = (String)ARequestParams["DateFormatString"]; String NumberFormat = (String)ARequestParams["NumberFormat"]; FNewLine = (String)ARequestParams["NewLine"]; // Set culture from parameters FCultureInfoNumberFormat = new CultureInfo(NumberFormat.Equals("American") ? "en-US" : "de-DE"); FCultureInfoDate = new CultureInfo("en-GB"); FCultureInfoDate.DateTimeFormat.ShortDatePattern = FDateFormatString; bool TaxDeductiblePercentageEnabled = Convert.ToBoolean( TSystemDefaults.GetSystemDefault(SharedConstants.SYSDEFAULT_TAXDEDUCTIBLEPERCENTAGE, "FALSE")); // Initialise our working variables decimal totalBatchAmount = 0; Boolean CancelledByUser = false; string ImportMessage = Catalog.GetString("Initialising"); // This needs to be initialised because we will be calling the method TSharedFinanceValidationHelper.GetValidPeriodDatesDelegate = @TAccountingPeriodsWebConnector.GetPeriodDates; TSharedFinanceValidationHelper.GetFirstDayOfAccountingPeriodDelegate = @TAccountingPeriodsWebConnector.GetFirstDayOfAccountingPeriod; TDBTransaction Transaction = null; bool SubmissionOK = false; Int32 RowNumber = 0; DBAccess.GDBAccessObj.BeginAutoTransaction(IsolationLevel.Serializable, ref Transaction, ref SubmissionOK, delegate { try { // Load supplementary tables that we are going to need for validation ALedgerTable LedgerTable = ALedgerAccess.LoadByPrimaryKey(FLedgerNumber, Transaction); ACostCentreTable CostCentreTable = ACostCentreAccess.LoadViaALedger(FLedgerNumber, Transaction); AAccountTable AccountTable = AAccountAccess.LoadViaALedger(FLedgerNumber, Transaction); AMotivationGroupTable MotivationGroupTable = AMotivationGroupAccess.LoadViaALedger(FLedgerNumber, Transaction); AMotivationDetailTable MotivationDetailTable = AMotivationDetailAccess.LoadViaALedger(FLedgerNumber, Transaction); AMethodOfGivingTable MethodOfGivingTable = AMethodOfGivingAccess.LoadAll(Transaction); AMethodOfPaymentTable MethodOfPaymentTable = AMethodOfPaymentAccess.LoadAll(Transaction); PMailingTable MailingTable = PMailingAccess.LoadAll(Transaction); PFormTable MailingFormTable = TFormTemplatesWebConnector.GetPartnerForms(); AGiftBatchTable giftBatchTable = AGiftBatchAccess.LoadByPrimaryKey(FLedgerNumber, AGiftBatchNumber, Transaction); FMainDS.AGiftBatch.ImportRow(giftBatchTable[0]); FMainDS.AcceptChanges(); AGiftBatchRow giftBatch = FMainDS.AGiftBatch[0]; if (LedgerTable.Rows.Count == 0) { throw new Exception(String.Format(Catalog.GetString("Ledger {0} doesn't exist."), FLedgerNumber)); } string LedgerBaseCurrency = ((ALedgerRow)LedgerTable.Rows[0]).BaseCurrency; string LedgerIntlCurrency = ((ALedgerRow)LedgerTable.Rows[0]).IntlCurrency; decimal intlRateFromBase = -1.0m; DateTime firstOfMonth; if (TSharedFinanceValidationHelper.GetFirstDayOfAccountingPeriod(FLedgerNumber, giftBatch.GlEffectiveDate, out firstOfMonth)) { intlRateFromBase = TExchangeRateTools.GetCorporateExchangeRate(LedgerBaseCurrency, LedgerIntlCurrency, firstOfMonth, giftBatch.GlEffectiveDate); } ImportMessage = Catalog.GetString("Parsing first line"); AGiftRow previousGift = null; // Go round a loop reading the file line by line FImportLine = sr.ReadLine(); Boolean ImportingEsr = false; Int32 PercentDone = 10; Int32 PreviousPercentDone = 0; Int32 InitialTextLength = AImportString.Length; Int32 totalRows = AImportString.Split('\n').Length; TValidationControlsDict EmptyControlsDict = new TValidationControlsDict(); while (FImportLine != null) { RowNumber++; PercentDone = 10 + ((RowNumber * 90) / totalRows); // skip empty lines and commented lines if ((FImportLine.Trim().Length > 0) && !FImportLine.StartsWith("/*") && !FImportLine.StartsWith("#")) { // number of elements is incremented by 1 as though the line started with 'T' int numberOfElements = StringHelper.GetCSVList(FImportLine, FDelimiter).Count + 1; Boolean IsEsrString = false; if (numberOfElements == 2) { IsEsrString = ((FImportLine.Trim().Length == 100) && (FImportLine.Substring(53, 2) == " ")); } if (ImportingEsr && !IsEsrString) // I did previously succeed with ESR, but now not so much - { // I'm probably at the last line of the file. FImportLine = sr.ReadLine(); continue; } if (!IsEsrString) { // It is a Transaction row if (numberOfElements < 13) // Perhaps this CSV file is a summary, and can't be imported? { Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), Catalog.GetString( "Wrong number of gift columns. Expected at least 13 columns. (This may be a summary?)"), TResultSeverity.Resv_Critical)); FImportLine = sr.ReadLine(); continue; } } // Parse the line into a new row ImportMessage = Catalog.GetString("Parsing transaction line"); Int32 preParseMessageCount = Messages.Count; AGiftRow gift = FMainDS.AGift.NewRowTyped(true); AGiftDetailRow giftDetails = FMainDS.AGiftDetail.NewRowTyped(true); if (IsEsrString) { ImportingEsr = ParseEsrTransactionLine( FImportLine, giftBatch, gift, giftDetails, intlRateFromBase, MotivationDetailTable, NeedRecipientLedgerNumber, Messages ); } else { ParseTransactionLine(gift, giftBatch, ref previousGift, numberOfElements, ref totalBatchAmount, ref ImportMessage, RowNumber, intlRateFromBase, Messages, MotivationDetailTable, NeedRecipientLedgerNumber, giftDetails); } if (Messages.Count == preParseMessageCount) // No parsing errors so we can validate { // (parsing errors will have assumed, probably invalid, values) ImportMessage = Catalog.GetString("Validating the gift data"); int messageCountBeforeValidate = preParseMessageCount; TPartnerClass RecipientClass; string RecipientDescription; TPartnerServerLookups.GetPartnerShortName(giftDetails.RecipientKey, out RecipientDescription, out RecipientClass); // Do our standard validation on this gift AGiftValidation.Validate(this, gift, ref Messages, EmptyControlsDict); TSharedFinanceValidation_Gift.ValidateGiftManual(this, gift, giftBatch.BatchYear, giftBatch.BatchPeriod, null, ref Messages, EmptyControlsDict, MethodOfGivingTable, MethodOfPaymentTable, MailingFormTable); ImportMessage = Catalog.GetString("Validating the gift details data"); AGiftDetailValidation.Validate(this, giftDetails, ref Messages, EmptyControlsDict); TSharedFinanceValidation_Gift.ValidateGiftDetailManual(this, (GiftBatchTDSAGiftDetailRow)giftDetails, ref Messages, EmptyControlsDict, RecipientClass, null, CostCentreTable, AccountTable, MotivationGroupTable, MotivationDetailTable, MailingTable, giftDetails.RecipientKey); // Fix up the messages for (int i = messageCountBeforeValidate; i < Messages.Count; i++) { ((TVerificationResult)Messages[i]).OverrideResultContext(String.Format(MCommonConstants. StrValidationErrorInLine, RowNumber)); if (Messages[i] is TScreenVerificationResult) { TVerificationResult downgrade = new TVerificationResult((TScreenVerificationResult)Messages[i]); Messages.RemoveAt(i); Messages.Insert(i, downgrade); } } } if (TaxDeductiblePercentageEnabled) { // Sets TaxDeductiblePct and uses it to calculate the tax deductibility amounts for a Gift Detail TGift.SetDefaultTaxDeductibilityData(ref giftDetails, gift.DateEntered, Transaction); } } if (TProgressTracker.GetCurrentState(DomainManager.GClientID.ToString()).CancelJob == true) { CancelledByUser = true; break; } if (Messages.HasCriticalErrors && (Messages.Count > 100)) { // This probably means that it is a big file and the user has made the same mistake many times over break; } // Update progress tracker every few percent if ((PercentDone - PreviousPercentDone) > 3) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), String.Format(Catalog.GetString("Importing row {0}"), RowNumber), (PercentDone > 98) ? 98 : PercentDone); PreviousPercentDone = PercentDone; } // Read the next line FImportLine = sr.ReadLine(); } // while CSV lines if (CancelledByUser) { Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, String.Format(Catalog.GetString("{0} messages reported."), Messages.Count), TResultSeverity.Resv_Info)); Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, "The import was cancelled by the user.", TResultSeverity.Resv_Info)); return; } // Finished reading the file - did we have critical errors? if (!TVerificationHelper.IsNullOrOnlyNonCritical(Messages)) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Batch has critical errors"), 100); // Record error count Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, String.Format(Catalog.GetString("{0} messages reported."), Messages.Count), TResultSeverity.Resv_Info)); if (FImportLine == null) { // We did reach the end of the file Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString( "Reached the end of file but errors occurred. When these errors are fixed the batch will import successfully."), TResultSeverity.Resv_Info)); } else { // We gave up before the end Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString( "Stopped reading the file after generating more than 100 messages. The file may contian more errors beyond the ones listed here."), TResultSeverity.Resv_Info)); } // we do not want to think about Gift Destination problems if the import has failed for another reason NeedRecipientLedgerNumber.Clear(); // Do the 'finally' actions and return false return; } // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination then the import will fail if (NeedRecipientLedgerNumber.Rows.Count > 0) { // Do the 'finally' actions and return false return; } // Everything is ok, so we can do our finish actions //Update batch total for the last batch entered. if ((giftBatch != null) && !ImportingEsr) { giftBatch.BatchTotal = totalBatchAmount; } TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Saving all data into the database"), 100); //Finally save pending changes (the last number is updated !) ImportMessage = Catalog.GetString("Saving gift batch"); AGiftBatchAccess.SubmitChanges(FMainDS.AGiftBatch, Transaction); FMainDS.AGiftBatch.AcceptChanges(); ImportMessage = Catalog.GetString("Saving gifts"); AGiftAccess.SubmitChanges(FMainDS.AGift, Transaction); FMainDS.AGift.AcceptChanges(); ImportMessage = Catalog.GetString("Saving giftdetails"); AGiftDetailAccess.SubmitChanges(FMainDS.AGiftDetail, Transaction); FMainDS.AGiftDetail.AcceptChanges(); ImportMessage = Catalog.GetString("Saving ledger"); ALedgerAccess.SubmitChanges(LedgerTable, Transaction); LedgerTable.AcceptChanges(); // Commit the transaction (we know that we got a new one and can control it) SubmissionOK = true; } catch (Exception ex) { // Parse the exception text for possible references to database foreign keys // Make the message more friendly in that case string friendlyExceptionText = MakeFriendlyFKExceptions(ex); if (RowNumber > 0) { // At least we made a start string msg = ImportMessage; if (friendlyExceptionText.Length > 0) { msg += FNewLine + friendlyExceptionText; } if (ImportMessage.StartsWith(Catalog.GetString("Saving "))) { // Do not display any specific line number because these errors occur outside the parsing loop Messages.Add(new TVerificationResult(MCommonConstants.StrExceptionWhileSavingTransactions, msg, TResultSeverity.Resv_Critical)); } else { Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileParsingLine, RowNumber), msg, TResultSeverity.Resv_Critical)); } } else { // We got an exception before we even started parsing the rows (getting a transaction?) Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileParsingLine, RowNumber), friendlyExceptionText, TResultSeverity.Resv_Critical)); } TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Exception Occurred"), 0); SubmissionOK = false; } finally { sr.Close(); if (SubmissionOK) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Gift batch import successful"), 100); } else { Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString("None of the data from the import was saved."), TResultSeverity.Resv_Critical)); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Data could not be saved."), 0); } TProgressTracker.FinishJob(DomainManager.GClientID.ToString()); } // end of 'finally' }); // Set our 'out' parameters ANeedRecipientLedgerNumber = NeedRecipientLedgerNumber; AMessages = Messages; return SubmissionOK; }
/// <summary> /// Import Gift batch data /// The data file contents from the client is sent as a string, imported in the database /// and committed immediately /// </summary> /// <param name="ARequestParams">Hashtable containing the given params </param> /// <param name="AImportString">Big parts of the export file as a simple String</param> /// <param name="ANeedRecipientLedgerNumber">Gifts in this table are responsible for failing the /// import becuase their Family recipients do not have an active Gift Destination</param> /// <param name="AMessages">Additional messages to display in a messagebox</param> /// <returns>false if error</returns> public bool ImportGiftBatches( Hashtable ARequestParams, String AImportString, out GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber, out TVerificationResultCollection AMessages ) { TProgressTracker.InitProgressTracker(DomainManager.GClientID.ToString(), Catalog.GetString("Importing Gift Batches"), 100); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Initialising"), 0); TVerificationResultCollection Messages = new TVerificationResultCollection(); // fix for Mono issue with out parameter: https://bugzilla.xamarin.com/show_bug.cgi?id=28196 AMessages = Messages; GiftBatchTDSAGiftDetailTable NeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); FMainDS = new GiftBatchTDS(); StringReader sr = new StringReader(AImportString); // Parse the supplied parameters FDelimiter = (String)ARequestParams["Delimiter"]; FLedgerNumber = (Int32)ARequestParams["ALedgerNumber"]; FDateFormatString = (String)ARequestParams["DateFormatString"]; String NumberFormat = (String)ARequestParams["NumberFormat"]; FNewLine = (String)ARequestParams["NewLine"]; // Set culture from parameters FCultureInfoNumberFormat = new CultureInfo(NumberFormat.Equals("American") ? "en-US" : "de-DE"); FCultureInfoDate = new CultureInfo("en-GB"); FCultureInfoDate.DateTimeFormat.ShortDatePattern = FDateFormatString; bool TaxDeductiblePercentageEnabled = Convert.ToBoolean( TSystemDefaults.GetSystemDefault(SharedConstants.SYSDEFAULT_TAXDEDUCTIBLEPERCENTAGE, "FALSE")); // Initialise our working variables AGiftBatchRow giftBatch = null; decimal totalBatchAmount = 0; Int32 RowNumber = 0; Int32 InitialTextLength = AImportString.Length; Int32 TextProcessedLength = 0; Int32 PercentDone = 10; Int32 PreviousPercentDone = 0; Boolean CancelledByUser = false; decimal intlRateFromBase = -1.0m; string ImportMessage = Catalog.GetString("Initialising"); // This needs to be initialised because we will be calling the method TSharedFinanceValidationHelper.GetValidPeriodDatesDelegate = @TAccountingPeriodsWebConnector.GetPeriodDates; TSharedFinanceValidationHelper.GetFirstDayOfAccountingPeriodDelegate = @TAccountingPeriodsWebConnector.GetFirstDayOfAccountingPeriod; TDBTransaction Transaction = null; bool SubmissionOK = false; DBAccess.GDBAccessObj.BeginAutoTransaction(IsolationLevel.Serializable, ref Transaction, ref SubmissionOK, delegate { try { // Load supplementary tables that we are going to need for validation ALedgerTable LedgerTable = ALedgerAccess.LoadByPrimaryKey(FLedgerNumber, Transaction); AAccountTable AccountTable = AAccountAccess.LoadViaALedger(FLedgerNumber, Transaction); ACostCentreTable CostCentreTable = ACostCentreAccess.LoadViaALedger(FLedgerNumber, Transaction); AMotivationGroupTable MotivationGroupTable = AMotivationGroupAccess.LoadViaALedger(FLedgerNumber, Transaction); AMotivationDetailTable MotivationDetailTable = AMotivationDetailAccess.LoadViaALedger(FLedgerNumber, Transaction); AAccountPropertyTable AccountPropertyTable = AAccountPropertyAccess.LoadViaALedger(FLedgerNumber, Transaction); AAccountingPeriodTable AccountingPeriodTable = AAccountingPeriodAccess.LoadViaALedger(FLedgerNumber, Transaction); AMethodOfGivingTable MethodOfGivingTable = AMethodOfGivingAccess.LoadAll(Transaction); AMethodOfPaymentTable MethodOfPaymentTable = AMethodOfPaymentAccess.LoadAll(Transaction); ACurrencyTable CurrencyTable = ACurrencyAccess.LoadAll(Transaction); PMailingTable MailingTable = PMailingAccess.LoadAll(Transaction); if (LedgerTable.Rows.Count == 0) { throw new Exception(String.Format(Catalog.GetString("Ledger {0} doesn't exist."), FLedgerNumber)); } string LedgerBaseCurrency = ((ALedgerRow)LedgerTable.Rows[0]).BaseCurrency; string LedgerIntlCurrency = ((ALedgerRow)LedgerTable.Rows[0]).IntlCurrency; ACorporateExchangeRateTable CorporateExchangeRateTable = ACorporateExchangeRateAccess.LoadViaACurrencyToCurrencyCode( LedgerIntlCurrency, Transaction); ADailyExchangeRateTable DailyExchangeRateTable = ADailyExchangeRateAccess.LoadAll(Transaction); ImportMessage = Catalog.GetString("Parsing first line"); AGiftRow previousGift = null; // Go round a loop reading the file line by line FImportLine = sr.ReadLine(); TValidationControlsDict EmptyControlsDict = new TValidationControlsDict(); while (FImportLine != null) { RowNumber++; TextProcessedLength += (FImportLine.Length + FNewLine.Length); PercentDone = 10 + ((TextProcessedLength * 90) / InitialTextLength); // skip empty lines and commented lines if ((FImportLine.Trim().Length > 0) && !FImportLine.StartsWith("/*") && !FImportLine.StartsWith("#")) { int numberOfElements = StringHelper.GetCSVList(FImportLine, FDelimiter).Count; // Read the row analysisType - there is no 'validation' on this so we can make the call with null parameters string RowType = TCommonImport.ImportString(ref FImportLine, FDelimiter, Catalog.GetString("row type"), null, RowNumber, Messages, null); if (RowType == "B") { ImportMessage = Catalog.GetString("Parsing a batch row"); // It is a Batch row if (numberOfElements < 8) { Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), Catalog.GetString( "Wrong number of batch columns. The correct number is either 8 columns (in which case the gift type is assumed to be 'Gift') or 9 columns, which allows for alternative gift types."), TResultSeverity.Resv_Critical)); FImportLine = sr.ReadLine(); if (FImportLine != null) { TextProcessedLength += (FImportLine.Length + FNewLine.Length); } continue; } //Check if this is the start of a new batch (i.e. not the first batch) if ((previousGift != null) && (giftBatch != null)) { //New batch so set total amount of Batch for previous batch giftBatch.BatchTotal = totalBatchAmount; intlRateFromBase = -1.0m; if (TVerificationHelper.IsNullOrOnlyNonCritical(Messages)) { ImportMessage = Catalog.GetString("Saving batch"); AGiftBatchAccess.SubmitChanges(FMainDS.AGiftBatch, Transaction); FMainDS.AGiftBatch.AcceptChanges(); ImportMessage = Catalog.GetString("Saving gift"); AGiftAccess.SubmitChanges(FMainDS.AGift, Transaction); FMainDS.AGift.AcceptChanges(); ImportMessage = Catalog.GetString("Saving giftdetails"); AGiftDetailAccess.SubmitChanges(FMainDS.AGiftDetail, Transaction); FMainDS.AGiftDetail.AcceptChanges(); } previousGift = null; } ImportMessage = Catalog.GetString("Starting new batch"); totalBatchAmount = 0; // Parse the complete line and validate it ParseBatchLine(ref giftBatch, ref Transaction, ref LedgerTable, ref ImportMessage, RowNumber, LedgerBaseCurrency, LedgerIntlCurrency, Messages, EmptyControlsDict, AccountTable, AccountPropertyTable, AccountingPeriodTable, CostCentreTable, CorporateExchangeRateTable, CurrencyTable); if (TVerificationHelper.IsNullOrOnlyNonCritical(Messages)) { // This row passes validation so we can do final actions // Validation will have ensured that we have a corporate rate for intl currency // at least for the first day of the accounting period. // (There may possibly be others between then and the effective date) // We need to know what that rate is... DateTime firstOfMonth; if (TSharedFinanceValidationHelper.GetFirstDayOfAccountingPeriod(FLedgerNumber, giftBatch.GlEffectiveDate, out firstOfMonth)) { intlRateFromBase = TExchangeRateTools.GetCorporateExchangeRate(LedgerBaseCurrency, LedgerIntlCurrency, firstOfMonth, giftBatch.GlEffectiveDate); if (intlRateFromBase <= 0.0m) { // This should never happen (see above) Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), String.Format( "There is no Corporate Exchange Rate for {0} to {1} applicable to the period {2} to {3}. Please set up an appropriate rate and then import the data again.", LedgerBaseCurrency, LedgerIntlCurrency, StringHelper.DateToLocalizedString(firstOfMonth), StringHelper.DateToLocalizedString(giftBatch.GlEffectiveDate)), TResultSeverity.Resv_Critical)); } } } if (TVerificationHelper.IsNullOrOnlyNonCritical(Messages)) { // This row passes validation so we can do final actions // If the batch is not in the ledger currency we populate the Daily Exchange Rate table if (giftBatch.CurrencyCode != LedgerBaseCurrency) { ImportMessage = Catalog.GetString("Updating foreign exchange data"); // we need to create a daily exchange rate pair for the transaction date // start with To Ledger currency if (UpdateDailyExchangeRateTable(DailyExchangeRateTable, giftBatch.CurrencyCode, LedgerBaseCurrency, giftBatch.ExchangeRateToBase, giftBatch.GlEffectiveDate)) { Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrImportInformationForLine, RowNumber), String.Format(Catalog.GetString( "An exchange rate of {0} for '{1}' to '{2}' on {3} will be added to the Daily Exchange Rate table after a successful import."), giftBatch.ExchangeRateToBase, giftBatch.CurrencyCode, LedgerBaseCurrency, StringHelper.DateToLocalizedString(giftBatch.GlEffectiveDate)), TResultSeverity.Resv_Info)); } // Now the inverse for From Ledger currency decimal inverseRate = Math.Round(1 / giftBatch.ExchangeRateToBase, 10); UpdateDailyExchangeRateTable(DailyExchangeRateTable, LedgerBaseCurrency, giftBatch.CurrencyCode, inverseRate, giftBatch.GlEffectiveDate); } } } else if (RowType == "T") { ImportMessage = Catalog.GetString("Parsing a transaction row"); // It is a Transaction row if (numberOfElements < 13) // Perhaps this CSV file is a summary, and can't be imported? { Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), Catalog.GetString( "Wrong number of gift columns. Expected at least 13 columns. (This may be a summary?)"), TResultSeverity.Resv_Critical)); FImportLine = sr.ReadLine(); if (FImportLine != null) { TextProcessedLength += (FImportLine.Length + FNewLine.Length); } continue; } if (giftBatch == null) { Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), Catalog.GetString( "Expected a GiftBatch line, but found a Gift Transaction. Will create a dummy working batch for the current period."), TResultSeverity.Resv_Critical)); // in order to carry on we will make a dummy batch and force the date to fit giftBatch = TGiftBatchFunctions.CreateANewGiftBatchRow(ref FMainDS, ref Transaction, ref LedgerTable, FLedgerNumber, DateTime.Today); } // Parse the line into a new row Int32 preParseMessageCount = Messages.Count; AGiftRow gift = FMainDS.AGift.NewRowTyped(true); AGiftDetailRow giftDetails = FMainDS.AGiftDetail.NewRowTyped(true); ParseTransactionLine(gift, giftBatch, ref previousGift, numberOfElements, ref totalBatchAmount, ref ImportMessage, RowNumber, intlRateFromBase, Messages, MotivationDetailTable, NeedRecipientLedgerNumber, giftDetails); if (Messages.Count == preParseMessageCount) // No parsing errors so we can validate { // (parsing errors will have assumed, probably invalid, values) ImportMessage = Catalog.GetString("Validating the gift data"); int messageCountBeforeValidate = preParseMessageCount; TPartnerClass RecipientClass; string RecipientDescription; TPartnerServerLookups.GetPartnerShortName(giftDetails.RecipientKey, out RecipientDescription, out RecipientClass); // Do our standard validation on this gift AGiftValidation.Validate(this, gift, ref Messages, EmptyControlsDict); TSharedFinanceValidation_Gift.ValidateGiftManual(this, gift, giftBatch.BatchYear, giftBatch.BatchPeriod, null, ref Messages, EmptyControlsDict, MethodOfGivingTable, MethodOfPaymentTable); ImportMessage = Catalog.GetString("Validating the gift details data"); AGiftDetailValidation.Validate(this, giftDetails, ref Messages, EmptyControlsDict); TSharedFinanceValidation_Gift.ValidateGiftDetailManual(this, (GiftBatchTDSAGiftDetailRow)giftDetails, ref Messages, EmptyControlsDict, RecipientClass, null, CostCentreTable, AccountTable, MotivationGroupTable, MotivationDetailTable, MailingTable, giftDetails.RecipientKey); // Fix up the messages for (int i = messageCountBeforeValidate; i < Messages.Count; i++) { ((TVerificationResult)Messages[i]).OverrideResultContext(String.Format(MCommonConstants. StrValidationErrorInLine, RowNumber)); if (Messages[i] is TScreenVerificationResult) { TVerificationResult downgrade = new TVerificationResult((TScreenVerificationResult)Messages[i]); Messages.RemoveAt(i); Messages.Insert(i, downgrade); } } } if (TaxDeductiblePercentageEnabled) { // Sets TaxDeductiblePct and uses it to calculate the tax deductibility amounts for a Gift Detail TGift.SetDefaultTaxDeductibilityData(ref giftDetails, gift.DateEntered, Transaction); } if (TVerificationHelper.IsNullOrOnlyNonCritical(Messages)) { if ((LedgerBaseCurrency != LedgerIntlCurrency) && (giftDetails.GiftAmountIntl != 0)) { // Check if the intl amount is what we expected if (giftDetails.GiftAmountIntl != GLRoutines.Divide(giftDetails.GiftAmount, intlRateFromBase, 2)) { ImportMessage = Catalog.GetString("Updating international exchange rate data"); // The import has used an intl rate that is different from the corporate rate // so we should add a Daily Exchange Rate row pair // start with To Ledger currency decimal fromIntlToBase = GLRoutines.Divide(giftDetails.GiftAmount, giftDetails.GiftAmountIntl); if (UpdateDailyExchangeRateTable(DailyExchangeRateTable, LedgerIntlCurrency, LedgerBaseCurrency, fromIntlToBase, giftBatch.GlEffectiveDate)) { Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrImportInformationForLine, RowNumber), String.Format(Catalog.GetString( "An exchange rate of {0} for '{1}' to '{2}' on {3} will be added to the Daily Exchange Rate table after a successful import."), fromIntlToBase, StringHelper.DateToLocalizedString(giftBatch.GlEffectiveDate)), TResultSeverity.Resv_Info)); } // Now the inverse for From Ledger currency decimal inverseRate = GLRoutines.Divide(giftDetails.GiftAmountIntl, giftDetails.GiftAmount); UpdateDailyExchangeRateTable(DailyExchangeRateTable, LedgerBaseCurrency, LedgerIntlCurrency, inverseRate, giftBatch.GlEffectiveDate); } } } } // If known row analysisType else { if (giftBatch == null) { string msg = Catalog.GetString( "Expecting a Row Type definition. Valid types are 'B' or 'T'. Maybe you are opening a 'Transactions' file."); msg += Catalog.GetString( " You need to be on the 'Transactions' Tab to import transaction-only data into an existing batch."); msg += Catalog.GetString(" Alternatively you may have selected the wrong Field Delimiter."); msg += Catalog.GetString(" Choose a delimiter that shows multiple columns in the preview window."); Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), msg, TResultSeverity.Resv_Critical)); break; } else { Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), String.Format(Catalog.GetString( "'{0}' is not a valid Row Type. Valid types are 'B' or 'T'."), RowType), TResultSeverity.Resv_Critical)); } } } // if the CSV line qualifies if (TProgressTracker.GetCurrentState(DomainManager.GClientID.ToString()).CancelJob == true) { CancelledByUser = true; break; } if (Messages.Count > 100) { // This probably means that it is a big file and the user has made the same mistake many times over break; } // Update progress tracker every few percent if ((PercentDone - PreviousPercentDone) > 3) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), String.Format(Catalog.GetString("Importing row {0}"), RowNumber), (PercentDone > 98) ? 98 : PercentDone); PreviousPercentDone = PercentDone; } // Read the next line FImportLine = sr.ReadLine(); if (FImportLine != null) { TextProcessedLength += (FImportLine.Length + FNewLine.Length); } } // while CSV lines if (CancelledByUser) { Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, String.Format(Catalog.GetString("{0} messages reported."), Messages.Count), TResultSeverity.Resv_Info)); Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, "The import was cancelled by the user.", TResultSeverity.Resv_Info)); return; } // Finished reading the file - did we have critical errors? if (!TVerificationHelper.IsNullOrOnlyNonCritical(Messages)) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Batch has critical errors"), 0); // Record error count Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, String.Format(Catalog.GetString("{0} messages reported."), Messages.Count), TResultSeverity.Resv_Info)); if (FImportLine == null) { // We did reach the end of the file Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString( "Reached the end of file but errors occurred. When these errors are fixed the batch will import successfully."), TResultSeverity.Resv_Info)); } else { // We gave up before the end if (Messages.Count > 100) { Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString( "Stopped reading the file after generating more than 100 messages. The file may contian more errors beyond the ones listed here."), TResultSeverity.Resv_Info)); } else { Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString( "Stopped reading the file. Please check you are using a Gift Batch Import file and have chosen the correct Field Delimiter."), TResultSeverity.Resv_Info)); } } // we do not want to think about Gift Destination problems if the import has failed for another reason NeedRecipientLedgerNumber.Clear(); // Do the 'finally' actions and return false return; } // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination then the import will fail if (NeedRecipientLedgerNumber.Rows.Count > 0) { return; } // Everything is ok, so we can do our finish actions //Update batch total for the last batch entered. if (giftBatch != null) { giftBatch.BatchTotal = totalBatchAmount; } ImportMessage = Catalog.GetString("Saving all data into the database"); //Finally save pending changes (the last number is updated !) ImportMessage = Catalog.GetString("Saving daily exchange rates"); ADailyExchangeRateAccess.SubmitChanges(DailyExchangeRateTable, Transaction); DailyExchangeRateTable.AcceptChanges(); ImportMessage = Catalog.GetString("Saving final batch"); AGiftBatchAccess.SubmitChanges(FMainDS.AGiftBatch, Transaction); FMainDS.AGiftBatch.AcceptChanges(); ImportMessage = Catalog.GetString("Saving final gift"); AGiftAccess.SubmitChanges(FMainDS.AGift, Transaction); FMainDS.AGift.AcceptChanges(); ImportMessage = Catalog.GetString("Saving final giftdetails"); AGiftDetailAccess.SubmitChanges(FMainDS.AGiftDetail, Transaction); FMainDS.AGiftDetail.AcceptChanges(); ImportMessage = Catalog.GetString("Saving ledger changes"); ALedgerAccess.SubmitChanges(LedgerTable, Transaction); FMainDS.ALedger.AcceptChanges(); // Commit the transaction (we know that we got a new one and can control it) SubmissionOK = true; } catch (Exception ex) { // Parse the exception text for possible references to database foreign keys // Make the message more friendly in that case string friendlyExceptionText = MakeFriendlyFKExceptions(ex); if (RowNumber > 0) { // At least we made a start string msg = ImportMessage; if (friendlyExceptionText.Length > 0) { msg += FNewLine + friendlyExceptionText; } if (ImportMessage.StartsWith(Catalog.GetString("Saving "))) { // Do not display any specific line number because these errors occur outside the parsing loop Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileSavingBatch, giftBatch.BatchDescription), msg, TResultSeverity.Resv_Critical)); } else { Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileParsingLine, RowNumber), msg, TResultSeverity.Resv_Critical)); } } else { // We got an exception before we even started parsing the rows (getting a transaction?) Messages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileParsingLine, RowNumber), friendlyExceptionText, TResultSeverity.Resv_Critical)); } TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Exception Occurred"), 0); SubmissionOK = false; } finally { sr.Close(); if (SubmissionOK) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Gift batch import successful"), 100); } else { Messages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString("None of the data from the import was saved."), TResultSeverity.Resv_Critical)); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Data could not be saved."), 0); } TProgressTracker.FinishJob(DomainManager.GClientID.ToString()); } // end of 'finally' }); // Set our 'out' parameters AMessages = Messages; ANeedRecipientLedgerNumber = NeedRecipientLedgerNumber; return SubmissionOK; }
/// <summary> /// This "Einzahlungsschein mit Referenznummer" (ESR) input format is only used in Switzerland. /// This method could be pulled out of here, but sits here quite nicely. /// </summary> /// <param name="AImportLine"></param> /// <param name="AgiftBatch"></param> /// <param name="Agift"></param> /// <param name="AgiftDetails"></param> /// <param name="AIntlRateToBase"></param> /// <param name="AMotivationDetailTable"></param> /// <param name="ANeedRecipientLedgerNumber"></param> /// <param name="AMessages"></param> /// <returns></returns> private Boolean ParseEsrTransactionLine( String AImportLine, AGiftBatchRow AgiftBatch, AGiftRow Agift, AGiftDetailRow AgiftDetails, Decimal AIntlRateToBase, AMotivationDetailTable AMotivationDetailTable, GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber, TVerificationResultCollection AMessages ) { Boolean NonNumericError = false; String Field = AImportLine.Substring(0, 3); Int32 FunctionType = 0; NonNumericError &= !Int32.TryParse(Field, out FunctionType); Int64 DonorKey = 0; Field = AImportLine.Substring(12, 10); NonNumericError &= !Int64.TryParse(Field, out DonorKey); Int64 RecipientKey = 0; Field = AImportLine.Substring(22, 10); NonNumericError &= !Int64.TryParse(Field, out RecipientKey); Int64 intAmount = 0; Field = AImportLine.Substring(39, 10); NonNumericError &= !Int64.TryParse(Field, out intAmount); Decimal Amount = intAmount / 100; if (NonNumericError) { return false; } String MotivGroup = "GIFT"; String MotivDetail = "UNDESIG"; TGuiTools.GetMotivationGroupAndDetail(RecipientKey, ref MotivGroup, ref MotivDetail); Agift.LedgerNumber = AgiftBatch.LedgerNumber; Agift.BatchNumber = AgiftBatch.BatchNumber; Agift.GiftTransactionNumber = AgiftBatch.LastGiftNumber + 1; AgiftBatch.LastGiftNumber++; AgiftBatch.BatchTotal += Amount; Agift.LastDetailNumber = 1; ExchangeFieldsInEsrTransaction(ref DonorKey, ref RecipientKey, AMessages, Agift.GiftTransactionNumber); Agift.DonorKey = DonorKey; Agift.MethodOfGivingCode = "DEFAULT"; Agift.MethodOfPaymentCode = "ESR"; FMainDS.AGift.Rows.Add(Agift); AgiftDetails.RecipientKey = RecipientKey; AgiftDetails.LedgerNumber = AgiftBatch.LedgerNumber; AgiftDetails.BatchNumber = AgiftBatch.BatchNumber; AgiftDetails.GiftTransactionNumber = Agift.GiftTransactionNumber; AgiftDetails.DetailNumber = 1; AgiftDetails.GiftTransactionAmount = Amount; AgiftDetails.GiftAmount = GLRoutines.Divide(Amount, AgiftBatch.ExchangeRateToBase); // amount in ledger currency if (AIntlRateToBase > 0.0m) { AgiftDetails.GiftAmountIntl = GLRoutines.Divide(AgiftDetails.GiftAmount, AIntlRateToBase, 2); } AgiftDetails.RecipientLedgerNumber = TGiftTransactionWebConnector.GetRecipientFundNumber(AgiftDetails.RecipientKey, AgiftBatch.GlEffectiveDate); AgiftDetails.MotivationGroupCode = MotivGroup; AgiftDetails.MotivationDetailCode = MotivDetail; AgiftDetails.CostCentreCode = TGiftTransactionWebConnector.RetrieveCostCentreCodeForRecipient( AgiftDetails.LedgerNumber, AgiftDetails.RecipientKey, AgiftDetails.RecipientLedgerNumber, Agift.DateEntered, AgiftDetails.MotivationGroupCode, AgiftDetails.MotivationDetailCode); AMotivationDetailRow motivationDetailRow = (AMotivationDetailRow)AMotivationDetailTable.Rows.Find( new object[] { FLedgerNumber, AgiftDetails.MotivationGroupCode, AgiftDetails.MotivationDetailCode }); // Account Code is inferred from the motivation detail. Boolean IsTaxDeductible = false; string NewAccountCode = null; string NewTaxDeductibleAccountCode = null; if (motivationDetailRow != null) { IsTaxDeductible = motivationDetailRow.TaxDeductible; NewAccountCode = motivationDetailRow.AccountCode; NewTaxDeductibleAccountCode = motivationDetailRow.TaxDeductibleAccountCode; } AgiftDetails.TaxDeductible = IsTaxDeductible; AgiftDetails.AccountCode = NewAccountCode; AgiftDetails.TaxDeductibleAccountCode = NewTaxDeductibleAccountCode; // If the gift has a recipient with no Gift Destination then the import will fail. Gift is added to a table and returned to client. if ((AgiftDetails.RecipientLedgerNumber == 0) && (AgiftDetails.MotivationGroupCode == MFinanceConstants.MOTIVATION_GROUP_GIFT)) { ((GiftBatchTDSAGiftDetailRow)AgiftDetails).RecipientDescription = "Fault: RecipientLedger Not known"; ANeedRecipientLedgerNumber.Rows.Add((object[])AgiftDetails.ItemArray.Clone()); } FMainDS.AGiftDetail.Rows.Add(AgiftDetails); return true; }
/// <summary> /// Import a transactions file or a clipboard equivalent /// </summary> /// <param name="ACurrentBatchRow">The batch to import to</param> /// <param name="AImportSource">The import source - eg File or Clipboard</param> /// <returns>True if the import was successful</returns> public bool ImportTransactions(AGiftBatchRow ACurrentBatchRow, TGiftImportDataSourceEnum AImportSource) { bool ok = false; String importString; String impOptions; OpenFileDialog dialog = null; if (FPetraUtilsObject.HasChanges) { // saving failed, therefore do not try to import MessageBox.Show(Catalog.GetString("Please save before calling this function!"), Catalog.GetString( "Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if ((ACurrentBatchRow == null) || (ACurrentBatchRow.BatchStatus != MFinanceConstants.BATCH_UNPOSTED)) { MessageBox.Show(Catalog.GetString("Please select an unposted batch to import transactions."), Catalog.GetString( "Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if (ACurrentBatchRow.LastGiftNumber > 0) { if (MessageBox.Show(Catalog.GetString( "The current batch already contains some gift transactions. Do you really want to add more transactions to this batch?"), Catalog.GetString("Gift Transaction Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No) { return false; } } FdlgSeparator = new TDlgSelectCSVSeparator(false); if (AImportSource == TGiftImportDataSourceEnum.FromClipboard) { importString = Clipboard.GetText(TextDataFormat.UnicodeText); if ((importString == null) || (importString.Length == 0)) { MessageBox.Show(Catalog.GetString("Please first copy data from your spreadsheet application!"), Catalog.GetString("Failure"), MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } impOptions = TUserDefaults.GetStringDefault("Imp Options", ";American"); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator = new TDlgSelectCSVSeparator(false); FdlgSeparator.SelectedSeparator = "\t"; FdlgSeparator.CSVData = importString; FdlgSeparator.DateFormat = dateFormatString; if (impOptions.Length > 1) { FdlgSeparator.NumberFormat = impOptions.Substring(1); } } else if (AImportSource == TGiftImportDataSourceEnum.FromFile) { dialog = new OpenFileDialog(); dialog.FileName = TUserDefaults.GetStringDefault("Imp Filename", TClientSettings.GetExportPath() + Path.DirectorySeparatorChar + "import.csv"); dialog.Title = Catalog.GetString("Import Transactions from CSV File"); dialog.Filter = Catalog.GetString("Gift Transactions files (*.csv)|*.csv"); impOptions = TUserDefaults.GetStringDefault("Imp Options", ";" + TDlgSelectCSVSeparator.NUMBERFORMAT_AMERICAN); if (dialog.ShowDialog() == DialogResult.OK) { Boolean fileCanOpen = FdlgSeparator.OpenCsvFile(dialog.FileName); if (!fileCanOpen) { MessageBox.Show(Catalog.GetString("Unable to open file."), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; } importString = File.ReadAllText(dialog.FileName); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator.DateFormat = dateFormatString; if (impOptions.Length > 1) { FdlgSeparator.NumberFormat = impOptions.Substring(1); } FdlgSeparator.SelectedSeparator = impOptions.Substring(0, 1); } else { return false; } } else { // unknown source!! The following need a value... impOptions = String.Empty; importString = String.Empty; } if (FdlgSeparator.ShowDialog() == DialogResult.OK) { Hashtable requestParams = new Hashtable(); requestParams.Add("ALedgerNumber", FLedgerNumber); requestParams.Add("Delimiter", FdlgSeparator.SelectedSeparator); requestParams.Add("DateFormatString", FdlgSeparator.DateFormat); requestParams.Add("NumberFormat", FdlgSeparator.NumberFormat); requestParams.Add("NewLine", Environment.NewLine); bool Repeat = true; while (Repeat) { Repeat = false; TVerificationResultCollection AMessages = new TVerificationResultCollection(); GiftBatchTDSAGiftDetailTable NeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); Thread ImportThread = new Thread(() => ImportGiftTransactions( requestParams, importString, ACurrentBatchRow.BatchNumber, out AMessages, out ok, out NeedRecipientLedgerNumber)); using (TProgressDialog ImportDialog = new TProgressDialog(ImportThread)) { ImportDialog.ShowDialog(); } ShowMessages(AMessages); // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination // then the import will have failed and we need to alert the user if (NeedRecipientLedgerNumber.Rows.Count > 0) { bool OfferToRunImportAgain = true; // for each gift in which the recipient needs a Git Destination foreach (GiftBatchTDSAGiftDetailRow Row in NeedRecipientLedgerNumber.Rows) { if (MessageBox.Show(string.Format( Catalog.GetString( "Gift Import has been cancelled as the recipient '{0}' ({1}) has no Gift Destination assigned."), Row.RecipientDescription, Row.RecipientKey) + "\n\n" + Catalog.GetString("Do you want to assign a Gift Destination to this partner now?"), Catalog.GetString("Gift Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { // allow the user to assign a Gift Destingation TFrmGiftDestination GiftDestinationForm = new TFrmGiftDestination(FPetraUtilsObject.GetForm(), Row.RecipientKey); GiftDestinationForm.ShowDialog(); } else { OfferToRunImportAgain = false; } } // if the user has clicked yes to assigning Gift Destinations then offer to restart the import if (OfferToRunImportAgain && (MessageBox.Show(Catalog.GetString("Would you like to import these Gift Transactions again?"), Catalog.GetString("Gift Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)) { Repeat = true; } } } } if (ok) { MessageBox.Show(Catalog.GetString("Your data was imported successfully!"), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Information); SaveUserDefaults(dialog, impOptions); //FMyUserControl.LoadBatchesForCurrentYear(); FPetraUtilsObject.DisableSaveButton(); } return ok; }
/// <summary> /// Wrapper method to handle returned bool value from remoting call to ImportGiftTransactions /// </summary> /// <param name="ARequestParams"></param> /// <param name="AImportString"></param> /// <param name="ABatchNumber"></param> /// <param name="AMessages"></param> /// <param name="ok"></param> /// <param name="ANeedRecipientLedgerNumber"></param> private void ImportGiftTransactions(Hashtable ARequestParams, string AImportString, Int32 ABatchNumber, out TVerificationResultCollection AMessages, out bool ok, out GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber) { TVerificationResultCollection AResultMessages; bool ImportIsSuccessful; ImportIsSuccessful = TRemote.MFinance.Gift.WebConnectors.ImportGiftTransactions( ARequestParams, AImportString, ABatchNumber, out ANeedRecipientLedgerNumber, out AResultMessages); ok = ImportIsSuccessful; AMessages = AResultMessages; }
/// <summary> /// Main method to post a specified batch /// </summary> /// <param name="ACurrentBatchRow">The batch row to post</param> /// <returns>True if the batch was successfully posted</returns> public bool PostBatch(AGiftBatchRow ACurrentBatchRow) { if ((ACurrentBatchRow == null) || (ACurrentBatchRow.BatchStatus != MFinanceConstants.BATCH_UNPOSTED)) { return(false); } FSelectedBatchNumber = ACurrentBatchRow.BatchNumber; TVerificationResultCollection Verifications; try { FMyForm.EnsureGiftDataPresent(FLedgerNumber, FSelectedBatchNumber); GiftBatchTDSAGiftDetailTable BatchGiftDetails = new GiftBatchTDSAGiftDetailTable(); foreach (GiftBatchTDSAGiftDetailRow Row in FMainDS.AGiftDetail.Rows) { if (Row.BatchNumber == FSelectedBatchNumber) { BatchGiftDetails.Rows.Add((object[])Row.ItemArray.Clone()); } } // there are no gifts in this batch! if (BatchGiftDetails.Rows.Count == 0) { FMyForm.Cursor = Cursors.Default; MessageBox.Show(Catalog.GetString("Batch is empty!"), Catalog.GetString("Posting failed"), MessageBoxButtons.OK, MessageBoxIcon.Stop); return(false); } bool CancelledDueToExWorkerOrAnonDonor; // save first, then post if (!FMyForm.SaveChangesForPosting(BatchGiftDetails, out CancelledDueToExWorkerOrAnonDonor)) { FMyForm.Cursor = Cursors.Default; if (!CancelledDueToExWorkerOrAnonDonor) { // saving failed, therefore do not try to post MessageBox.Show(Catalog.GetString("The batch was not posted due to problems during saving; ") + Environment.NewLine + Catalog.GetString("Please first correct and save the batch, and then post it!")); } return(false); } } catch (Exception ex) { throw ex; } //Check for missing international exchange rate bool IsTransactionInIntlCurrency = false; if (FMyForm.InternationalCurrencyExchangeRate(ACurrentBatchRow, out IsTransactionInIntlCurrency, true) == 0) { return(false); } //Check for inactive KeyMinistries DataTable GiftsWithInactiveKeyMinistries; if (TRemote.MFinance.Gift.WebConnectors.InactiveKeyMinistriesFoundInBatch(FLedgerNumber, FSelectedBatchNumber, out GiftsWithInactiveKeyMinistries)) { string listOfOffendingRows = "Gift Detail Recipient KeyMinistry" + Environment.NewLine; listOfOffendingRows += "------------------------------------------------"; foreach (DataRow dr in GiftsWithInactiveKeyMinistries.Rows) { listOfOffendingRows += String.Format("{0}{1:0000} {2:00} {3:00000000000} {4}", Environment.NewLine, dr[0], dr[1], dr[2], dr[3]); } string msg = String.Format(Catalog.GetString("Cannot post Batch {0} as inactive Key Ministries found in gifts:{1}{1}{2}"), FSelectedBatchNumber, Environment.NewLine, listOfOffendingRows); MessageBox.Show(msg, Catalog.GetString("Inactive Key Ministries Found")); return(false); } // ask if the user really wants to post the batch if (MessageBox.Show(String.Format(Catalog.GetString("Do you really want to post gift batch {0}?"), FSelectedBatchNumber), Catalog.GetString("Confirm posting of Gift Batch"), MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel) { return(false); } Verifications = new TVerificationResultCollection(); try { FPostingInProgress = true; Thread postingThread = new Thread(() => PostGiftBatch(out Verifications)); using (TProgressDialog dialog = new TProgressDialog(postingThread)) { dialog.ShowDialog(); } if (!TVerificationHelper.IsNullOrOnlyNonCritical(Verifications)) { string ErrorMessages = String.Empty; foreach (TVerificationResult verif in Verifications) { ErrorMessages += "[" + verif.ResultContext + "] " + verif.ResultTextCaption + ": " + verif.ResultText + Environment.NewLine; } System.Windows.Forms.MessageBox.Show(ErrorMessages, Catalog.GetString("Posting failed")); } else { MessageBox.Show(Catalog.GetString("The batch has been posted successfully!")); return(true); } } catch (Exception ex) { string msg = (String.Format(Catalog.GetString("Unexpected error occurred during the posting of a Gift Batch!{0}{1}{2}{1} {3}"), Utilities.GetMethodSignature(), Environment.NewLine, ex.Message, ex.InnerException.Message)); TLogging.Log(msg); throw ex; //MessageBox.Show(msg, "Post Gift Batch Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { FPostingInProgress = false; } return(false); }
/// <summary> /// Looks for gifts where the recipient is an ExWorker and asks the user if they want to continue. /// (Make sure GetDataFromControls is called before this method so that AMainDS is up-to-date.) /// </summary> /// <param name="AAction">Why this method is being called</param> /// <param name="AMainDS"></param> /// <param name="APetraUtilsObject"></param> /// <param name="APostingGiftDetails">Only used when being called in order to carry out a batch posting</param> /// <returns>Returns true if saving/posting can continue</returns> public static bool CanContinueWithAnyExWorkers(GiftBatchAction AAction, GiftBatchTDS AMainDS, TFrmPetraEditUtils APetraUtilsObject, DataTable APostingGiftDetails = null) { DataTable ExWorkers = null; string Msg = string.Empty; int BatchNumber = -1; int ExWorkerGifts = 0; string ExWorkerSpecialType = TSystemDefaults.GetStringDefault(SharedConstants.SYSDEFAULT_EXWORKERSPECIALTYPE, "EX-WORKER"); // first check for Ex-Workers in the batch that is being posted/submitted (if a batch is being posted/submitted) if ((APostingGiftDetails != null) && (APostingGiftDetails.Rows.Count > 0)) { ExWorkers = TRemote.MFinance.Gift.WebConnectors.FindGiftRecipientExWorker(APostingGiftDetails, BatchNumber); ExWorkerGifts += ExWorkers.Rows.Count; Msg = GetExWorkersString(AAction, ExWorkerSpecialType, ExWorkers); if (ExWorkers.Rows.Count > 0) { BatchNumber = (int)APostingGiftDetails.Rows[0][GiftBatchTDSAGiftDetailTable.GetBatchNumberDBName()]; } } // check for Ex-Workers in all added and modified data if (APetraUtilsObject.HasChanges) { DataTable Changes = new DataTable(); if (AMainDS.AGiftDetail.GetChangesTyped() != null) { Changes.Merge(AMainDS.AGiftDetail.GetChangesTyped()); } else if (AMainDS.ARecurringGiftDetail.GetChangesTyped() != null) { Changes.Merge(AMainDS.ARecurringGiftDetail.GetChangesTyped()); } if ((Changes != null) && (Changes.Rows.Count > 0)) { ExWorkers = TRemote.MFinance.Gift.WebConnectors.FindGiftRecipientExWorker(Changes, BatchNumber); ExWorkerGifts += ExWorkers.Rows.Count; Msg += GetExWorkersString(null, ExWorkerSpecialType, ExWorkers); } } // alert the user to any recipients who are Ex-Workers if (Msg != string.Empty) { if (AAction == GiftBatchAction.SAVING) { Msg += Environment.NewLine + Environment.NewLine; Msg += Catalog.GetString("Do you want to continue with saving anyway?"); } else { Msg += Environment.NewLine + Environment.NewLine; Msg += Catalog.GetString("(any changes will also need to be saved before "); if (AAction == GiftBatchAction.NEWBATCH) { Msg += Catalog.GetString("a new batch can be created"); } else //POSTING, CANCELLING, SUBMITTING, DELETING { Msg += Catalog.GetString("this batch continues with " + AAction.ToString().ToLower()); } Msg += ")" + Environment.NewLine + Environment.NewLine; Msg += Catalog.GetString("Do you want to continue?"); } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(APetraUtilsObject.GetForm()); if (extendedMessageBox.ShowDialog(Msg, Catalog.GetString("Ex-Workers Found"), string.Empty, TFrmExtendedMessageBox.TButtons.embbYesNo, TFrmExtendedMessageBox.TIcon.embiWarning) == TFrmExtendedMessageBox.TResult.embrNo) { return(false); } } return(true); }
/// <summary> /// this supports the batch export files from Petra 2.x. /// Each line starts with a type specifier, B for batch, J for journal, T for transaction /// </summary> public void ImportBatches(TGiftImportDataSourceEnum AImportSource, GiftBatchTDS AMainDS) { bool ImportOK = false; bool RefreshGUIAfterImport = false; OpenFileDialog OFileDialog = null; if (FPetraUtilsObject.HasChanges) { // saving failed, therefore do not try to import MessageBox.Show(Catalog.GetString("Please save before calling this function!"), Catalog.GetString( "Failure"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } ALedgerRow LedgerRow = (ALedgerRow)AMainDS.ALedger.Rows[0]; int CurrentTopBatchNumber = LedgerRow.LastGiftBatchNumber; try { FMyForm.FCurrentGiftBatchAction = Logic.TExtraGiftBatchChecks.GiftBatchAction.IMPORTING; bool datesMayBeIntegers = TUserDefaults.GetBooleanDefault(MCommonConstants.USERDEFAULT_IMPORTEDDATESMAYBEINTEGERS, false); FdlgSeparator = new TDlgSelectCSVSeparator(false); FdlgSeparator.DateMayBeInteger = datesMayBeIntegers; if (AImportSource == TGiftImportDataSourceEnum.FromClipboard) { string ImportString = Clipboard.GetText(TextDataFormat.UnicodeText); if ((ImportString == null) || (ImportString.Length == 0)) { MessageBox.Show(Catalog.GetString("Please first copy data from your spreadsheet application!"), Catalog.GetString("Failure"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } FdlgSeparator.CSVData = ImportString; } else if (AImportSource == TGiftImportDataSourceEnum.FromFile) { OFileDialog = new OpenFileDialog(); string exportPath = TClientSettings.GetExportPath(); string fullPath = TUserDefaults.GetStringDefault("Imp Filename", exportPath + Path.DirectorySeparatorChar + "import.csv"); TImportExportDialogs.SetOpenFileDialogFilePathAndName(OFileDialog, fullPath, exportPath); OFileDialog.Title = Catalog.GetString("Import Batches from CSV File"); OFileDialog.Filter = Catalog.GetString("Gift Batch Files(*.csv)|*.csv|Text Files(*.txt)|*.txt"); // This call fixes Windows7 Open File Dialogs. It must be the line before ShowDialog() TWin7FileOpenSaveDialog.PrepareDialog(Path.GetFileName(fullPath)); if (OFileDialog.ShowDialog() == DialogResult.OK) { Boolean fileCanOpen = FdlgSeparator.OpenCsvFile(OFileDialog.FileName); if (!fileCanOpen) { MessageBox.Show(Catalog.GetString("Unable to open file."), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Stop); return; } } else { return; } } else { // unknown source!! return; } String impOptions = TUserDefaults.GetStringDefault("Imp Options", ";" + TDlgSelectCSVSeparator.NUMBERFORMAT_AMERICAN); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator.DateFormat = dateFormatString; FdlgSeparator.NumberFormat = (impOptions.Length > 1) ? impOptions.Substring(1) : TDlgSelectCSVSeparator.NUMBERFORMAT_AMERICAN; FdlgSeparator.SelectedSeparator = StringHelper.GetCSVSeparator(FdlgSeparator.FileContent) ?? ((impOptions.Length > 0) ? impOptions.Substring(0, 1) : ";"); if (FdlgSeparator.ShowDialog() == DialogResult.OK) { Hashtable requestParams = new Hashtable(); requestParams.Add("ALedgerNumber", FLedgerNumber); requestParams.Add("Delimiter", FdlgSeparator.SelectedSeparator); requestParams.Add("DateFormatString", FdlgSeparator.DateFormat); requestParams.Add("DatesMayBeIntegers", datesMayBeIntegers); requestParams.Add("NumberFormat", FdlgSeparator.NumberFormat); requestParams.Add("NewLine", Environment.NewLine); bool Repeat = true; while (Repeat) { Repeat = false; TVerificationResultCollection AMessages = new TVerificationResultCollection(); GiftBatchTDSAGiftDetailTable NeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); Thread ImportThread = new Thread(() => ImportGiftBatches( requestParams, FdlgSeparator.FileContent, out AMessages, out ImportOK, out RefreshGUIAfterImport, out NeedRecipientLedgerNumber)); using (TProgressDialog ImportDialog = new TProgressDialog(ImportThread)) { ImportDialog.ShowDialog(); } // If NeedRecipientLedgerNumber contains data then AMessages will only ever contain // one message alerting the user that no data has been imported. // We do not want to show this as we will be displaying another more detailed message. if (NeedRecipientLedgerNumber.Rows.Count == 0) { if (TVerificationHelper.ResultsContainErrorCode(AMessages, PetraErrorCodes.ERR_DB_SERIALIZATION_EXCEPTION)) { TConcurrentServerTransactions.ShowTransactionSerializationExceptionDialog(); } else { ShowMessages(AMessages); } } // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination // then the import will have failed and we need to alert the user if (NeedRecipientLedgerNumber.Rows.Count > 0) { bool OfferToRunImportAgain = true; bool DoNotShowMessageBoxEverytime = false; TFrmExtendedMessageBox.TResult Result = TFrmExtendedMessageBox.TResult.embrUndefined; int count = 1; // for each gift in which the recipient needs a Git Destination foreach (GiftBatchTDSAGiftDetailRow Row in NeedRecipientLedgerNumber.Rows) { if (!DoNotShowMessageBoxEverytime) { string CheckboxText = string.Empty; // only show checkbox if there is at least one more occurrence of this error if (NeedRecipientLedgerNumber.Rows.Count - count > 0) { CheckboxText = string.Format( Catalog.GetString( "Do this for all further occurrences ({0})?"), NeedRecipientLedgerNumber.Rows.Count - count); } TFrmExtendedMessageBox extendedMessageBox = new TFrmExtendedMessageBox(FPetraUtilsObject.GetForm()); extendedMessageBox.ShowDialog(string.Format( Catalog.GetString( "Gift Import has been cancelled as the recipient '{0}' ({1}) has no Gift Destination assigned."), Row.RecipientDescription, Row.RecipientKey) + "\n\r\n\r\n\r" + Catalog.GetString("Do you want to assign a Gift Destination to this partner now?"), Catalog.GetString("Import Errors"), CheckboxText, TFrmExtendedMessageBox.TButtons.embbYesNo, TFrmExtendedMessageBox.TIcon.embiWarning); Result = extendedMessageBox.GetResult(out DoNotShowMessageBoxEverytime); } if (Result == TFrmExtendedMessageBox.TResult.embrYes) { // allow the user to assign a Gift Destingation TFrmGiftDestination GiftDestinationForm = new TFrmGiftDestination(FPetraUtilsObject.GetForm(), Row.RecipientKey); GiftDestinationForm.ShowDialog(); } else { OfferToRunImportAgain = false; if (DoNotShowMessageBoxEverytime) { break; } } count++; } // if the user has clicked yes to assigning Gift Destinations then offer to restart the import if (OfferToRunImportAgain && (MessageBox.Show(Catalog.GetString("Would you like to import this Gift Batch again?"), Catalog.GetString("Gift Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)) { Repeat = true; } } } } // We save the defaults even if ok is false - because the client will probably want to try and import // the same file again after correcting any errors SaveUserDefaults(OFileDialog); if (ImportOK) { MessageBox.Show(Catalog.GetString("Your data was imported successfully!"), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Information); } if (ImportOK) { FMyUserControl.LoadBatchesForCurrentYear(); FMyForm.GetBatchControl().SelectRowInBatchGrid(1); DataView allNewBatches = new DataView(AMainDS.AGiftBatch); allNewBatches.RowFilter = String.Format("{0} > {1}", AGiftBatchTable.GetBatchNumberDBName(), CurrentTopBatchNumber); foreach (DataRowView drv in allNewBatches) { drv.Row.SetModified(); } FPetraUtilsObject.SetChangedFlag(); //Force initial inactive values check FMyForm.SaveChangesManual(FMyForm.FCurrentGiftBatchAction); } else if (RefreshGUIAfterImport) { FMyUserControl.LoadBatchesForCurrentYear(); FMyForm.GetBatchControl().SelectRowInBatchGrid(1); } } finally { FMyForm.FCurrentGiftBatchAction = Logic.TExtraGiftBatchChecks.GiftBatchAction.NONE; } }
public void SpeedTestLoadIntoTypedTable() { TDBTransaction ReadTransaction = null; DateTime before = DateTime.Now; DateTime after = DateTime.Now; GiftBatchTDS ds = new GiftBatchTDS(); DBAccess.GDBAccessObj.GetNewOrExistingAutoReadTransaction( IsolationLevel.ReadCommitted, TEnforceIsolationLevel.eilMinimum, ref ReadTransaction, delegate { string sql = "SELECT PUB_a_gift_detail.*, false AS AlreadyMatched, PUB_a_gift_batch.a_batch_status_c AS BatchStatus " + "FROM PUB_a_gift_batch, PUB_a_gift_detail " + "WHERE PUB_a_gift_detail.a_ledger_number_i = PUB_a_gift_batch.a_ledger_number_i AND PUB_a_gift_detail.a_batch_number_i = PUB_a_gift_batch.a_batch_number_i"; before = DateTime.Now; DataTable untyped = DBAccess.GDBAccessObj.SelectDT(sql, "test", ReadTransaction); after = DateTime.Now; TLogging.Log(String.Format("loading all {0} gift details into an untyped table took {1} milliseconds", untyped.Rows.Count, (after.Subtract(before)).TotalMilliseconds)); GiftBatchTDSAGiftDetailTable typed = new GiftBatchTDSAGiftDetailTable(); before = DateTime.Now; DBAccess.GDBAccessObj.SelectDT(typed, sql, ReadTransaction, new OdbcParameter[0], 0, 0); after = DateTime.Now; TLogging.Log(String.Format("loading all {0} gift details into a typed table took {1} milliseconds", typed.Rows.Count, (after.Subtract(before)).TotalMilliseconds)); AMotivationDetailAccess.LoadAll(ds, ReadTransaction); before = DateTime.Now; DBAccess.GDBAccessObj.Select(ds, sql, ds.AGiftDetail.TableName, ReadTransaction); after = DateTime.Now; }); TLogging.Log(String.Format("loading all {0} gift details into a typed dataset took {1} milliseconds", ds.AGiftDetail.Rows.Count, (after.Subtract(before)).TotalMilliseconds)); before = DateTime.Now; GiftBatchTDS ds2 = new GiftBatchTDS(); ds2.Merge(ds.AGiftDetail); after = DateTime.Now; TLogging.Log(String.Format("merging typed table into other dataset took {0} milliseconds", (after.Subtract(before)).TotalMilliseconds)); }
// auto populate recipient info using the donor's last gift private void AutoPopulateGiftDetail(Int64 ADonorKey) { FAutoPopulatingGift = true; try { AGiftTable GiftTable = new AGiftTable(); GiftBatchTDSAGiftDetailTable GiftDetailTable = new GiftBatchTDSAGiftDetailTable(); // check if the donor has another gift in this same batch foreach (AGiftRow GiftRow in FMainDS.AGift.Rows) { if ((GiftRow.RowState != DataRowState.Deleted) && (GiftRow.DonorKey == ADonorKey) && (GiftRow.GiftTransactionNumber != GetSelectedDetailRow().GiftTransactionNumber)) { GiftTable.Rows.Add((object[])GiftRow.ItemArray.Clone()); } } // if the donor does have another gift then get the AGiftDetail records for the most recent gift if (GiftTable.Rows.Count > 0) { // find the most recent gift (probably the last gift in the table) AGiftRow LatestGiftRow = (AGiftRow)GiftTable.Rows[GiftTable.Rows.Count - 1]; for (int i = GiftTable.Rows.Count - 2; i >= 0; i--) { if (LatestGiftRow.DateEntered < ((AGiftRow)GiftTable.Rows[i]).DateEntered) { LatestGiftRow = (AGiftRow)GiftTable.Rows[i]; } } foreach (AGiftDetailRow GiftDetailRow in FMainDS.AGiftDetail.Rows) { if ((GiftDetailRow.LedgerNumber == LatestGiftRow.LedgerNumber) && (GiftDetailRow.BatchNumber == LatestGiftRow.BatchNumber) && (GiftDetailRow.GiftTransactionNumber == LatestGiftRow.GiftTransactionNumber)) { GiftDetailTable.Rows.Add((object[])GiftDetailRow.ItemArray.Clone()); } } } else { // if the donor does not have another gift in this gift batch then search the database for // the last gift from this donor GiftDetailTable = TRemote.MFinance.Gift.WebConnectors.LoadDonorLastGift(ADonorKey, FLedgerNumber); } // if this is the donor's first ever gift if ((GiftDetailTable == null) || (GiftDetailTable.Rows.Count == 0)) { // set FirstTimeGift field in AGift to true GiftBatchTDSAGiftDetailRow CurrentDetail = GetSelectedDetailRow(); AGiftRow CurrentGift = (AGiftRow)FMainDS.AGift.Rows.Find( new object[] { CurrentDetail.LedgerNumber, CurrentDetail.BatchNumber, CurrentDetail.GiftTransactionNumber }); CurrentGift.FirstTimeGift = true; // add donor key to list so that new donor warning can be shown if (!FNewDonorsList.Contains(ADonorKey)) { FNewDonorsList.Add(ADonorKey); } } bool SplitGift = false; // if the last gift was a split gift (multiple details) then ask the user if they would like this new gift to also be split if ((GiftDetailTable != null) && (GiftDetailTable.Rows.Count > 1)) { GiftDetailTable.DefaultView.Sort = GiftBatchTDSAGiftDetailTable.GetDetailNumberDBName() + " ASC"; string Message = string.Format(Catalog.GetString( "The last gift from this donor was a split gift.{0}{0}Here are the details:{0}"), "\n"); int DetailNumber = 1; foreach (DataRowView dvr in GiftDetailTable.DefaultView) { GiftBatchTDSAGiftDetailRow Row = (GiftBatchTDSAGiftDetailRow)dvr.Row; Message += DetailNumber + ") "; if (Row.RecipientKey > 0) { Message += string.Format(Catalog.GetString("Recipient: {0} ({1}); Motivation Group: {2}; Motivation Detail: {3}; Amount: {4}"), Row.RecipientDescription, Row.RecipientKey, Row.MotivationGroupCode, Row.MotivationDetailCode, StringHelper.FormatUsingCurrencyCode(Row.GiftTransactionAmount, GetBatchRow().CurrencyCode) + " " + FBatchRow.CurrencyCode) + "\n"; } DetailNumber++; } Message += "\n" + Catalog.GetString("Do you want to create the same split gift again?"); SplitGift = MessageBox.Show(Message, Catalog.GetString("Create Split Gift"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; } if ((GiftDetailTable != null) && (GiftDetailTable.Rows.Count > 0)) { int CurrentTransaction = 0; while (true) { GiftBatchTDSAGiftDetailRow Row = (GiftBatchTDSAGiftDetailRow)GiftDetailTable.DefaultView[CurrentTransaction].Row; // populate gift detail txtDetailDonorKey.Text = String.Format("{0:0000000000}", ADonorKey); txtDetailRecipientKey.Text = String.Format("{0:0000000000}", Row.RecipientKey); cmbDetailMotivationGroupCode.SetSelectedString(Row.MotivationGroupCode); cmbDetailMotivationDetailCode.SetSelectedString(Row.MotivationDetailCode); chkDetailConfidentialGiftFlag.Checked = Row.ConfidentialGiftFlag; chkDetailChargeFlag.Checked = Row.ChargeFlag; chkDetailTaxDeductible.Checked = Row.TaxDeductible; ToggleTaxDeductible(this, null); cmbDetailMailingCode.SetSelectedString(Row.MailingCode, -1); if (SplitGift) { // only populate amount if a split gift txtDetailGiftTransactionAmount.NumberValueDecimal = Row.GiftTransactionAmount; CurrentTransaction++; // if there are more details that are part of this gift if (CurrentTransaction < GiftDetailTable.Rows.Count) { // clear previous validation errors. // otherwise we get an error if the user has changed the control immediately after changing the donor key. FPetraUtilsObject.VerificationResultCollection.Clear(); // create a new gift detail CreateANewGift(false); } else { break; } } else { break; } } } } finally { FAutoPopulatingGift = false; } }
public static GiftBatchTDSAGiftDetailTable LoadDonorLastGift(Int64 ADonorPartnerKey, Int32 ALedgerNumber) { #region Validate Arguments if (ADonorPartnerKey < 0) { throw new ArgumentException(String.Format(Catalog.GetString( "Function:{0} - The Donor Partnerkey cannot be a negative number!"), Utilities.GetMethodName(true))); } #endregion Validate Arguments GiftBatchTDSAGiftDetailTable LastGiftData = new GiftBatchTDSAGiftDetailTable(); TDBTransaction Transaction = null; DBAccess.GDBAccessObj.GetNewOrExistingAutoReadTransaction(IsolationLevel.ReadCommitted, ref Transaction, delegate { // load latest gift from donor string Query = "SELECT Gift.*" + " FROM a_gift AS Gift" + " WHERE Gift.a_ledger_number_i = " + ALedgerNumber + " AND Gift.p_donor_key_n = " + ADonorPartnerKey + " AND Gift.a_date_entered_d =" + "(SELECT MAX(a_gift.a_date_entered_d)" + " FROM a_gift" + " WHERE a_gift.a_ledger_number_i = " + ALedgerNumber + " AND a_gift.p_donor_key_n = " + ADonorPartnerKey + ")"; DataTable GiftTable = DBAccess.GDBAccessObj.SelectDT(Query, AGiftTable.GetTableDBName(), Transaction); if ((GiftTable == null) || (GiftTable.Rows.Count == 0)) { return; } DataRow GiftRow = GiftTable.Rows[0]; // load gift details for the latest gift Query = "SELECT a_gift_detail.*, p_partner.p_partner_short_name_c AS RecipientDescription" + " FROM a_gift_detail, p_partner" + " WHERE a_gift_detail.a_ledger_number_i = " + ALedgerNumber + " AND a_gift_detail.a_batch_number_i = " + GiftRow[AGiftTable.GetBatchNumberDBName()] + " AND a_gift_detail.a_gift_transaction_number_i = " + GiftRow[AGiftTable.GetGiftTransactionNumberDBName()] + " AND a_gift_detail.p_recipient_key_n = p_partner.p_partner_key_n"; DBAccess.GDBAccessObj.SelectDT(LastGiftData, Query, Transaction); }); LastGiftData.AcceptChanges(); return LastGiftData; }
private void ParseTransactionLine(AGiftRow AGift, AGiftBatchRow AGiftBatch, ref AGiftRow APreviousGift, int ANumberOfColumns, ref decimal ATotalBatchAmount, ref string AImportMessage, int ARowNumber, TVerificationResultCollection AMessages, TValidationControlsDict AValidationControlsDictGift, TValidationControlsDict AValidationControlsDictGiftDetail, ACostCentreTable AValidationCostCentreTable, AMotivationGroupTable AValidationMotivationGroupTable, AMotivationDetailTable AValidationMotivationDetailTable, AMethodOfGivingTable AValidationMethodOfGivingTable, AMethodOfPaymentTable AValidationMethodOfPaymentTable, ref GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber, out AGiftDetailRow AGiftDetails) { // Is this the format with extra columns? // Actually if it has the extra columns but does not have the optional final 8 columns we cannot distiguish using this test... // A file without extra columns will have between 13 and 21 columns - depending on whether some of the optional ones at the end are included. // A file with extra columns will be between 19 and 27. // So any count between 19 and 21 is ambiguous. We will assume that if the file has extra columns it also has // at least enough of the optional ones to exceed 21. bool HasExtraColumns = (ANumberOfColumns > 21); AImportMessage = Catalog.GetString("Importing the gift data"); AGift.DonorKey = ImportInt64(Catalog.GetString("Donor key"), FMainDS.AGift.ColumnDonorKey, ARowNumber, AMessages, AValidationControlsDictGift); ImportString(Catalog.GetString("short name of donor (unused)"), null, null); // unused // This group is optional and database NULL's are allowed AGift.MethodOfGivingCode = ImportString(Catalog.GetString("Method of giving Code"), FMainDS.AGift.ColumnMethodOfGivingCode, AValidationControlsDictGift, false); AGift.MethodOfPaymentCode = ImportString(Catalog.GetString("Method Of Payment Code"), FMainDS.AGift.ColumnMethodOfPaymentCode, AValidationControlsDictGift, false); AGift.Reference = ImportString(Catalog.GetString("Reference"), FMainDS.AGift.ColumnReference, AValidationControlsDictGift, false); AGift.ReceiptLetterCode = ImportString(Catalog.GetString("Receipt letter code"), FMainDS.AGift.ColumnReceiptLetterCode, AValidationControlsDictGift, false); if (HasExtraColumns) { ImportInt32(Catalog.GetString("Receipt number"), FMainDS.AGift.ColumnReceiptNumber, ARowNumber, AMessages, AValidationControlsDictGift); ImportBoolean(Catalog.GetString("First time gift"), FMainDS.AGift.ColumnFirstTimeGift, AValidationControlsDictGift); ImportBoolean(Catalog.GetString("Receipt printed"), FMainDS.AGift.ColumnReceiptPrinted, AValidationControlsDictGift); } AImportMessage = Catalog.GetString("Importing the gift details"); AGiftDetails = FMainDS.AGiftDetail.NewRowTyped(true); if ((APreviousGift != null) && (AGift.DonorKey == APreviousGift.DonorKey) && (AGift.MethodOfGivingCode == APreviousGift.MethodOfGivingCode) && (AGift.MethodOfPaymentCode == APreviousGift.MethodOfPaymentCode) && (AGift.Reference == APreviousGift.Reference) && (AGift.ReceiptLetterCode == APreviousGift.ReceiptLetterCode) && (AGift.ReceiptNumber == APreviousGift.ReceiptNumber) && (AGift.FirstTimeGift == APreviousGift.FirstTimeGift) && (AGift.ReceiptPrinted == APreviousGift.ReceiptPrinted)) { // this row is a new detail for the previousGift AGift = APreviousGift; AGift.LastDetailNumber++; AGiftDetails.DetailNumber = AGift.LastDetailNumber; } else { APreviousGift = AGift; AGift.LedgerNumber = AGiftBatch.LedgerNumber; AGift.BatchNumber = AGiftBatch.BatchNumber; AGift.GiftTransactionNumber = AGiftBatch.LastGiftNumber + 1; AGiftBatch.LastGiftNumber++; AGift.LastDetailNumber = 1; FMainDS.AGift.Rows.Add(AGift); AGiftDetails.DetailNumber = 1; } AGiftDetails.LedgerNumber = AGift.LedgerNumber; AGiftDetails.BatchNumber = AGiftBatch.BatchNumber; AGiftDetails.GiftTransactionNumber = AGift.GiftTransactionNumber; FMainDS.AGiftDetail.Rows.Add(AGiftDetails); AGiftDetails.RecipientKey = ImportInt64(Catalog.GetString("Recipient key"), FMainDS.AGiftDetail.ColumnRecipientKey, ARowNumber, AMessages, AValidationControlsDictGiftDetail); ImportString(Catalog.GetString("short name of recipient (unused)"), null, null); // unused if (HasExtraColumns) { ImportInt32(Catalog.GetString("Recipient ledger number"), FMainDS.AGiftDetail.ColumnRecipientLedgerNumber, ARowNumber, AMessages, AValidationControlsDictGiftDetail); } // we always calculate RecipientLedgerNumber AGiftDetails.RecipientLedgerNumber = TGiftTransactionWebConnector.GetRecipientFundNumber( AGiftDetails.RecipientKey, AGiftBatch.GlEffectiveDate); decimal currentGiftAmount = ImportDecimal(Catalog.GetString("Gift amount"), FMainDS.AGiftDetail.ColumnGiftTransactionAmount, ARowNumber, AMessages, AValidationControlsDictGiftDetail); AGiftDetails.GiftTransactionAmount = currentGiftAmount; // amount in batch currency ATotalBatchAmount += currentGiftAmount; AGiftDetails.GiftAmount = GLRoutines.Divide(currentGiftAmount, AGiftBatch.ExchangeRateToBase); // amount in ledger currency if (HasExtraColumns) { // amount in international currency ImportDecimal(Catalog.GetString("Gift amount intl"), FMainDS.AGiftDetail.ColumnGiftAmountIntl, ARowNumber, AMessages, AValidationControlsDictGiftDetail); } AGiftDetails.ConfidentialGiftFlag = ImportBoolean(Catalog.GetString("Confidential gift"), FMainDS.AGiftDetail.ColumnConfidentialGiftFlag, AValidationControlsDictGiftDetail, "no"); AGiftDetails.MotivationGroupCode = ImportString(Catalog.GetString("Motivation group code"), FMainDS.AGiftDetail.ColumnMotivationGroupCode, AValidationControlsDictGiftDetail); AGiftDetails.MotivationDetailCode = ImportString(Catalog.GetString("Motivation detail"), FMainDS.AGiftDetail.ColumnMotivationDetailCode, AValidationControlsDictGiftDetail); if (HasExtraColumns) { ImportString(Catalog.GetString("Cost centre code"), FMainDS.AGiftDetail.ColumnCostCentreCode, AValidationControlsDictGiftDetail); } // "In Petra Cost Centre is always inferred from recipient field and motivation detail so is not needed in the import." AGiftDetails.CostCentreCode = InferCostCentre(AGiftDetails); // All the remaining columns are optional and can contain database NULL AGiftDetails.GiftCommentOne = ImportString(Catalog.GetString("Gift comment one"), FMainDS.AGiftDetail.ColumnGiftCommentOne, AValidationControlsDictGiftDetail, false); string commentOneType = ImportString(Catalog.GetString("Comment one type"), FMainDS.AGiftDetail.ColumnCommentOneType, AValidationControlsDictGiftDetail, false); AGiftDetails.MailingCode = ImportString(Catalog.GetString("Mailing code"), FMainDS.AGiftDetail.ColumnMailingCode, AValidationControlsDictGiftDetail, false); AGiftDetails.GiftCommentTwo = ImportString(Catalog.GetString("Gift comment two"), FMainDS.AGiftDetail.ColumnGiftCommentTwo, AValidationControlsDictGiftDetail, false); string commentTwoType = ImportString(Catalog.GetString("Comment two type"), FMainDS.AGiftDetail.ColumnCommentTwoType, AValidationControlsDictGiftDetail, false); AGiftDetails.GiftCommentThree = ImportString(Catalog.GetString("Gift comment three"), FMainDS.AGiftDetail.ColumnGiftCommentThree, AValidationControlsDictGiftDetail, false); string commentThreeType = ImportString(Catalog.GetString("Comment three type"), FMainDS.AGiftDetail.ColumnCommentThreeType, AValidationControlsDictGiftDetail, false); SetCommentTypeCase(ref commentOneType); AGiftDetails.CommentOneType = commentOneType; SetCommentTypeCase(ref commentTwoType); AGiftDetails.CommentOneType = commentTwoType; SetCommentTypeCase(ref commentThreeType); AGiftDetails.CommentOneType = commentThreeType; // Find the default Tax deductabilty from the motivation detail. This ensures that the column can be missing. AMotivationDetailRow motivationDetailRow = (AMotivationDetailRow)AValidationMotivationDetailTable.Rows.Find( new object[] { FLedgerNumber, AGiftDetails.MotivationGroupCode, AGiftDetails.MotivationDetailCode }); string defaultTaxDeductible = ((motivationDetailRow != null) && !motivationDetailRow.IsTaxDeductibleAccountNull() && motivationDetailRow.TaxDeductible) ? "yes" : "no"; AGiftDetails.TaxDeductible = ImportBoolean(Catalog.GetString("Tax deductible"), FMainDS.AGiftDetail.ColumnTaxDeductible, AValidationControlsDictGiftDetail, defaultTaxDeductible); // Date entered cannot be imported although it can be modified in the GUI. // This is because it would have to be the last column in the import for compatibility // but it belongs with the gift and not the detail so it would need to go in an earlier column. // For now the import date entered is the effective date. AGift.DateEntered = AGiftBatch.GlEffectiveDate; // Enforce the correct case for our GIFT constant if (String.Compare(AGiftDetails.MotivationGroupCode, MFinanceConstants.MOTIVATION_GROUP_GIFT, true) == 0) { AGiftDetails.MotivationGroupCode = MFinanceConstants.MOTIVATION_GROUP_GIFT; } TPartnerClass RecipientClass; string RecipientDescription; TPartnerServerLookups.GetPartnerShortName(AGiftDetails.RecipientKey, out RecipientDescription, out RecipientClass); // If the gift has a Family recipient with no Gift Destination then the import will fail. Gift is added to a table and returned to client. if ((AGiftDetails.RecipientLedgerNumber == 0) && (AGiftDetails.MotivationGroupCode == MFinanceConstants.MOTIVATION_GROUP_GIFT)) { if (RecipientClass == TPartnerClass.FAMILY) { ((GiftBatchTDSAGiftDetailRow)AGiftDetails).RecipientDescription = RecipientDescription; ANeedRecipientLedgerNumber.Rows.Add((object[])AGiftDetails.ItemArray.Clone()); } } AImportMessage = Catalog.GetString("Validating the gift data"); int messageCountBeforeValidate = AMessages.Count; // Do our standard validation on this gift AGiftValidation.Validate(this, AGift, ref AMessages, AValidationControlsDictGift); TSharedFinanceValidation_Gift.ValidateGiftManual(this, AGift, AGiftBatch.BatchYear, AGiftBatch.BatchPeriod, null, ref AMessages, AValidationControlsDictGift, AValidationMethodOfGivingTable, AValidationMethodOfPaymentTable); AImportMessage = Catalog.GetString("Validating the gift details data"); AGiftDetailValidation.Validate(this, AGiftDetails, ref AMessages, AValidationControlsDictGiftDetail); TSharedFinanceValidation_Gift.ValidateGiftDetailManual(this, (GiftBatchTDSAGiftDetailRow)AGiftDetails, ref AMessages, AValidationControlsDictGiftDetail, RecipientClass, AValidationCostCentreTable, AValidationMotivationGroupTable, AValidationMotivationDetailTable, AGiftDetails.RecipientKey); for (int i = messageCountBeforeValidate; i < AMessages.Count; i++) { ((TVerificationResult)AMessages[i]).OverrideResultContext(String.Format(MCommonConstants.StrValidationErrorInLine, ARowNumber)); if (AMessages[i] is TScreenVerificationResult) { TVerificationResult downgrade = new TVerificationResult((TScreenVerificationResult)AMessages[i]); AMessages.RemoveAt(i); AMessages.Insert(i, downgrade); } } }
/// <summary> /// Main method to post a specified batch /// </summary> /// <param name="ACurrentBatchRow">The batch row to post</param> /// <returns>True if the batch was successfully posted</returns> public bool PostBatch(AGiftBatchRow ACurrentBatchRow) { if ((ACurrentBatchRow == null) || (ACurrentBatchRow.BatchStatus != MFinanceConstants.BATCH_UNPOSTED)) { return false; } FSelectedBatchNumber = ACurrentBatchRow.BatchNumber; TVerificationResultCollection Verifications; try { FMyForm.Cursor = Cursors.WaitCursor; FMyForm.EnsureGiftDataPresent(FLedgerNumber, FSelectedBatchNumber); GiftBatchTDSAGiftDetailTable BatchGiftDetails = new GiftBatchTDSAGiftDetailTable(); foreach (GiftBatchTDSAGiftDetailRow Row in FMainDS.AGiftDetail.Rows) { if (Row.BatchNumber == FSelectedBatchNumber) { BatchGiftDetails.Rows.Add((object[])Row.ItemArray.Clone()); } } // there are no gifts in this batch! if (BatchGiftDetails.Rows.Count == 0) { FMyForm.Cursor = Cursors.Default; MessageBox.Show(Catalog.GetString("Batch is empty!"), Catalog.GetString("Posting failed"), MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; } bool CancelledDueToExWorkerOrAnonDonor; // save first, then post if (!FMyForm.SaveChangesForPosting(BatchGiftDetails, out CancelledDueToExWorkerOrAnonDonor)) { FMyForm.Cursor = Cursors.Default; if (!CancelledDueToExWorkerOrAnonDonor) { // saving failed, therefore do not try to post MessageBox.Show(Catalog.GetString("The batch was not posted due to problems during saving; ") + Environment.NewLine + Catalog.GetString("Please first save the batch, and then post it!")); } return false; } } finally { FMyForm.Cursor = Cursors.Default; } //Check for missing international exchange rate bool IsTransactionInIntlCurrency = false; if (FMyForm.InternationalCurrencyExchangeRate(ACurrentBatchRow, out IsTransactionInIntlCurrency, true) == 0) { return false; } //Check for inactive KeyMinistries DataTable GiftsWithInactiveKeyMinistries; if (TRemote.MFinance.Gift.WebConnectors.InactiveKeyMinistriesFoundInBatch(FLedgerNumber, FSelectedBatchNumber, out GiftsWithInactiveKeyMinistries)) { string listOfRow = "Gift Detail Recipient KeyMinistry" + Environment.NewLine; listOfRow += "------------------------------------------------"; foreach (DataRow dr in GiftsWithInactiveKeyMinistries.Rows) { listOfRow += String.Format("{0}{1:0000} {2:00} {3:00000000000} {4}", Environment.NewLine, dr[0], dr[1], dr[2], dr[3]); } string msg = String.Format(Catalog.GetString("Cannot post Batch {0} as inactive Key Ministries found in gifts:{1}{1}{2}"), FSelectedBatchNumber, Environment.NewLine, listOfRow); MessageBox.Show(msg, Catalog.GetString("Inactive Key Ministries Found")); return false; } // ask if the user really wants to post the batch if (MessageBox.Show(String.Format(Catalog.GetString("Do you really want to post gift batch {0}?"), FSelectedBatchNumber), Catalog.GetString("Confirm posting of Gift Batch"), MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel) { return false; } Verifications = new TVerificationResultCollection(); try { FPostingInProgress = true; Thread postingThread = new Thread(() => PostGiftBatch(out Verifications)); using (TProgressDialog dialog = new TProgressDialog(postingThread)) { dialog.ShowDialog(); } if (!TVerificationHelper.IsNullOrOnlyNonCritical(Verifications)) { string ErrorMessages = String.Empty; foreach (TVerificationResult verif in Verifications) { ErrorMessages += "[" + verif.ResultContext + "] " + verif.ResultTextCaption + ": " + verif.ResultText + Environment.NewLine; } System.Windows.Forms.MessageBox.Show(ErrorMessages, Catalog.GetString("Posting failed")); } else { MessageBox.Show(Catalog.GetString("The batch has been posted successfully!")); return true; } } catch { //Do nothing } finally { FPostingInProgress = false; } return false; }
/// <summary> /// Import Gift batch data /// The data file contents from the client is sent as a string, imported in the database /// and committed immediately /// </summary> /// <param name="ARequestParams">Hashtable containing the given params </param> /// <param name="AImportString">Big parts of the export file as a simple String</param> /// <param name="ANeedRecipientLedgerNumber">Gifts in this table are responsible for failing the /// import becuase their Family recipients do not have an active Gift Destination</param> /// <param name="AMessages">Additional messages to display in a messagebox</param> /// <returns>false if error</returns> public bool ImportGiftBatches( Hashtable ARequestParams, String AImportString, out GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber, out TVerificationResultCollection AMessages ) { TProgressTracker.InitProgressTracker(DomainManager.GClientID.ToString(), Catalog.GetString("Importing Gift Batches"), 100); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Initialising"), 0); AMessages = new TVerificationResultCollection(); FMainDS = new GiftBatchTDS(); StringReader sr = new StringReader(AImportString); ANeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); // Parse the supplied parameters FDelimiter = (String)ARequestParams["Delimiter"]; FLedgerNumber = (Int32)ARequestParams["ALedgerNumber"]; FDateFormatString = (String)ARequestParams["DateFormatString"]; String NumberFormat = (String)ARequestParams["NumberFormat"]; FNewLine = (String)ARequestParams["NewLine"]; // Set culture from parameters FCultureInfoNumberFormat = new CultureInfo(NumberFormat.Equals("American") ? "en-US" : "de-DE"); FCultureInfoDate = new CultureInfo("en-GB"); FCultureInfoDate.DateTimeFormat.ShortDatePattern = FDateFormatString; bool TaxDeductiblePercentageEnabled = Convert.ToBoolean( TSystemDefaults.GetSystemDefault(SharedConstants.SYSDEFAULT_TAXDEDUCTIBLEPERCENTAGE, "FALSE")); // Initialise our working variables TDBTransaction Transaction = null; AGiftBatchRow giftBatch = null; decimal totalBatchAmount = 0; Int32 RowNumber = 0; Int32 InitialTextLength = AImportString.Length; Int32 TextProcessedLength = 0; Int32 PercentDone = 10; Int32 PreviousPercentDone = 0; bool ok = false; string ImportMessage = Catalog.GetString("Initialising"); // Create some validation dictionaries TValidationControlsDict ValidationControlsDictBatch = new TValidationControlsDict(); TValidationControlsDict ValidationControlsDictGift = new TValidationControlsDict(); TValidationControlsDict ValidationControlsDictGiftDetail = new TValidationControlsDict(); try { // This needs to be initialised because we will be calling the method TSharedFinanceValidationHelper.GetValidPeriodDatesDelegate = @TAccountingPeriodsWebConnector.GetPeriodDates; TSharedFinanceValidationHelper.GetFirstDayOfAccountingPeriodDelegate = @TAccountingPeriodsWebConnector.GetFirstDayOfAccountingPeriod; // Get a new transaction Transaction = DBAccess.GDBAccessObj.BeginTransaction(IsolationLevel.Serializable); // If we did not succeed there is something wrong (a transaction is already dangling somewhere?) if (Transaction == null) { throw new Exception(Catalog.GetString( "Could not create a new import transaction because an existing transaction has not completed.")); } // Load supplementary tables that we are going to need for validation ALedgerTable LedgerTable = ALedgerAccess.LoadByPrimaryKey(FLedgerNumber, Transaction); AAccountTable AccountTable = AAccountAccess.LoadViaALedger(FLedgerNumber, Transaction); ACostCentreTable CostCentreTable = ACostCentreAccess.LoadViaALedger(FLedgerNumber, Transaction); AMotivationGroupTable MotivationGroupTable = AMotivationGroupAccess.LoadViaALedger(FLedgerNumber, Transaction); AMotivationDetailTable MotivationDetailTable = AMotivationDetailAccess.LoadViaALedger(FLedgerNumber, Transaction); AAccountPropertyTable AccountPropertyTable = AAccountPropertyAccess.LoadViaALedger(FLedgerNumber, Transaction); AAccountingPeriodTable AccountingPeriodTable = AAccountingPeriodAccess.LoadViaALedger(FLedgerNumber, Transaction); AMethodOfGivingTable MethodOfGivingTable = AMethodOfGivingAccess.LoadAll(Transaction); AMethodOfPaymentTable MethodOfPaymentTable = AMethodOfPaymentAccess.LoadAll(Transaction); ACurrencyTable CurrencyTable = ACurrencyAccess.LoadAll(Transaction); if (LedgerTable.Rows.Count == 0) { throw new Exception(String.Format(Catalog.GetString("Ledger {0} doesn't exist."), FLedgerNumber)); } FLedgerBaseCurrency = ((ALedgerRow)LedgerTable.Rows[0]).BaseCurrency; FLedgerIntlCurrency = ((ALedgerRow)LedgerTable.Rows[0]).IntlCurrency; ACorporateExchangeRateTable CorporateExchangeToLedgerTable = ACorporateExchangeRateAccess.LoadViaACurrencyFromCurrencyCode( FLedgerBaseCurrency, Transaction); ADailyExchangeRateTable DailyExchangeToLedgerTable = ADailyExchangeRateAccess.LoadViaACurrencyToCurrencyCode(FLedgerBaseCurrency, Transaction); ADailyExchangeRateTable DailyExchangeToIntlTable = ADailyExchangeRateAccess.LoadViaACurrencyToCurrencyCode(FLedgerIntlCurrency, Transaction); ImportMessage = Catalog.GetString("Parsing first line"); AGiftRow previousGift = null; // Go round a loop reading the file line by line FImportLine = sr.ReadLine(); while (FImportLine != null) { RowNumber++; TextProcessedLength += (FImportLine.Length + FNewLine.Length); PercentDone = 10 + ((TextProcessedLength * 90) / InitialTextLength); // skip empty lines and commented lines if ((FImportLine.Trim().Length > 0) && !FImportLine.StartsWith("/*") && !FImportLine.StartsWith("#")) { int numberOfElements = StringHelper.GetCSVList(FImportLine, FDelimiter).Count; // Read the row analysisType - there is no 'validation' on this so we can make the call with null parameters string RowType = ImportString(Catalog.GetString("row type"), null, null); if (RowType == "B") { ImportMessage = Catalog.GetString("Parsing a batch row"); // It is a Batch row if (numberOfElements < 8) { AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), Catalog.GetString( "Wrong number of batch columns. The correct number is either 8 columns (in which case the gift type is assumed to be 'Gift') or 9 columns, which allows for alternative gift types."), TResultSeverity.Resv_Critical)); FImportLine = sr.ReadLine(); if (FImportLine != null) { TextProcessedLength += (FImportLine.Length + FNewLine.Length); } continue; } //Check if this is the start of a new batch (i.e. not the first batch) if ((previousGift != null) && (giftBatch != null)) { //New batch so set total amount of Batch for previous batch giftBatch.BatchTotal = totalBatchAmount; if (TVerificationHelper.IsNullOrOnlyNonCritical(AMessages)) { ImportMessage = Catalog.GetString("Saving batch"); AGiftBatchAccess.SubmitChanges(FMainDS.AGiftBatch, Transaction); FMainDS.AGiftBatch.AcceptChanges(); ImportMessage = Catalog.GetString("Saving gift"); AGiftAccess.SubmitChanges(FMainDS.AGift, Transaction); FMainDS.AGift.AcceptChanges(); ImportMessage = Catalog.GetString("Saving giftdetails"); AGiftDetailAccess.SubmitChanges(FMainDS.AGiftDetail, Transaction); FMainDS.AGiftDetail.AcceptChanges(); } previousGift = null; } ImportMessage = Catalog.GetString("Starting new batch"); totalBatchAmount = 0; // Parse the complete line and validate it ParseBatchLine(ref giftBatch, ref Transaction, ref LedgerTable, ref ImportMessage, RowNumber, AMessages, ValidationControlsDictBatch, AccountTable, AccountPropertyTable, AccountingPeriodTable, CostCentreTable, CorporateExchangeToLedgerTable, CurrencyTable); if (TVerificationHelper.IsNullOrOnlyNonCritical(AMessages)) { // This row passes validation so we can do final actions if the batch is not in the ledger currency if (giftBatch.CurrencyCode != FLedgerBaseCurrency) { ImportMessage = Catalog.GetString("Updating foreign exchange data"); // Validation will have ensured that we have a corporate rate for the effective date // We need to know what that rate is... DateTime firstOfMonth = new DateTime(giftBatch.GlEffectiveDate.Year, giftBatch.GlEffectiveDate.Month, 1); ACorporateExchangeRateRow corporateRateRow = (ACorporateExchangeRateRow)CorporateExchangeToLedgerTable.Rows.Find( new object[] { giftBatch.CurrencyCode, FLedgerBaseCurrency, firstOfMonth }); decimal corporateRate = corporateRateRow.RateOfExchange; if (Math.Abs((giftBatch.ExchangeRateToBase - corporateRate) / corporateRate) > 0.20m) { AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrImportValidationWarningInLine, RowNumber), String.Format(Catalog.GetString( "The exchange rate of {0} differs from the Corporate Rate of {1} for the month commencing {2} by more than 20 percent."), giftBatch.ExchangeRateToBase, corporateRate, StringHelper.DateToLocalizedString(firstOfMonth)), TResultSeverity.Resv_Noncritical)); } // we need to create a daily exchange rate pair for the transaction date // start with To Ledger currency if (UpdateDailyExchangeRateTable(DailyExchangeToLedgerTable, giftBatch.CurrencyCode, FLedgerBaseCurrency, giftBatch.ExchangeRateToBase, giftBatch.GlEffectiveDate)) { ADailyExchangeRateAccess.SubmitChanges(DailyExchangeToLedgerTable, Transaction); DailyExchangeToLedgerTable.AcceptChanges(); AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrImportInformationForLine, RowNumber), String.Format(Catalog.GetString("Added exchange rate of {0} to Daily Exchange Rate table for {1}"), giftBatch.ExchangeRateToBase, StringHelper.DateToLocalizedString(giftBatch.GlEffectiveDate)), TResultSeverity.Resv_Info)); } // Now the inverse for From Ledger currency ADailyExchangeRateTable DailyExchangeFromTable = ADailyExchangeRateAccess.LoadViaACurrencyFromCurrencyCode(giftBatch.CurrencyCode, Transaction); decimal inverseRate = Math.Round(1 / giftBatch.ExchangeRateToBase, 10); if (UpdateDailyExchangeRateTable(DailyExchangeFromTable, FLedgerBaseCurrency, giftBatch.CurrencyCode, inverseRate, giftBatch.GlEffectiveDate)) { ADailyExchangeRateAccess.SubmitChanges(DailyExchangeFromTable, Transaction); } } } } else if (RowType == "T") { ImportMessage = Catalog.GetString("Parsing a transaction row"); // It is a Transaction row if (numberOfElements < 13) // Perhaps this CSV file is a summary, and can't be imported? { AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), Catalog.GetString("Wrong number of gift columns. Expected at least 13 columns. (This may be a summary?)"), TResultSeverity.Resv_Critical)); FImportLine = sr.ReadLine(); if (FImportLine != null) { TextProcessedLength += (FImportLine.Length + FNewLine.Length); } continue; } if (giftBatch == null) { AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), Catalog.GetString( "Expected a GiftBatch line, but found a Gift Transaction. Will create a dummy working batch for the current period."), TResultSeverity.Resv_Critical)); // in order to carry on we will make a dummy batch and force the date to fit giftBatch = TGiftBatchFunctions.CreateANewGiftBatchRow(ref FMainDS, ref Transaction, ref LedgerTable, FLedgerNumber, DateTime.Today); } // Parse the line into a new row AGiftRow gift = FMainDS.AGift.NewRowTyped(true); AGiftDetailRow giftDetails; ParseTransactionLine(gift, giftBatch, ref previousGift, numberOfElements, ref totalBatchAmount, ref ImportMessage, RowNumber, AMessages, ValidationControlsDictGift, ValidationControlsDictGiftDetail, CostCentreTable, MotivationGroupTable, MotivationDetailTable, MethodOfGivingTable, MethodOfPaymentTable, ref ANeedRecipientLedgerNumber, out giftDetails); if (TaxDeductiblePercentageEnabled) { // Sets TaxDeductiblePct and uses it to calculate the tax deductibility amounts for a Gift Detail TGift.SetDefaultTaxDeductibilityData(ref giftDetails, gift.DateEntered, Transaction); } if (TVerificationHelper.IsNullOrOnlyNonCritical(AMessages)) { if ((FLedgerBaseCurrency != FLedgerIntlCurrency) && (giftDetails.GiftAmountIntl != 0)) { ImportMessage = Catalog.GetString("Updating international exchange rate data"); // We should add a Daily Exchange Rate row pair // start with To Ledger currency decimal fromIntlToBase = GLRoutines.Divide(giftDetails.GiftAmount, giftDetails.GiftAmountIntl); if (UpdateDailyExchangeRateTable(DailyExchangeToLedgerTable, FLedgerIntlCurrency, FLedgerBaseCurrency, fromIntlToBase, giftBatch.GlEffectiveDate)) { ADailyExchangeRateAccess.SubmitChanges(DailyExchangeToLedgerTable, Transaction); DailyExchangeToLedgerTable.AcceptChanges(); AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrImportInformationForLine, RowNumber), String.Format(Catalog.GetString( "Added exchange rate of {0} to Daily Exchange Rate table for ledger currency / international currency on {1}"), fromIntlToBase, StringHelper.DateToLocalizedString(giftBatch.GlEffectiveDate)), TResultSeverity.Resv_Info)); } // Now the inverse for From Ledger currency decimal inverseRate = GLRoutines.Divide(giftDetails.GiftAmountIntl, giftDetails.GiftAmount); if (UpdateDailyExchangeRateTable(DailyExchangeToIntlTable, FLedgerBaseCurrency, FLedgerIntlCurrency, inverseRate, giftBatch.GlEffectiveDate)) { ADailyExchangeRateAccess.SubmitChanges(DailyExchangeToIntlTable, Transaction); DailyExchangeToIntlTable.AcceptChanges(); } } } } // If known row analysisType else { AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), Catalog.GetString("Invalid Row Type. Perhaps using wrong CSV separator?"), TResultSeverity.Resv_Critical)); } } // if the CSV line qualifies if (AMessages.Count > 100) { // This probably means that it is a big file and the user has made the same mistake many times over break; } // Update progress tracker every few percent if ((PercentDone - PreviousPercentDone) > 3) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), String.Format(Catalog.GetString("Importing row {0}"), RowNumber), (PercentDone > 98) ? 98 : PercentDone); PreviousPercentDone = PercentDone; } // Read the next line FImportLine = sr.ReadLine(); if (FImportLine != null) { TextProcessedLength += (FImportLine.Length + FNewLine.Length); } } // while CSV lines // Finished reading the file - did we have critical errors? if (!TVerificationHelper.IsNullOrOnlyNonCritical(AMessages)) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Batch has critical errors"), 0); // Record error count AMessages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, String.Format(Catalog.GetString("{0} messages reported."), AMessages.Count), TResultSeverity.Resv_Info)); if (FImportLine == null) { // We did reach the end of the file AMessages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString( "Reached the end of file but errors occurred. When these errors are fixed the batch will import successfully."), TResultSeverity.Resv_Info)); } else { // We gave up before the end AMessages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString( "Stopped reading the file after generating more than 100 messages. The file may contian more errors beyond the ones listed here."), TResultSeverity.Resv_Info)); } TLogging.Log("Return from here!"); // we do not want to think about Gift Destination problems if the import has failed for another reason ANeedRecipientLedgerNumber.Clear(); // Do the 'finally' actions and return false return false; } // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination then the import will fail if (ANeedRecipientLedgerNumber.Rows.Count > 0) { return false; } // Everything is ok, so we can do our finish actions //Update batch total for the last batch entered. if (giftBatch != null) { giftBatch.BatchTotal = totalBatchAmount; } ImportMessage = Catalog.GetString("Saving all data into the database"); //Finally save pending changes (the last number is updated !) ImportMessage = Catalog.GetString("Saving final batch"); AGiftBatchAccess.SubmitChanges(FMainDS.AGiftBatch, Transaction); FMainDS.AGiftBatch.AcceptChanges(); ImportMessage = Catalog.GetString("Saving final gift"); AGiftAccess.SubmitChanges(FMainDS.AGift, Transaction); FMainDS.AGift.AcceptChanges(); ImportMessage = Catalog.GetString("Saving final giftdetails"); AGiftDetailAccess.SubmitChanges(FMainDS.AGiftDetail, Transaction); FMainDS.AGiftDetail.AcceptChanges(); ImportMessage = Catalog.GetString("Saving ledger changes"); ALedgerAccess.SubmitChanges(LedgerTable, Transaction); FMainDS.ALedger.AcceptChanges(); // Commit the transaction (we know that we got a new one and can control it) DBAccess.GDBAccessObj.CommitTransaction(); ok = true; } catch (Exception ex) { // Parse the exception text for possible references to database foreign keys // Make the message more friendly in that case string friendlyExceptionText = MakeFriendlyFKExceptions(ex); if (AMessages == null) { AMessages = new TVerificationResultCollection(); } if (RowNumber > 0) { // At least we made a start string msg = ImportMessage; if (friendlyExceptionText.Length > 0) { msg += FNewLine + friendlyExceptionText; } if (ImportMessage.StartsWith(Catalog.GetString("Saving "))) { // Do not display any specific line number because these errors occur outside the parsing loop AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileSavingBatch, giftBatch.BatchDescription), msg, TResultSeverity.Resv_Critical)); } else { AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileParsingLine, RowNumber), msg, TResultSeverity.Resv_Critical)); } } else { // We got an exception before we even started parsing the rows (getting a transaction?) AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileParsingLine, RowNumber), friendlyExceptionText, TResultSeverity.Resv_Critical)); } TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Exception Occurred"), 0); ok = false; } finally { try { sr.Close(); } catch (Exception Exc) { TLogging.Log("An Exception occured while closing the Import File:" + Environment.NewLine + Exc.ToString()); if (AMessages == null) { AMessages = new TVerificationResultCollection(); } AMessages.Add(new TVerificationResult(Catalog.GetString("Import exception"), Catalog.GetString("A problem was encountered while closing the Import File:"), TResultSeverity.Resv_Critical)); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Exception Occurred"), 0); TProgressTracker.FinishJob(DomainManager.GClientID.ToString()); throw; } if (ok) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Gift batch import successful"), 100); } else { DBAccess.GDBAccessObj.RollbackTransaction(); if (AMessages == null) { AMessages = new TVerificationResultCollection(); } AMessages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString("None of the data from the import was saved."), TResultSeverity.Resv_Critical)); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Data could not be saved."), 0); } TProgressTracker.FinishJob(DomainManager.GClientID.ToString()); } // end of 'finally' return ok; }
private void FPetraUtilsObject_DataSavingStarted_NewDonorWarning() { GetDataFromControls(); FGiftDetailTable = FMainDS.AGiftDetail.GetChangesTyped(); }
/// <summary> /// Import Gift Transactions from a file /// </summary> /// <param name="ARequestParams"></param> /// <param name="AImportString"></param> /// <param name="AGiftBatchNumber"></param> /// <param name="ANeedRecipientLedgerNumber"></param> /// <param name="AMessages"></param> /// <returns></returns> public bool ImportGiftTransactions( Hashtable ARequestParams, String AImportString, Int32 AGiftBatchNumber, out GiftBatchTDSAGiftDetailTable ANeedRecipientLedgerNumber, out TVerificationResultCollection AMessages ) { TProgressTracker.InitProgressTracker(DomainManager.GClientID.ToString(), Catalog.GetString("Importing Gift Batches"), 100); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Initialising"), 5); AMessages = new TVerificationResultCollection(); FMainDS = new GiftBatchTDS(); StringReader sr = new StringReader(AImportString); ANeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); // Parse the supplied parameters FDelimiter = (String)ARequestParams["Delimiter"]; FLedgerNumber = (Int32)ARequestParams["ALedgerNumber"]; FDateFormatString = (String)ARequestParams["DateFormatString"]; String NumberFormat = (String)ARequestParams["NumberFormat"]; FNewLine = (String)ARequestParams["NewLine"]; // Set culture from parameters FCultureInfoNumberFormat = new CultureInfo(NumberFormat.Equals("American") ? "en-US" : "de-DE"); FCultureInfoDate = new CultureInfo("en-GB"); FCultureInfoDate.DateTimeFormat.ShortDatePattern = FDateFormatString; bool TaxDeductiblePercentageEnabled = Convert.ToBoolean( TSystemDefaults.GetSystemDefault(SharedConstants.SYSDEFAULT_TAXDEDUCTIBLEPERCENTAGE, "FALSE")); // Initialise our working variables TDBTransaction Transaction = null; decimal totalBatchAmount = 0; Int32 RowNumber = 0; Int32 InitialTextLength = AImportString.Length; Int32 TextProcessedLength = 0; Int32 PercentDone = 10; Int32 PreviousPercentDone = 0; bool ok = false; string ImportMessage = Catalog.GetString("Initialising"); // Create some validation dictionaries TValidationControlsDict ValidationControlsDictGift = new TValidationControlsDict(); TValidationControlsDict ValidationControlsDictGiftDetail = new TValidationControlsDict(); try { // This needs to be initialised because we will be calling the method TSharedFinanceValidationHelper.GetValidPeriodDatesDelegate = @TAccountingPeriodsWebConnector.GetPeriodDates; TSharedFinanceValidationHelper.GetFirstDayOfAccountingPeriodDelegate = @TAccountingPeriodsWebConnector.GetFirstDayOfAccountingPeriod; // Get a new transaction Transaction = DBAccess.GDBAccessObj.BeginTransaction(IsolationLevel.Serializable); // If we did not succeed there is something wrong (a transaction is already dangling somewhere?) if (Transaction == null) { throw new Exception(Catalog.GetString( "Could not create a new import transaction because an existing transaction has not completed.")); } // Load supplementary tables that we are going to need for validation ALedgerTable LedgerTable = ALedgerAccess.LoadByPrimaryKey(FLedgerNumber, Transaction); ACostCentreTable CostCentreTable = ACostCentreAccess.LoadViaALedger(FLedgerNumber, Transaction); AMotivationGroupTable MotivationGroupTable = AMotivationGroupAccess.LoadViaALedger(FLedgerNumber, Transaction); AMotivationDetailTable MotivationDetailTable = AMotivationDetailAccess.LoadViaALedger(FLedgerNumber, Transaction); AMethodOfGivingTable MethodOfGivingTable = AMethodOfGivingAccess.LoadAll(Transaction); AMethodOfPaymentTable MethodOfPaymentTable = AMethodOfPaymentAccess.LoadAll(Transaction); AGiftBatchTable giftBatchTable = AGiftBatchAccess.LoadViaALedger(FLedgerNumber, Transaction); DataView giftBatchDV = new DataView(giftBatchTable, String.Format("{0}={1}", AGiftBatchTable.GetBatchNumberDBName(), AGiftBatchNumber), "", DataViewRowState.CurrentRows); FMainDS.AGiftBatch.ImportRow(giftBatchDV[0].Row); FMainDS.AcceptChanges(); AGiftBatchRow giftBatch = (AGiftBatchRow)FMainDS.AGiftBatch.Rows.Find(new object[] { FLedgerNumber, AGiftBatchNumber }); if (LedgerTable.Rows.Count == 0) { throw new Exception(String.Format(Catalog.GetString("Ledger {0} doesn't exist."), FLedgerNumber)); } ImportMessage = Catalog.GetString("Parsing first line"); AGiftRow previousGift = null; // Go round a loop reading the file line by line FImportLine = sr.ReadLine(); while (FImportLine != null) { RowNumber++; TextProcessedLength += (FImportLine.Length + FNewLine.Length); PercentDone = 10 + ((TextProcessedLength * 90) / InitialTextLength); // skip empty lines and commented lines if ((FImportLine.Trim().Length > 0) && !FImportLine.StartsWith("/*") && !FImportLine.StartsWith("#")) { // number of elements is incremented by 1 as though the line started with 'T' int numberOfElements = StringHelper.GetCSVList(FImportLine, FDelimiter).Count + 1; // It is a Transaction row if (numberOfElements < 13) // Perhaps this CSV file is a summary, and can't be imported? { AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrParsingErrorInLine, RowNumber), Catalog.GetString("Wrong number of gift columns. Expected at least 13 columns. (This may be a summary?)"), TResultSeverity.Resv_Critical)); FImportLine = sr.ReadLine(); if (FImportLine != null) { TextProcessedLength += (FImportLine.Length + FNewLine.Length); } continue; } // Parse the line into a new row ImportMessage = Catalog.GetString("Parsing transaction line"); AGiftRow gift = FMainDS.AGift.NewRowTyped(true); AGiftDetailRow giftDetails; ParseTransactionLine(gift, giftBatch, ref previousGift, numberOfElements, ref totalBatchAmount, ref ImportMessage, RowNumber, AMessages, ValidationControlsDictGift, ValidationControlsDictGiftDetail, CostCentreTable, MotivationGroupTable, MotivationDetailTable, MethodOfGivingTable, MethodOfPaymentTable, ref ANeedRecipientLedgerNumber, out giftDetails); if (TaxDeductiblePercentageEnabled) { // Sets TaxDeductiblePct and uses it to calculate the tax deductibility amounts for a Gift Detail TGift.SetDefaultTaxDeductibilityData(ref giftDetails, gift.DateEntered, Transaction); } } if (AMessages.Count > 100) { // This probably means that it is a big file and the user has made the same mistake many times over break; } // Update progress tracker every few percent if ((PercentDone - PreviousPercentDone) > 3) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), String.Format(Catalog.GetString("Importing row {0}"), RowNumber), (PercentDone > 98) ? 98 : PercentDone); PreviousPercentDone = PercentDone; } // Read the next line FImportLine = sr.ReadLine(); if (FImportLine != null) { TextProcessedLength += (FImportLine.Length + FNewLine.Length); } } // while CSV lines // Finished reading the file - did we have critical errors? if (!TVerificationHelper.IsNullOrOnlyNonCritical(AMessages)) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Batch has critical errors"), 100); // Record error count AMessages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, String.Format(Catalog.GetString("{0} messages reported."), AMessages.Count), TResultSeverity.Resv_Info)); if (FImportLine == null) { // We did reach the end of the file AMessages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString( "Reached the end of file but errors occurred. When these errors are fixed the batch will import successfully."), TResultSeverity.Resv_Info)); } else { // We gave up before the end AMessages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString( "Stopped reading the file after generating more than 100 messages. The file may contian more errors beyond the ones listed here."), TResultSeverity.Resv_Info)); } TLogging.Log("Return from here!"); // we do not want to think about Gift Destination problems if the import has failed for another reason ANeedRecipientLedgerNumber.Clear(); // Do the 'finally' actions and return false return false; } // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination then the import will fail if (ANeedRecipientLedgerNumber.Rows.Count > 0) { // Do the 'finally' actions and return false return false; } // Everything is ok, so we can do our finish actions //Update batch total for the last batch entered. if (giftBatch != null) { giftBatch.BatchTotal = totalBatchAmount; } TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Saving all data into the database"), 100); //Finally save pending changes (the last number is updated !) ImportMessage = Catalog.GetString("Saving gift batch"); AGiftBatchAccess.SubmitChanges(FMainDS.AGiftBatch, Transaction); FMainDS.AGiftBatch.AcceptChanges(); ImportMessage = Catalog.GetString("Saving gifts"); AGiftAccess.SubmitChanges(FMainDS.AGift, Transaction); FMainDS.AGift.AcceptChanges(); ImportMessage = Catalog.GetString("Saving giftdetails"); AGiftDetailAccess.SubmitChanges(FMainDS.AGiftDetail, Transaction); FMainDS.AGiftDetail.AcceptChanges(); ImportMessage = Catalog.GetString("Saving ledger"); ALedgerAccess.SubmitChanges(LedgerTable, Transaction); LedgerTable.AcceptChanges(); // Commit the transaction (we know that we got a new one and can control it) DBAccess.GDBAccessObj.CommitTransaction(); ok = true; } catch (Exception ex) { // Parse the exception text for possible references to database foreign keys // Make the message more friendly in that case string friendlyExceptionText = MakeFriendlyFKExceptions(ex); if (AMessages == null) { AMessages = new TVerificationResultCollection(); } if (RowNumber > 0) { // At least we made a start string msg = ImportMessage; if (friendlyExceptionText.Length > 0) { msg += FNewLine + friendlyExceptionText; } if (ImportMessage.StartsWith(Catalog.GetString("Saving "))) { // Do not display any specific line number because these errors occur outside the parsing loop AMessages.Add(new TVerificationResult(MCommonConstants.StrExceptionWhileSavingTransactions, msg, TResultSeverity.Resv_Critical)); } else { AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileParsingLine, RowNumber), msg, TResultSeverity.Resv_Critical)); } } else { // We got an exception before we even started parsing the rows (getting a transaction?) AMessages.Add(new TVerificationResult(String.Format(MCommonConstants.StrExceptionWhileParsingLine, RowNumber), friendlyExceptionText, TResultSeverity.Resv_Critical)); } TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Exception Occurred"), 0); ok = false; } finally { try { sr.Close(); } catch (Exception Exc) { TLogging.Log("An Exception occured while closing the Import File:" + Environment.NewLine + Exc.ToString()); if (AMessages == null) { AMessages = new TVerificationResultCollection(); } AMessages.Add(new TVerificationResult(Catalog.GetString("Import exception"), Catalog.GetString("A problem was encountered while closing the Import File:"), TResultSeverity.Resv_Critical)); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Exception Occurred"), 0); TProgressTracker.FinishJob(DomainManager.GClientID.ToString()); throw; } if (ok) { TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Gift batch import successful"), 100); } else { DBAccess.GDBAccessObj.RollbackTransaction(); if (AMessages == null) { AMessages = new TVerificationResultCollection(); } AMessages.Add(new TVerificationResult(MCommonConstants.StrImportInformation, Catalog.GetString("None of the data from the import was saved."), TResultSeverity.Resv_Critical)); TProgressTracker.SetCurrentState(DomainManager.GClientID.ToString(), Catalog.GetString("Data could not be saved."), 0); } TProgressTracker.FinishJob(DomainManager.GClientID.ToString()); } // end of 'finally' return ok; }
/// <summary> /// Import a transactions file or a clipboard equivalent /// </summary> /// <param name="ACurrentBatchRow">The batch to import to</param> /// <param name="AImportSource">The import source - eg File or Clipboard</param> /// <returns>True if the import was successful</returns> public bool ImportTransactions(AGiftBatchRow ACurrentBatchRow, TGiftImportDataSourceEnum AImportSource) { bool ok = false; String importString; String impOptions; OpenFileDialog dialog = null; Boolean IsPlainText = false; if (FPetraUtilsObject.HasChanges) { // saving failed, therefore do not try to import MessageBox.Show(Catalog.GetString("Please save before calling this function!"), Catalog.GetString( "Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } if ((ACurrentBatchRow == null) || (ACurrentBatchRow.BatchStatus != MFinanceConstants.BATCH_UNPOSTED)) { MessageBox.Show(Catalog.GetString("Please select an unposted batch to import transactions."), Catalog.GetString( "Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } if (ACurrentBatchRow.LastGiftNumber > 0) { if (MessageBox.Show(Catalog.GetString( "The current batch already contains some gift transactions. Do you really want to add more transactions to this batch?"), Catalog.GetString("Gift Transaction Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No) { return(false); } } FdlgSeparator = new TDlgSelectCSVSeparator(false); if (AImportSource == TGiftImportDataSourceEnum.FromClipboard) { importString = Clipboard.GetText(TextDataFormat.UnicodeText); if ((importString == null) || (importString.Length == 0)) { MessageBox.Show(Catalog.GetString("Please first copy data from your spreadsheet application!"), Catalog.GetString("Failure"), MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } impOptions = TUserDefaults.GetStringDefault("Imp Options", ";American"); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator = new TDlgSelectCSVSeparator(false); FdlgSeparator.SelectedSeparator = "\t"; FdlgSeparator.CSVData = importString; FdlgSeparator.DateFormat = dateFormatString; if (impOptions.Length > 1) { FdlgSeparator.NumberFormat = impOptions.Substring(1); } } else if (AImportSource == TGiftImportDataSourceEnum.FromFile) { dialog = new OpenFileDialog(); string exportPath = TClientSettings.GetExportPath(); string fullPath = TUserDefaults.GetStringDefault("Imp Filename", exportPath + Path.DirectorySeparatorChar + "import.csv"); TImportExportDialogs.SetOpenFileDialogFilePathAndName(dialog, fullPath, exportPath); dialog.Title = Catalog.GetString("Import Transactions from CSV File"); dialog.Filter = Catalog.GetString("Gift Transactions files (*.csv)|*.csv|Text Files (*.txt)|*.txt"); impOptions = TUserDefaults.GetStringDefault("Imp Options", ";" + TDlgSelectCSVSeparator.NUMBERFORMAT_AMERICAN); // This call fixes Windows7 Open File Dialogs. It must be the line before ShowDialog() TWin7FileOpenSaveDialog.PrepareDialog(Path.GetFileName(fullPath)); if (dialog.ShowDialog() == DialogResult.OK) { Boolean fileCanOpen = FdlgSeparator.OpenCsvFile(dialog.FileName); if (!fileCanOpen) { MessageBox.Show(Catalog.GetString("Unable to open file."), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Stop); return(false); } importString = File.ReadAllText(dialog.FileName, Encoding.Default); IsPlainText = (Path.GetExtension(dialog.FileName).ToLower() == ".txt"); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator.DateFormat = dateFormatString; if (impOptions.Length > 1) { FdlgSeparator.NumberFormat = impOptions.Substring(1); } FdlgSeparator.SelectedSeparator = impOptions.Substring(0, 1); } else { return(false); } } else { // unknown source!! The following need a value... impOptions = String.Empty; importString = String.Empty; } if (IsPlainText || (FdlgSeparator.ShowDialog() == DialogResult.OK)) { Hashtable requestParams = new Hashtable(); requestParams.Add("ALedgerNumber", FLedgerNumber); requestParams.Add("Delimiter", FdlgSeparator.SelectedSeparator); requestParams.Add("DateFormatString", FdlgSeparator.DateFormat); requestParams.Add("NumberFormat", FdlgSeparator.NumberFormat); requestParams.Add("NewLine", Environment.NewLine); bool Repeat = true; while (Repeat) { Repeat = false; TVerificationResultCollection AMessages = new TVerificationResultCollection(); GiftBatchTDSAGiftDetailTable NeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); Thread ImportThread = new Thread(() => ImportGiftTransactions( requestParams, importString, ACurrentBatchRow.BatchNumber, out AMessages, out ok, out NeedRecipientLedgerNumber)); using (TProgressDialog ImportDialog = new TProgressDialog(ImportThread)) { ImportDialog.ShowDialog(); } ShowMessages(AMessages); // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination // then the import will have failed and we need to alert the user if (NeedRecipientLedgerNumber.Rows.Count > 0) { bool OfferToRunImportAgain = true; // for each gift in which the recipient needs a Git Destination foreach (GiftBatchTDSAGiftDetailRow Row in NeedRecipientLedgerNumber.Rows) { if (MessageBox.Show(string.Format( Catalog.GetString( "Gift Import has been cancelled as the recipient '{0}' ({1}) has no Gift Destination assigned."), Row.RecipientDescription, Row.RecipientKey) + "\n\n" + Catalog.GetString("Do you want to assign a Gift Destination to this partner now?"), Catalog.GetString("Gift Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { // allow the user to assign a Gift Destingation TFrmGiftDestination GiftDestinationForm = new TFrmGiftDestination(FPetraUtilsObject.GetForm(), Row.RecipientKey); GiftDestinationForm.ShowDialog(); } else { OfferToRunImportAgain = false; } } // if the user has clicked yes to assigning Gift Destinations then offer to restart the import if (OfferToRunImportAgain && (MessageBox.Show(Catalog.GetString("Would you like to import these Gift Transactions again?"), Catalog.GetString("Gift Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)) { Repeat = true; } } } // We save the defaults even if ok is false - because the client will probably want to try and import // the same file again after correcting any errors SaveUserDefaults(dialog, impOptions); } if (ok) { MessageBox.Show(Catalog.GetString("Your data was imported successfully!"), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Information); //FMyUserControl.LoadBatchesForCurrentYear(); FPetraUtilsObject.DisableSaveButton(); } return(ok); }
/// <summary> /// auto populate new gift recipient info using the donor's last gift /// </summary> /// <param name="ADonorKey"></param> /// <param name="APartnerShortName"></param> /// <param name="AGiftTransactionNumber"></param> private void AutoPopulateGiftDetail(Int64 ADonorKey, String APartnerShortName, Int32 AGiftTransactionNumber) { FAutoPopulatingGiftInProcess = true; bool IsSplitGift = false; DateTime LatestUnpostedGiftDateEntered = new DateTime(1900, 1, 1); try { //Check for Donor in loaded gift batches // and record most recent date entered AGiftTable DonorRecentGiftsTable = new AGiftTable(); GiftBatchTDSAGiftDetailTable GiftDetailTable = new GiftBatchTDSAGiftDetailTable(); AGiftRow MostRecentLoadedGiftForDonorRow = null; DataView giftDV = new DataView(FMainDS.AGift); giftDV.RowStateFilter = DataViewRowState.CurrentRows; giftDV.RowFilter = string.Format("{0}={1} And Not ({2}={3} And {4}={5})", AGiftTable.GetDonorKeyDBName(), ADonorKey, AGiftTable.GetBatchNumberDBName(), FBatchNumber, AGiftTable.GetGiftTransactionNumberDBName(), AGiftTransactionNumber); giftDV.Sort = String.Format("{0} DESC, {1} DESC", AGiftTable.GetDateEnteredDBName(), AGiftTable.GetGiftTransactionNumberDBName()); if (giftDV.Count > 0) { //Take first row = most recent date entered value MostRecentLoadedGiftForDonorRow = (AGiftRow)giftDV[0].Row; LatestUnpostedGiftDateEntered = MostRecentLoadedGiftForDonorRow.DateEntered; DonorRecentGiftsTable.Rows.Add((object[])MostRecentLoadedGiftForDonorRow.ItemArray.Clone()); } //Check for even more recent saved gifts on server (i.e. not necessarily loaded) GiftDetailTable = TRemote.MFinance.Gift.WebConnectors.LoadDonorLastPostedGift(ADonorKey, FLedgerNumber, LatestUnpostedGiftDateEntered); if (((GiftDetailTable != null) && (GiftDetailTable.Count > 0))) { //UnLoaded/Saved gift from donor is more recent IsSplitGift = (GiftDetailTable.Count > 1); } else if (MostRecentLoadedGiftForDonorRow != null) { //Loaded/unsaved gift from donor is more recent DataView giftDetailDV = new DataView(FMainDS.AGiftDetail); giftDetailDV.RowStateFilter = DataViewRowState.CurrentRows; giftDetailDV.RowFilter = string.Format("{0}={1} And {2}={3}", AGiftDetailTable.GetBatchNumberDBName(), MostRecentLoadedGiftForDonorRow.BatchNumber, AGiftDetailTable.GetGiftTransactionNumberDBName(), MostRecentLoadedGiftForDonorRow.GiftTransactionNumber); foreach (DataRowView drv in giftDetailDV) { GiftBatchTDSAGiftDetailRow gDR = (GiftBatchTDSAGiftDetailRow)drv.Row; GiftDetailTable.Rows.Add((object[])gDR.ItemArray.Clone()); } IsSplitGift = (GiftDetailTable.Count > 1); } else { //nothing to autocopy return; } // if the last gift was a split gift (multiple details) then ask the user if they would like this new gift to also be split if (IsSplitGift) { GiftDetailTable.DefaultView.Sort = GiftBatchTDSAGiftDetailTable.GetDetailNumberDBName() + " ASC"; string Message = string.Format(Catalog.GetString( "The last gift from this donor was a split gift.{0}{0}Here are the details:{0}"), "\n"); int DetailNumber = 1; foreach (DataRowView dvr in GiftDetailTable.DefaultView) { GiftBatchTDSAGiftDetailRow Row = (GiftBatchTDSAGiftDetailRow)dvr.Row; Message += DetailNumber + ") "; if (Row.RecipientKey > 0) { Message += string.Format(Catalog.GetString("Recipient: {0} ({1}); Motivation Group: {2}; Motivation Detail: {3}; Amount: {4}"), Row.RecipientDescription, Row.RecipientKey, Row.MotivationGroupCode, Row.MotivationDetailCode, StringHelper.FormatUsingCurrencyCode(Row.GiftTransactionAmount, GetBatchRow().CurrencyCode) + " " + FBatchRow.CurrencyCode) + "\n"; } DetailNumber++; } Message += "\n" + Catalog.GetString("Do you want to create the same split gift again?"); if (!(MessageBox.Show(Message, Catalog.GetString( "Create Split Gift"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)) { if (cmbDetailMethodOfGivingCode.CanFocus) { cmbDetailMethodOfGivingCode.Focus(); } else if (txtDetailReference.CanFocus) { txtDetailReference.Focus(); } return; } } this.Cursor = Cursors.WaitCursor; GiftBatchTDSAGiftDetailRow giftDetailRow = (GiftBatchTDSAGiftDetailRow)GiftDetailTable.DefaultView[0].Row; // Handle first row, which is FPreviouslySelectedDetailRow txtDetailDonorKey.Text = String.Format("{0:0000000000}", ADonorKey); txtDetailRecipientKey.Text = String.Format("{0:0000000000}", giftDetailRow.RecipientKey); cmbDetailMotivationGroupCode.SetSelectedString(giftDetailRow.MotivationGroupCode); txtDetailMotivationDetailCode.Text = giftDetailRow.MotivationDetailCode; cmbMotivationDetailCode.SetSelectedString(giftDetailRow.MotivationDetailCode); chkDetailConfidentialGiftFlag.Checked = giftDetailRow.ConfidentialGiftFlag; // Change #5481 chkDetailChargeFlag.Checked = true; cmbDetailMethodOfPaymentCode.SetSelectedString(FBatchMethodOfPayment, -1); cmbDetailMethodOfGivingCode.SetSelectedString(giftDetailRow.MethodOfGivingCode, -1); //Handle mailing code if (FSETAutoCopyIncludeMailingCodeFlag) { cmbDetailMailingCode.SetSelectedString(giftDetailRow.MailingCode, -1); } else { cmbDetailMailingCode.SelectedIndex = -1; } //Copy the comments and comment types if required if (FSETAutoCopyIncludeCommentsFlag) { txtDetailGiftCommentOne.Text = giftDetailRow.GiftCommentOne; cmbDetailCommentOneType.SetSelectedString(giftDetailRow.CommentOneType); txtDetailGiftCommentTwo.Text = giftDetailRow.GiftCommentTwo; cmbDetailCommentTwoType.SetSelectedString(giftDetailRow.CommentTwoType); txtDetailGiftCommentThree.Text = giftDetailRow.GiftCommentThree; cmbDetailCommentThreeType.SetSelectedString(giftDetailRow.CommentThreeType); } //Handle tax fields on current row if (FSETUseTaxDeductiblePercentageFlag) { bool taxDeductible = (giftDetailRow.IsTaxDeductibleNull() ? true : giftDetailRow.TaxDeductible); giftDetailRow.TaxDeductible = taxDeductible; try { FPetraUtilsObject.SuppressChangeDetection = true; chkDetailTaxDeductible.Checked = taxDeductible; EnableTaxDeductibilityPct(taxDeductible); } finally { FPetraUtilsObject.SuppressChangeDetection = false; } if (!IsSplitGift) { //Most commonly not a split gift (?) if (!taxDeductible) { txtDeductiblePercentage.NumberValueDecimal = 0.0m; } txtTaxDeductAmount.NumberValueDecimal = 0.0m; txtNonDeductAmount.NumberValueDecimal = 0.0m; } else { if (taxDeductible) { //In case the tax percentage has changed or null values in amount fields ReconcileTaxDeductibleAmounts(giftDetailRow); } else { //Changing this will update the unbound amount textboxes txtDeductiblePercentage.NumberValueDecimal = 0.0m; } } } //Process values that are not bound to a control giftDetailRow.ReceiptPrinted = false; giftDetailRow.ReceiptNumber = 0; //Now process other gift details if they exist if (IsSplitGift) { //Only copy amount to first row if copying split gifts txtDetailGiftTransactionAmount.NumberValueDecimal = giftDetailRow.GiftTransactionAmount; // clear previous validation errors. // otherwise we get an error if the user has changed the control immediately after changing the donor key. FPetraUtilsObject.VerificationResultCollection.Clear(); bool SelectEndRow = (FBatchRow.LastGiftNumber == FPreviouslySelectedDetailRow.GiftTransactionNumber); //Just retain other details to add giftDetailRow.Delete(); GiftDetailTable.AcceptChanges(); foreach (DataRowView drv in GiftDetailTable.DefaultView) { GiftBatchTDSAGiftDetailRow detailRow = (GiftBatchTDSAGiftDetailRow)drv.Row; //______________________ //Update basic field values detailRow.LedgerNumber = FLedgerNumber; detailRow.BatchNumber = FBatchNumber; detailRow.GiftTransactionNumber = AGiftTransactionNumber; detailRow.DetailNumber = ++FGift.LastDetailNumber; detailRow.DonorName = APartnerShortName; detailRow.DonorClass = FPreviouslySelectedDetailRow.DonorClass; detailRow.DateEntered = FGift.DateEntered; detailRow.MethodOfPaymentCode = FPreviouslySelectedDetailRow.MethodOfPaymentCode; detailRow.ReceiptPrinted = false; detailRow.ReceiptNumber = 0; // Change #5481 detailRow.ChargeFlag = true; if (!FSETAutoCopyIncludeMailingCodeFlag) { detailRow.MailingCode = string.Empty; } //______________________ //process recipient details to get most recent data Int64 partnerKey = detailRow.RecipientKey; string partnerShortName = string.Empty; TPartnerClass partnerClass; bool recipientIsValid = true; if (TServerLookup.TMPartner.GetPartnerShortName(partnerKey, out partnerShortName, out partnerClass)) { detailRow.RecipientDescription = partnerShortName; detailRow.RecipientClass = partnerClass.ToString(); if (partnerClass == TPartnerClass.FAMILY) { detailRow.RecipientLedgerNumber = TRemote.MFinance.Gift.WebConnectors.GetRecipientFundNumber(partnerKey, FGift.DateEntered); detailRow.RecipientField = detailRow.RecipientLedgerNumber; detailRow.RecipientKeyMinistry = string.Empty; } else { //Class - UNIT Int64 field; string keyMinName; recipientIsValid = TFinanceControls.GetRecipientKeyMinData(partnerKey, out field, out keyMinName); detailRow.RecipientLedgerNumber = field; detailRow.RecipientField = field; detailRow.RecipientKeyMinistry = keyMinName; if (!recipientIsValid) { string msg = String.Format(Catalog.GetString( "Gift: {0}, Detail: {1} has a recipient: '{2}-{3}' that is an inactive Key Ministry!"), AGiftTransactionNumber, detailRow.DetailNumber, partnerKey, keyMinName); MessageBox.Show(msg, Catalog.GetString( "Copying Previous Split Gift"), MessageBoxButtons.OK, MessageBoxIcon.Warning); } } } else { recipientIsValid = false; string msg = String.Format(Catalog.GetString("Gift: {0}, Detail: {1} has an invalid Recipient key: '{2}'!"), AGiftTransactionNumber, detailRow.DetailNumber, partnerKey); MessageBox.Show(msg, Catalog.GetString("Copying Previous Split Gift"), MessageBoxButtons.OK, MessageBoxIcon.Warning); } //______________________ //Process motivation if (string.IsNullOrEmpty(detailRow.MotivationGroupCode)) { detailRow.MotivationGroupCode = string.Empty; string msg = String.Format(Catalog.GetString("Gift: {0}, Detail: {1} has no Motivation Group!"), AGiftTransactionNumber, detailRow.DetailNumber); MessageBox.Show(msg, Catalog.GetString("Copying Previous Split Gift"), MessageBoxButtons.OK, MessageBoxIcon.Warning); } else if (string.IsNullOrEmpty(detailRow.MotivationDetailCode)) { detailRow.MotivationDetailCode = string.Empty; string msg = String.Format(Catalog.GetString("Gift: {0}, Detail: {1} has no Motivation Detail!"), AGiftTransactionNumber, detailRow.DetailNumber); MessageBox.Show(msg, Catalog.GetString("Copying Previous Split Gift"), MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { AMotivationDetailRow motivationDetailRow = null; string motivationGroup = detailRow.MotivationGroupCode; string motivationDetail = detailRow.MotivationDetailCode; motivationDetailRow = (AMotivationDetailRow)FMainDS.AMotivationDetail.Rows.Find( new object[] { FLedgerNumber, motivationGroup, motivationDetail }); if (motivationDetailRow != null) { if (partnerKey > 0) { bool partnerIsMissingLink = false; detailRow.CostCentreCode = TRemote.MFinance.Gift.WebConnectors.RetrieveCostCentreCodeForRecipient(FLedgerNumber, partnerKey, detailRow.RecipientLedgerNumber, detailRow.DateEntered, motivationGroup, motivationDetail, out partnerIsMissingLink); } else { if (motivationGroup != MFinanceConstants.MOTIVATION_GROUP_GIFT) { detailRow.RecipientDescription = motivationGroup; } else { detailRow.RecipientDescription = string.Empty; } detailRow.CostCentreCode = motivationDetailRow.CostCentreCode; } detailRow.AccountCode = motivationDetailRow.AccountCode; if (FSETUseTaxDeductiblePercentageFlag && string.IsNullOrEmpty(motivationDetailRow.TaxDeductibleAccountCode)) { detailRow.TaxDeductibleAccountCode = string.Empty; string msg = String.Format(Catalog.GetString( "Gift: {0}, Detail: {1} has Motivation Detail: {2} which has no Tax Deductible Account!" + "This can be added in Finance / Setup / Motivation Details.{3}{3}" + "Unless this is changed it will be impossible to assign a Tax Deductible Percentage to this gift."), AGiftTransactionNumber, detailRow.DetailNumber, motivationDetail, Environment.NewLine); MessageBox.Show(msg, Catalog.GetString( "Copying Previous Split Gift"), MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { detailRow.TaxDeductibleAccountCode = motivationDetailRow.TaxDeductibleAccountCode; } } else { string msg = String.Format(Catalog.GetString( "Gift: {0}, Detail: {1} has Motivation Group and Detail codes ('{2} : {3}') not found in the database!"), AGiftTransactionNumber, detailRow.DetailNumber, motivationGroup, motivationDetail); MessageBox.Show(msg, Catalog.GetString("Copying Previous Split Gift"), MessageBoxButtons.OK, MessageBoxIcon.Warning); detailRow.TaxDeductible = false; } } //______________________ //Handle tax fields detailRow.TaxDeductiblePct = RetrieveTaxDeductiblePct((recipientIsValid ? detailRow.RecipientKey : 0), detailRow.TaxDeductible); AGiftDetailRow giftDetails = (AGiftDetailRow)detailRow; TaxDeductibility.UpdateTaxDeductibiltyAmounts(ref giftDetails); //______________________ //Process comments if (!FSETAutoCopyIncludeCommentsFlag) { detailRow.SetCommentOneTypeNull(); detailRow.SetCommentTwoTypeNull(); detailRow.SetCommentThreeTypeNull(); detailRow.SetGiftCommentOneNull(); detailRow.SetGiftCommentTwoNull(); detailRow.SetGiftCommentThreeNull(); } detailRow.AcceptChanges(); detailRow.SetAdded(); } //Add in the new records (latter two arguments put in to parallel recurring form) FMainDS.AGiftDetail.Merge(GiftDetailTable, false, MissingSchemaAction.Ignore); int indexOfLatestRow = FMainDS.AGiftDetail.Rows.Count - 1; //Select last row added if (SelectEndRow) { grdDetails.SelectRowInGrid(grdDetails.Rows.Count - 1); } else if (!SelectDetailRowByDataTableIndex(indexOfLatestRow)) { if (!FFilterAndFindObject.IsActiveFilterEqualToBase) { MessageBox.Show( MCommonResourcestrings.StrNewRecordIsFiltered, MCommonResourcestrings.StrAddNewRecordTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); FFilterAndFindObject.FilterPanelControls.ClearAllDiscretionaryFilters(); if (FFilterAndFindObject.FilterFindPanel.ShowApplyFilterButton != TUcoFilterAndFind.FilterContext.None) { FFilterAndFindObject.ApplyFilter(); } SelectDetailRowByDataTableIndex(indexOfLatestRow); } } ClearKeyMinistries(); cmbMotivationDetailCode.Clear(); mniRecipientHistory.Enabled = false; btnDeleteAll.Enabled = btnDelete.Enabled; UpdateRecordNumberDisplay(); FLastDonor = -1; } else { txtDetailDonorKey.FocusTextBoxPartAfterFindScreenCloses = false; txtDetailGiftTransactionAmount.Focus(); } FPetraUtilsObject.SetChangedFlag(); } finally { this.Cursor = Cursors.Default; FAutoPopulatingGiftInProcess = false; } }
/// <summary> /// Looks for gifts where the donor is anoymous but the gift is not marked as confidential and asks the user if they want to continue. /// (Make sure GetDataFromControls is called before this method so that AMainDS is up-to-date.) /// </summary> /// <param name="AMainDS"></param> public static bool CanContinueWithAnyAnonymousDonors(GiftBatchTDS AMainDS) { GiftBatchTDSAGiftDetailTable UnConfidentialGiftsWithAnonymousDonors = new GiftBatchTDSAGiftDetailTable(); foreach (GiftBatchTDSAGiftDetailRow Row in AMainDS.AGiftDetail.Rows) { if (!Row.ConfidentialGiftFlag) { PPartnerRow PartnerRow = (PPartnerRow)AMainDS.DonorPartners.Rows.Find(Row.DonorKey); if ((PartnerRow != null) && PartnerRow.AnonymousDonor) { UnConfidentialGiftsWithAnonymousDonors.Rows.Add((object[])Row.ItemArray.Clone()); } } } if (UnConfidentialGiftsWithAnonymousDonors.Rows.Count > 0) { string Message = string.Empty; DataView dv = UnConfidentialGiftsWithAnonymousDonors.DefaultView; dv.Sort = GiftBatchTDSAGiftDetailTable.GetGiftTransactionNumberDBName() + " ASC"; DataTable sortedDT = dv.ToTable(); if (UnConfidentialGiftsWithAnonymousDonors.Rows.Count == 1) { Message = Catalog.GetString( "The gift listed below in this batch is not marked as confidential but the donor has asked to remain anonymous."); } else { Message = Catalog.GetString( "The gifts listed below in this batch are not marked as confidential but the donors have asked to remain anonymous."); } Message += "\n\n"; foreach (DataRow UnConfidentialGifts in sortedDT.Rows) { Message += Catalog.GetString("Batch: ") + UnConfidentialGifts[GiftBatchTDSAGiftDetailTable.GetBatchNumberDBName()] + "; " + Catalog.GetString("Gift: ") + UnConfidentialGifts[GiftBatchTDSAGiftDetailTable.GetGiftTransactionNumberDBName()] + "; " + Catalog.GetString("Donor: ") + UnConfidentialGifts[GiftBatchTDSAGiftDetailTable.GetDonorNameDBName()] + " (" + UnConfidentialGifts[GiftBatchTDSAGiftDetailTable.GetDonorKeyDBName()] + ")\n"; } Message += "\n" + Catalog.GetString("Do you want to continue with posting anyway?"); if (MessageBox.Show( Message, Catalog.GetString("Anonymous Donor Warning"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) { return false; } } return true; }
/// <summary> /// Import a transactions file or a clipboard equivalent /// </summary> /// <param name="ACurrentBatchRow">The batch to import to</param> /// <param name="AImportSource">The import source - eg File or Clipboard</param> /// <returns>True if the import was successful</returns> public bool ImportTransactions(AGiftBatchRow ACurrentBatchRow, TGiftImportDataSourceEnum AImportSource) { bool ok = false; bool RefreshGUIAfterImport = false; OpenFileDialog dialog = null; Boolean IsPlainText = false; if (FPetraUtilsObject.HasChanges) { // saving failed, therefore do not try to import MessageBox.Show(Catalog.GetString("Please save any changes before calling this function!"), Catalog.GetString( "Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } if ((ACurrentBatchRow == null) || (ACurrentBatchRow.BatchStatus != MFinanceConstants.BATCH_UNPOSTED)) { MessageBox.Show(Catalog.GetString("Please select an unposted batch to import transactions."), Catalog.GetString( "Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } if (ACurrentBatchRow.LastGiftNumber > 0) { if (MessageBox.Show(Catalog.GetString( "The current batch already contains some gift transactions. Do you really want to add more transactions to this batch?"), Catalog.GetString("Gift Transaction Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No) { return(false); } } FdlgSeparator = new TDlgSelectCSVSeparator(false); FdlgSeparator.DateMayBeInteger = TUserDefaults.GetBooleanDefault(MCommonConstants.USERDEFAULT_IMPORTEDDATESMAYBEINTEGERS, false); if (AImportSource == TGiftImportDataSourceEnum.FromClipboard) { string importString = Clipboard.GetText(TextDataFormat.UnicodeText); if ((importString == null) || (importString.Length == 0)) { MessageBox.Show(Catalog.GetString("Please first copy data from your spreadsheet application!"), Catalog.GetString("Failure"), MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } FdlgSeparator.CSVData = importString; } else if (AImportSource == TGiftImportDataSourceEnum.FromFile) { dialog = new OpenFileDialog(); string exportPath = TClientSettings.GetExportPath(); string fullPath = TUserDefaults.GetStringDefault("Imp Filename", exportPath + Path.DirectorySeparatorChar + "import.csv"); TImportExportDialogs.SetOpenFileDialogFilePathAndName(dialog, fullPath, exportPath); dialog.Title = Catalog.GetString("Import Transactions from CSV File"); dialog.Filter = Catalog.GetString("Gift Transactions files (*.csv)|*.csv|Text Files (*.txt)|*.txt"); // This call fixes Windows7 Open File Dialogs. It must be the line before ShowDialog() TWin7FileOpenSaveDialog.PrepareDialog(Path.GetFileName(fullPath)); if (dialog.ShowDialog() == DialogResult.OK) { Boolean fileCanOpen = FdlgSeparator.OpenCsvFile(dialog.FileName); if (!fileCanOpen) { MessageBox.Show(Catalog.GetString("Unable to open file."), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Stop); return(false); } IsPlainText = (Path.GetExtension(dialog.FileName).ToLower() == ".txt"); } else { return(false); } } else { // unknown source!! The following need a value... return(false); } String impOptions = TUserDefaults.GetStringDefault("Imp Options", ";" + TDlgSelectCSVSeparator.NUMBERFORMAT_AMERICAN); String dateFormatString = TUserDefaults.GetStringDefault("Imp Date", "MDY"); FdlgSeparator.DateFormat = dateFormatString; FdlgSeparator.NumberFormat = (impOptions.Length > 1) ? impOptions.Substring(1) : TDlgSelectCSVSeparator.NUMBERFORMAT_AMERICAN; FdlgSeparator.SelectedSeparator = StringHelper.GetCSVSeparator(FdlgSeparator.FileContent) ?? ((impOptions.Length > 0) ? impOptions.Substring(0, 1) : ";"); if (IsPlainText || (FdlgSeparator.ShowDialog() == DialogResult.OK)) { Hashtable requestParams = new Hashtable(); requestParams.Add("ALedgerNumber", FLedgerNumber); requestParams.Add("Delimiter", FdlgSeparator.SelectedSeparator); requestParams.Add("DateFormatString", FdlgSeparator.DateFormat); requestParams.Add("NumberFormat", FdlgSeparator.NumberFormat); requestParams.Add("NewLine", Environment.NewLine); bool Repeat = true; while (Repeat) { Repeat = false; TVerificationResultCollection AMessages = new TVerificationResultCollection(); GiftBatchTDSAGiftDetailTable NeedRecipientLedgerNumber = new GiftBatchTDSAGiftDetailTable(); Thread ImportThread = new Thread(() => ImportGiftTransactions( requestParams, FdlgSeparator.FileContent, ACurrentBatchRow.BatchNumber, out AMessages, out ok, out RefreshGUIAfterImport, out NeedRecipientLedgerNumber)); using (TProgressDialog ImportDialog = new TProgressDialog(ImportThread)) { ImportDialog.ShowDialog(); } // if the import contains gifts with Motivation Group 'GIFT' and that have a Family recipient with no Gift Destination // then the import will have failed and we need to alert the user int numberOfMissingGiftDestinations = NeedRecipientLedgerNumber.Rows.Count; if (numberOfMissingGiftDestinations == 0) { if (TVerificationHelper.ResultsContainErrorCode(AMessages, PetraErrorCodes.ERR_DB_SERIALIZATION_EXCEPTION)) { TConcurrentServerTransactions.ShowTransactionSerializationExceptionDialog(); } else { ShowMessages(AMessages); } } if (numberOfMissingGiftDestinations > 0) { bool offerToRunImportAgain = true; int currentMissingGiftDestinationNo = 1; // for each gift in which the recipient needs a Git Destination foreach (GiftBatchTDSAGiftDetailRow Row in NeedRecipientLedgerNumber.Rows) { //Lookup the partner shortname string partnerShortName = string.Empty; TPartnerClass partnerClass; if (TServerLookup.TMPartner.GetPartnerShortName(Row.RecipientKey, out partnerShortName, out partnerClass)) { Row.RecipientDescription = partnerShortName; } if (MessageBox.Show(string.Format( Catalog.GetString( "Error: {0:0000} of {1:0000} - Recipient '{2}' ({3}) has no Gift Destination assigned."), currentMissingGiftDestinationNo, numberOfMissingGiftDestinations, Row.RecipientDescription, Row.RecipientKey) + "\n\n" + Catalog.GetString("Do you want to assign a Gift Destination to this partner now?"), Catalog.GetString("Gift Import Cancelled"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { // allow the user to assign a Gift Destingation TFrmGiftDestination GiftDestinationForm = new TFrmGiftDestination(FPetraUtilsObject.GetForm(), Row.RecipientKey); GiftDestinationForm.ShowDialog(); } else { offerToRunImportAgain = false; } currentMissingGiftDestinationNo++; } // if the user has clicked yes to assigning Gift Destinations then offer to restart the import if (offerToRunImportAgain && (MessageBox.Show(Catalog.GetString("Would you like to import these Gift Transactions again?"), Catalog.GetString("Gift Import"), MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)) { Repeat = true; } } } } // We save the defaults even if ok is false - because the client will probably want to try and import // the same file again after correcting any errors if (!IsPlainText) { SaveUserDefaults(dialog); } if (ok) { MessageBox.Show(Catalog.GetString("Your data was imported successfully!"), Catalog.GetString("Gift Import"), MessageBoxButtons.OK, MessageBoxIcon.Information); } if (ok || RefreshGUIAfterImport) { FMyUserControl.LoadBatchesForCurrentYear(); FPetraUtilsObject.DisableSaveButton(); return(true); // This completes the refresh } return(false); }