mirror of
https://github.com/stokebob/BealeEngineering.git
synced 2026-03-19 06:37:15 +00:00
221 lines
9.8 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|