websitepanel/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Ecommerce/InvoiceController.cs
2013-04-30 10:47:34 +03:00

375 lines
16 KiB
C#

// Copyright (c) 2012, Outercurve Foundation.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// - Neither the name of the Outercurve Foundation nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using ES = WebsitePanel.EnterpriseServer;
using System.Threading;
using WebsitePanel.EnterpriseServer;
using WebsitePanel.Templates;
namespace WebsitePanel.Ecommerce.EnterpriseServer
{
public class InvoiceController
{
private InvoiceController()
{
}
#region Ecommerce v2.1.0 routines
#region Helper methods
public static string BuildAddXmlForInvoiceItems(List<InvoiceItem> items)
{
XmlDocument xml = new XmlDocument();
XmlElement root = xml.CreateElement("items");
foreach (InvoiceItem item in items)
{
XmlElement node = xml.CreateElement("item");
node.SetAttribute("serviceid", item.ServiceId.ToString());
node.SetAttribute("itemname", item.ItemName);
node.SetAttribute("typename", item.TypeName);
node.SetAttribute("quantity", item.Quantity.ToString());
node.SetAttribute("total", item.Total.ToString(CultureInfo.InvariantCulture));
node.SetAttribute("subtotal", item.SubTotal.ToString(CultureInfo.InvariantCulture));
node.SetAttribute("unitprice", item.UnitPrice.ToString(CultureInfo.InvariantCulture));
root.AppendChild(node);
}
return root.OuterXml;
}
public static List<InvoiceItem> CalculateInvoiceLinesForServices(List<int> services)
{
List<InvoiceItem> lines = new List<InvoiceItem>();
foreach (int serviceId in services)
{
ProductType svc_type = ServiceController.GetServiceItemType(serviceId);
//
IServiceProvisioning controller = (IServiceProvisioning)Activator.CreateInstance(
Type.GetType(svc_type.ProvisioningController));
//
InvoiceItem[] ilines = controller.CalculateInvoiceLines(serviceId);
foreach (InvoiceItem iline in ilines)
{
iline.SubTotal = iline.UnitPrice * iline.Quantity;
iline.Total = iline.SubTotal;
}
//
lines.AddRange(ilines);
}
//
return lines;
}
#endregion
public static int VoidCustomerInvoice(int invoiceId)
{
SecurityResult result = StorehouseController.CheckAccountIsAdminOrReseller();
if (!result.Success)
return result.ResultCode;
// void
EcommerceProvider.VoidCustomerInvoice(ES.SecurityContext.User.UserId, invoiceId);
//
return 0;
}
public static Taxation GetCustomerTaxation(string contractId, string country, string state)
{
return ES.ObjectUtils.FillObjectFromDataReader<Taxation>(
EcommerceProvider.GetCustomerTaxation(contractId, country, state));
}
public static void CalculateInvoiceChargeAmounts(Taxation tax, List<InvoiceItem> items,
out decimal totalAmount, out decimal subTotalAmount, out decimal taxAmount)
{
totalAmount = subTotalAmount = taxAmount = 0;
// calculate all invoice items
foreach (InvoiceItem item in items)
subTotalAmount += item.SubTotal;
//
totalAmount = subTotalAmount;
// tax applies
if (tax != null)
{
switch (tax.Type)
{
case TaxationType.Fixed:
taxAmount = tax.Amount;
totalAmount += taxAmount;
break;
case TaxationType.Percentage:
taxAmount = (subTotalAmount / 100) * tax.Amount;
totalAmount += taxAmount;
break;
case TaxationType.TaxIncluded:
taxAmount = totalAmount - totalAmount * 100 / (100M + tax.Amount);
subTotalAmount -= taxAmount;
break;
}
}
}
public static int AddInvoice(string contractId, List<InvoiceItem> invoiceLines, KeyValueBunch extraArgs)
{
ContractAccount account = ContractSystem.ContractController.GetContractAccountSettings(contractId);
// read customer tax
Taxation tax = GetCustomerTaxation(contractId, account[ContractAccount.COUNTRY], account[ContractAccount.STATE]);
int taxationId = (tax == null) ? -1 : tax.TaxationId;
// Calculate invoice amounts
decimal totalAmount = 0, subTotalAmount = 0, taxAmount = 0;
CalculateInvoiceChargeAmounts(tax, invoiceLines, out totalAmount, out subTotalAmount, out taxAmount);
// align svcs suspend date
int[] svcs = new int[invoiceLines.Count];
for (int i = 0; i < invoiceLines.Count; i++)
svcs[i] = invoiceLines[i].ServiceId;
DateTime sdateAligned = ServiceController.GetSvcsSuspendDateAligned(svcs, DateTime.Now);
//
StoreSettings settings = StorehouseController.GetStoreSettings(ES.SecurityContext.User.UserId,
StoreSettings.SYSTEM_SETTINGS);
// get invoice grace period in days
int gracePeriod = Common.Utils.Utils.ParseInt(settings["InvoiceGracePeriod"], 0);
//
if (gracePeriod < 0) gracePeriod = 0;
//
DateTime created = DateTime.Now;
DateTime dueDate = sdateAligned.AddDays(gracePeriod);
//
return AddInvoice(contractId, created, dueDate, taxationId, totalAmount, subTotalAmount, taxAmount,
invoiceLines, extraArgs);
}
public static int AddInvoice(string contractId, DateTime created, DateTime dueDate,
int taxationId, decimal totalAmount, decimal subTotalAmount, decimal taxAmount, List<InvoiceItem> invoiceLines, KeyValueBunch extraArgs)
{
//
try
{
Contract contract = ContractSystem.ContractController.GetContract(contractId);
//
ES.TaskManager.StartTask(SystemTasks.SOURCE_ECOMMERCE, SystemTasks.TASK_ADD_INVOICE);
// build xml representation
string invoiceLinesXml = BuildAddXmlForInvoiceItems(invoiceLines);
// add invoice
int result = EcommerceProvider.AddInvoice(contractId, created, dueDate,
taxationId, totalAmount, subTotalAmount, taxAmount, invoiceLinesXml,
StorehouseController.GetBaseCurrency(contract.ResellerId));
// check error
if (result < 1)
return result; // EXIT
// build invoice number
Invoice invoice = GetCustomerInvoiceInternally(result);
StoreSettings settings = StorehouseController.GetStoreSettings(contract.ResellerId, StoreSettings.SYSTEM_SETTINGS);
if (!String.IsNullOrEmpty(settings["InvoiceNumberFormat"]))
{
Hashtable options = new Hashtable();
options["ID"] = result;
invoice.InvoiceNumber = StorehouseController.ApplyStringCustomFormat(
settings["InvoiceNumberFormat"], options);
}
else
{
invoice.InvoiceNumber = result.ToString();
}
// update invoice
InvoiceController.UpdateInvoice(invoice.InvoiceId, invoice.InvoiceNumber, invoice.DueDate,
invoice.Total, invoice.SubTotal, invoice.TaxationId, invoice.TaxAmount, invoice.Currency);
//
ES.TaskManager.TaskParameters[SystemTaskParams.PARAM_CONTRACT] = contract;
ES.TaskManager.TaskParameters[SystemTaskParams.PARAM_INVOICE] = invoice;
ES.TaskManager.TaskParameters[SystemTaskParams.PARAM_INVOICE_LINES] = invoiceLines;
ES.TaskManager.TaskParameters[SystemTaskParams.PARAM_EXTRA_ARGS] = extraArgs;
//
return result;
}
catch (Exception ex)
{
throw ES.TaskManager.WriteError(ex);
}
finally
{
ES.TaskManager.CompleteTask();
}
}
public static int UpdateInvoice(int invoiceId, string invoiceNumber, DateTime dueDate,
decimal total, decimal subTotal, int taxationId, decimal taxAmount, string currency)
{
return EcommerceProvider.UpdateInvoice(ES.SecurityContext.User.UserId, invoiceId,
invoiceNumber, dueDate, total, subTotal, taxationId, taxAmount, currency);
}
public static Invoice GetCustomerInvoiceInternally(int invoiceId)
{
return ES.ObjectUtils.FillObjectFromDataReader<Invoice>(
EcommerceProvider.GetCustomerInvoice(ES.SecurityContext.User.UserId, invoiceId));
}
public static List<InvoiceItem> GetCustomerInvoiceItems(int invoiceId)
{
return ES.ObjectUtils.CreateListFromDataReader<InvoiceItem>(
EcommerceProvider.GetCustomerInvoiceItems(ES.SecurityContext.User.UserId, invoiceId));
}
public static string GetCustomerInvoiceFormattedInternally(int invoiceId, string cultureName)
{
Invoice invoice = GetCustomerInvoiceInternally(invoiceId);
//
return GetCustomerInvoiceFormattedInternally(invoice.ContractId, invoiceId, cultureName);
}
internal static string GetCustomerInvoiceFormattedInternally(string contractId, int invoiceId, string cultureName)
{
Contract contract = ContractSystem.ContractController.GetContract(contractId);
ContractAccount accountSettings = ContractSystem.ContractController.GetContractAccountSettings(contractId);
//
return GetCustomerInvoiceFormattedInternally(contract, invoiceId, accountSettings, cultureName);
}
internal static string GetCustomerInvoiceFormattedInternally(Contract contract, int invoiceId, ContractAccount accountSettings, string cultureName)
{
//
Invoice invoiceInfo = GetCustomerInvoiceInternally(invoiceId);
// impersonate
ES.SecurityContext.SetThreadPrincipal(contract.ResellerId);
// load settings
StoreSettings settings = StorehouseController.GetStoreSettings(contract.ResellerId, StoreSettings.NEW_INVOICE);
//
string templateBody = settings["HtmlBody"];
//
Taxation invoiceTax = StorehouseController.GetTaxation(contract.ResellerId, invoiceInfo.TaxationId);
//
List<InvoiceItem> invoiceLines = GetCustomerInvoiceItems(invoiceId);
Dictionary<int, Service> invoiceServices = ServiceController.GetServicesDictionary(invoiceLines);
//
Template tm = new Template(templateBody);
tm["Invoice"] = invoiceInfo;
tm["InvoiceLines"] = invoiceLines;
tm["InvoiceServices"] = invoiceServices;
tm["Customer"] = accountSettings;
tm["Tax"] = invoiceTax;
StringWriter writer = new StringWriter();
try
{
// Preserve an original thread culture
CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture;
//
if (!String.IsNullOrEmpty(cultureName))
{
try
{
CultureInfo formattingCulture = new CultureInfo(cultureName);
// Empty currency symbol to supporty 3-letters ISO format
// hardcorded in HTML templates
formattingCulture.NumberFormat.CurrencySymbol = String.Empty;
// Set formatting culture
Thread.CurrentThread.CurrentCulture = formattingCulture;
}
catch (Exception ex)
{
TaskManager.WriteWarning("Wrong culture name has been provided. Culture name: {0}.", cultureName);
TaskManager.WriteWarning(ex.StackTrace);
TaskManager.WriteWarning(ex.Message);
}
}
// Process template
tm.Evaluate(writer);
templateBody = writer.ToString();
// Revert the original thread's culture back
Thread.CurrentThread.CurrentCulture = originalCulture;
}
catch (ParserException ex)
{
return String.Format("Error in template (Line {0}, Column {1}): {2}",
ex.Line, ex.Column, ex.Message);
}
return templateBody;
}
public static List<Invoice> GetUnpaidInvoices(int resellerId)
{
return ES.ObjectUtils.CreateListFromDataReader<Invoice>(
EcommerceProvider.GetUnpaidInvoices(ES.SecurityContext.User.UserId, resellerId));
}
#endregion
#region New implementation
public static List<InvoiceItem> GetInvoicesItemsToActivate(int resellerId)
{
return ES.ObjectUtils.CreateListFromDataReader<InvoiceItem>(
EcommerceProvider.GetInvoicesItemsToActivate(ES.SecurityContext.User.UserId, resellerId));
}
public static List<InvoiceItem> GetInvoicesItemsOverdue(int resellerId, DateTime dueDate)
{
return ES.ObjectUtils.CreateListFromDataReader<InvoiceItem>(
EcommerceProvider.GetInvoicesItemsOverdue(ES.SecurityContext.User.UserId, resellerId, dueDate));
}
public static int SetInvoiceItemProcessed(int invoiceId, int itemId)
{
return EcommerceProvider.SetInvoiceItemProcessed(invoiceId, itemId);
}
#endregion
#region Provisioning routines
#endregion
}
}