Browse Source

New timberline poster

Kenric Nugteren 1 năm trước cách đây
mục cha
commit
6c89e9d568

+ 8 - 0
prs.classes/Entities/Bill/Bill.cs

@@ -59,9 +59,17 @@ namespace Comal.Classes
         [IntegerEditor(Editable = Editable.Hidden)]
         public int Documents { get; set; }
 
+        [NullEditor]
+        [LoggableProperty]
         public DateTime Posted { get; set; }
+
+        [NullEditor]
+        [LoggableProperty]
         public PostedStatus PostedStatus { get; set; }
 
+        [NullEditor]
+        public string PostedNote { get; set; }
+
         protected override void Init()
         {
             base.Init();

+ 3 - 0
prs.classes/Entities/Invoice/Invoice.cs

@@ -144,6 +144,9 @@ namespace Comal.Classes
         [LoggableProperty]
         public DateTime Posted { get; set; }
 
+        [NullEditor]
+        public string PostedNote { get; set; }
+
         public Expression<Func<Invoice, int>> AutoIncrementField()
         {
             return x => x.Number;

+ 8 - 4
prs.desktop/Panels/Invoices/InvoiceListGrid.cs

@@ -19,6 +19,7 @@ namespace PRSDesktop
     {
         private static readonly BitmapImage? tick = PRSDesktop.Resources.tick.AsBitmapImage();
         private static readonly BitmapImage? warning = PRSDesktop.Resources.warning.AsBitmapImage();
+        private static readonly BitmapImage? refresh = PRSDesktop.Resources.refresh.AsBitmapImage();
 
         public InvoiceListGrid()
         {
@@ -29,6 +30,7 @@ namespace PRSDesktop
             HiddenColumns.Add(x => x.CustomerLink.ID);
             HiddenColumns.Add(x => x.JobLink.ID);
             HiddenColumns.Add(x => x.PostedStatus);
+            HiddenColumns.Add(x => x.PostedNote);
             ActionColumns.Add(new DynamicImageColumn(Posted_Image, Posted_Click)
             {
                 ToolTip = Posted_ToolTip
@@ -48,7 +50,8 @@ namespace PRSDesktop
             }
             return column.TextToolTip(row.Get<Invoice, PostedStatus>(x => x.PostedStatus) switch
             {
-                PostedStatus.PostFailed => "Processing Failed",
+                PostedStatus.PostFailed => "Post failed: " + row.Get<Invoice, string>(x => x.PostedNote),
+                PostedStatus.RequiresRepost => "Repost required: " + row.Get<Invoice, string>(x => x.PostedNote),
                 PostedStatus.Posted => "Processed",
                 PostedStatus.NeverPosted or _ => "Not posted yet",
             });
@@ -61,6 +64,7 @@ namespace PRSDesktop
             {
                 PostedStatus.PostFailed => warning,
                 PostedStatus.Posted => tick,
+                PostedStatus.RequiresRepost => refresh,
                 PostedStatus.NeverPosted or _ => null,
             };
         }
@@ -69,13 +73,13 @@ namespace PRSDesktop
         
         public bool IncludePaidInvoices { get; set; }
 
-        protected override void Reload(Filters<Invoice> criteria, Columns<Invoice> columns, ref SortOrder<Invoice> sort,
-            Action<CoreTable, Exception> action)
+        protected override void Reload(Filters<Invoice> criteria, Columns<Invoice> columns, ref SortOrder<Invoice>? sort,
+            Action<CoreTable?, Exception?> action)
         {
             if (JobID != Guid.Empty)
                 criteria.Add(new Filter<Invoice>(x => x.JobLink.ID).IsEqualTo(JobID));
             if (!IncludePaidInvoices)
-                criteria.Add(new Filter<Invoice>(x=>x.Balance).IsNotEqualTo(FilterConstant.Zero));
+                criteria.Add(new Filter<Invoice>(x => x.Balance).IsNotEqualTo(FilterConstant.Zero));
             base.Reload(criteria, columns, ref sort, action);
         }
 

+ 6 - 1
prs.desktop/Panels/Suppliers/SupplierBills.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Windows;
 using System.Windows.Media.Imaging;
+using com.sun.org.apache.xpath.@internal;
 using Comal.Classes;
 using InABox.Core;
 using InABox.DynamicGrid;
@@ -15,11 +16,13 @@ namespace PRSDesktop
     {
         private static readonly BitmapImage? tick = PRSDesktop.Resources.tick.AsBitmapImage();
         private static readonly BitmapImage? warning = PRSDesktop.Resources.warning.AsBitmapImage();
+        private static readonly BitmapImage? refresh = PRSDesktop.Resources.refresh.AsBitmapImage();
         private readonly BitmapImage pdf = PRSDesktop.Resources.doc_pdf.AsBitmapImage();
 
         public SupplierBills()
         {
             HiddenColumns.Add(x => x.PostedStatus);
+            HiddenColumns.Add(x => x.PostedNote);
 
             ActionColumns.Add(new DynamicImageColumn(Posted_Image, null)
             {
@@ -35,7 +38,8 @@ namespace PRSDesktop
             }
             return column.TextToolTip(row.Get<Bill, PostedStatus>(x => x.PostedStatus) switch
             {
-                PostedStatus.PostFailed => "Processing Failed",
+                PostedStatus.PostFailed => "Post failed: " + row.Get<Bill, string>(x => x.PostedNote),
+                PostedStatus.RequiresRepost => "Repost required: " + row.Get<Bill, string>(x => x.PostedNote),
                 PostedStatus.Posted => "Processed",
                 PostedStatus.NeverPosted or _ => "Not posted yet",
             });
@@ -48,6 +52,7 @@ namespace PRSDesktop
             {
                 PostedStatus.PostFailed => warning,
                 PostedStatus.Posted => tick,
+                PostedStatus.RequiresRepost => refresh,
                 PostedStatus.NeverPosted or _ => null,
             };
         }

+ 1 - 0
prs.shared/PRS.Shared.csproj

@@ -12,6 +12,7 @@
     <ProjectReference Include="..\..\inabox\inabox.client.rest\InABox.Client.Rest\InABox.Client.Rest.csproj" />
     <ProjectReference Include="..\..\InABox\InABox.Database\InABox.Database.csproj" />
     <ProjectReference Include="..\..\inabox\InABox.Poster.CSV\InABox.Poster.CSV.csproj" />
+    <ProjectReference Include="..\..\inabox\InABox.Poster.Timberline\InABox.Poster.Timberline.csproj" />
     <ProjectReference Include="..\..\InABox\InABox.WPF\InABox.Wpf.csproj" />
     <ProjectReference Include="..\PRS.Classes\PRSClasses.csproj" />
   </ItemGroup>

+ 0 - 0
prs.shared/Posters/BillCSVPoster.cs → prs.shared/Posters/CSV/BillCSVPoster.cs


+ 0 - 0
prs.shared/Posters/InvoiceCSVPoster.cs → prs.shared/Posters/CSV/InvoiceCSVPoster.cs


+ 375 - 0
prs.shared/Posters/Timberline/BillTimberlinePoster.cs

@@ -0,0 +1,375 @@
+using Comal.Classes;
+using ControlzEx.Standard;
+using CsvHelper;
+using CsvHelper.Configuration.Attributes;
+using FastReport.DevComponents.WinForms.Drawing;
+using InABox.Core;
+using InABox.Core.Postable;
+using InABox.Poster.Timberline;
+using InABox.Scripting;
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static System.Windows.Forms.VisualStyles.VisualStyleElement;
+
+namespace PRS.Shared
+{
+    public class BillTimberlineHeader
+    {
+        [Ignore]
+        public List<BillTimberlineDistribution> Distributions { get; set; } = new();
+
+        [Index(1)]
+        public string RecordID { get; set; } = "APIF";
+
+        [Index(2)]
+        public string Vendor { get; set; }
+
+        [Index(3)]
+        public string Invoice { get; set; }
+
+        [Index(4)]
+        public string Description { get; set; }
+
+        [Index(5)]
+        public double Amount { get; set; }
+
+        [Index(6)]
+        public double Tax { get; set; }
+
+        [Index(7)]
+        public double DiscountOffered { get; set; }
+
+        [Index(8)]
+        public double MiscDeduction { get; set; }
+
+        [Index(9)]
+        public DateTime InvoiceDate { get; set; }
+
+        [Index(10)]
+        public DateTime DateReceived { get; set; }
+
+        [Index(11)]
+        public DateTime DiscountDate { get; set; }
+
+        [Index(12)]
+        public DateTime PaymentDate { get; set; }
+
+        [Index(13)]
+        public DateTime AccountingDate { get; set; }
+
+        [Index(14)]
+        public string InvoiceCode1 { get; set; }
+
+        [Index(15)]
+        public string InvoiceCode2 { get; set; }
+
+        [Index(16)]
+        public string SmryPayeeName { get; set; }
+
+        [Index(17)]
+        public string SmryPayeeAddress1 { get; set; }
+
+        [Index(18)]
+        public string SmryPayeeAddress2 { get; set; }
+
+        [Index(19)]
+        public string SmryPayeeCity { get; set; }
+
+        [Index(20)]
+        public string SmryPayeeState { get; set; }
+
+        [Index(21)]
+        public string SmryPayeeZip { get; set; }
+    }
+
+    public class BillTimberlineDistribution
+    {
+        [Index(1)]
+        public string RecordID { get; set; } = "APDF";
+
+        [Index(2)]
+        public string Commitment { get; set; }
+
+        [Index(3)]
+        public int CommitmentLineItem { get; set; }
+
+        [Index(4)]
+        public string Equipment { get; set; }
+
+        [Index(5)]
+        public string EQCostCode { get; set; }
+
+        [Index(6)]
+        public string Job { get; set; }
+
+        [Index(7)]
+        public string Extra { get; set; }
+
+        [Index(8)]
+        public string CostCode { get; set; }
+
+        [Index(9)]
+        public string Category { get; set; }
+
+        [Index(10)]
+        public string BLStdItem { get; set; }
+
+        [Index(11)]
+        public string Reserved { get; set; }
+
+        [Index(12)]
+        public string ExpenseAccount { get; set; }
+
+        [Index(13)]
+        public string APAccount { get; set; }
+
+        [Index(14)]
+        public double TaxablePayments { get; set; }
+
+        [Index(15)]
+        public string TaxGroup { get; set; }
+
+        [Index(16)]
+        public double Units { get; set; }
+
+        [Index(17)]
+        public double UnitCost { get; set; }
+
+        [Index(18)]
+        public double Amount { get; set; }
+
+        [Index(19)]
+        public double Tax { get; set; }
+
+        [Index(20)]
+        public double TaxLiability { get; set; }
+
+        [Index(21)]
+        public double DiscountOffered { get; set; }
+
+        [Index(22)]
+        public double Retainage { get; set; }
+
+        [Index(23)]
+        public double MiscDeduction { get; set; }
+
+        [Index(24)]
+        [BooleanTrueValues("t", "T", "1", "Y", "y")]
+        [BooleanFalseValues("f", "F", "0", "N", "n")]
+        public bool TaxablePaymentsExempt { get; set; }
+
+        [Index(25)]
+        public string DistCode { get; set; }
+
+        [Index(26)]
+        public string MiscEntry1 { get; set; }
+
+        [Index(27)]
+        public double MiscEntryUnits1 { get; set; }
+
+        [Index(28)]
+        public string MiscEntry2 { get; set; }
+
+        [Index(29)]
+        public double MiscEntryUnits2 { get; set; }
+
+        [Index(30)]
+        public double MeterOdometer { get; set; }
+
+        [Index(31)]
+        public string Description { get; set; }
+
+        [Index(32)]
+        public string Authorization { get; set; }
+
+        [Index(33)]
+        public string JointPayee { get; set; }
+    }
+
+    public class BillTimberlineSettings : TimberlinePosterSettings<Bill>
+    {
+        protected override string DefaultScript()
+        {
+            return @"
+using PRS.Shared;
+using InABox.Core;
+using System.Collections.Generic;
+
+public class Module
+{
+    public void BeforePost(IDataModel<Bill> model)
+    {
+        // Perform pre-processing
+    }
+
+    public void ProcessHeader(IDataModel<Bill> model, Bill bill, BillTimberlineHeader header)
+    {
+        // Do extra processing for a header line
+    }
+
+    public void ProcessLine(IDataModel<Bill> model, BillLine bill, BillTimberlineDistribution distribution)
+    {
+        // Do extra processing for a distribution line
+    }
+
+    public void AfterPost(IDataModel<Bill> model)
+    {
+        // Perform post-processing
+    }
+}";
+        }
+    }
+
+    public class BillTimberlinePoster : ITimberlinePoster<Bill, BillTimberlineSettings>
+    {
+        public ScriptDocument? Script { get; set; }
+
+        public bool BeforePost(IDataModel<Bill> model)
+        {
+            model.SetIsDefault<Document>(false, alias: "CompanyLogo");
+            model.SetIsDefault<CoreTable>(false, alias: "CompanyInformation");
+            model.SetIsDefault<Employee>(false);
+
+            model.SetIsDefault<BillLine>(true, "Bill_BillLine");
+            model.AddChildTable<BillLine, PurchaseOrderItem>(x => x.OrderItem.ID, x => x.ID, isdefault: true, parentalias: "Bill_BillLine", childalias: "POItem");
+
+            Script?.Execute(methodname: "BeforePost", parameters: new object[] { model });
+            return true;
+        }
+
+        private void ProcessHeader(IDataModel<Bill> model, Bill bill, BillTimberlineHeader header)
+        {
+            Script?.Execute(methodname: "ProcessHeader", parameters: new object[] { model, bill, header });
+        }
+        private void ProcessLine(IDataModel<Bill> model, BillLine bill, BillTimberlineDistribution distribution)
+        {
+            Script?.Execute(methodname: "ProcessLine", parameters: new object[] { model, bill, distribution });
+        }
+
+        private List<BillTimberlineHeader> DoProcess(IDataModel<Bill> model)
+        {
+            var apifs = new List<BillTimberlineHeader>();
+            foreach(var bill in model.GetTable<Bill>().ToObjects<Bill>())
+            {
+                var apif = new BillTimberlineHeader
+                {
+                    Vendor = bill.SupplierLink.Code,
+                    Invoice = bill.Number,
+                    Description = "",
+                    Amount = bill.IncTax,
+                    Tax = bill.Tax,
+                    // DiscountOffered
+                    // Misc. Deduction
+                    InvoiceDate = bill.BillDate,
+                    // DateReceived doesn't exist
+                    DiscountDate = bill.BillDate,
+                    PaymentDate = bill.PaymentDate,
+                    AccountingDate = bill.AccountingDate,
+                    // InvoiceCode1
+                    // InvoiceCode2
+                    // SmryPayeeName
+                    // SmryPayeeAddress1
+                    // SmryPayeeAddress2
+                    // SmryPayeeCity
+                    // SmryPayeeState
+                    // SmryPayeeZip
+                };
+                ProcessHeader(model, bill, apif);
+
+                var purchaseOrderItems = model.GetTable<PurchaseOrderItem>("POItem").ToObjects<PurchaseOrderItem>()
+                    .ToDictionary(x => x.ID, x => x);
+                foreach (var billLine in model.GetTable<BillLine>("Bill_BillLine").ToObjects<BillLine>())
+                {
+                    var apdf = new BillTimberlineDistribution
+                    {
+                        // Equipment
+                        // EQ Cost Code
+                        // Extra
+                        // Cost Code
+                        // Category
+                        /// BL STd Item
+                        // Reserved
+                        // Expense account
+                        // AP Account
+                        // Taxable Payments
+                        TaxGroup = billLine.TaxCode.Code,
+                        Amount = billLine.IncTax,
+                        Tax = billLine.Tax,
+                        // Tax Liability
+                        // Discount OFfered
+                        // Retainage
+                        // MIsc Deduction
+                        // Tax Payments Exempt
+                        // Dist Code
+                        // Misc Entry 1
+                        // Misc Units 1
+                        // Misc Entry 2
+                        // Misc Units 2
+                        // Meter
+                        Description = billLine.Description,
+                        // Authorization
+                        // Joint Payee
+                    };
+                    if(purchaseOrderItems.TryGetValue(billLine.OrderItem.ID, out var poItem))
+                    {
+                        apdf.Commitment = poItem.PONumber;
+                        apdf.Job = poItem.Job.JobNumber;
+                        // apdf.CommitmentLineItem : Leaving this blank
+                        apdf.Units = poItem.Qty;
+                        apdf.UnitCost = poItem.Cost;
+                    }
+
+                    ProcessLine(model, billLine, apdf);
+                    apif.Distributions.Add(apdf);
+                }
+                apifs.Add(apif);
+            }
+            return apifs;
+        }
+
+        public bool Process(IDataModel<Bill> model)
+        {
+            var apifs = DoProcess(model);
+
+            var dlg = new SaveFileDialog()
+            {
+                Filter = "CSV Files (*.csv)|*.csv"
+            };
+
+            if (dlg.ShowDialog() == true)
+            {
+                using var writer = new StreamWriter(dlg.FileName);
+                using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
+                foreach(var apif in apifs)
+                {
+                    csv.WriteRecord(apif);
+                    csv.NextRecord();
+                    foreach(var apdf in apif.Distributions)
+                    {
+                        csv.WriteRecord(apdf);
+                        csv.NextRecord();
+                    }
+                }
+                return true;
+            }
+            else
+            {
+                throw new PostCancelledException();
+            }
+        }
+        public void AfterPost(IDataModel<Bill> model)
+        {
+            Script?.Execute(methodname: "AfterPost", parameters: new object[] { model });
+        }
+    }
+
+    public class BillTimberlinePosterEngine<T> : TimberlinePosterEngine<Bill, BillTimberlineSettings>
+    {
+    }
+}