public int InvoiceRun(DateTime callCutoffDate) { if (runInProgress) { throw new InvoiceRunInProgressException(); } runInProgress = true; try { // SRD-PCMS-40 (001-62) Only invoice once per month DateTime? lastInvoiceDate = _invoiceSettings.LastInvoiceRunPerformedDate; if (lastInvoiceDate != null && lastInvoiceDate.Value.Month == callCutoffDate.Month && lastInvoiceDate.Value.Year == callCutoffDate.Year) { LoggingUtility.LogDebug("InvoiceRun", "AirtimeBilling.Services.InvoicingService", string.Format( "Attempted Invoice Run more than once in the same month. Last Run Date={0}. Current Date={1}", lastInvoiceDate.Value, _dateTime.Now)); throw new InvoiceRunFrequencyException(); } int runNumber = 0; using (var ts = new TransactionScope()) { var rootAccounts = _accountRepository.GetAllRootAccounts(); if (rootAccounts.Count == 0) { LoggingUtility.LogDebug("InvoiceRun", "InvoicingService", "An Invoice Run was Started but no accounts were found."); return 0; } runNumber = _numberGeneratorService.NextInvoiceRunNumber(); DateTime fromDate = DateTime.MinValue; if (lastInvoiceDate.HasValue) { fromDate = lastInvoiceDate.Value.AddDays(1); } var context = new InvoiceRunContext(runNumber, fromDate, callCutoffDate); var factory = new InvoiceFactory(_invoiceSettings, _dateTime, _contractRepository, _accountRepository, _planRepository, _networkRepository, _contractService, _companyRepository, _contactRepository, _numberGeneratorService, context); foreach (var rootAccount in rootAccounts) { var invoice = factory.GenerateInvoice(rootAccount); if (invoice == null) continue; _invoiceRepository.InsertInvoice(invoice); if (invoice.Id == null) { // TODO Return failure reason and log. return 0; } rootAccount.LogActivity("Invoice Number '" + invoice.InvoiceNumber + "' created in Invoice Run " + runNumber); rootAccount.AmountPaid = 0; rootAccount.PreviousBill = invoice.CurrentBill; if (!_accountRepository.UpdateAccount(rootAccount)) { return 0; } } _invoiceSettings.LastInvoiceRunPerformedDate = callCutoffDate; ts.Complete(); } // Report generation times out the transaction. // Report generation doesn't participate in the ambient transaction so // there's no real reason to do it in the transaction. var invoices = _invoiceRepository.FindInvoicesByRunNumber(runNumber); foreach (var invoice in invoices) _invoiceHardcopyRepository.Save(invoice); // SRD-PCMS-54 (001-76) Invoice data file emailed // Now make a manual process to cope with credit cards. //SendCustomerInvoiceInEmail(runNumber); return runNumber; } catch (Exception ex) { LoggingUtility.LogException(ex); throw; //return 0; } finally { runInProgress = false; } }