diff --git a/src/Apps/W1/Shopify/App/src/Document Links/Codeunits/ShpfyDocumentLinkMgt.Codeunit.al b/src/Apps/W1/Shopify/App/src/Document Links/Codeunits/ShpfyDocumentLinkMgt.Codeunit.al index 2c2830ca09..c20f5551dd 100644 --- a/src/Apps/W1/Shopify/App/src/Document Links/Codeunits/ShpfyDocumentLinkMgt.Codeunit.al +++ b/src/Apps/W1/Shopify/App/src/Document Links/Codeunits/ShpfyDocumentLinkMgt.Codeunit.al @@ -64,6 +64,16 @@ codeunit 30262 "Shpfy Document Link Mgt." [EventSubscriber(ObjectType::Codeunit, Codeunit::"Sales-Post", 'OnAfterPostSalesDoc', '', true, false)] local procedure OnAfterSalesPosting(var SalesHeader: Record "Sales Header"; PreviewMode: Boolean; SalesShptHdrNo: Code[20]; SalesInvHdrNo: Code[20]; RetRcpHdrNo: Code[20]; SalesCrMemoHdrNo: Code[20]) + var + ShpfyAutoPostTransactions: Codeunit "Shpfy Auto Post Transactions"; + begin + CreateDocLinksToBCDocs(SalesHeader, PreviewMode, SalesShptHdrNo, SalesInvHdrNo, RetRcpHdrNo, SalesCrMemoHdrNo); + + Commit(); // Ensure Doc. Link To Doc. creation is committed before running the automatic transaction posting. + ShpfyAutoPostTransactions.AutoPostTransactions(SalesInvHdrNo, SalesCrMemoHdrNo); + end; + + local procedure CreateDocLinksToBCDocs(var SalesHeader: Record "Sales Header"; PreviewMode: Boolean; SalesShptHdrNo: Code[20]; SalesInvHdrNo: Code[20]; RetRcpHdrNo: Code[20]; SalesCrMemoHdrNo: Code[20]) var SalesShipmentHeader: Record "Sales Shipment Header"; SalesInvoiceLine: Record "Sales Invoice Line"; diff --git a/src/Apps/W1/Shopify/App/src/PermissionSets/ShpfyObjects.PermissionSet.al b/src/Apps/W1/Shopify/App/src/PermissionSets/ShpfyObjects.PermissionSet.al index 52af1b5cba..aa065d2006 100644 --- a/src/Apps/W1/Shopify/App/src/PermissionSets/ShpfyObjects.PermissionSet.al +++ b/src/Apps/W1/Shopify/App/src/PermissionSets/ShpfyObjects.PermissionSet.al @@ -103,6 +103,8 @@ permissionset 30104 "Shpfy - Objects" report "Shpfy Translator" = X, codeunit "Company Details Checklist Item" = X, codeunit "Shpfy Authentication Mgt." = X, + codeunit "Shpfy Auto Gen. Jnl.-Post" = X, + codeunit "Shpfy Auto Post Transactions" = X, codeunit "Shpfy Background Syncs" = X, codeunit "Shpfy Balance Today" = X, codeunit "Shpfy Base64" = X, @@ -441,6 +443,7 @@ permissionset 30104 "Shpfy - Objects" page "Shpfy Customers" = X, page "Shpfy Data Capture List" = X, page "Shpfy Disputes" = X, + page "Shpfy Filter Transactions" = X, page "Shpfy Fulfillment Order Card" = X, page "Shpfy Fulfillment Order Lines" = X, page "Shpfy Fulfillment Orders" = X, diff --git a/src/Apps/W1/Shopify/App/src/Transactions/Codeunits/ShpfyAutoGenJnlPost.Codeunit.al b/src/Apps/W1/Shopify/App/src/Transactions/Codeunits/ShpfyAutoGenJnlPost.Codeunit.al new file mode 100644 index 0000000000..91cebf76ae --- /dev/null +++ b/src/Apps/W1/Shopify/App/src/Transactions/Codeunits/ShpfyAutoGenJnlPost.Codeunit.al @@ -0,0 +1,29 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Integration.Shopify; + +using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Finance.GeneralLedger.Posting; + +/// +/// Codeunit Shpfy Auto Gen. Jnl.-Post (ID 30422). +/// +codeunit 30422 "Shpfy Auto Gen. Jnl.-Post" +{ + EventSubscriberInstance = Manual; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post", 'OnBeforeCode', '', false, false)] + local procedure OnBeforeCode(var GenJournalLine: Record "Gen. Journal Line"; var HideDialog: Boolean) + begin + HideDialog := true; + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post", 'OnBeforeShowPostResultMessage', '', false, false)] + local procedure OnBeforeShowPostResultMessage(var GenJnlLine: Record "Gen. Journal Line"; TempJnlBatchName: Code[10]; var IsHandled: Boolean) + begin + IsHandled := true; + end; +} diff --git a/src/Apps/W1/Shopify/App/src/Transactions/Codeunits/ShpfyAutoPostTransactions.Codeunit.al b/src/Apps/W1/Shopify/App/src/Transactions/Codeunits/ShpfyAutoPostTransactions.Codeunit.al new file mode 100644 index 0000000000..ac8dbeb6d1 --- /dev/null +++ b/src/Apps/W1/Shopify/App/src/Transactions/Codeunits/ShpfyAutoPostTransactions.Codeunit.al @@ -0,0 +1,105 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Integration.Shopify; + +using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Finance.GeneralLedger.Posting; +using Microsoft.Sales.History; + +/// +/// Codeunit Shpfy Auto Post Transactions (ID 30236). +/// +codeunit 30236 "Shpfy Auto Post Transactions" +{ + Access = Internal; + + internal procedure AutoPostTransactions(SalesInvoiceHeaderNo: Code[20]; SalesCrMemoHeaderNo: Code[20]) + begin + if SalesInvoiceHeaderNo <> '' then + PostOrderTransaction(SalesInvoiceHeaderNo); + if SalesCrMemoHeaderNo <> '' then + PostRefundTransaction(SalesCrMemoHeaderNo); + end; + + local procedure PostOrderTransaction(SalesInvoiceHeaderNo: Code[20]) + var + SalesInvoiceHeader: Record "Sales Invoice Header"; + OrderTransaction: Record "Shpfy Order Transaction"; + begin + if not SalesInvoiceHeader.Get(SalesInvoiceHeaderNo) then + exit; + + if SalesInvoiceHeader."Shpfy Order Id" = 0 then + exit; + + OrderTransaction.SetRange("Shopify Order Id", SalesInvoiceHeader."Shpfy Order Id"); + OrderTransaction.SetFilter(Type, '%1|%2', OrderTransaction.Type::Capture, OrderTransaction.Type::Sale); + PostTransaction(OrderTransaction, SalesInvoiceHeader."Posting Date"); + end; + + local procedure PostRefundTransaction(SalesCrMemoHeaderNo: Code[20]) + var + SalesCrMemoHeader: Record "Sales Cr.Memo Header"; + OrderTransaction: Record "Shpfy Order Transaction"; + begin + if not SalesCrMemoHeader.Get(SalesCrMemoHeaderNo) then + exit; + + if SalesCrMemoHeader."Shpfy Refund Id" = 0 then + exit; + + OrderTransaction.SetRange("Refund Id", SalesCrMemoHeader."Shpfy Refund Id"); + OrderTransaction.SetRange(Type, OrderTransaction.Type::Refund); + PostTransaction(OrderTransaction, SalesCrMemoHeader."Posting Date"); + end; + + local procedure PostTransaction(var OrderTransaction: Record "Shpfy Order Transaction"; PostingDate: Date) + begin + OrderTransaction.SetRange(Status, OrderTransaction.Status::Success); + OrderTransaction.SetRange(Used, false); + if OrderTransaction.FindSet() then + repeat + if ShouldAutoPost(OrderTransaction) then + CreateAndPostJournalLine(OrderTransaction, PostingDate); + until OrderTransaction.Next() = 0; + end; + + local procedure ShouldAutoPost(OrderTransaction: Record "Shpfy Order Transaction"): Boolean + var + PaymentMethodMapping: Record "Shpfy Payment Method Mapping"; + begin + if not PaymentMethodMapping.Get(OrderTransaction.Shop, OrderTransaction.Gateway, OrderTransaction."Credit Card Company") then + exit(false); + + if not PaymentMethodMapping."Post Automatically" then + exit(false); + + if (PaymentMethodMapping."Auto-Post Jnl. Template" = '') or + (PaymentMethodMapping."Auto-Post Jnl. Batch" = '') then + exit(false); + + exit(true); + end; + + local procedure CreateAndPostJournalLine(var OrderTransaction: Record "Shpfy Order Transaction"; PostingDate: Date) + var + GenJournalLine: Record "Gen. Journal Line"; + PaymentMethodMapping: Record "Shpfy Payment Method Mapping"; + SuggestPayments: Report "Shpfy Suggest Payments"; + AutoGenJnlPost: Codeunit "Shpfy Auto Gen. Jnl.-Post"; + begin + PaymentMethodMapping.Get(OrderTransaction.Shop, OrderTransaction.Gateway, OrderTransaction."Credit Card Company"); + SuggestPayments.SetJournalParameters(PaymentMethodMapping."Auto-Post Jnl. Template", PaymentMethodMapping."Auto-Post Jnl. Batch", PostingDate); + SuggestPayments.GetOrderTransactions(OrderTransaction); + SuggestPayments.CreateGeneralJournalLines(); + GenJournalLine.SetRange("Shpfy Transaction Id", OrderTransaction."Shopify Transaction Id"); + if GenJournalLine.FindFirst() then begin + BindSubscription(AutoGenJnlPost); + GenJournalLine.SendToPosting(Codeunit::"Gen. Jnl.-Post"); + UnbindSubscription(AutoGenJnlPost); + end; + end; +} \ No newline at end of file diff --git a/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyFilterTransactions.Page.al b/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyFilterTransactions.Page.al new file mode 100644 index 0000000000..be7153dba0 --- /dev/null +++ b/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyFilterTransactions.Page.al @@ -0,0 +1,67 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Integration.Shopify; + +/// +/// Page Shpfy Filter Transactions (ID 30176). +/// +page 30176 "Shpfy Filter Transactions" +{ + Caption = 'Filter Postable Transactions'; + PageType = StandardDialog; + ApplicationArea = All; + + layout + { + area(Content) + { + field(Gateway; Gateway) + { + Caption = 'Gateway'; + ToolTip = 'Specifies the transaction gateway to filter transactions by. Leave blank to include all gateways.'; + Editable = false; + + trigger OnAssistEdit() + var + PaymentMethodMapping: Record "Shpfy Payment Method Mapping"; + begin + PaymentMethodMapping.SetRange("Post Automatically", true); + if Page.RunModal(0, PaymentMethodMapping) = Action::LookupOK then begin + ShopCode := PaymentMethodMapping."Shop Code"; + Gateway := PaymentMethodMapping.Gateway; + CreditCardCompany := PaymentMethodMapping."Credit Card Company"; + end; + end; + } + field(StartDate; StartDate) + { + Caption = 'Start Date'; + ToolTip = 'Specifies the earliest transaction creation date to include in the filter. Leave blank to include all transactions from the beginning.'; + } + field(EndDate; EndDate) + { + Caption = 'End Date'; + ToolTip = 'Specifies the latest transaction creation date to include in the filter. Leave blank to include all transactions.'; + } + } + } + + var + ShopCode: Code[20]; + Gateway: Text[30]; + CreditCardCompany: Text[50]; + StartDate: Date; + EndDate: Date; + + internal procedure GetParameters(var NewShopCode: Code[20]; var NewGateway: Text[30]; var NewCreditCardCompany: Text[50]; var NewStartDate: DateTime; var NewEndDate: DateTime) + begin + NewShopCode := ShopCode; + NewGateway := Gateway; + NewCreditCardCompany := CreditCardCompany; + NewStartDate := CreateDateTime(StartDate, 0T); + NewEndDate := CreateDateTime(EndDate, 0T); + end; +} \ No newline at end of file diff --git a/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyPaymentMethodsMapping.Page.al b/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyPaymentMethodsMapping.Page.al index e5cab053ed..e4f85863b1 100644 --- a/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyPaymentMethodsMapping.Page.al +++ b/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyPaymentMethodsMapping.Page.al @@ -37,6 +37,25 @@ page 30132 "Shpfy Payment Methods Mapping" ApplicationArea = All; ToolTip = 'Specifies the corresponding payment method in D365BC.'; } + field(PostAutomatically; Rec."Post Automatically") + { + ApplicationArea = All; + ToolTip = 'Specifies whether payment transactions using this gateway should be automatically posted when the related invoice or credit memo is posted.'; + } + field(AutoPostJnlTemplate; Rec."Auto-Post Jnl. Template") + { + ApplicationArea = All; + ToolTip = 'Specifies the general journal template to use for automatically posting payment transactions.'; + Enabled = Rec."Post Automatically"; + ShowMandatory = Rec."Post Automatically"; + } + field(AutoPostJnlBatch; Rec."Auto-Post Jnl. Batch") + { + ApplicationArea = All; + ToolTip = 'Specifies the general journal batch to use for automatically posting payment transactions.'; + Enabled = Rec."Post Automatically"; + ShowMandatory = Rec."Post Automatically"; + } } } } diff --git a/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyTransactions.Page.al b/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyTransactions.Page.al index 04b48cbf04..f056e31515 100644 --- a/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyTransactions.Page.al +++ b/src/Apps/W1/Shopify/App/src/Transactions/Pages/ShpfyTransactions.Page.al @@ -137,6 +137,11 @@ page 30134 "Shpfy Transactions" ApplicationArea = All; ToolTip = 'Specifies the Posted Invoice number to which the transaction relates.'; } + field("Auto-Post Enabled"; Rec."Auto-Post Enabled") + { + ApplicationArea = All; + ToolTip = 'Specifies whether auto-posting is enabled for the transaction.'; + } } } } @@ -194,6 +199,31 @@ page 30134 "Shpfy Transactions" SuggestPayments.Run(); end; } + action(ShowPostableTransactions) + { + ApplicationArea = All; + Caption = 'Filter Postable Transactions'; + Image = FilterLines; + ToolTip = 'Show transactions that need to be posted. Filters by auto-post enabled, not yet posted, and linked to a posted invoice. Optionally filter by gateway and date range.'; + + trigger OnAction() + begin + FilterPostableTransactions() + end; + } + action(ClearFilter) + { + ApplicationArea = All; + Caption = 'Clear Filter'; + Image = ClearFilter; + ToolTip = 'Remove the postable transactions filter and show all transactions.'; + + trigger OnAction() + begin + Rec.ClearMarks(); + Rec.MarkedOnly(false); + end; + } } area(Promoted) { @@ -210,6 +240,8 @@ page 30134 "Shpfy Transactions" { Caption = 'Related'; actionref(CustLedgerEntries_Promoted; CustLedgerEntries) { } + actionref(ShowPostableTransactions_Promoted; ShowPostableTransactions) { } + actionref(ClearFilter_Promoted; ClearFilter) { } } } } @@ -232,4 +264,58 @@ page 30134 "Shpfy Transactions" PresentmentCurrencyVisible := OrderHeader.IsPresentmentCurrencyOrder(); end; + + local procedure FilterPostableTransactions() + var + PaymentMethodMapping: Record "Shpfy Payment Method Mapping"; + FilterTransactions: Page "Shpfy Filter Transactions"; + FilterShopCode: Code[20]; + FilterCreditCardCompany: Text[50]; + FilterGateway: Text[30]; + FilterStartDate: DateTime; + FilterEndDate: DateTime; + begin + if not (FilterTransactions.RunModal() = Action::OK) then + exit; + + FilterTransactions.GetParameters(FilterShopCode, FilterGateway, FilterCreditCardCompany, FilterStartDate, FilterEndDate); + if (FilterStartDate <> 0DT) or (FilterEndDate <> 0DT) then + if FilterEndDate <> 0DT then + Rec.SetRange("Created At", FilterStartDate, FilterEndDate) + else + Rec.SetRange("Created At", FilterStartDate, CreateDateTime(DMY2Date(31, 12, 9999), 0T)); + Rec.SetRange(Used, false); + Rec.SetFilter("Posted Invoice No.", '<>%1', ''); + + Rec.ClearMarks(); + Rec.MarkedOnly(false); + if FilterGateway <> '' then + MarkPostableTransactions(FilterShopCode, FilterCreditCardCompany, FilterGateway) + else begin + PaymentMethodMapping.SetRange("Post Automatically", true); + if PaymentMethodMapping.FindSet() then + repeat + MarkPostableTransactions(PaymentMethodMapping."Shop Code", PaymentMethodMapping."Credit Card Company", PaymentMethodMapping.Gateway); + until PaymentMethodMapping.Next() = 0; + end; + + Rec.MarkedOnly(true); + Rec.SetRange(Shop); + Rec.SetRange(Gateway); + Rec.SetRange("Credit Card Company"); + Rec.SetRange("Created At"); + Rec.SetRange(Used); + Rec.SetRange("Posted Invoice No."); + end; + + local procedure MarkPostableTransactions(FilterShopCode: Code[20]; FilterCreditCardCompany: Text[50]; FilterGateway: Text[30]) + begin + Rec.SetRange(Shop, FilterShopCode); + Rec.SetRange(Gateway, FilterGateway); + Rec.SetRange("Credit Card Company", FilterCreditCardCompany); + if Rec.FindSet() then + repeat + Rec.Mark(true); + until Rec.Next() = 0; + end; } \ No newline at end of file diff --git a/src/Apps/W1/Shopify/App/src/Transactions/Reports/ShpfySuggestPayments.Report.al b/src/Apps/W1/Shopify/App/src/Transactions/Reports/ShpfySuggestPayments.Report.al index 8f95f48835..6b6fd80d28 100644 --- a/src/Apps/W1/Shopify/App/src/Transactions/Reports/ShpfySuggestPayments.Report.al +++ b/src/Apps/W1/Shopify/App/src/Transactions/Reports/ShpfySuggestPayments.Report.al @@ -210,6 +210,21 @@ report 30118 "Shpfy Suggest Payments" IgnorePostedTransactions := NewIgnorePostedTransactions; end; + internal procedure SetOrderTransaction(NewOrderTransaction: Record "Shpfy Order Transaction") + begin + OrderTransaction := NewOrderTransaction; + end; + + internal procedure SetJournalParameters(NewTemplateName: Code[10]; NewBatchName: Code[10]; NewPostingDate: Date) + begin + GeneralJournalTemplateName := NewTemplateName; + GeneralJournalBatchName := NewBatchName; + GenJournalLine."Journal Template Name" := NewTemplateName; + GenJournalLine."Journal Batch Name" := NewBatchName; + PostingDate := NewPostingDate; + ValidatePostingDate(); + end; + local procedure ValidatePostingDate() var NoSeries: Codeunit "No. Series"; @@ -252,7 +267,7 @@ report 30118 "Shpfy Suggest Payments" repeat if SalesInvoiceHeader.Closed then continue; - ApplyCustomerLedgerEntries(SalesInvoiceHeader."No.", "Gen. Journal Document Type"::Invoice, AmountToApply, Applied); + ApplyCustomerLedgerEntries(OrderTransaction, SalesInvoiceHeader."No.", "Gen. Journal Document Type"::Invoice, AmountToApply, Applied); until SalesInvoiceHeader.Next() = 0 else begin DocLinkToDoc.SetRange("Shopify Document Type", DocLinkToDoc."Shopify Document Type"::"Shopify Shop Order"); @@ -263,12 +278,12 @@ report 30118 "Shpfy Suggest Payments" SalesInvoiceHeader.Get(DocLinkToDoc."Document No."); if SalesInvoiceHeader.Closed then continue; - ApplyCustomerLedgerEntries(SalesInvoiceHeader."No.", "Gen. Journal Document Type"::Invoice, AmountToApply, Applied); + ApplyCustomerLedgerEntries(OrderTransaction, SalesInvoiceHeader."No.", "Gen. Journal Document Type"::Invoice, AmountToApply, Applied); until DocLinkToDoc.Next() = 0; end; if Applied and (AmountToApply > 0) then - CreateSuggestPaymentGLAccount(AmountToApply, true); + CreateSuggestPaymentGLAccount(OrderTransaction, AmountToApply, true); end; OrderTransaction.Type::Refund: begin @@ -283,18 +298,18 @@ report 30118 "Shpfy Suggest Payments" repeat if SalesCreditMemoHeader.Paid then continue; - ApplyCustomerLedgerEntries(SalesCreditMemoHeader."No.", "Gen. Journal Document Type"::"Credit Memo", AmountToApply, Applied); + ApplyCustomerLedgerEntries(OrderTransaction, SalesCreditMemoHeader."No.", "Gen. Journal Document Type"::"Credit Memo", AmountToApply, Applied); until SalesCreditMemoHeader.Next() = 0; until RefundHeader.Next() = 0; if Applied and (AmountToApply > 0) then - CreateSuggestPaymentGLAccount(AmountToApply, false); + CreateSuggestPaymentGLAccount(OrderTransaction, AmountToApply, false); end; end; end; end; - local procedure ApplyCustomerLedgerEntries(DocumentNo: Code[20]; DocumentType: Enum "Gen. Journal Document Type"; var AmountToApply: Decimal; var Applied: Boolean) + local procedure ApplyCustomerLedgerEntries(OrderTransaction: Record "Shpfy Order Transaction"; DocumentNo: Code[20]; DocumentType: Enum "Gen. Journal Document Type"; var AmountToApply: Decimal; var Applied: Boolean) var CustLedgerEntry: Record "Cust. Ledger Entry"; begin @@ -307,12 +322,12 @@ report 30118 "Shpfy Suggest Payments" if CustLedgerEntry.FindSet() then begin Applied := true; repeat - CreateSuggestPaymentDocument(CustLedgerEntry, AmountToApply, DocumentType = "Gen. Journal Document Type"::Invoice); + CreateSuggestPaymentDocument(CustLedgerEntry, OrderTransaction, AmountToApply, DocumentType = "Gen. Journal Document Type"::Invoice); until CustLedgerEntry.Next() = 0; end; end; - local procedure CreateSuggestPaymentDocument(var CustLedgerEntry: Record "Cust. Ledger Entry"; var AmountToApply: Decimal; IsInvoice: Boolean) + local procedure CreateSuggestPaymentDocument(var CustLedgerEntry: Record "Cust. Ledger Entry"; OrderTransaction: Record "Shpfy Order Transaction"; var AmountToApply: Decimal; IsInvoice: Boolean) begin TempSuggestPayment.Init(); EntryNo += 1; @@ -346,7 +361,7 @@ report 30118 "Shpfy Suggest Payments" TempSuggestPayment.Insert(); end; - local procedure CreateSuggestPaymentGLAccount(AmountToApply: Decimal; IsInvoice: Boolean) + local procedure CreateSuggestPaymentGLAccount(OrderTransaction: Record "Shpfy Order Transaction"; AmountToApply: Decimal; IsInvoice: Boolean) begin TempSuggestPayment.Init(); EntryNo += 1; @@ -375,6 +390,8 @@ report 30118 "Shpfy Suggest Payments" if GenJournalLine.FindLast() then LastLineNo := GenJournalLine."Line No."; + RemoveGenJournalLines(TempSuggestPayment."Shpfy Transaction Id"); + if OrderNoInDescription then TempSuggestPayment.SetAutoCalcFields("Shpfy Order No."); if TempSuggestPayment.FindSet() then @@ -426,6 +443,13 @@ report 30118 "Shpfy Suggest Payments" until TempSuggestPayment.Next() = 0; end; + local procedure RemoveGenJournalLines(ShopifyTransactionId: BigInteger) + begin + GenJournalLine.SetRange("Shpfy Transaction Id", ShopifyTransactionId); + if not GenJournalLine.IsEmpty() then + GenJournalLine.DeleteAll(true); + end; + local procedure SetGenJournallLineDimension(CustomerLedgerEntryDimensionSetId: Integer) var DimensionManagement: Codeunit DimensionManagement; diff --git a/src/Apps/W1/Shopify/App/src/Transactions/Table Extensions/ShpfyGenJournalLine.TableExt.al b/src/Apps/W1/Shopify/App/src/Transactions/Table Extensions/ShpfyGenJournalLine.TableExt.al index 48bcbacdb0..76865a958e 100644 --- a/src/Apps/W1/Shopify/App/src/Transactions/Table Extensions/ShpfyGenJournalLine.TableExt.al +++ b/src/Apps/W1/Shopify/App/src/Transactions/Table Extensions/ShpfyGenJournalLine.TableExt.al @@ -17,5 +17,10 @@ tableextension 30202 "Shpfy Gen. Journal Line" extends "Gen. Journal Line" DataClassification = SystemMetadata; Editable = false; } + field(30101; "Automatically Posted"; Boolean) + { + Caption = 'Automatically Posted'; + DataClassification = SystemMetadata; + } } } \ No newline at end of file diff --git a/src/Apps/W1/Shopify/App/src/Transactions/Tables/ShpfyOrderTransaction.Table.al b/src/Apps/W1/Shopify/App/src/Transactions/Tables/ShpfyOrderTransaction.Table.al index 809a064dc4..a3a702ac51 100644 --- a/src/Apps/W1/Shopify/App/src/Transactions/Tables/ShpfyOrderTransaction.Table.al +++ b/src/Apps/W1/Shopify/App/src/Transactions/Tables/ShpfyOrderTransaction.Table.al @@ -271,6 +271,12 @@ table 30133 "Shpfy Order Transaction" Caption = 'Shop Code'; TableRelation = "Shpfy Shop"; } + field(100; "Auto-Post Enabled"; Boolean) + { + Caption = 'Auto-Post Enabled'; + FieldClass = FlowField; + CalcFormula = lookup("Shpfy Payment Method Mapping"."Post Automatically" where("Shop Code" = field("Shop"), Gateway = field(Gateway), "Credit Card Company" = field("Credit Card Company"))); + } } keys diff --git a/src/Apps/W1/Shopify/App/src/Transactions/Tables/ShpfyPaymentMethodMapping.Table.al b/src/Apps/W1/Shopify/App/src/Transactions/Tables/ShpfyPaymentMethodMapping.Table.al index e1ee2fb335..c57b7f5e7d 100644 --- a/src/Apps/W1/Shopify/App/src/Transactions/Tables/ShpfyPaymentMethodMapping.Table.al +++ b/src/Apps/W1/Shopify/App/src/Transactions/Tables/ShpfyPaymentMethodMapping.Table.al @@ -6,6 +6,7 @@ namespace Microsoft.Integration.Shopify; using Microsoft.Bank.BankAccount; +using Microsoft.Finance.GeneralLedger.Journal; /// /// Table Shpfy Payment Method Mapping (ID 30134). @@ -14,6 +15,8 @@ table 30134 "Shpfy Payment Method Mapping" { Access = Internal; Caption = 'Shopify Payment Method'; + DrillDownPageID = "Shpfy Payment Methods Mapping"; + LookupPageID = "Shpfy Payment Methods Mapping"; DataClassification = CustomerContent; fields @@ -59,6 +62,33 @@ table 30134 "Shpfy Payment Method Mapping" DataClassification = SystemMetadata; Editable = false; } + field(7; "Post Automatically"; Boolean) + { + Caption = 'Post Automatically'; + DataClassification = CustomerContent; + } + field(8; "Auto-Post Jnl. Template"; Code[10]) + { + Caption = 'Auto-Post Journal Template'; + DataClassification = CustomerContent; + TableRelation = "Gen. Journal Template" where(Type = const("Cash Receipts")); + } + field(9; "Auto-Post Jnl. Batch"; Code[10]) + { + Caption = 'Auto-Post Journal Batch'; + DataClassification = CustomerContent; + TableRelation = "Gen. Journal Batch".Name where("Journal Template Name" = field("Auto-Post Jnl. Template")); + + trigger OnValidate() + var + GenJournalBatch: Record "Gen. Journal Batch"; + begin + if "Auto-Post Jnl. Batch" <> '' then begin + GenJournalBatch.Get("Auto-Post Jnl. Template", "Auto-Post Jnl. Batch"); + GenJournalBatch.TestField("Bal. Account No."); + end; + end; + } } keys { diff --git a/src/Apps/W1/Shopify/Test/Payments/ShpfyAutoPostTransTest.Codeunit.al b/src/Apps/W1/Shopify/Test/Payments/ShpfyAutoPostTransTest.Codeunit.al new file mode 100644 index 0000000000..4688231372 --- /dev/null +++ b/src/Apps/W1/Shopify/Test/Payments/ShpfyAutoPostTransTest.Codeunit.al @@ -0,0 +1,503 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Integration.Shopify.Test; + +using Microsoft.Finance.GeneralLedger.Account; +using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Finance.GeneralLedger.Setup; +using Microsoft.Finance.VAT.Setup; +using Microsoft.Foundation.Enums; +using Microsoft.Foundation.NoSeries; +using Microsoft.Integration.Shopify; +using Microsoft.Inventory.Item; +using Microsoft.Sales.Customer; +using Microsoft.Sales.Document; +using Microsoft.Sales.History; +using Microsoft.Sales.Receivables; +using System.TestLibraries.Utilities; + +/// +/// Codeunit Shpfy Auto Post Transaction Test (ID 139614). +/// +codeunit 139614 "Shpfy Auto Post Trans. Test" +{ + Subtype = Test; + TestPermissions = Disabled; + + var + Customer: Record Customer; + Item: Record Item; + Shop: Record "Shpfy Shop"; + PaymentMethodMapping: Record "Shpfy Payment Method Mapping"; + LibraryAssert: Codeunit "Library Assert"; + LibraryRandom: Codeunit "Library - Random"; + LibrarySales: Codeunit "Library - Sales"; + IsInitialized: Boolean; + + [Test] + procedure UnitTestAutoPostJnlBatchValidateWithBalAccountNo() + var + ShpfyPaymentMethodMapping: Record "Shpfy Payment Method Mapping"; + GenJournalBatch: Record "Gen. Journal Batch"; + begin + // [SCENARIO] Auto-Post Jnl. Batch field validates successfully when journal batch has a balancing account number + + // [GIVEN] A Gen. Journal Batch with a balancing account number + CreateJournalBatch(GenJournalBatch); + ShpfyPaymentMethodMapping."Auto-Post Jnl. Template" := GenJournalBatch."Journal Template Name"; + + // [WHEN] Auto-Post Jnl. Batch is validated + ShpfyPaymentMethodMapping.Validate("Auto-Post Jnl. Batch", GenJournalBatch.Name); + + // [THEN] Validation passes without error + LibraryAssert.AreEqual(GenJournalBatch.Name, ShpfyPaymentMethodMapping."Auto-Post Jnl. Batch", 'Auto-Post Jnl. Batch should be set'); + end; + + [Test] + procedure UnitTestAutoPostJnlBatchValidateWithoutBalAccountNo() + var + ShpfyPaymentMethodMapping: Record "Shpfy Payment Method Mapping"; + GenJournalBatch: Record "Gen. Journal Batch"; + begin + // [SCENARIO] Auto-Post Jnl. Batch field validation fails when journal batch does not have a balancing account number + + // [GIVEN] A Gen. Journal Batch without a balancing account number + CreateJournalBatch(GenJournalBatch); + GenJournalBatch."Bal. Account No." := ''; + GenJournalBatch.Modify(); + ShpfyPaymentMethodMapping."Auto-Post Jnl. Template" := GenJournalBatch."Journal Template Name"; + + // [WHEN] Auto-Post Jnl. Batch is validated + // [THEN] Validation fails with error + asserterror ShpfyPaymentMethodMapping.Validate("Auto-Post Jnl. Batch", GenJournalBatch.Name); + end; + + [Test] + procedure UnitTestAutoPostJnlBatchValidateWithEmptyValue() + var + ShpfyPaymentMethodMapping: Record "Shpfy Payment Method Mapping"; + begin + // [SCENARIO] Auto-Post Jnl. Batch field can be set to empty without validation error + + // [WHEN] Auto-Post Jnl. Batch is set to empty + ShpfyPaymentMethodMapping.Validate("Auto-Post Jnl. Batch", ''); + + // [THEN] Validation passes without error + LibraryAssert.AreEqual('', ShpfyPaymentMethodMapping."Auto-Post Jnl. Batch", 'Auto-Post Jnl. Batch should be empty'); + end; + + [Test] + procedure UnitTestPostSalesOrderWithAutoPostTransaction() + var + SalesHeader: Record "Sales Header"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + OrderId: BigInteger; + TransactionId: BigInteger; + begin + // [SCENARIO] When a sales order with Shopify Order Id is posted and Post Automatically is true, transaction is auto-posted + + // [GIVEN] Initialized test environment + Initialize(); + + // [GIVEN] A Shopify order with transaction + OrderId := LibraryRandom.RandIntInRange(1000000, 1999999); + TransactionId := LibraryRandom.RandIntInRange(1000000, 1999999); + CreateShopifyOrder(OrderId); + CreateOrderTransaction(TransactionId, OrderId, 0, PaymentMethodMapping.Gateway, Enum::"Shpfy Transaction Type"::Sale, Item."Unit Price"); + + // [GIVEN] Payment method mapping with auto-post enabled + EnablePaymentMethodMappingAutoPost(true); + + // [GIVEN] A sales order with Shopify Order Id + CreateSalesOrder(SalesHeader, OrderId); + + // [WHEN] The sales order is posted + LibrarySales.PostSalesDocument(SalesHeader, true, true); + + // [THEN] A Cust. Ledger Entry is created + CustLedgerEntry.SetRange("Shpfy Transaction Id", TransactionId); + LibraryAssert.IsTrue(not CustLedgerEntry.IsEmpty(), 'Cust. Ledger Entry should be created for the auto-posted transaction'); + end; + + [Test] + procedure UnitTestPostSalesOrderWithoutAutoPostTransaction() + var + SalesHeader: Record "Sales Header"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + OrderId: BigInteger; + TransactionId: BigInteger; + begin + // [SCENARIO] When a sales order with Shopify Order Id is posted and Post Automatically is false, transaction is not auto-posted + + // [GIVEN] Initialized test environment + Initialize(); + + // [GIVEN] A Shopify order with transaction + OrderId := LibraryRandom.RandIntInRange(2000000, 2999999); + TransactionId := LibraryRandom.RandIntInRange(2000000, 2999999); + CreateShopifyOrder(OrderId); + CreateOrderTransaction(TransactionId, OrderId, 0, PaymentMethodMapping.Gateway, Enum::"Shpfy Transaction Type"::Sale, Item."Unit Price"); + + // [GIVEN] Payment method mapping with auto-post disabled + EnablePaymentMethodMappingAutoPost(false); + + // [GIVEN] A sales order with Shopify Order Id + CreateSalesOrder(SalesHeader, OrderId); + + // [WHEN] The sales order is posted + LibrarySales.PostSalesDocument(SalesHeader, true, true); + + // [THEN] A Cust. Ledger Entry is not created + CustLedgerEntry.SetRange("Shpfy Transaction Id", TransactionId); + LibraryAssert.IsTrue(CustLedgerEntry.IsEmpty(), 'Cust. Ledger Entry should not be created for the non-auto-posted transaction'); + end; + + [Test] + procedure UnitTestPostSalesOrderWithAutoPostMultipleTransaction() + var + SalesHeader: Record "Sales Header"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + TransactionId1: BigInteger; + TransactionId2: BigInteger; + OrderId: BigInteger; + begin + // [SCENARIO] When a sales order with Shopify Order Id is posted and Post Automatically is true, multiple transactions are auto-posted + + // [GIVEN] Initialized test environment + Initialize(); + + // [GIVEN] A Shopify order with multiple transactions + OrderId := LibraryRandom.RandIntInRange(3000000, 3999999); + CreateShopifyOrder(OrderId); + TransactionId1 := LibraryRandom.RandIntInRange(3000000, 3499999); + TransactionId2 := LibraryRandom.RandIntInRange(3500000, 3999999); + CreateOrderTransaction(TransactionId1, OrderId, 0, PaymentMethodMapping.Gateway, Enum::"Shpfy Transaction Type"::Sale, Item."Unit Price" / 2); + CreateOrderTransaction(TransactionId2, OrderId, 0, PaymentMethodMapping.Gateway, Enum::"Shpfy Transaction Type"::Sale, Item."Unit Price" / 2); + + // [GIVEN] Payment method mapping with auto-post enabled + EnablePaymentMethodMappingAutoPost(true); + + // [GIVEN] A sales order with Shopify Order Id + CreateSalesOrder(SalesHeader, OrderId); + + // [WHEN] The sales order is posted + LibrarySales.PostSalesDocument(SalesHeader, true, true); + + // [THEN] A Cust. Ledger Entry is created + CustLedgerEntry.SetRange("Shpfy Transaction Id", TransactionId1); + LibraryAssert.IsTrue(not CustLedgerEntry.IsEmpty(), 'Cust. Ledger Entry should be created for the auto-posted transaction'); + CustLedgerEntry.SetRange("Shpfy Transaction Id", TransactionId2); + LibraryAssert.IsTrue(not CustLedgerEntry.IsEmpty(), 'Cust. Ledger Entry should be created for the auto-posted transaction'); + end; + + [Test] + procedure UnitTestPostSalesOrderWithMultipleTransaction() + var + SalesHeader: Record "Sales Header"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + TransactionId1: BigInteger; + TransactionId2: BigInteger; + OrderId: BigInteger; + begin + // [SCENARIO] When a sales order with Shopify Order Id is posted and Post Automatically is true, only transactions linked to auto post Payment Method Mapping are auto-posted + + // [GIVEN] Initialized test environment + Initialize(); + + // [GIVEN] A Shopify order + OrderId := LibraryRandom.RandIntInRange(4000000, 4999999); + CreateShopifyOrder(OrderId); + + // [GIVEN] Payment method mapping with auto-post enabled + EnablePaymentMethodMappingAutoPost(true); + + // [GIVEN] Transaction linked to auto post Payment Method Mapping + TransactionId1 := LibraryRandom.RandIntInRange(4000000, 4499999); + CreateOrderTransaction(TransactionId1, OrderId, 0, PaymentMethodMapping.Gateway, Enum::"Shpfy Transaction Type"::Sale, Item."Unit Price" / 2); + + // [GIVEN] Transaction not linked to auto post Payment Method Mapping + TransactionId2 := LibraryRandom.RandIntInRange(4500000, 4999999); + CreateOrderTransaction(TransactionId2, OrderId, 0, 'auto post disabled', Enum::"Shpfy Transaction Type"::Sale, Item."Unit Price" / 2); + + // [GIVEN] A sales order with Shopify Order Id + CreateSalesOrder(SalesHeader, OrderId); + + // [WHEN] The sales order is posted + LibrarySales.PostSalesDocument(SalesHeader, true, true); + + // [THEN] A Cust. Ledger Entry is created + CustLedgerEntry.SetRange("Shpfy Transaction Id", TransactionId1); + LibraryAssert.IsTrue(not CustLedgerEntry.IsEmpty(), 'Cust. Ledger Entry should be created for the auto-posted transaction'); + CustLedgerEntry.SetRange("Shpfy Transaction Id", TransactionId2); + LibraryAssert.IsTrue(CustLedgerEntry.IsEmpty(), 'Cust. Ledger Entry should not be created for the non-auto-posted transaction'); + end; + + [Test] + procedure UnitTestPostCreditMemoWithAutoPostTransaction() + var + SalesHeader: Record "Sales Header"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + TransactionId: BigInteger; + RefundId: BigInteger; + OrderId: BigInteger; + begin + // [SCENARIO] When a credit memo with Shopify Refund Id is posted and Post Automatically is true, refund transaction is auto-posted + + // [GIVEN] Initialized test environment + Initialize(); + + // [GIVEN] A refund with transaction + RefundId := LibraryRandom.RandIntInRange(5000000, 5999999); + OrderId := LibraryRandom.RandIntInRange(5000000, 5999999); + CreateShopifyOrder(OrderId); + CreateRefund(RefundId, OrderId); + TransactionId := LibraryRandom.RandIntInRange(5000000, 5999999); + CreateOrderTransaction(TransactionId, OrderId, RefundId, PaymentMethodMapping.Gateway, Enum::"Shpfy Transaction Type"::Refund, Item."Unit Price"); + + // [GIVEN] Payment method mapping with auto-post enabled + EnablePaymentMethodMappingAutoPost(true); + + // [GIVEN] A sales credit memo with Shopify Refund Id + CreateCreditMemo(SalesHeader, RefundId); + + // [WHEN] The credit memo is posted + LibrarySales.PostSalesDocument(SalesHeader, true, true); + + // [THEN] A Cust. Ledger Entry is created + CustLedgerEntry.SetRange("Shpfy Transaction Id", TransactionId); + LibraryAssert.IsTrue(not CustLedgerEntry.IsEmpty(), 'Cust. Ledger Entry should be created for the auto-posted refund transaction'); + end; + + [Test] + procedure UnitTestPostSalesOrderWithUnsuccessfulTransactionPost() + var + SalesHeader: Record "Sales Header"; + SalesInvoiceHeader: Record "Sales Invoice Header"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + OrderId: BigInteger; + TransactionId: BigInteger; + begin + // [SCENARIO] When a sales order with Shopify Order Id is posted and Post Automatically is true, transaction post is unsuccessful, but sales order posting is completed + + // [GIVEN] Initialized test environment + Initialize(); + + // [GIVEN] A Shopify order with transaction + OrderId := LibraryRandom.RandIntInRange(6000000, 6999999); + TransactionId := LibraryRandom.RandIntInRange(6000000, 6999999); + CreateShopifyOrder(OrderId); + CreateOrderTransaction(TransactionId, OrderId, 0, PaymentMethodMapping.Gateway, Enum::"Shpfy Transaction Type"::Sale, Item."Unit Price"); + + // [GIVEN] Payment method mapping with auto-post enabled + EnablePaymentMethodMappingAutoPost(true); + + // [GIVEN] A sales order with Shopify Order Id + CreateSalesOrder(SalesHeader, OrderId); + + // [GIVEN] Transaction auto post No. Series is closed + OpenNoSeriesLine(false); + + // [WHEN] The sales order is posted + asserterror LibrarySales.PostSalesDocument(SalesHeader, true, true); + + // [THEN] Sales order posting is completed + SalesInvoiceHeader.SetRange("Shpfy Order Id", OrderId); + LibraryAssert.IsTrue(not SalesInvoiceHeader.IsEmpty(), 'Posted sales invoice should exist'); + + // [THEN] A Cust. Ledger Entry is not created + CustLedgerEntry.SetRange("Shpfy Transaction Id", TransactionId); + LibraryAssert.IsTrue(CustLedgerEntry.IsEmpty(), 'Cust. Ledger Entry should not be created for the auto-posted transaction'); + + OpenNoSeriesLine(true); + end; + + local procedure Initialize() + var + LibraryERMCountryData: Codeunit "Library - ERM Country Data"; + CommunicationMgt: Codeunit "Shpfy Communication Mgt."; + begin + if IsInitialized then + exit; + + Codeunit.Run(Codeunit::"Shpfy Initialize Test"); + + LibraryERMCountryData.CreateVATData(); + LibraryERMCountryData.UpdateGeneralPostingSetup(); + CreateItem(); + LibrarySales.CreateCustomer(Customer); + + Shop := CommunicationMgt.GetShopRecord(); + + CreatePaymentMethodMapping(); + + DisablePostWithJobQueue(); + + IsInitialized := true; + end; + + local procedure DisablePostWithJobQueue() + var + GeneralLedgerSetup: Record "General Ledger Setup"; + begin + GeneralLedgerSetup.Get(); + GeneralLedgerSetup."Post with Job Queue" := false; + GeneralLedgerSetup.Modify(); + end; + + local procedure CreateItem() + var + LibraryInventory: Codeunit "Library - Inventory"; + Amount: Decimal; + begin + Amount := LibraryRandom.RandIntInRange(10000, 99999); + LibraryInventory.CreateItem(Item); + Item.Validate("Unit Price", Amount); + Item.Validate("Last Direct Cost", Amount); + Item.Modify(true); + end; + + local procedure CreateShopifyOrder(OrderId: BigInteger) + var + ShpfyOrderHeader: Record "Shpfy Order Header"; + begin + ShpfyOrderHeader.Init(); + ShpfyOrderHeader."Shopify Order Id" := OrderId; + ShpfyOrderHeader.Processed := true; + ShpfyOrderHeader.Insert(); + end; + + local procedure CreateOrderTransaction(TransactionId: BigInteger; OrderId: BigInteger; RefundId: BigInteger; Gateway: Text[30]; TransactionType: Enum "Shpfy Transaction Type"; Amount: Decimal) + var + OrderTransaction: Record "Shpfy Order Transaction"; + begin + OrderTransaction.Init(); + OrderTransaction."Shopify Transaction Id" := TransactionId; + OrderTransaction."Shopify Order Id" := OrderId; + OrderTransaction."Refund Id" := RefundId; + OrderTransaction.Shop := Shop.Code; + OrderTransaction.Gateway := Gateway; + OrderTransaction.Type := TransactionType; + OrderTransaction.Status := OrderTransaction.Status::Success; + OrderTransaction.Amount := Amount; + OrderTransaction.Used := false; + OrderTransaction.Insert(); + end; + + local procedure CreateSalesOrder(var SalesHeader: Record "Sales Header"; OrderId: BigInteger) + var + SalesLine: Record "Sales Line"; + begin + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Invoice, Customer."No."); + SalesHeader."Shpfy Order Id" := OrderId; + SalesHeader.Modify(); + LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", 1); + end; + + local procedure CreateCreditMemo(var SalesHeader: Record "Sales Header"; RefundId: BigInteger) + var + SalesLine: Record "Sales Line"; + begin + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Credit Memo", Customer."No."); + SalesHeader."Shpfy Refund Id" := RefundId; + SalesHeader.Modify(); + LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", 1); + end; + + local procedure CreateRefund(RefundId: BigInteger; OrderId: BigInteger) + var + RefundHeader: Record "Shpfy Refund Header"; + begin + RefundHeader.Init(); + RefundHeader."Refund Id" := RefundId; + RefundHeader."Order Id" := OrderId; + RefundHeader.Insert(); + end; + + local procedure EnablePaymentMethodMappingAutoPost(AutoPost: Boolean) + begin + PaymentMethodMapping."Post Automatically" := AutoPost; + PaymentMethodMapping.Modify(); + end; + + local procedure CreatePaymentMethodMapping() + var + GenJournalBatch: Record "Gen. Journal Batch"; + begin + PaymentMethodMapping.Init(); + PaymentMethodMapping."Shop Code" := Shop.Code; + PaymentMethodMapping.Gateway := CopyStr(LibraryRandom.RandText(30), 1, MaxStrLen(PaymentMethodMapping.Gateway)); + PaymentMethodMapping."Post Automatically" := true; + CreateJournalBatch(GenJournalBatch); + PaymentMethodMapping."Auto-Post Jnl. Template" := GenJournalBatch."Journal Template Name"; + PaymentMethodMapping."Auto-Post Jnl. Batch" := GenJournalBatch.Name; + PaymentMethodMapping.Insert(); + end; + + local procedure CreateJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch") + var + GenJournalTemplate: Record "Gen. Journal Template"; + begin + GenJournalTemplate.Name := CopyStr(LibraryRandom.RandText(10), 1, MaxStrLen(GenJournalTemplate.Name)); + GenJournalTemplate.Type := GenJournalTemplate.Type::"Cash Receipts"; + GenJournalTemplate.Insert(); + + GenJournalBatch."Journal Template Name" := GenJournalTemplate.Name; + GenJournalBatch.Name := CopyStr(LibraryRandom.RandText(10), 1, MaxStrLen(GenJournalBatch.Name)); + GenJournalBatch."Bal. Account Type" := GenJournalBatch."Bal. Account Type"::"G/L Account"; + GenJournalBatch."Bal. Account No." := CreateGLAccount(); + GenJournalBatch."No. Series" := CopyStr(LibraryRandom.RandText(20), 1, MaxStrLen(GenJournalBatch."No. Series")); + CreateNoSeries(GenJournalBatch."No. Series"); + GenJournalBatch.Insert(); + end; + + local procedure CreateGLAccount(): Code[20] + var + GLAccount: Record "G/L Account"; + VATPostingSetup: Record "VAT Posting Setup"; + LibraryERM: Codeunit "Library - ERM"; + ShpfyInitializeTest: Codeunit "Shpfy Initialize Test"; + begin + LibraryERM.CreateVATPostingSetupWithAccounts(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT", LibraryRandom.RandDecInDecimalRange(10, 25, 0)); + GLAccount.Get(LibraryERM.CreateGLAccountWithVATPostingSetup(VATPostingSetup, Enum::"General Posting Type"::Sale)); + GLAccount."Direct Posting" := true; + + ShpfyInitializeTest.CreateVATPostingSetup(Shop."VAT Bus. Posting Group", GLAccount."VAT Prod. Posting Group"); + + GLAccount.Modify(false); + exit(GLAccount."No."); + end; + + local procedure CreateNoSeries(Code: Code[20]) + var + NoSeries: Record "No. Series"; + NoSeriesLine: Record "No. Series Line"; + begin + if not NoSeries.Get(Code) then begin + NoSeries.Code := Code; + NoSeries."Default Nos." := true; + NoSeries.Insert(); + NoSeriesLine."Series Code" := Code; + NoSeriesLine."Starting No." := Format(LibraryRandom.RandIntInRange(10000, 39999)); + NoSeriesLine."Increment-by No." := 1; + NoSeriesLine."Ending No." := Format(LibraryRandom.RandIntInRange(50000, 99999)); + NoSeriesLine.Open := true; + NoSeriesLine.Insert(); + end; + end; + + local procedure OpenNoSeriesLine(Open: Boolean) + var + GenJournalBatch: Record "Gen. Journal Batch"; + NoSeriesLine: Record "No. Series Line"; + begin + GenJournalBatch.Get(PaymentMethodMapping."Auto-Post Jnl. Template", PaymentMethodMapping."Auto-Post Jnl. Batch"); + NoSeriesLine.SetRange("Series Code", GenJournalBatch."No. Series"); + if NoSeriesLine.FindFirst() then begin + NoSeriesLine.Open := Open; + NoSeriesLine.Modify(); + end; + end; +}