Files
BealeEngineering/BealeEngineering/BealeEngineering.Core/Logic/Sale/SaleInvoiceAssign.cs

221 lines
9.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace BealeEngineering.Core.Logic.Sale
{
public class SaleInvoiceAssign
{
string statusModified = new Data.SaleInvoiceFormat().ReadStatusStringModified();
string statusNew = new Data.SaleInvoiceFormat().ReadStatusStringNew();
string sqlConnectionString;
int timeCheckMinutes = 15;
DateTime timeCheckPostpone = new DateTime();
int timeCheckPostponeMinutes = 15;
public SaleInvoiceAssign(string sqlConnectionString)
{
this.sqlConnectionString = sqlConnectionString;
}
public bool SplitInvoice { get; set; } = false;
public DateTime LastImportDateTime { get; private set; } = default(DateTime);
public void ToPurchaseOrderLine(string saleInvoiceNumber, int purchaseOrderLineId)
{
using (var scope = new TransactionScope())
{
var readInvoice = new Data.Database.Sale.ReadInvoice(sqlConnectionString);
readInvoice.InvoiceNumber = new List<string> { saleInvoiceNumber };
Model.Sale.Invoice invoice = readInvoice.Read()[0];
int invoiceId = invoice.SaleInvoiceID;
decimal? facilityNet = new Data.Database.Client.ReadPurchaseOrderLineFacility(sqlConnectionString).Read(purchaseOrderLineId);
if (facilityNet == null)
{ throw new Exception("Supplied ClientPurchaseOrderLineID '" + purchaseOrderLineId + "' does not exist."); }
if (facilityNet < invoice.InvoiceNetTotal && SplitInvoice == false)
{
return;
}
// get purchase order header info
Model.Client.PurchaseOrderHeader poHeader
= new Data.Database.Client.ReadPurchaseOrder(sqlConnectionString).ByPurchaseOrderLineId(purchaseOrderLineId);
var updateInvoice = new Data.Database.Sale.UpdateInvoice(sqlConnectionString);
if (facilityNet >= invoice.InvoiceNetTotal)
{
invoice.Reference = poHeader.ClientReference;
invoice.Status = statusModified;
}
else if (facilityNet < invoice.InvoiceNetTotal && SplitInvoice == true)
{
// Import time check
if (!ImportTimeCheck())
{
if (timeCheckPostpone == new DateTime() || DateTime.Now > timeCheckPostpone.AddMinutes(1))
{
throw new Exception("Last invoice import too long ago. Override check or import invoices");
}
}
// save check values & get currency symbol
decimal invTotal = invoice.InvoiceTotal;
decimal invTaxTotal = invoice.TaxTotal;
var culture = new Data.CurrencyFormat().ReadCulture(invoice.CurrencyCode);
// prep second invoice
var newInvoice = invoice.Copy();
newInvoice.Status = statusNew;
// prep first invoice
invoice.Reference = poHeader.ClientReference;
invoice.Status = statusModified;
//loop though lines to find split location
int i = 0;
decimal lineSum = 0;
bool cleanSplit = true;
for (i = 0; i < invoice.InvoiceLineList.Count(); i++)
{
lineSum += invoice.InvoiceLineList[i].LineNetAmount;
if (lineSum == facilityNet)
{
cleanSplit = true;
break;
}
else if (lineSum > facilityNet)
{
cleanSplit = false;
break;
}
}
string splitText = null;
decimal splitAmount1 = 0;
decimal splitAmount2 = 0;
if (cleanSplit == false)
{
// record line details
//decimal lineNet = invoice.InvoiceLineList[i].LineNetAmount;
decimal lineTax = invoice.InvoiceLineList[i].TaxAmount;
//decimal lineUnitAmount = invoice.InvoiceLineList[i].UnitAmount;
decimal lineQtyByUnit = invoice.InvoiceLineList[i].UnitAmount * invoice.InvoiceLineList[i].Quantity;
//create split text
splitText = Environment.NewLine + Environment.NewLine
+ "Line split (" + invoice.InvoiceLineList[i].Quantity.ToString("0.######") + " x " + invoice.InvoiceLineList[i].UnitAmount.ToString("C", culture)
+ " = " + (invoice.InvoiceLineList[i].Quantity * invoice.InvoiceLineList[i].UnitAmount).ToString("C", culture) + ")" + Environment.NewLine ;
newInvoice.InvoiceLineList[i].Quantity = 1;
splitAmount2 = lineSum - (decimal)facilityNet;
newInvoice.InvoiceLineList[i].UnitAmount = splitAmount2;
invoice.InvoiceLineList[i].Quantity = 1;
splitAmount1 = lineQtyByUnit - splitAmount2;
invoice.InvoiceLineList[i].UnitAmount = splitAmount1;
invoice.InvoiceLineList[i].TaxAmount =
decimal.Round((invoice.InvoiceLineList[i].TaxAmount * (splitAmount1 / lineQtyByUnit)), 2, MidpointRounding.AwayFromZero);
newInvoice.InvoiceLineList[i].TaxAmount = lineTax - invoice.InvoiceLineList[i].TaxAmount;
}
//delete lines
invoice.InvoiceLineList.RemoveRange(i + 1, (invoice.InvoiceLineList.Count - (i + 1)));
if (cleanSplit)
{ newInvoice.InvoiceLineList.RemoveRange(0, i + 1); }
else
{
if (i > 0)
{ newInvoice.InvoiceLineList.RemoveRange(0, i); }
}
// update invoice totals
invoice.TaxTotal = invoice.InvoiceLineList.Sum(x => x.TaxAmount);
invoice.InvoiceTotal = invoice.InvoiceLineList.Sum(x => x.LineNetAmount) + invoice.TaxTotal;
newInvoice.TaxTotal = newInvoice.InvoiceLineList.Sum(x => x.TaxAmount);
newInvoice.InvoiceTotal = newInvoice.InvoiceLineList.Sum(x => x.LineNetAmount) + newInvoice.TaxTotal;
//checks
if (invoice.InvoiceNetTotal != facilityNet)
{ throw new Exception("Invoice net total does not equal facility."); }
if (invoice.InvoiceTotal + newInvoice.InvoiceTotal != invTotal)
{ throw new Exception("Invoice totals does not match."); }
if (invoice.TaxTotal + newInvoice.TaxTotal != invTaxTotal)
{ throw new Exception("Invoice tax totals does not match."); }
// continue, and update
if (newInvoice.InvoiceTotal < 0)
{ newInvoice.IsCreditNote = true; }
if (cleanSplit == false)
{
newInvoice.SaleInvoiceNumber = new Data.Database.Sale.ReadNextInvoiceNumber(sqlConnectionString).Read(newInvoice.IsCreditNote);
splitText = splitText
+ invoice.SaleInvoiceNumber + " = " + splitAmount1.ToString("C", culture)
+ Environment.NewLine + newInvoice.SaleInvoiceNumber + " = " + splitAmount2.ToString("C", culture);
invoice.InvoiceLineList[i].Description += splitText;
newInvoice.InvoiceLineList[0].Description += splitText;
}
// validate
if ( invoice.IsValid() == false)
{
throw new Exception("Invalid invoice: " + invoice.ValidationResults[0]);
}
if (newInvoice.IsValid() == false)
{
throw new Exception("Invalid invoice: " + newInvoice.ValidationResults[0]);
}
// add new invoice to db
updateInvoice.ByInvoice(newInvoice, true);
}
// update existing invoice and add link invoice to purchaseOrder line
updateInvoice.ByInvoice(invoice);
new Data.Database.Client.CreatePurchaseOrderAllocation(sqlConnectionString).Create(invoiceId, purchaseOrderLineId);
scope.Complete();
}
}
public bool ImportTimeCheck()
{
LastImportDateTime = new Data.Database.Log.ReadDateTime(sqlConnectionString)
.ByMatchString("XeroSaleInvoiceFlatFileImport");
var datesss = DateTime.UtcNow;
datesss = datesss.AddMinutes(timeCheckMinutes * -1);
if (LastImportDateTime < datesss)
{
if (timeCheckPostpone == new DateTime() || DateTime.Now > timeCheckPostpone)
{ return false; }
else { return true; }
}
else
{ return true; }
}
public void ImportTimeCheckPostpone()
{
timeCheckPostpone = DateTime.Now.AddMinutes(timeCheckPostponeMinutes);
}
}
}