瀏覽代碼

Added Progress Claims for Job Scopes

Kenric Nugteren 11 月之前
父節點
當前提交
d8790b2c93

+ 8 - 0
prs.classes/Entities/Job/JobScopes/JobScopeLink.cs

@@ -16,5 +16,13 @@ namespace Comal.Classes
         [EditorSequence(1)]
         [MemoEditor(Visible = Visible.Default, Editable = Editable.Hidden)]
         public string Description { get; set; }
+
+        [CurrencyEditor(Summary = Summary.Sum)]
+        public double InvoiceExTax { get; set; }
+
+        [CurrencyEditor(Summary = Summary.Sum)]
+        public double ExTax { get; set; }
+
+        public TaxCodeLink TaxCode { get; set; }
     }
 }

+ 62 - 0
prs.desktop/Panels/Invoices/InvoiceGrid.cs

@@ -14,6 +14,7 @@ using System.Windows.Media.Imaging;
 using InABox.Configuration;
 using System.Collections.Generic;
 using System.Threading;
+using PRSDesktop.Panels.Invoices;
 
 namespace PRSDesktop
 {
@@ -86,6 +87,67 @@ namespace PRSDesktop
             base.Reload(criteria, columns, ref sort, token, action);
         }
 
+        protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
+        {
+            if(Master == null || Master.ID == Guid.Empty)
+            {
+                base.DoAdd(OpenEditorOnDirectEdit);
+            }
+            else
+            {
+                var menu = new ContextMenu();
+                menu.AddItem("Invoice", null, () => base.DoAdd(OpenEditorOnDirectEdit));
+                menu.AddItem("Progress Claim", null, () =>
+                {
+                    var grid = new ProgressClaimGrid
+                    {
+                        JobID = Master.ID
+                    };
+                    var window = new DynamicContentDialog(grid)
+                    {
+                        Title = "Create progress claim",
+                        Width = 800
+                    };
+                    grid.OnChanged += (o, e) =>
+                    {
+                        window.CanSave = grid.Items.Any(x => !x.PercentCost.IsEffectivelyEqual(x.PreviouslyClaimedPercent));
+                    };
+                    grid.Refresh(true, true);
+                    if(window.ShowDialog() == true)
+                    {
+                        var invoice = new Invoice();
+                        invoice.Description = $"Progress claim for {DateTime.Today:MMM yyyy}";
+                        invoice.JobLink.CopyFrom(Master);
+                        invoice.CustomerLink.CopyFrom(Master.Account);
+
+                        var lines = new List<InvoiceLine>();
+                        foreach(var item in grid.Items.Where(x => !x.Cost.IsEffectivelyEqual(0.0)))
+                        {
+                            var line = new InvoiceLine();
+
+                            line.Description = item.JobScope.Description;
+                            line.ExTax = item.Cost;
+                            line.TaxCode.CopyFrom(item.JobScope.TaxCode);
+                            line.Scope.CopyFrom(item.JobScope);
+
+                            lines.Add(line);
+                        }
+
+                        Client.Save(invoice, "Progress claim created by user.");
+
+                        foreach(var line in lines)
+                        {
+                            line.InvoiceLink.ID = invoice.ID;
+                        }
+                        Client.Save(lines, "Progress claim created by user.");
+
+                        Refresh(false, true);
+                    }
+                });
+                menu.IsOpen = true;
+            }
+        }
+
         protected override bool CanCreateItems()
         {
             return base.CanCreateItems() && (Master == null || Master.ID != Guid.Empty);

+ 179 - 0
prs.desktop/Panels/Invoices/ProgressClaimGrid.cs

@@ -0,0 +1,179 @@
+using Comal.Classes;
+using InABox.Clients;
+using InABox.Core;
+using InABox.DynamicGrid;
+using Syncfusion.Windows.Shared;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Forms;
+using System.Windows.Media;
+
+namespace PRSDesktop.Panels.Invoices;
+
+public class ProgressClaim : BaseObject
+{
+    public JobScopeLink JobScope { get; set; }
+
+    public double PreviouslyClaimed { get; set; }
+
+    public double PreviouslyClaimedPercent { get; set; }
+
+    [DoubleEditor]
+    public double PercentCost { get; set; }
+
+    [CurrencyEditor(Editable = Editable.Disabled)]
+    public double Cost { get; set; }
+}
+
+public class ProgressClaimGrid : DynamicItemsListGrid<ProgressClaim>
+{
+    private DynamicGridCustomColumnsComponent<ProgressClaim> ColumnsComponent;
+
+    public Guid JobID { get; set; }
+
+    protected override void Init()
+    {
+        base.Init();
+        ColumnsComponent = new(this, nameof(ProgressClaimGrid));
+    }
+
+    protected override void DoReconfigure(DynamicGridOptions options)
+    {
+        base.DoReconfigure(options);
+
+        options.SelectColumns = true;
+    }
+
+    private bool _loadedData = false;
+    private void LoadData()
+    {
+        var columns =
+            Columns.None<JobScope>()
+                .Add(x => x.ID)
+                .Add(x => x.Number)
+                .Add(x => x.ExTax).Add(x => x.InvoiceExTax)
+                .Add(x => x.TaxCode.ID).Add(x => x.TaxCode.Rate)
+                .Add(x => x.Description);
+
+        var scopeColumn = new Column<ProgressClaim>(x => x.JobScope).Property + ".";
+        foreach(var column in DataColumns().Where(x => x.Property.StartsWith(scopeColumn)))
+        {
+            columns.Add(column.Property[scopeColumn.Length..]);
+        }
+
+        var scopes = Client.Query<JobScope>(
+                new Filter<JobScope>(x => x.Job.ID).IsEqualTo(JobID)
+                    .And(x => x.Status.Approved).IsEqualTo(true), columns)
+            .ToArray<JobScope>();
+
+        var items = new List<ProgressClaim>();
+        foreach(var scope in scopes)
+        {
+            var newItem = new ProgressClaim();
+            newItem.JobScope.CopyFrom(scope);
+            newItem.PreviouslyClaimed = scope.InvoiceExTax;
+            newItem.PreviouslyClaimedPercent = scope.ExTax.IsEffectivelyEqual(0.0) ? 0.0 : scope.InvoiceExTax / scope.ExTax * 100;
+            newItem.PercentCost = newItem.PreviouslyClaimedPercent;
+            newItem.Cost = 0;
+            items.Add(newItem);
+        }
+        Items = items;
+
+        _loadedData = true;
+    }
+
+    protected override void Reload(Filters<ProgressClaim> criteria, Columns<ProgressClaim> columns, ref SortOrder<ProgressClaim>? sort, CancellationToken token, Action<CoreTable?, Exception?> action)
+    {
+        LoadData();
+        base.Reload(criteria, columns, ref sort, token, action);
+    }
+
+    protected override void SaveColumns(DynamicGridColumns columns)
+    {
+        ColumnsComponent.SaveColumns(columns);
+    }
+
+    protected override void LoadColumnsMenu(ContextMenu menu)
+    {
+        ColumnsComponent.LoadColumnsMenu(menu);
+    }
+
+    public override DynamicGridColumns GenerateColumns()
+    {
+        var columns = new DynamicGridColumns();
+
+        columns.Add<ProgressClaim, string>(x => x.JobScope.Number, 80, "Number", "", Alignment.MiddleCenter);
+        columns.Add<ProgressClaim, string>(x => x.JobScope.Description, 0, "Description", "", Alignment.MiddleCenter);
+        columns.Add<ProgressClaim, double>(x => x.JobScope.ExTax, 100, "Quote $", "", Alignment.MiddleCenter);
+        columns.Add<ProgressClaim, double>(x => x.PreviouslyClaimed, 100, "Prev $", "C2", Alignment.MiddleCenter);
+        columns.Add<ProgressClaim, double>(x => x.PreviouslyClaimedPercent, 80, "Prev %", "", Alignment.MiddleCenter);
+
+        return columns;
+    }
+
+    protected override DynamicGridColumns LoadColumns()
+    {
+        var columns = ColumnsComponent.LoadColumns();
+
+        ActionColumns.Clear();
+
+        ActionColumns.Add(new DynamicTemplateColumn(row =>
+        {
+            var item = LoadItem(row);
+            var editor = new DoubleTextBox
+            {
+                VerticalAlignment = VerticalAlignment.Stretch,
+                HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center,
+                HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
+                Background = new SolidColorBrush(Colors.LightYellow),
+                BorderThickness = new Thickness(0.0),
+                MinValue = 0.0,
+                MaxValue = 100.0,
+                Value = item.PercentCost
+            };
+            editor.ValueChanged += (o, e) =>
+            {
+                var maxValue = 100.0;
+                var value = (double?)e.NewValue ?? default;
+                if(value > maxValue)
+                {
+                    Dispatcher.BeginInvoke(() => editor.Value = maxValue);
+                }
+                else
+                {
+                    item.PercentCost = value;
+                    item.Cost = item.JobScope.ExTax * item.PercentCost / 100 - item.PreviouslyClaimed;
+                    UpdateRow(row, item);
+                    InvalidateRow(row);
+                    DoChanged();
+                }
+            };
+
+            return editor;
+        })
+        {
+            HeaderText = "Cur %",
+            Width = 80
+        });
+        ActionColumns.Add(new DynamicTextColumn(row =>
+        {
+            if (row is null) return null;
+
+            var item = LoadItem(row);
+            return item.Cost;
+        })
+        {
+            Format = "C2",
+            HeaderText = "Claim $",
+            Width = 100
+        });
+
+        return columns;
+    }
+}