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.Sale; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Markup.Localizer; using Invoice = Comal.Classes.Invoice; using MYOBReceipt = MYOB.AccountRight.SDK.Contracts.Version2.Sale.CustomerPayment; using MYOBInvoiceReceipt = MYOB.AccountRight.SDK.Contracts.Version2.Sale.CustomerPaymentLine; namespace PRS.Shared.Posters.MYOB; public class ReceiptMYOBPosterSettings : MYOBPosterSettings { [EditorSequence(1)] [TextBoxEditor(ToolTip = "The MYOB account code for receipts")] public string Account { get; set; } public override string DefaultScript(Type TPostable) { return @"using MYOBReceipt = MYOB.AccountRight.SDK.Contracts.Version2.Sale.CustomerPayment; using MYOBInvoiceReceipt = MYOB.AccountRight.SDK.Contracts.Version2.Sale.CustomerPaymentLine; public class Module { public void BeforePost(IDataModel model) { // Perform pre-processing } public void ProcessReceipt(IDataModel model, Receipt receipt, MYOBReceipt myobReceipt) { // Do extra processing for a receipt; throw an exception to fail this receipt. } public void ProcessInvoiceReceipt(IDataModel model, InvoiceReceipt invoiceReceipt, MYOBInvoiceReceipt myobInvoiceReceipt) { // Do extra processing for an invoice receipt; throw an exception to fail this invoice receipt (and thus fail the entire receipt) } }"; } } public class ReceiptMYOBPoster : IMYOBPoster { public ScriptDocument? Script { get; set; } public MYOBConnectionData ConnectionData { get; set; } public ReceiptMYOBPosterSettings Settings { get; set; } public MYOBGlobalPosterSettings GlobalSettings { get; set; } public bool BeforePost(IDataModel model) { foreach(var (_, table) in model.ModelTables) { table.IsDefault = false; } model.SetIsDefault(true); model.SetColumns(RequiredReceiptColumns()); model.SetIsDefault(true, alias: "Receipt_InvoiceReceipt"); model.SetColumns(RequiredInvoiceReceiptColumns(), alias: "Receipt_InvoiceReceipt"); model.SetIsDefault(true, alias: "Receipt_Customer"); model.SetColumns(RequiredCustomerColumns(), alias: "Receipt_Customer"); Script?.Execute(methodname: "BeforePost", parameters: [model]); return true; } #region Script Functions private Result ProcessReceipt(IDataModel model, Receipt receipt, MYOBReceipt myobReceipt) { return this.WrapScript("ProcessReceipt", model, receipt, myobReceipt); } private Result ProcessInvoiceReceipt(IDataModel model, InvoiceReceipt invoiceReceipt, MYOBInvoiceReceipt myobInvoiceReceipt) { return this.WrapScript("ProcessInvoiceReceipt", model, invoiceReceipt, myobInvoiceReceipt); } #endregion private static Columns RequiredReceiptColumns() { return Columns.None() .Add(x => x.ID) .Add(x => x.PostedReference) .Add(x => x.PostedStatus) .Add(x => x.CustomerLink.ID) .Add(x => x.Date) .Add(x => x.Total) .Add(x => x.Notes); } private static Columns RequiredInvoiceReceiptColumns() { return Columns.None() .Add(x => x.ID) .Add(x => x.Amount) .Add(x => x.ReceiptLink.ID) .Add(x => x.InvoiceLink.Number) .Add(x => x.InvoiceLink.PostedReference); } private static Columns RequiredCustomerColumns() { return CustomerMYOBPoster.RequiredColumns(); } public IPostResult Process(IDataModel model) { // https://developer.myob.com/api/myob-business-api/v2/sale/customerpayment/ var results = new PostResult(); var service = new CustomerPaymentService(ConnectionData.Configuration, null, ConnectionData.AuthKey); var receipts = model.GetTable().ToArray(); var customers = model.GetTable("Receipt_Customer") .ToObjects().ToDictionary(x => x.ID); var invoices = model.GetTable("Receipt_InvoiceReceipt") .ToObjects().GroupBy(x => x.ReceiptLink.ID).ToDictionary(x => x.Key, x => x.ToArray()); foreach(var receipt in receipts) { // For receipts, always create a new one, so we cannot posted already posted stuff. if(receipt.PostedStatus == PostedStatus.Posted) { continue; } var myobReceipt = new MYOBReceipt(); myobReceipt.DepositTo = DepositTo.Account; // Setting this to null right now. myobReceipt.Account ??= new(); if (Settings.Account.IsNullOrWhiteSpace()) { throw new MissingSettingException(x => x.Account); } else if(AccountMYOBUtils.GetAccount(ConnectionData, Settings.Account).Get(out var accountID, out var error)) { myobReceipt.Account.UID = accountID; } else { CoreUtils.LogException("", error); results.AddFailed(receipt, error.Message); continue; } if(customers.TryGetValue(receipt.CustomerLink.ID, out var customer)) { if(!CustomerMYOBPoster.MapCustomer(ConnectionData, customer, GlobalSettings).Get(out var customerID, out var error)) { CoreUtils.LogException("", error, $"Error while posting receipt {receipt.ID}"); results.AddFailed(receipt, error.Message); continue; } myobReceipt.Customer ??= new(); myobReceipt.Customer.UID = customerID; results.AddFragment(customer, customer.PostedStatus); } // myobReceipt.ReceiptNumber = myobReceipt.Date = receipt.Date; myobReceipt.AmountReceived = (decimal)receipt.Total; // myobReceipt.AmountReceivedForeign = 0; // myobReceipt.PaymentMethod = myobReceipt.Memo = receipt.Notes.Truncate(255); if(invoices.TryGetValue(receipt.ID, out var receiptInvoices)) { var myobInvoices = new CustomerPaymentLine[receiptInvoices.Length]; string? failed = null; for(int i = 0; i < receiptInvoices.Length; ++i) { var invoice = receiptInvoices[i]; var line = new CustomerPaymentLine(); // line.RowID = i + 1; line.Number = invoice.InvoiceLink.Number.ToString().Truncate(8); line.AmountApplied = (decimal)invoice.Amount; line.Type = CustomerPaymentLineType.Invoice; if(Guid.TryParse(invoice.InvoiceLink.PostedReference, out var myobInvoiceID)) { line.UID = myobInvoiceID; } else { failed = $"Invoice {invoice.InvoiceLink.Number} hasn't been posted yet; it must be posted before this receipt can be."; break; } if(!ProcessInvoiceReceipt(model, invoice, line).Get(out var error)) { failed = error.Message; break; } myobInvoices[i] = line; } if(failed is not null) { results.AddFailed(receipt, failed); continue; } myobReceipt.Invoices = myobInvoices; } else { myobReceipt.Invoices = []; } if(!ProcessReceipt(model, receipt, myobReceipt).Get(out var e)) { results.AddFailed(receipt, e.Message); continue; } if(service.Save(ConnectionData, myobReceipt).Get(out var result, out e)) { receipt.PostedReference = result.UID.ToString(); results.AddSuccess(receipt); } else { CoreUtils.LogException("", e, $"Error while posting receipt {receipt.ID}"); results.AddFailed(receipt, e.Message); } } return results; } } public class ReceiptMYOBPosterEngine : MYOBPosterEngine { }