Free cookie consent management tool by TermsFeed Policy Generator

source: branches/1888_OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/BillingEngine.cs @ 16724

Last change on this file since 16724 was 10013, checked in by spimming, 11 years ago

#1888:

  • enabled transactions
  • enabled tracing output
  • set correct invoice data
  • saving invoices
File size: 7.4 KB
Line 
1
2using System;
3using System.Collections.Generic;
4using System.Configuration;
5using System.Diagnostics;
6using System.Linq;
7using System.Threading;
8using System.Transactions;
9using HeuristicLab.Services.Optimization.Billing.Business;
10using HeuristicLab.Services.Optimization.Billing.Interfaces;
11using HeuristicLab.Services.Optimization.Billing.Model;
12namespace HeuristicLab.Services.Optimization.Billing.BillingEngine {
13  public class BillingEngine {
14    private bool stop;
15    private AutoResetEvent waitHandle;
16    private TimeSpan interval;
17    private DateTime currentDate;
18
19    private IOptimizationBilling billingService;
20    public IOptimizationBilling BillingService {
21      get {
22        if (billingService == null) {
23          billingService = new BillingService();
24        }
25        return billingService;
26      }
27      set { billingService = value; }
28    }
29
30    private IInvoiceFormattingEngine invoiceFormattingEngine;
31    public IInvoiceFormattingEngine InvoiceFormattingEngine {
32      get {
33        if (invoiceFormattingEngine == null) {
34          invoiceFormattingEngine = new PlainTextInvoiceFormattingEngine();
35        }
36        return invoiceFormattingEngine;
37      }
38      set { invoiceFormattingEngine = value; }
39    }
40
41    public BillingEngine() {
42      stop = false;
43      interval = TimeSpan.Parse(ConfigurationManager.AppSettings["BillingEngineInterval"]);
44      waitHandle = new AutoResetEvent(true);
45    }
46
47    public void StopBillingEngine() {
48      stop = true;
49      waitHandle.Set();
50    }
51
52    public void Run() {
53      while (!stop) {
54        TransactionOptions options = new TransactionOptions();
55        options.IsolationLevel = IsolationLevel.ReadUncommitted;
56        TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required, options);
57        try {
58          Trace.WriteLine("[BillingEngine] Start billing cycle");
59          currentDate = DateTime.Now.Date;
60          Trace.WriteLine(string.Format("[BillingEngine] Current date: {0}", currentDate));
61          IList<Order> activeOrders = BillingService.GetOrdersByState(OrderState.Active);
62          Trace.WriteLine(string.Format("[BillingEngine] Processing {0} active orders.", activeOrders.Count));
63          foreach (Order order in activeOrders) {
64            Trace.WriteLine(string.Format("[BillingEngine] Processing order with id: {0}", order.OrderId));
65
66            if (!order.NextBillableDay.HasValue) {
67              // An invoice has never been generated from this order
68              order.NextBillableDay = currentDate;
69              order.EntityState = State.Modified;
70            }
71
72            if (order.NextBillableDay <= currentDate) {
73              // Collect Usage Data
74              Trace.WriteLine("[BillingEngine] Collecting usage data");
75              //IList<UsageRecord> usageRecrods = BillingService.GetUsageRecords(order.User.Name, order.LastBillableDay.Value, currentDate);
76
77              // Collect Invoice Data
78              Trace.WriteLine("[BillingEngine] Collecting invoice data");
79              Invoice invoice = new Invoice();
80              invoice.Order = order;
81              invoice.User = order.User;
82              invoice.Due = currentDate.AddMonths(1);
83              invoice.InvoiceDate = currentDate;
84              invoice.Status = InvoiceStatus.Open;
85              invoice.InvoiceLines = new List<InvoiceLine>();
86              foreach (OrderLine orderLine in order.OrderLines) {
87                InvoiceLine invoiceLine = new InvoiceLine();
88                invoiceLine.Invoice = invoice;
89                invoiceLine.Product = orderLine.Product;
90                invoiceLine.ProductPrice = orderLine.ProductPrice;
91                invoiceLine.Quantity = orderLine.Quantity;
92                invoice.InvoiceLines.Add(invoiceLine);
93              }
94
95              InvoiceLine usageCharges = new InvoiceLine();
96              usageCharges.Invoice = invoice;
97              usageCharges.Product = billingService.GetProductByName("Oaas Usage Charges").First();
98              usageCharges.ProductPrice = 999.99;
99              usageCharges.Quantity = 1;
100              invoice.InvoiceLines.Add(usageCharges);
101
102              // Bill Post Processing: Apply Discounts or Promotions
103              // add discounts, sum up items to sub-total, calc. tax -> total current charges
104              // maybe use rule execution feature from the windows workflow foundation for this task
105              Trace.WriteLine("[BillingEngine] Bill post preccessing");
106              double subTotal = 0.0;
107              foreach (InvoiceLine invoiceLine in invoice.InvoiceLines) {
108                subTotal += invoiceLine.ProductPrice;
109              }
110              invoice.SubTotal = subTotal;
111              invoice.Tax = invoice.SubTotal * 0.2;
112              invoice.Total = invoice.SubTotal + invoice.Tax;
113
114              // Invoice Formatting Engine: Generate Invoice
115              Trace.WriteLine("[BillingEngine] Generating invoice document");
116              invoice.InvoiceDocument = InvoiceFormattingEngine.Generate(invoice);
117
118              UpdateBillingState(order);
119              billingService.UpdateOrder(order);
120              billingService.SaveInvoice(invoice);
121
122              transaction.Complete();
123            }
124          }
125
126          Trace.WriteLine("[BillingEngine] Finished billing cycle");
127        }
128        catch (Exception e) {
129          Trace.WriteLine(string.Format("[BillingEngine] The following exception occured: {0}", e.ToString()));
130        }
131        finally {
132          transaction.Dispose();
133        }
134
135        waitHandle.WaitOne(interval);
136      }
137      waitHandle.Close();
138    }
139
140    private void UpdateBillingState(Order order) {
141      if (order.BillingType == BillingType.Pre) {
142        throw new Exception("This billing type is currently not supported: " + order.BillingType);
143      }
144
145      order.LastBillableDay = currentDate;
146      DateTime nextBillingDay = CalculateNextBillingDate(order);
147
148      if (order.ActiveUntil.HasValue && order.ActiveUntil == currentDate) {
149        order.State = OrderState.Finished;
150        order.NextBillableDay = null;
151      } else if (order.ActiveUntil.HasValue && order.ActiveUntil < nextBillingDay) {
152        order.NextBillableDay = order.ActiveUntil;
153      } else {
154        order.NextBillableDay = nextBillingDay;
155      }
156
157      order.EntityState = State.Modified;
158    }
159
160    private DateTime CalculateNextBillingDate(Order order) {
161      DateTime nextBillingDay = currentDate;
162
163      if (order.BillingPeriod == BillingPeriod.Weekly) {
164        nextBillingDay = Next(currentDate, DayOfWeek.Sunday);
165      } else if (order.BillingPeriod == BillingPeriod.Monthly) {
166        DateTime endOfNextMonth = new DateTime(
167          currentDate.AddMonths(1).Year,
168          currentDate.AddMonths(1).Month,
169          DateTime.DaysInMonth(currentDate.AddMonths(1).Year, currentDate.AddMonths(1).Month));
170        nextBillingDay = endOfNextMonth;
171      } else if (order.BillingPeriod == BillingPeriod.Yearly) {
172        nextBillingDay = new DateTime(currentDate.AddYears(1).Year, 12, 31);
173      }
174
175      return nextBillingDay;
176    }
177
178    private DateTime Next(DateTime from, DayOfWeek dayOfWeek) {
179      int start = (int)from.DayOfWeek;
180      int target = (int)dayOfWeek;
181      if (target <= start)
182        target += 7;
183      return from.AddDays(target - start);
184    }
185  }
186}
Note: See TracBrowser for help on using the repository browser.