瀏覽代碼

Added some TImberline export formats to prs.media.
Changed logic in stockmovement export to think about whole transactions.
Started to write code for loading Bill Export Reject file

Kenric Nugteren 1 年之前
父節點
當前提交
71cbc0a3fa

+ 130 - 0
prs.media/TimberlineExportFiles/AP Import field table.pdf

@@ -0,0 +1,130 @@
+Import Invoices Format journal example (Fixed format)                  Page 1 of 3
+
+Import Invoices Format journal example (Fixed format)
+
+Accounts Payable Import Invoices
+
+APIF, Vendor, Invoice, Description, Amount, Tax, Discount Offered, Misc Deduction, Invoice Date, Date Received, Discount
+Date, Payment Date, Accounting Date, Invoice Code 1, Invoice Code 2, Smry Payee Name, Smry Payee Address 1, Smry
+Payee Address 2, Smry Payee City, Smry Payee State, Smry Payee ZIP
+
+APDF, Commitment, Commitment Line Item, Equipment, EQ Cost Code, Job, Extra, Cost Code, Category, BL Std Item,
+Property, Expense Account, Accounts Payable Account, Taxable Payments, Tax Group, Units, Unit Cost, Amount, Tax, Tax
+Liability, Discount Offered, , Misc Deduction, Taxable Payments Exempt, Dist Code, Draw, Misc Entry #1, Misc Entry Units #1,
+Misc Entry #2, Misc Entry Units #2, Meter/Odometer, Description, Authorization, Joint Payee
+
+APTXF, Tax Item, Tax Amount, Tax Liability
+
+Description                     Field type             Maximum length  Usage notes
+
+Record ID 'APIF' – API invoice
+
+APIF                            Alpha                  4               Always Required
+Vendor                                                                 Always Required
+Invoice                         Alpha                  10              Always Required
+Description
+Amount                          Alpha                  15
+Tax
+Discount Offered                Alpha                  30
+Misc. Deduction
+Invoice Date                    Numeric                -9.2
+Date Received
+Discount Date                   Numeric                -7.2
+Payment Date
+Accounting Date                 Numeric                -7.2
+Invoice Code 1
+Invoice Code 2                  Numeric                -7.2
+Smry Payee Name
+Smry Payee Address 1            Date
+Smry Payee Address 2
+Smry Payee City                 Date
+
+                                Date
+
+                                Date
+
+                                Date
+
+                                Alpha                  10
+
+                                Alpha                  10
+
+                                Alpha                  30
+
+                                Alpha                  33
+
+                                Alpha                  33
+
+                                Alpha                  15
+
+mk:@MSITStore:C:\Program%20Files%20(x86)\Timberline%20Office\Shared\Help\AP.c... 7/08/2023
+Import Invoices Format journal example (Fixed format)                    Page 2 of 3
+
+   Smry Payee State                  Alpha             4        Always required
+   Smry Payee Zip                                               xx-xxxx
+Record ID 'APDF' – API distribution  Alpha             10       xx-xxx
+   APDF                                                         xx-xxx
+   Commitment                        Alpha             4        xx-xxx
+   Commitment Line Item              Alpha             12       Not used.
+   Equipment                         Numeric                    xx-xxxx
+   EQ Cost Code                      Alpha-Numeric        5     xx-xxxx
+   Job                               Alpha-Numeric        7
+   Extra                             Alpha-Numeric        6     Formats can be:
+   Cost Code                         Alpha                6     t, T, 1, Y, y, f, F, N, n, 0
+   Category                          Alpha-Numeric        10
+   BL Std Item                       Alpha                6
+   Reserved                          Alpha                3
+   Expense Account                   Alpha-Numeric        10
+   AP Account                        Alpha                8
+   Taxable Payments                  Alpha                7
+   Tax Group                         Numeric              7
+   Units                             Alpha                2.3
+   Unit Cost                         Numeric              6
+   Amount                            Numeric              -8.4
+   Tax                               Numeric              -6.4
+   Tax Liability                     Numeric              -9.2
+   Discount Offered                  Numeric              -7.2
+   Retainage                         Numeric              -7.2
+   Misc Deduction                    Numeric              -7.2
+   Taxable Payments Exempt           Numeric              -7.2
+                                     Check Box            -7.2
+   Dist Code
+                                     Alpha                10
+
+mk:@MSITStore:C:\Program%20Files%20(x86)\Timberline%20Office\Shared\Help\AP.c... 7/08/2023
+Import Invoices Format journal example (Fixed format)        Page 3 of 3
+
+                                          Alpha        10
+
+Misc Entry #1                             Alpha        10
+
+Misc Entry Units #1                       Alpha        -8.4
+
+Misc Entry #2                             Alpha        10
+
+Misc Entry Units #2                       Numeric      -8.4
+
+Meter/Odometer                            Numeric      7.2
+
+Description                               Alpha        30
+
+Authorization                             Alpha        10
+
+Joint Payee                               Alpha        30
+
+Record ID 'APTXF' – API tax distribution
+
+APTXF                                     Alpha        5
+Tax Intern
+Tax Amount                                Alpha        6
+Tax Liability
+                                          Numeric      -7.2
+
+                                          Numeric      -7.2
+
+ More resources
+You can visit Sage City to join product discussions, search articles in the Sage knowledgebase, or chat online with an expert.
+For additional training on Sage products, visit Sage University.
+
+mk:@MSITStore:C:\Program%20Files%20(x86)\Timberline%20Office\Shared\Help\AP.c... 7/08/2023
+

+ 66 - 0
prs.media/TimberlineExportFiles/JC - Direct cost Import layout.pdf

@@ -0,0 +1,66 @@
+Direct cost                                                             Page 1 of 2
+
+Direct cost
+
+Items required to be entered are marked as such in the Comment column.
+
+Number       Type     Length  Item                                      Comment
+1            alpha    2       record ID                                 required, must be DC. In a GL only entry, must
+                                                                        be GL.
+2            alpha    10      job ID                                    required, ID separators can be entered or omitted
+                                                                        ID separators can be entered or omitted
+3            alpha    10      extra ID                                  required, ID separators can be entered or omitted
+                                                                        required, if using categories
+4            alpha    12      cost code                                 see 1st Note below
+                                                                        if blank, system date is used
+5            alpha    3       category                                  if blank, the Job Cost period end date is used
+                                                                        leave blank to retrieve from
+6            list     1       transaction type                          standard item, if used
+                                                                        required if unit cost entered
+7            date     10      transaction date                          required only if no amount; leave
+                                                                        blank to retrieve from units-based
+8            date     10      accounting date                           standard item, if used
+                                                                        required, defaults to units times unit cost if not
+9            alpha    30      description                               entered; leave
+                                                                        blank to retrieve from amounts-
+10           numeric  8.4     units                                     based standard item, if used
+                                                                        required if interfacing with GL and
+11           numeric  6.4     unit cost                                 account cannot be retrieved
+
+12           numeric  9.2     amount                                    when importing inventory costs from Purchasing
+                                                                        & Inventory (PO/IV), the Posting Sequence is
+13           alpha    25      debit account                             used
+
+                              see Notes below                           if used, must be setup in the Billing application
+
+14           alpha    25      credit account
+
+                              see Notes below
+
+15           alpha    10      reference 1
+
+16           alpha    10      reference 2
+
+17           alpha    10      standard item
+
+        Notes:
+
+               Transaction types: 1 = AP Cost, 2 = JC Cost, 3 = PR Cost, 4 = EQ Cost, and 5 = IV Cost.
+               The default is AP Cost. Also, if extras and/or categories are not used, they must still be represented by
+               comma separators.
+
+mk:@MSITStore:C:\Program%20Files%20(x86)\Timberline%20Office\Shared\Help\JC.... 29/11/2023
+Direct cost  Page 2 of 2
+
+                   If you have specified in the GL Entry Settings window that the cost account is to be retrieved, no debit
+                   account is required. If no valid debit account can be retrieved, you must enter the debit account or the
+                   transaction is rejected.
+                   If you have specified in the Import Settings window that a balanced import file is required, then total debits
+                   must equal total credits in the import file or all records are rejected.
+
+ More resources
+You can visit Sage City to join product discussions, search articles in the Sage knowledgebase, or chat online with an expert.
+For additional training on Sage products, visit Sage University.
+
+mk:@MSITStore:C:\Program%20Files%20(x86)\Timberline%20Office\Shared\Help\JC.... 29/11/2023
+

+ 21 - 0
prs.media/TimberlineExportFiles/JC -GL entry Import layout.pdf

@@ -0,0 +1,21 @@
+GL-only entry                                                                    Page 1 of 1
+
+GL-only entry
+
+Number         Type     Length  Item              Comment
+1              alpha    2       record ID         required, must be GL
+2              date     10      transaction date  if blank, system date is used
+3              date     10      accounting date   if blank, JC End date is used
+4              alpha    30      description       optional
+5              numeric  9.2     amount            required
+6              alpha    25      debit account     required if no credit account
+7              alpha    25      credit account    required if no debit account
+8              alpha    10      reference 1
+9              alpha    10      reference 2
+
+ More resources
+You can visit Sage City to join product discussions, search articles in the Sage knowledgebase, or chat online with an expert.
+For additional training on Sage products, visit Sage University.
+
+mk:@MSITStore:C:\Program%20Files%20(x86)\Timberline%20Office\Shared\Help\JC.... 29/11/2023
+

+ 20 - 0
prs.media/TimberlineExportFiles/JC-Import direct cost example.pdf

@@ -0,0 +1,20 @@
+Import direct costs example  Page 1 of 1
+
+Import direct costs example
+
+;This is a comment in a sample import file
+;The next line is purposely split over two physical lines
+DC, 93120, , 01100, MAT, 2, 09/14/1995, 09/30/1995, +
+"weatherstripping, 12 ft.", 12, 2.2, 26.40, 01-825, 01-101
+;The next line wraps by itself
+DC, 93-433, , 02-100, LAB, 3, 091295, 093095, OT for Perry,3.25, 19.5, 63.38, 01-224, 01-835
+;The next line is a GL-only entry
+GL, 092395, 093095, Interco xfer, 1539.25, 01-830, 02-830, 5017
+
+  More resources
+ You can visit Sage City to join product discussions, search articles in the Sage knowledgebase, or chat online with an
+ expert.
+ For additional training on Sage products, visit Sage University.
+
+mk:@MSITStore:C:\Program%20Files%20(x86)\Timberline%20Office\Shared\Help\JC.... 29/11/2023
+

+ 122 - 46
prs.shared/Posters/Timberline/StockMovementTimberlinePoster.cs

@@ -16,6 +16,7 @@ using System.Threading.Tasks;
 using System.Windows;
 using Microsoft.Win32;
 using CsvHelper.TypeConversion;
+using NPOI.SS.Formula.Functions;
 
 namespace PRS.Shared
 {
@@ -283,7 +284,7 @@ public class Module
 
             var firstMovements = model.GetTable<StockMovement>();
             var full = model.GetTable<StockMovement>("FullTransactions")
-                .ToObjects<StockMovement>();
+                .ToObjects<StockMovement>().GroupBy(x => x.Transaction);
             var products = model.GetTable<Product>().ToObjects<Product>()
                 .ToDictionary(x => x.ID, x => x);
             var jobs = model.GetTable<Job>().ToObjects<Job>()
@@ -291,66 +292,141 @@ public class Module
             var batches = model.GetTable<StockMovementBatch>().ToObjects<StockMovementBatch>()
                 .ToDictionary(x => x.ID, x => x);
 
-            foreach (var movement in full)
+            StockMovementTimberlineDirectCost CreateDirectCost(StockMovement movement)
             {
-                if (!movement.IsTransfer)
-                {
-                    result.AddSuccess(movement, null);
-                    continue;
-                }
+                var job = jobs[movement.Job.ID];
+                var product = products[movement.Product.ID];
 
-                var batch = batches.GetValueOrDefault(movement.Batch.ID);
-                if (batch is not null && batch.Type == StockMovementBatchType.Receipt)
+                var directCost = new StockMovementTimberlineDirectCost
                 {
-                    result.AddSuccess(movement, null);
-                    continue;
-                }
-
-                IStockMovementTimberlineLine line;
+                    Job = job.JobNumber,
+                    Extra = "",
+                    CostCode = product.CostCentre.Code,
+                    Category = "",
+                    Units = movement.Units,
+                    UnitCost = movement.Cost,
+                    // TransactionType = ???
+                };
+                return ModifyLine(directCost, movement);
+            }
+            T ModifyLine<T>(T line, StockMovement movement)
+                where T : IStockMovementTimberlineLine
+            {
                 var product = products[movement.Product.ID];
-                if (movement.Job.ID != Guid.Empty)
-                {
-                    var job = jobs[movement.Job.ID];
-                    var directCost = new StockMovementTimberlineDirectCost
-                    {
-                        Job = job.JobNumber,
-                        Extra = "",
-                        CostCode = product.CostCentre.Code,
-                        Category = "",
-                        Units = movement.Units,
-                        UnitCost = movement.Cost,
-                        // TransactionType = ???
-                    };
-                    line = directCost;
-                }
-                else
-                {
-                    line = new StockMovementTimberlineGL
-                    {
-                    };
-                }
+                var batch = batches.GetValueOrDefault(movement.Batch.ID);
+
                 line.TransactionDate = movement.Date;
                 line.Description = product.Name;
                 line.Amount = movement.Value;
                 line.CreditAccount = product.PurchaseGL.Code;
                 line.BatchType = batch?.Type ?? StockMovementBatchType.Transfer;
+                return line;
+            }
 
-                bool success = true;
-                if (line is StockMovementTimberlineDirectCost dc)
-                {
-                    success = ProcessDirectCostLine(model, movement, dc);
-                }
-                else if (line is StockMovementTimberlineGL gl)
+            foreach (var transaction in full)
+            {
+                var movements = new List<StockMovement>();
+                foreach(var movement in transaction)
                 {
-                    success = ProcessGLLine(model, movement, gl);
+                    if (!movement.IsTransfer)
+                    {
+                        // Ignore these ones.
+                        result.AddSuccess(movement, null);
+                    }
+                    else
+                    {
+                        movements.Add(movement);
+                    }
                 }
-                if (success)
+
+                if(movements.Count == 1)
                 {
-                    result.AddSuccess(movement, line);
+                    var mvt = movements[0];
+                    var batch = batches.GetValueOrDefault(mvt.Batch.ID);
+                    if(batch is null)
+                    {
+                        // What to do?
+                    }
+
+                    if(batch?.Type == StockMovementBatchType.Stocktake)
+                    {
+                        if(mvt.Job.ID == Guid.Empty)
+                        {
+                            var gl = new StockMovementTimberlineGL { };
+                            gl = ModifyLine(gl, mvt);
+                            if (ProcessGLLine(model, mvt, gl))
+                            {
+                                result.AddSuccess(mvt, gl);
+                            }
+                            else
+                            {
+                                result.AddFailed(mvt, "Failed by script.");
+                            }
+                        }
+                        else
+                        {
+                            var dc = CreateDirectCost(mvt);
+                            if (ProcessDirectCostLine(model, mvt, dc))
+                            {
+                                result.AddSuccess(mvt, dc);
+                            }
+                            else
+                            {
+                                result.AddFailed(mvt, "Failed by script.");
+                            }
+                        }
+                    }
+                    else
+                    {
+                        result.AddSuccess(mvt, null);
+                    }
                 }
-                else
+                else if(movements.Count == 2)
                 {
-                    result.AddFailed(movement, "Failed by script.");
+                    var mvtFrom = movements[0];
+                    var mvtTo = movements[1];
+                    if(mvtFrom.Job.ID == mvtTo.Job.ID)
+                    {
+                        // Ignore these ones.
+                        result.AddSuccess(mvtFrom, null);
+                        result.AddSuccess(mvtTo, null);
+                    }
+                    else if(mvtFrom.Job.ID == Guid.Empty || mvtTo.Job.ID == Guid.Empty)
+                    {
+                        var jobMvt = mvtFrom.Job.ID == Guid.Empty ? mvtTo : mvtFrom;
+
+                        var directCost = CreateDirectCost(jobMvt);
+                        if(ProcessDirectCostLine(model, jobMvt, directCost))
+                        {
+                            result.AddSuccess(jobMvt, directCost);
+                        }
+                        else
+                        {
+                            result.AddFailed(jobMvt, "Failed by script.");
+                        }
+                    }
+                    else
+                    {
+                        var directCostFrom = CreateDirectCost(mvtFrom);
+                        var directCostTo = CreateDirectCost(mvtTo);
+
+                        if (ProcessDirectCostLine(model, mvtFrom, directCostFrom))
+                        {
+                            result.AddSuccess(mvtFrom, directCostFrom);
+                        }
+                        else
+                        {
+                            result.AddFailed(mvtFrom, "Failed by script.");
+                        }
+                        if (ProcessDirectCostLine(model, mvtTo, directCostTo))
+                        {
+                            result.AddSuccess(mvtTo, directCostTo);
+                        }
+                        else
+                        {
+                            result.AddFailed(mvtTo, "Failed by script.");
+                        }
+                    }
                 }
             }