|
@@ -0,0 +1,310 @@
|
|
|
+using Comal.Classes;
|
|
|
+using InABox.Core;
|
|
|
+using InABox.Core.Postable;
|
|
|
+using InABox.Poster.MYOB;
|
|
|
+using InABox.Scripting;
|
|
|
+using MYOB.AccountRight.SDK.Contracts.Version2.Sale;
|
|
|
+using MYOB.AccountRight.SDK.Services.GeneralLedger;
|
|
|
+using MYOB.AccountRight.SDK.Services.Purchase;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using MYOBPurchaseOrder = MYOB.AccountRight.SDK.Contracts.Version2.Purchase.ServicePurchaseOrder;
|
|
|
+using MYOBPurchaseOrderItem = MYOB.AccountRight.SDK.Contracts.Version2.Purchase.ServicePurchaseOrderLine;
|
|
|
+using MYOBTaxCode = MYOB.AccountRight.SDK.Contracts.Version2.GeneralLedger.TaxCode;
|
|
|
+
|
|
|
+namespace PRS.Shared.Posters.MYOB;
|
|
|
+
|
|
|
+public class PurchaseOrderMYOBPosterSettings : MYOBPosterSettings
|
|
|
+{
|
|
|
+ public override string DefaultScript(Type TPostable)
|
|
|
+ {
|
|
|
+ return @"using MYOBPurchaseOrder = MYOB.AccountRight.SDK.Contracts.Version2.Purchase.ServicePurchaseOrder;
|
|
|
+using MYOBPurchaseOrderItem = MYOB.AccountRight.SDK.Contracts.Version2.Purchase.ServicePurchaseOrderLine;
|
|
|
+
|
|
|
+public class Module
|
|
|
+{
|
|
|
+ public void BeforePost(IDataModel<PurchaseOrder> model)
|
|
|
+ {
|
|
|
+ // Perform pre-processing
|
|
|
+ }
|
|
|
+
|
|
|
+ public void ProcessPurchaseOrder(IDataModel<PurchaseOrder> model, PurchaseOrder purchaseOrder, MYOBPurchaseOrder myobPurchaseOrder)
|
|
|
+ {
|
|
|
+ // Do extra processing for a purchase order; throw an exception to fail this purchase order.
|
|
|
+ }
|
|
|
+
|
|
|
+ public void ProcessPurchaseOrderItem(IDataModel<PurchaseOrder> model, PurchaseOrderItem purchaseOrderItem, MYOBPurchaseOrderItem myobPurchaseOrderItem)
|
|
|
+ {
|
|
|
+ // Do extra processing for a purchase order item; throw an exception to fail this purchase order item (and thus fail the entire purchase order)
|
|
|
+ }
|
|
|
+}";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public class PurchaseOrderMYOBPoster : IMYOBPoster<PurchaseOrder, PurchaseOrderMYOBPosterSettings>
|
|
|
+{
|
|
|
+ public ScriptDocument? Script { get; set; }
|
|
|
+ public MYOBConnectionData ConnectionData { get; set; }
|
|
|
+ public PurchaseOrderMYOBPosterSettings Settings { get; set; }
|
|
|
+ public MYOBGlobalPosterSettings GlobalSettings { get; set; }
|
|
|
+
|
|
|
+ public bool BeforePost(IDataModel<PurchaseOrder> model)
|
|
|
+ {
|
|
|
+ foreach (var (_, table) in model.ModelTables)
|
|
|
+ {
|
|
|
+ table.IsDefault = false;
|
|
|
+ }
|
|
|
+ model.SetIsDefault<PurchaseOrder>(true);
|
|
|
+ model.SetColumns<PurchaseOrder>(RequiredPurchaseOrderColumns());
|
|
|
+
|
|
|
+ model.SetIsDefault<PurchaseOrderItem>(true, alias: "PurchaseOrder_PurchaseOrderItem");
|
|
|
+ model.SetColumns<PurchaseOrderItem>(RequiredPurchaseOrderItemColumns(), alias: "PurchaseOrder_PurchaseOrderItem");
|
|
|
+
|
|
|
+ model.SetIsDefault<Supplier>(true, alias: "PurchaseOrder_Supplier");
|
|
|
+ model.SetColumns<Supplier>(RequiredSupplierColumns(), alias: "PurchaseOrder_Supplier");
|
|
|
+
|
|
|
+ Script?.Execute(methodname: "BeforePost", parameters: new object[] { model });
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ #region Script Functions
|
|
|
+
|
|
|
+ private Result<Exception> ProcessPurchaseOrder(IDataModel<PurchaseOrder> model, PurchaseOrder po, MYOBPurchaseOrder myobPO)
|
|
|
+ {
|
|
|
+ return this.WrapScript("ProcessPurchaseOrder", model, po, myobPO);
|
|
|
+ }
|
|
|
+ private Result<Exception> ProcessPurchaseOrderItem(IDataModel<PurchaseOrder> model, PurchaseOrderItem poItem, MYOBPurchaseOrderItem myobPOItem)
|
|
|
+ {
|
|
|
+ return this.WrapScript("ProcessPurchaseOrderItem", model, poItem, myobPOItem);
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ private static Columns<PurchaseOrder> RequiredPurchaseOrderColumns()
|
|
|
+ {
|
|
|
+ return Columns.None<PurchaseOrder>()
|
|
|
+ .Add(x => x.ID)
|
|
|
+ .Add(x => x.PostedReference)
|
|
|
+ .Add(x => x.IssuedDate)
|
|
|
+ .Add(x => x.PONumber)
|
|
|
+ .Add(x => x.SupplierLink.ID)
|
|
|
+ .Add(x => x.Description);
|
|
|
+ }
|
|
|
+ private static Columns<PurchaseOrderItem> RequiredPurchaseOrderItemColumns()
|
|
|
+ {
|
|
|
+ return Columns.None<PurchaseOrderItem>()
|
|
|
+ .Add(x => x.ID)
|
|
|
+ .Add(x => x.PurchaseOrderLink.ID)
|
|
|
+ .Add(x => x.Description)
|
|
|
+ .Add(x => x.IncTax)
|
|
|
+ .Add(x => x.PurchaseGL.ID)
|
|
|
+ .Add(x => x.PurchaseGL.Code)
|
|
|
+ .Add(x => x.PurchaseGL.PostedReference)
|
|
|
+ .Add(x => x.TaxCode.ID)
|
|
|
+ .Add(x => x.TaxCode.Code)
|
|
|
+ .Add(x => x.TaxCode.PostedReference);
|
|
|
+ }
|
|
|
+ private static Columns<Supplier> RequiredSupplierColumns()
|
|
|
+ {
|
|
|
+ return SupplierMYOBPoster.RequiredColumns();
|
|
|
+ }
|
|
|
+
|
|
|
+ public IPostResult<PurchaseOrder> Process(IDataModel<PurchaseOrder> model)
|
|
|
+ {
|
|
|
+ var results = new PostResult<PurchaseOrder>();
|
|
|
+ var service = new ServicePurchaseOrderService(ConnectionData.Configuration, null, ConnectionData.AuthKey);
|
|
|
+
|
|
|
+ var pos = model.GetTable<PurchaseOrder>().ToArray<PurchaseOrder>();
|
|
|
+ if(pos.Any(x => x.IssuedDate.IsEmpty()))
|
|
|
+ {
|
|
|
+ throw new PostFailedMessageException($"We can't process unissued purchase orders; please set [{nameof(PurchaseOrder.IssuedDate)}] for" +
|
|
|
+ $" all purchase orders before processing.");
|
|
|
+ }
|
|
|
+
|
|
|
+ var poItems = model.GetTable<PurchaseOrderItem>("PurchaseOrder_PurchaseOrderItem")
|
|
|
+ .ToObjects<PurchaseOrderItem>().GroupBy(x => x.PurchaseOrderLink.ID).ToDictionary(x => x.Key, x => x.ToArray());
|
|
|
+
|
|
|
+ var suppliers = model.GetTable<Supplier>("PurchaseOrder_Supplier")
|
|
|
+ .ToObjects<Supplier>().ToDictionary(x => x.ID);
|
|
|
+
|
|
|
+ foreach(var po in pos)
|
|
|
+ {
|
|
|
+ MYOBPurchaseOrder myobPO;
|
|
|
+ Exception? error;
|
|
|
+ bool isNew;
|
|
|
+ if(Guid.TryParse(po.PostedReference, out var myobID))
|
|
|
+ {
|
|
|
+ if(!service.Get(ConnectionData, myobID).Get(out var newPO, out error))
|
|
|
+ {
|
|
|
+ CoreUtils.LogException("", error, $"Failed to find Purchase Order in MYOB with id {myobID}");
|
|
|
+ results.AddFailed(po, $"Failed to find Purchase Order in MYOB with id {myobID}: {error.Message}");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ myobPO = newPO;
|
|
|
+ isNew = false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ myobPO = new MYOBPurchaseOrder();
|
|
|
+ isNew = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ myobPO.Number = po.PONumber.Truncate(13);
|
|
|
+ myobPO.Date = po.IssuedDate;
|
|
|
+ // myobPO.SupplierInvoiceNumber
|
|
|
+
|
|
|
+ if(suppliers.TryGetValue(po.SupplierLink.ID, out var supplier))
|
|
|
+ {
|
|
|
+ if(!SupplierMYOBPoster.MapSupplier(ConnectionData, supplier, GlobalSettings).Get(out var supplierID, out error))
|
|
|
+ {
|
|
|
+ CoreUtils.LogException("", error, $"Error while posting purchase order {po.ID}");
|
|
|
+ results.AddFailed(po, error.Message);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ myobPO.Supplier ??= new();
|
|
|
+ myobPO.Supplier.UID = supplierID;
|
|
|
+ results.AddFragment(supplier, supplier.PostedStatus);
|
|
|
+ }
|
|
|
+
|
|
|
+ // myobPO.ShipToAddress =
|
|
|
+ // myobPO.Terms =
|
|
|
+ myobPO.IsTaxInclusive = true;
|
|
|
+ myobPO.IsReportable = true;
|
|
|
+
|
|
|
+ // myobPO.Freight =
|
|
|
+ // myobPO.FreightForeign =
|
|
|
+
|
|
|
+ if (isNew)
|
|
|
+ {
|
|
|
+ if(!this.GetDefaultTaxCode().Get(out var taxCodeID, out error))
|
|
|
+ {
|
|
|
+ results.AddFailed(po, error.Message);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ myobPO.FreightTaxCode ??= new();
|
|
|
+ myobPO.FreightTaxCode.UID = taxCodeID;
|
|
|
+ }
|
|
|
+
|
|
|
+ // myobPO.Category =
|
|
|
+ myobPO.Comment = po.Description.Truncate(2000);
|
|
|
+ // myobPO.ShippingMethod =
|
|
|
+ // myobPO.PromisedDate =
|
|
|
+ // myobPO.JournalMemo =
|
|
|
+ // myobPO.OrderDeliveryStatus =
|
|
|
+
|
|
|
+ if(poItems.TryGetValue(po.ID, out var lines))
|
|
|
+ {
|
|
|
+ var newLines = new MYOBPurchaseOrderItem[lines.Length];
|
|
|
+ string? failed = null;
|
|
|
+ for(int i = 0; i < lines.Length; ++i)
|
|
|
+ {
|
|
|
+ var poItem = lines[i];
|
|
|
+
|
|
|
+ var line = new MYOBPurchaseOrderItem();
|
|
|
+ line.Type = OrderLineType.Transaction;
|
|
|
+ line.Description = poItem.Description.Truncate(1000);
|
|
|
+
|
|
|
+ if(poItem.PurchaseGL.ID == Guid.Empty)
|
|
|
+ {
|
|
|
+ failed = "Not all lines have a PurchaseGL code set.";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if(!Guid.TryParse(poItem.PurchaseGL.PostedReference, out var accountID))
|
|
|
+ {
|
|
|
+ if(AccountMYOBUtils.GetAccount(ConnectionData, poItem.PurchaseGL.Code).Get(out accountID, out error))
|
|
|
+ {
|
|
|
+ results.AddFragment(new GLCode { ID = poItem.PurchaseGL.ID, PostedReference = accountID.ToString() });
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ CoreUtils.LogException("", error);
|
|
|
+ failed = error.Message;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ line.Account ??= new();
|
|
|
+ line.Account.UID = accountID;
|
|
|
+ line.Total = (decimal)poItem.IncTax;
|
|
|
+ line.TotalForeign = 0;
|
|
|
+ // line.UnitsOfMeasure =
|
|
|
+ // line.UnitCount =
|
|
|
+ // line.UnitPrice =
|
|
|
+ // line.UnitPriceForeign =
|
|
|
+ // line.DiscountPercent =
|
|
|
+ // line.Job =
|
|
|
+
|
|
|
+ if(poItem.TaxCode.ID == Guid.Empty)
|
|
|
+ {
|
|
|
+ failed = "Not all lines have a TaxCode set.";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if(!Guid.TryParse(poItem.TaxCode.PostedReference, out var taxCodeID))
|
|
|
+ {
|
|
|
+ if (!ConnectionData.GetUID<TaxCodeService, MYOBTaxCode>(
|
|
|
+ new Filter<MYOBTaxCode>(x => x.Code).IsEqualTo(poItem.TaxCode.Code))
|
|
|
+ .Get(out taxCodeID, out error))
|
|
|
+ {
|
|
|
+ CoreUtils.LogException("", error, $"Failed to find TaxCode in MYOB with code {poItem.TaxCode.Code}");
|
|
|
+ failed = $"Failed to find TaxCode in MYOB with code {poItem.TaxCode.Code}: {error.Message}";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ else if (taxCodeID == Guid.Empty)
|
|
|
+ {
|
|
|
+ failed = $"Failed to find TaxCode in MYOB with code {poItem.TaxCode.Code}";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ results.AddFragment(new TaxCode { ID = taxCodeID, PostedReference = taxCodeID.ToString() });
|
|
|
+ }
|
|
|
+ line.TaxCode ??= new();
|
|
|
+ line.TaxCode.UID = taxCodeID;
|
|
|
+
|
|
|
+ if(!ProcessPurchaseOrderItem(model, poItem, line).Get(out error))
|
|
|
+ {
|
|
|
+ failed = error.Message;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ newLines[i] = line;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(failed is not null)
|
|
|
+ {
|
|
|
+ results.AddFailed(po, failed);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ myobPO.Lines = newLines;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ myobPO.Lines = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!ProcessPurchaseOrder(model, po, myobPO).Get(out error))
|
|
|
+ {
|
|
|
+ results.AddFailed(po, error.Message);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(service.Save(ConnectionData, myobPO).Get(out var result, out error))
|
|
|
+ {
|
|
|
+ po.PostedReference = result.UID.ToString();
|
|
|
+ results.AddSuccess(po);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ CoreUtils.LogException("", error, $"Error while posting purchase order {po.ID}");
|
|
|
+ results.AddFailed(po, error.Message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return results;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public class PurchaseOrderMYOBPosterEngine : MYOBPosterEngine<PurchaseOrder, PurchaseOrderMYOBPoster, PurchaseOrderMYOBPosterSettings>
|
|
|
+{
|
|
|
+}
|