mirror of
https://github.com/stokebob/BealeEngineering.git
synced 2026-03-19 06:37:15 +00:00
Sales invoice 'Status'
Added 'status' to sales invoice
This commit is contained in:
@@ -135,7 +135,7 @@ namespace BealeEngineering.Accounts
|
||||
{
|
||||
string fileInputPath =
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
|
||||
+ @"\Dropbox\Beale Engineering Services Ltd\BE Accounts\Xero-Export-Invoices - Orig.csv";
|
||||
+ @"\Dropbox\Beale Engineering Services Ltd\BE Accounts\Xero-Export-Invoices.csv";
|
||||
|
||||
string dialogText = "Importing file from location: " + Environment.NewLine + Environment.NewLine + fileInputPath;
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace BealeEngineering.Core.Data.Database.Sale
|
||||
,SaleInvoice.InvoiceTotal
|
||||
,SaleInvoice.TaxTotal
|
||||
,SaleInvoice.IsCreditNote
|
||||
,SaleInvoice.Status
|
||||
,SaleInvoiceLine.SaleInvoiceLineID
|
||||
,SaleInvoiceLine.SaleInvoiceID
|
||||
,SaleInvoiceLine.LineNumber
|
||||
|
||||
@@ -139,6 +139,7 @@ namespace BealeEngineering.Core.Data.Database.Sale
|
||||
,SaleInvoice.InvoiceTotal
|
||||
,SaleInvoice.TaxTotal
|
||||
,SaleInvoice.IsCreditNote
|
||||
,SaleInvoice.Status
|
||||
,Contact.ContactName
|
||||
FROM SaleInvoice
|
||||
INNER JOIN Contact ON SaleInvoice.ContactID = Contact.ContactID";
|
||||
|
||||
@@ -85,6 +85,7 @@ namespace BealeEngineering.Core.Data.Database.Sale
|
||||
,[InvoiceTotal] = @invoiceTotal
|
||||
,[TaxTotal] = @taxTotal
|
||||
,[IsCreditNote] = @isCreditNote
|
||||
,[Status] = @status
|
||||
WHERE SaleInvoiceID = @saleInvoiceId;
|
||||
|
||||
DELETE FROM SaleInvoiceLine WHERE SaleInvoiceID = @saleInvoiceId;";
|
||||
@@ -102,6 +103,7 @@ namespace BealeEngineering.Core.Data.Database.Sale
|
||||
,[InvoiceTotal]
|
||||
,[TaxTotal]
|
||||
,[IsCreditNote]
|
||||
,[Status]
|
||||
)
|
||||
OUTPUT INSERTED.SaleInvoiceID
|
||||
VALUES(
|
||||
@@ -114,6 +116,7 @@ namespace BealeEngineering.Core.Data.Database.Sale
|
||||
,@invoiceTotal
|
||||
,@taxTotal
|
||||
,@isCreditNote
|
||||
,@status
|
||||
)";
|
||||
}
|
||||
else
|
||||
@@ -134,6 +137,7 @@ namespace BealeEngineering.Core.Data.Database.Sale
|
||||
cmd.Parameters.AddWithValue("@invoiceTotal", invoice.InvoiceTotal);
|
||||
cmd.Parameters.AddWithValue("@taxTotal", invoice.TaxTotal);
|
||||
cmd.Parameters.AddWithValue("@isCreditNote", invoice.IsCreditNote);
|
||||
cmd.Parameters.AddWithValue("@status", invoice.Status);
|
||||
|
||||
if (saleInvoiceId == 0)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,21 @@ namespace BealeEngineering.Core.Logic.Adapter
|
||||
{
|
||||
public class SaleInvoice
|
||||
{
|
||||
public SaleInvoice()
|
||||
{
|
||||
// ensure sale invoice hasn't changed
|
||||
int propertyCount = new Model.Sale.Invoice().GetType().GetProperties().Count();
|
||||
if (propertyCount != 14)
|
||||
{
|
||||
throw new Exception("Model.Import.XeroInvoiceFlatFile has changed, it's adapter class may need updating.");
|
||||
}
|
||||
propertyCount = new Model.Sale.Invoice.InvoiceLine().GetType().GetProperties().Count();
|
||||
if (propertyCount != 10)
|
||||
{
|
||||
throw new Exception("Model.Import.XeroInvoiceFlatFile.LineItem has changed, it's adapter class may need updating.");
|
||||
}
|
||||
}
|
||||
|
||||
public Model.Sale.Invoice XeroInvoiceFlatFIle(Model.Import.XeroInvoiceFlatFile xeroInvoice)
|
||||
{
|
||||
var result = XeroInvoiceFlatFile(new List<Model.Import.XeroInvoiceFlatFile> { xeroInvoice });
|
||||
@@ -33,6 +48,7 @@ namespace BealeEngineering.Core.Logic.Adapter
|
||||
else { throw new FormatException("Unknow value '" + xeroInvoiceList[i].Type + "' found in 'Type' field"); }
|
||||
invoice.Reference = xeroInvoiceList[i].Reference;
|
||||
invoice.SaleInvoiceNumber = xeroInvoiceList[i].InvoiceNumber;
|
||||
invoice.Status = xeroInvoiceList[i].Status;
|
||||
invoice.TaxTotal = xeroInvoiceList[i].TaxTotal;
|
||||
|
||||
invoice.InvoiceLineList = new List<Model.Sale.Invoice.InvoiceLine>();
|
||||
|
||||
@@ -8,6 +8,21 @@ namespace BealeEngineering.Core.Logic.Adapter
|
||||
{
|
||||
public class XeroInvoiceFlatFile
|
||||
{
|
||||
public XeroInvoiceFlatFile()
|
||||
{
|
||||
// ensure XeroInvoiceFlatFile hasn't changed
|
||||
int propertyCount = new Model.Import.XeroInvoiceFlatFile().GetType().GetProperties().Count();
|
||||
if (propertyCount != 32)
|
||||
{
|
||||
throw new Exception("Model.Import.XeroInvoiceFlatFile has changed, it's adapter class may need updating.");
|
||||
}
|
||||
propertyCount = new Model.Import.XeroInvoiceFlatFile.LineItem().GetType().GetProperties().Count();
|
||||
if (propertyCount != 13)
|
||||
{
|
||||
throw new Exception("Model.Import.XeroInvoiceFlatFile.LineItem has changed, it's adapter class may need updating.");
|
||||
}
|
||||
}
|
||||
|
||||
public List<Model.Import.XeroInvoiceFlatFile> SaleInvoice(List<Model.Sale.Invoice> invoiceList)
|
||||
{
|
||||
if (invoiceList == null || !invoiceList.Any()) { return null; }
|
||||
@@ -23,6 +38,7 @@ namespace BealeEngineering.Core.Logic.Adapter
|
||||
xeroInvoice.InvoiceDate = invoiceList[i].InvoiceDate;
|
||||
xeroInvoice.InvoiceNumber = invoiceList[i].SaleInvoiceNumber;
|
||||
xeroInvoice.Reference = invoiceList[i].Reference;
|
||||
xeroInvoice.Status = invoiceList[i].Status;
|
||||
xeroInvoice.TaxTotal = invoiceList[i].TaxTotal;
|
||||
xeroInvoice.Total = invoiceList[i].InvoiceTotal;
|
||||
if (invoiceList[i].IsCreditNote) { xeroInvoice.Type = "Sales credit note"; }
|
||||
@@ -59,19 +75,21 @@ namespace BealeEngineering.Core.Logic.Adapter
|
||||
|
||||
// ensure flat data is in invoice number order
|
||||
var invDictionary = new Dictionary<string, int>();
|
||||
string lastNumber = null;
|
||||
string lastUniqueString = "";
|
||||
foreach (var line in flatData)
|
||||
{
|
||||
if (line.InvoiceNumber != lastNumber)
|
||||
// invoice number isn't unique, can be duplicated if one invoice is void/deleted
|
||||
string uniqueString = line.InvoiceNumber + line.Status;
|
||||
if (uniqueString != lastUniqueString)
|
||||
{
|
||||
lastNumber = line.InvoiceNumber;
|
||||
if (invDictionary.ContainsKey(lastNumber))
|
||||
lastUniqueString = uniqueString;
|
||||
if (invDictionary.ContainsKey(lastUniqueString))
|
||||
{
|
||||
throw new Exception("Invoices are not grouped in CSV flatfile.");
|
||||
}
|
||||
else
|
||||
{
|
||||
invDictionary.Add(lastNumber, 0);
|
||||
invDictionary.Add(lastUniqueString, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,13 @@ namespace BealeEngineering.Core.Logic.Adapter
|
||||
public XeroInvoiceFlatFileDTO()
|
||||
{
|
||||
// ensure XeroInvoiceFlatFileDTO hasn't changed
|
||||
int dtoPropertyCouny = new Model.Import.XeroInvoiceFlatFileDTO().GetType().GetProperties().Count();
|
||||
if (dtoPropertyCouny != 44)
|
||||
int propertyCount = new Model.Import.XeroInvoiceFlatFileDTO().GetType().GetProperties().Count();
|
||||
if (propertyCount != 44)
|
||||
{
|
||||
throw new Exception("Model.Import.XeroInvoiceFlatFileDTO has changed, it's adapter class needs updating.");
|
||||
throw new Exception("Model.Import.XeroInvoiceFlatFileDTO has changed, it's adapter class may need updating.");
|
||||
}
|
||||
}
|
||||
|
||||
public List<Model.Import.XeroInvoiceFlatFileDTO> XeroInvoiceFlatFile(List<Model.Import.XeroInvoiceFlatFile> invoices)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace BealeEngineering.Core.Logic.Import
|
||||
this.sqlConnectionString = sqlConnectionString;
|
||||
}
|
||||
|
||||
private List<Model.Import.XeroInvoiceFlatFile> XeroInvoiceData { get; set; }
|
||||
private List<Model.Import.XeroInvoiceFlatFile> XeroFlatData { get; set; }
|
||||
|
||||
public int InvoicesCreated { get; private set; } = 0;
|
||||
|
||||
@@ -26,26 +26,41 @@ namespace BealeEngineering.Core.Logic.Import
|
||||
public void ByFilePath(string filePath, bool updateContacts = true)
|
||||
{
|
||||
// get xero data
|
||||
var data = new Data.Xero.FlatFile.ReadXeroInvoiceFlatFile();
|
||||
XeroInvoiceData = data.ByFilePath(filePath);
|
||||
var flatfileData = new Data.Xero.FlatFile.ReadXeroInvoiceFlatFile();
|
||||
XeroFlatData = flatfileData.ByFilePath(filePath);
|
||||
|
||||
// check data
|
||||
if (XeroFlatData == null || !XeroFlatData.Any()) { return; }
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < XeroFlatData.Count(); i++)
|
||||
{
|
||||
if (XeroFlatData[i].Status == "Deleted" || XeroFlatData[i].Status == "Voided")
|
||||
{ throw new Exception("Deleted/Voided invoices found in dataset."); }
|
||||
// xero flatfiles can have duplicate invoice numbers if one of the invoices is voided/deleted.
|
||||
// Long story short; to avoid missing invoices from db dataset, any voided/deleted invoices need
|
||||
// to be manually deleted on the database. While this has it's problems, it's more probable that
|
||||
// the db side will be correct this way.
|
||||
}
|
||||
}
|
||||
|
||||
// update db contacts
|
||||
UpdateContacts();
|
||||
|
||||
// populate/map xero data to invoice model list
|
||||
var dbInvoiceData = new Logic.Adapter.SaleInvoice().XeroInvoiceFlatFile(XeroInvoiceData);
|
||||
var xeroInvoiceList = new Logic.Adapter.SaleInvoice().XeroInvoiceFlatFile(XeroFlatData);
|
||||
|
||||
//check
|
||||
if (dbInvoiceData == null ||( XeroInvoiceData.Count != dbInvoiceData.Count))
|
||||
if (xeroInvoiceList == null ||( XeroFlatData.Count != xeroInvoiceList.Count))
|
||||
{
|
||||
throw new Exception("Something went wrong while mapping the data.");
|
||||
}
|
||||
|
||||
// send list to database (it will get validated in data layer)
|
||||
if (dbInvoiceData.Any())
|
||||
if (xeroInvoiceList.Any())
|
||||
{
|
||||
var updateInvoice = new Data.Database.Sale.UpdateInvoice(sqlConnectionString);
|
||||
updateInvoice.ByInvoiceList(dbInvoiceData, true);
|
||||
updateInvoice.ByInvoiceList(xeroInvoiceList, true);
|
||||
|
||||
InvoicesCreated = updateInvoice.RecordsCreated;
|
||||
InvoicesUpdated = updateInvoice.RecordsUpdated;
|
||||
@@ -65,11 +80,11 @@ namespace BealeEngineering.Core.Logic.Import
|
||||
{
|
||||
var contactAdapter = new Logic.Adapter.Contact();
|
||||
var dicContacts = new Dictionary<string, Model.Contact.Contact>();
|
||||
for (var i = 0; i < XeroInvoiceData.Count; i++)
|
||||
for (var i = 0; i < XeroFlatData.Count; i++)
|
||||
{
|
||||
if (!dicContacts.ContainsKey(XeroInvoiceData[0].ContactName))
|
||||
if (!dicContacts.ContainsKey(XeroFlatData[0].ContactName))
|
||||
{
|
||||
dicContacts.Add(XeroInvoiceData[0].ContactName, contactAdapter.XeroInvoiceFlatFile(XeroInvoiceData[0]));
|
||||
dicContacts.Add(XeroFlatData[0].ContactName, contactAdapter.XeroInvoiceFlatFile(XeroFlatData[0]));
|
||||
}
|
||||
}
|
||||
if (dicContacts.Any())
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace BealeEngineering.Core.Model.Sale
|
||||
public class Invoice : InvoiceHeader
|
||||
{
|
||||
public List<InvoiceLine> InvoiceLineList { get; set; } = new List<InvoiceLine>();
|
||||
|
||||
public bool InvoiceLineListIsSet
|
||||
{
|
||||
get
|
||||
@@ -18,26 +19,36 @@ namespace BealeEngineering.Core.Model.Sale
|
||||
else { return true; }
|
||||
}
|
||||
}
|
||||
|
||||
public class InvoiceLine
|
||||
{
|
||||
[Required(), Range(0, 255)]
|
||||
public int LineNumber { get; set; }
|
||||
|
||||
[Required(), StringLength(50)]
|
||||
public string InventoryItemCode { get; set; }
|
||||
|
||||
[StringLength(500)]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Required(), Range(0, 255)]
|
||||
public decimal Quantity { get; set; }
|
||||
|
||||
[Required()]
|
||||
public decimal UnitAmount { get; set; }
|
||||
|
||||
[Range(1, 100)]
|
||||
public int? Discount { get; set; }
|
||||
|
||||
[Required(), StringLength(10)]
|
||||
public string AccountCode { get; set; }
|
||||
|
||||
[Required(), StringLength(50)]
|
||||
public string TaxType { get; set; }
|
||||
|
||||
[Required()]
|
||||
public decimal TaxAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Line amount is Tax Exclusive
|
||||
/// </summary>
|
||||
@@ -52,6 +63,7 @@ namespace BealeEngineering.Core.Model.Sale
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
base.Validate(validationContext);
|
||||
|
||||
@@ -10,24 +10,37 @@ namespace BealeEngineering.Core.Model.Sale
|
||||
public class InvoiceHeader : ValidateModel
|
||||
{
|
||||
public int SaleInvoiceID { get; set; }
|
||||
|
||||
[Required(AllowEmptyStrings = false)]
|
||||
public string ContactName { get; set; }
|
||||
|
||||
[Required(AllowEmptyStrings = false), StringLength(50)]
|
||||
public string SaleInvoiceNumber { get; set; }
|
||||
|
||||
[Required()]
|
||||
public DateTime InvoiceDate { get; set; }
|
||||
|
||||
public DateTime? DueDate { get; set; }
|
||||
|
||||
[StringLength(50)]
|
||||
public string Reference { get; set; }
|
||||
|
||||
[Required(AllowEmptyStrings = false)]
|
||||
[StringLength(3, MinimumLength = 3)]
|
||||
public string CurrencyCode { get; set; }
|
||||
|
||||
[Required()]
|
||||
public decimal InvoiceTotal { get; set;}
|
||||
|
||||
[Required()]
|
||||
public decimal TaxTotal { get; set; }
|
||||
|
||||
[Required()]
|
||||
public bool IsCreditNote { get; set; }
|
||||
|
||||
[Required()]
|
||||
public string Status { get; set; }
|
||||
|
||||
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
base.Validate(validationContext);
|
||||
|
||||
Reference in New Issue
Block a user