├── .gitignore
├── .vscode
├── rad.json
└── launch.json
├── .gitattributes
├── EthanSorenson_SC Web Service Posting_1.0.0.3.app
├── Sample.json
├── WSPublishing.xml
├── app.json
├── extensionsPermissionSet.xml
├── README.md
├── Pag50211.SCPostTransactionsBatch.al
├── Tab50210.SCPostTransactions.al
├── Cod50213.SCSalesPostingProcedures.al
└── Cod50214.SCPurchPostingProcedures.al
/.gitignore:
--------------------------------------------------------------------------------
1 | .alpackages/
2 | .vscode/
--------------------------------------------------------------------------------
/.vscode/rad.json:
--------------------------------------------------------------------------------
1 | {"Added":[],"Modified":[],"Removed":[]}
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/EthanSorenson_SC Web Service Posting_1.0.0.3.app:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-sorenson/PostOrdersWebService/HEAD/EthanSorenson_SC Web Service Posting_1.0.0.3.app
--------------------------------------------------------------------------------
/Sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "@odata.type": "#NAV.SCPostTransactionBatch",
3 | "ReplacePostingDate": "True",
4 | "DocumentType": "Sales Invoice",
5 | "DocumentDateTo": "2020-04-06",
6 | "PostingDate": "2020-05-28",
7 | "Ship": "True",
8 | "CalcInvDiscount": "True",
9 | "DocumentDateFrom": "2020-04-01",
10 | "Invoice": "True",
11 | "ReplaceDocumentDate": "False"
12 | }
--------------------------------------------------------------------------------
/WSPublishing.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Page
6 | SCPostTransactionBatch
7 | 50211
8 | true
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "type": "al",
6 | "request": "launch",
7 | "name": "Microsoft cloud sandbox",
8 | "startupObjectId": 21,
9 | "startupObjectType": "Page",
10 | "breakOnError": true,
11 | "launchBrowser": true,
12 | "enableLongRunningSqlStatements": true,
13 | "enableSqlInformationDebugger": true,
14 | "schemaUpdateMode":"Synchronize"
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "691564b8-8fcb-4bc3-8652-b9f5246e8890",
3 | "name": "SC Web Service Posting",
4 | "publisher": "EthanSorenson",
5 | "brief": "",
6 | "description": "Web Service for batch posting Sales and Purchasing Transactions through the Odata web services",
7 | "version": "1.0.0.3",
8 | "privacyStatement": "",
9 | "EULA": "",
10 | "help": "",
11 | "url": "",
12 | "logo": "",
13 | "dependencies": [
14 | {
15 | "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f",
16 | "publisher": "Microsoft",
17 | "name": "System Application",
18 | "version": "17.0.0.0"
19 | },
20 | {
21 | "id": "437dbf0e-84ff-417a-965d-ed2bb9650972",
22 | "publisher": "Microsoft",
23 | "name": "Base Application",
24 | "version": "17.0.0.0"
25 | }
26 | ],
27 | "screenshots": [],
28 | "platform": "17.0.0.0",
29 | "application": "17.0.0.0",
30 | "idRanges": [{
31 | "from": 50200,
32 | "to": 50249
33 | }],
34 | "runtime": "4.1"
35 |
36 | }
--------------------------------------------------------------------------------
/extensionsPermissionSet.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 50210
6 | 0
7 | 1
8 | 1
9 | 1
10 | 1
11 | 0
12 |
13 |
14 |
15 | 50210
16 | 1
17 | 0
18 | 0
19 | 0
20 | 0
21 | 1
22 |
23 |
24 |
25 | 50214
26 | 5
27 | 0
28 | 0
29 | 0
30 | 0
31 | 1
32 |
33 |
34 |
35 | 50213
36 | 5
37 | 0
38 | 0
39 | 0
40 | 0
41 | 1
42 |
43 |
44 |
45 | 50211
46 | 8
47 | 0
48 | 0
49 | 0
50 | 0
51 | 1
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Post Orders Web Service
2 | This extension creates a web service for posting transactions.
3 |
4 | The Extension now supports the following entities:
5 | * Sales Order
6 | * Sales Invoice
7 | * Sales Credit Memo
8 | * Purchase Order
9 | * Purchase Invoice
10 | * Purchase Credit Memo
11 |
12 | The standard Business Central web services support posting transactions with bound services as documented [here](https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-creating-and-interacting-with-odatav4-bound-action). This method does not work with SmartConnect or allow batch posting.
13 |
14 | ### Overview
15 | This Extension recreates the Batch Posting window seen below.
16 | The Codeunits [Cod50213.SCSalesPostingProcedures.al](Cod50213.SCSalesPostingProcedures.al) and [Cod50214.SCPurchPostingProcedures.al](Cod50214.SCPurchPostingProcedures.al) use the standard posting codeunits to post the batches.
17 |
18 | 
19 |
20 | ### Getting Started
21 | 1. If you aren't familar with building AL extensions you can use the Microsoft [documentation](https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-dev-overview "documentation") to get started.
22 | 2. The [Tab50210.SCPostTransactions.al](Tab50210.SCPostTransactions.al) file can be modified as needed to use additional logic.
23 | 3. After publishing the extension you will be able to post batches using a json format similar to [Sample.json](Sample.json)
24 |
25 | ### Troubleshooting
26 | **Web Service isn't available after publishing**
27 | * Make sure the service is published as outlined [here](https://docs.microsoft.com/en-us/dynamics365/business-central/across-how-publish-web-service "documentation").
28 | * Make sure the service is named as expected ex. /ODataV4/Company('Sample')/SCPostTransactionBatch
29 |
30 | **Something else isn't working properly**
31 | * Use github's issue reporter on the right
32 | * Send me an email ethan.sorenson@eonesolutions.com (might take a few days)
33 |
34 | ### Updates
35 | * 1.0.0.1 first release on BC v14
36 | * 1.0.0.2 updated for BC v16, added support for Purchase Transactions
37 | * 1.0.0.3 updated for BC v17, replaced obsolete references
38 |
39 | ***Enjoy!***
--------------------------------------------------------------------------------
/Pag50211.SCPostTransactionsBatch.al:
--------------------------------------------------------------------------------
1 | page 50211 "SC Post Transactions Batch"
2 | {
3 | PageType = API;
4 | Caption = 'SC Post Transactions Batch';
5 | APIPublisher = 'EthanSorenson';
6 | APIGroup = 'sc';
7 | APIVersion = 'v1.0';
8 | EntityName = 'SCPostTransactionsBatch';
9 | EntitySetName = 'SCPostTransactionsBatch';
10 | SourceTable = "SC Post Transactions";
11 | SourceTableTemporary = true;
12 | DelayedInsert = true;
13 | //ODataKeyFields = SystemId;
14 | DeleteAllowed = true;
15 | ModifyAllowed = false;
16 |
17 | layout
18 | {
19 | area(Content)
20 | {
21 | group(Settings)
22 | {
23 | field(Ship; ShipReq)
24 | {
25 | ApplicationArea = All;
26 | Caption = 'Ship';
27 |
28 | }
29 | field(Invoice; InvReq)
30 | {
31 | ApplicationArea = All;
32 | Caption = 'Invoice';
33 |
34 | }
35 | field(PostingDate; PostingDateReq)
36 | {
37 | ApplicationArea = All;
38 | Caption = 'PostingDate';
39 |
40 | }
41 | field(ReplacePostingDate; ReplacePostingDate)
42 | {
43 | ApplicationArea = All;
44 | Caption = 'ReplacePostingDate';
45 |
46 | }
47 | field(ReplaceDocumentDate; ReplaceDocumentDate)
48 | {
49 | ApplicationArea = All;
50 | Caption = 'ReplaceDocumentDate';
51 | }
52 | field("CalcInvDiscount"; CalcInvDisc)
53 | {
54 | ApplicationArea = All;
55 | Caption = 'CalcInvDiscount';
56 |
57 | }
58 | field("DocumentType"; DocumentType)
59 | {
60 | ApplicationArea = All;
61 | Caption = 'DocumentType';
62 | ShowMandatory = true;
63 | }
64 | field("DocumentDateFrom"; DateFromFilter)
65 | {
66 | ApplicationArea = All;
67 | Caption = 'DateFrom';
68 | ShowMandatory = true;
69 | }
70 | field("DocumentDateTo"; DateToFilter)
71 | {
72 | ApplicationArea = All;
73 | Caption = 'DateTo';
74 | ShowMandatory = true;
75 | }
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Tab50210.SCPostTransactions.al:
--------------------------------------------------------------------------------
1 | table 50210 "SC Post Transactions"
2 | {
3 | DataClassification = ToBeClassified;
4 |
5 | fields
6 | {
7 | field(1; ShipReq; Boolean)
8 | {
9 | DataClassification = ToBeClassified;
10 | InitValue = false;
11 | }
12 | field(2; InvReq; Boolean)
13 | {
14 | DataClassification = ToBeClassified;
15 | InitValue = false;
16 | }
17 | field(3; PostingDateReq; Date)
18 | {
19 | DataClassification = ToBeClassified;
20 |
21 |
22 | }
23 | field(4; ReplacePostingDate; Boolean)
24 | {
25 | DataClassification = ToBeClassified;
26 | InitValue = false;
27 | }
28 | field(5; ReplaceDocumentDate; Boolean)
29 | {
30 | DataClassification = ToBeClassified;
31 | InitValue = false;
32 | }
33 | field(6; DateFromFilter; Date)
34 | {
35 | DataClassification = ToBeClassified;
36 |
37 |
38 | }
39 | field(7; DateToFilter; Date)
40 | {
41 | DataClassification = ToBeClassified;
42 |
43 |
44 | }
45 | field(8; CalcInvDisc; Boolean)
46 | {
47 | DataClassification = ToBeClassified;
48 | //InitValue = false;
49 | }
50 | field(9; DocumentType; Option)
51 | {
52 | DataClassification = ToBeClassified;
53 | OptionMembers = "Sales Order","Sales Invoice","Sales Credit Memo","Purchase Order","Purchase Invoice","Purchase Credit Memo";
54 | }
55 |
56 | field(8000; ID; Guid)
57 | {
58 | DataClassification = ToBeClassified;
59 |
60 |
61 | }
62 | }
63 |
64 | keys
65 | {
66 | key(ID; ID)
67 | {
68 | Clustered = true;
69 | }
70 | }
71 |
72 | trigger OnInsert()
73 | begin
74 | ID := CreateGuid();
75 | post();
76 | end;
77 |
78 | local procedure post()
79 | var
80 | SalesPostingProcedure: Codeunit "SC Sales Posting Procedures";
81 | PurchPostingProcedure: Codeunit "SC Purch Posting Procedures";
82 | SalesHeader: Record "Sales Header";
83 | PurchHeader: Record "Purchase Header";
84 | begin
85 | case DocumentType of
86 | 0:
87 | begin
88 | SalesHeader.SETRANGE("Document Type", SalesHeader."Document Type"::Order);
89 | SalesHeader.SETRANGE("Document Date", DateFromFilter, DateToFilter);
90 | SalesPostingProcedure.RunBatch(SalesHeader, ReplacePostingDate, PostingDateReq, ReplaceDocumentDate, CalcInvDisc, ShipReq, InvReq);
91 | end;
92 | 1:
93 | begin
94 | SalesHeader.SETRANGE("Document Type", SalesHeader."Document Type"::Invoice);
95 | SalesHeader.SETRANGE("Document Date", DateFromFilter, DateToFilter);
96 | SalesPostingProcedure.RunBatch(SalesHeader, ReplacePostingDate, PostingDateReq, ReplaceDocumentDate, CalcInvDisc, ShipReq, InvReq);
97 | end;
98 | 2:
99 | begin
100 | SalesHeader.SETRANGE("Document Type", SalesHeader."Document Type"::"Credit Memo");
101 | SalesHeader.SETRANGE("Document Date", DateFromFilter, DateToFilter);
102 | SalesPostingProcedure.RunBatch(SalesHeader, ReplacePostingDate, PostingDateReq, ReplaceDocumentDate, CalcInvDisc, ShipReq, InvReq);
103 | end;
104 | 3:
105 | begin
106 | PurchHeader.SETRANGE("Document Type", PurchHeader."Document Type"::Order);
107 | PurchHeader.SETRANGE("Document Date", DateFromFilter, DateToFilter);
108 | PurchPostingProcedure.RunBatch(PurchHeader, ReplacePostingDate, PostingDateReq, ReplaceDocumentDate, CalcInvDisc, ShipReq, InvReq);
109 | end;
110 | 4:
111 | begin
112 | PurchHeader.SETRANGE("Document Type", PurchHeader."Document Type"::Invoice);
113 | PurchHeader.SETRANGE("Document Date", DateFromFilter, DateToFilter);
114 | PurchPostingProcedure.RunBatch(PurchHeader, ReplacePostingDate, PostingDateReq, ReplaceDocumentDate, CalcInvDisc, ShipReq, InvReq);
115 | end;
116 | 5:
117 | begin
118 | PurchHeader.SETRANGE("Document Type", PurchHeader."Document Type"::"Credit Memo");
119 | PurchHeader.SETRANGE("Document Date", DateFromFilter, DateToFilter);
120 | PurchPostingProcedure.RunBatch(PurchHeader, ReplacePostingDate, PostingDateReq, ReplaceDocumentDate, CalcInvDisc, ShipReq, InvReq);
121 | end;
122 | end;
123 | end;
124 | }
--------------------------------------------------------------------------------
/Cod50213.SCSalesPostingProcedures.al:
--------------------------------------------------------------------------------
1 | codeunit 50213 "SC Sales Posting Procedures"
2 | {
3 | EventSubscriberInstance = Manual;
4 | Permissions = TableData "Batch Processing Parameter" = rimd,
5 | TableData "Batch Processing Session Map" = rimd;
6 | TableNo = "Sales Header";
7 |
8 | trigger OnRun()
9 | var
10 | SalesHeader: Record "Sales Header";
11 | SalesBatchPostMgt: Codeunit "Sales Batch Post Mgt.";
12 | begin
13 | SalesHeader.Copy(Rec);
14 |
15 | BindSubscription(SalesBatchPostMgt);
16 | SalesBatchPostMgt.SetPostingCodeunitId(PostingCodeunitId);
17 | SalesBatchPostMgt.SetBatchProcessor(BatchProcessingMgt);
18 | SalesBatchPostMgt.Code(SalesHeader);
19 |
20 | Rec := SalesHeader;
21 | end;
22 |
23 | var
24 | BatchProcessingMgt: Codeunit "Batch Processing Mgt.";
25 | PostingCodeunitId: Integer;
26 | PostingDateIsNotSetErr: Label 'Enter the posting date.';
27 | BatchPostingMsg: Label 'Bacth posting of sales documents.';
28 |
29 | procedure RunBatch(var SalesHeader: Record "Sales Header"; ReplacePostingDate: Boolean; PostingDate: Date; ReplaceDocumentDate: Boolean; CalcInvoiceDiscount: Boolean; Ship: Boolean; Invoice: Boolean)
30 | var
31 | TempErrorMessage: Record "Error Message" temporary;
32 | BatchPostParameterTypes: Enum "Batch Posting Parameter Type";
33 | SalesBatchPostMgt: Codeunit "Sales Batch Post Mgt.";
34 | ErrorMessages: Page "Error Messages";
35 | ErrorText: Text;
36 | MyRecordRef: RecordRef;
37 | ErrorRec: FieldRef;
38 | ErrorDesc: FieldRef;
39 | ErrorMessageMgt: Codeunit "Error Message Management";
40 | ErrorMessageHandler: Codeunit "Error Message Handler";
41 | ErrorContextElement: Codeunit "Error Context Element";
42 | begin
43 | ErrorMessageMgt.Activate(ErrorMessageHandler);
44 | if ReplacePostingDate and (PostingDate = 0D) then
45 | Error(PostingDateIsNotSetErr);
46 |
47 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::Invoice, Invoice);
48 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::Ship, Ship);
49 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::"Calculate Invoice Discount", CalcInvoiceDiscount);
50 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::"Posting Date", PostingDate);
51 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::"Replace Posting Date", ReplacePostingDate);
52 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::"Replace Document Date", ReplaceDocumentDate);
53 |
54 | ErrorMessageMgt.PushContext(ErrorContextElement, DATABASE::"Sales Header", 0, BatchPostingMsg);
55 |
56 | SalesBatchPostMgt.SetBatchProcessor(BatchProcessingMgt);
57 | Commit();
58 | if SalesBatchPostMgt.Run(SalesHeader) then;
59 | BatchProcessingMgt.ResetBatchID;
60 |
61 |
62 | //Error Handling
63 | if ErrorMessageMgt.GetLastErrorID > 0 then begin
64 | ErrorMessageMgt.GetErrors(TempErrorMessage);
65 | MyRecordRef.GetTable(TempErrorMessage);
66 | ErrorDesc := MyRecordRef.FIELD(5);
67 | ErrorRec := MyRecordRef.FIELD(10);
68 | if MyRecordRef.FINDSET(FALSE, FALSE) then begin
69 | repeat
70 | ErrorText := ErrorText + Format(ErrorRec.VALUE) + ': ' + Format(ErrorDesc.VALUE) + '\\';
71 | until MyRecordRef.NEXT = 0;
72 | end;
73 | ErrorText := 'Error Count: ' + Format(MyRecordRef.Count) + '\\Error Messages: ' + ErrorText;
74 |
75 | error(ErrorText);
76 | end;
77 | end;
78 |
79 | procedure GetBatchProcessor(var ResultBatchProcessingMgt: Codeunit "Batch Processing Mgt.")
80 | begin
81 | ResultBatchProcessingMgt := BatchProcessingMgt;
82 | end;
83 |
84 | procedure SetBatchProcessor(NewBatchProcessingMgt: Codeunit "Batch Processing Mgt.")
85 | begin
86 | BatchProcessingMgt := NewBatchProcessingMgt;
87 | end;
88 |
89 | procedure "Code"(var SalesHeader: Record "Sales Header")
90 | var
91 | RecRef: RecordRef;
92 | begin
93 | if PostingCodeunitId = 0 then
94 | PostingCodeunitId := CODEUNIT::"Sales-Post";
95 |
96 | RecRef.GetTable(SalesHeader);
97 |
98 | BatchProcessingMgt.SetProcessingCodeunit(PostingCodeunitId);
99 | BatchProcessingMgt.BatchProcess(RecRef);
100 |
101 | RecRef.SetTable(SalesHeader);
102 | end;
103 |
104 | local procedure PrepareSalesHeader(var SalesHeader: Record "Sales Header"; var BatchConfirm: Option)
105 | var
106 | BatchPostParameterTypes: Enum "Batch Posting Parameter Type";
107 | CalcInvoiceDiscont: Boolean;
108 | ReplacePostingDate: Boolean;
109 | PostingDate: Date;
110 | begin
111 | BatchProcessingMgt.GetBooleanParameter(SalesHeader.RecordId, BatchPostParameterTypes::"Calculate Invoice Discount", CalcInvoiceDiscont);
112 | BatchProcessingMgt.GetBooleanParameter(SalesHeader.RecordId, BatchPostParameterTypes::"Replace Posting Date", ReplacePostingDate);
113 | BatchProcessingMgt.GetDateParameter(SalesHeader.RecordId, BatchPostParameterTypes::"Posting Date", PostingDate);
114 |
115 | if CalcInvoiceDiscont then
116 | CalculateInvoiceDiscount(SalesHeader);
117 |
118 | SalesHeader.BatchConfirmUpdateDeferralDate(BatchConfirm, ReplacePostingDate, PostingDate);
119 |
120 | BatchProcessingMgt.GetBooleanParameter(SalesHeader.RecordId, BatchPostParameterTypes::Ship, SalesHeader.Ship);
121 | BatchProcessingMgt.GetBooleanParameter(SalesHeader.RecordId, BatchPostParameterTypes::Invoice, SalesHeader.Invoice);
122 | BatchProcessingMgt.GetBooleanParameter(SalesHeader.RecordId, BatchPostParameterTypes::Receive, SalesHeader.Receive);
123 | BatchProcessingMgt.GetBooleanParameter(SalesHeader.RecordId, BatchPostParameterTypes::Print, SalesHeader."Print Posted Documents");
124 |
125 | OnAfterPrepareSalesHeader(SalesHeader);
126 | end;
127 |
128 | procedure SetPostingCodeunitId(NewPostingCodeunitId: Integer)
129 | begin
130 | PostingCodeunitId := NewPostingCodeunitId;
131 | end;
132 |
133 | local procedure CalculateInvoiceDiscount(var SalesHeader: Record "Sales Header")
134 | var
135 | SalesLine: Record "Sales Line";
136 | begin
137 | SalesLine.Reset();
138 | SalesLine.SetRange("Document Type", SalesHeader."Document Type");
139 | SalesLine.SetRange("Document No.", SalesHeader."No.");
140 | if SalesLine.FindFirst then begin
141 | CODEUNIT.Run(CODEUNIT::"Sales-Calc. Discount", SalesLine);
142 | Commit();
143 | SalesHeader.Get(SalesHeader."Document Type", SalesHeader."No.");
144 | end;
145 | end;
146 |
147 | local procedure CanPostDocument(var SalesHeader: Record "Sales Header"): Boolean
148 | var
149 | ApprovalsMgmt: Codeunit "Approvals Mgmt.";
150 | begin
151 | if ApprovalsMgmt.IsSalesApprovalsWorkflowEnabled(SalesHeader) then
152 | exit(false);
153 |
154 | if SalesHeader.Status = SalesHeader.Status::"Pending Approval" then
155 | exit(false);
156 |
157 | if not SalesHeader.IsApprovedForPostingBatch then
158 | exit(false);
159 |
160 | exit(true);
161 | end;
162 |
163 | [EventSubscriber(ObjectType::Codeunit, 1380, 'OnBeforeBatchProcessing', '', false, false)]
164 | local procedure PrepareSalesHeaderOnBeforeBatchProcessing(var RecRef: RecordRef; var BatchConfirm: Option)
165 | var
166 | SalesHeader: Record "Sales Header";
167 | begin
168 | RecRef.SetTable(SalesHeader);
169 | PrepareSalesHeader(SalesHeader, BatchConfirm);
170 | RecRef.GetTable(SalesHeader);
171 | end;
172 |
173 | [EventSubscriber(ObjectType::Codeunit, 1380, 'OnVerifyRecord', '', false, false)]
174 | local procedure CheckSalesHeaderOnVerifyRecord(var RecRef: RecordRef; var Result: Boolean)
175 | var
176 | SalesHeader: Record "Sales Header";
177 | begin
178 | RecRef.SetTable(SalesHeader);
179 | Result := CanPostDocument(SalesHeader);
180 | RecRef.GetTable(SalesHeader);
181 | end;
182 |
183 | [IntegrationEvent(false, false)]
184 | local procedure OnAfterPrepareSalesHeader(var SalesHeader: Record "Sales Header")
185 | begin
186 | end;
187 | }
188 |
--------------------------------------------------------------------------------
/Cod50214.SCPurchPostingProcedures.al:
--------------------------------------------------------------------------------
1 | codeunit 50214 "SC Purch Posting Procedures"
2 | {
3 | EventSubscriberInstance = Manual;
4 | Permissions = TableData "Batch Processing Parameter" = rimd,
5 | TableData "Batch Processing Session Map" = rimd;
6 | TableNo = "Purchase Header";
7 |
8 | trigger OnRun()
9 | var
10 | PurchaseHeader: Record "Purchase Header";
11 | PurchaseBatchPostMgt: Codeunit "Purchase Batch Post Mgt.";
12 | begin
13 | PurchaseHeader.Copy(Rec);
14 |
15 | BindSubscription(PurchaseBatchPostMgt);
16 | PurchaseBatchPostMgt.SetPostingCodeunitId(PostingCodeunitId);
17 | PurchaseBatchPostMgt.SetBatchProcessor(BatchProcessingMgt);
18 | PurchaseBatchPostMgt.Code(PurchaseHeader);
19 |
20 | Rec := PurchaseHeader;
21 | end;
22 |
23 | var
24 | BatchProcessingMgt: Codeunit "Batch Processing Mgt.";
25 | PostingCodeunitId: Integer;
26 | PostingDateIsNotSetErr: Label 'Enter the posting date.';
27 | BatchPostingMsg: Label 'Bacth posting of purchase documents.';
28 |
29 | procedure RunBatch(var PurchaseHeader: Record "Purchase Header"; ReplacePostingDate: Boolean; PostingDate: Date; ReplaceDocumentDate: Boolean; CalcInvoiceDiscount: Boolean; Receive: Boolean; Invoice: Boolean)
30 | var
31 | TempErrorMessage: Record "Error Message" temporary;
32 | BatchPostParameterTypes: Enum "Batch Posting Parameter Type";
33 | PurchaseBatchPostMgt: Codeunit "Purchase Batch Post Mgt.";
34 | ErrorMessages: Page "Error Messages";
35 | ErrorText: Text;
36 | MyRecordRef: RecordRef;
37 | ErrorRec: FieldRef;
38 | ErrorDesc: FieldRef;
39 | ErrorMessageMgt: Codeunit "Error Message Management";
40 | ErrorMessageHandler: Codeunit "Error Message Handler";
41 | ErrorContextElement: Codeunit "Error Context Element";
42 | begin
43 | ErrorMessageMgt.Activate(ErrorMessageHandler);
44 | if ReplacePostingDate and (PostingDate = 0D) then
45 | Error(PostingDateIsNotSetErr);
46 |
47 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::Invoice, Invoice);
48 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::Receive, Receive);
49 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::"Calculate Invoice Discount", CalcInvoiceDiscount);
50 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::"Posting Date", PostingDate);
51 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::"Replace Posting Date", ReplacePostingDate);
52 | BatchProcessingMgt.SetParameter(BatchPostParameterTypes::"Replace Document Date", ReplaceDocumentDate);
53 |
54 | ErrorMessageMgt.PushContext(ErrorContextElement, DATABASE::"Purchase Header", 0, BatchPostingMsg);
55 | PurchaseBatchPostMgt.SetBatchProcessor(BatchProcessingMgt);
56 | Commit();
57 | if PurchaseBatchPostMgt.Run(PurchaseHeader) then;
58 | BatchProcessingMgt.ResetBatchID;
59 |
60 |
61 | //Error Handling
62 | if ErrorMessageMgt.GetLastErrorID > 0 then begin
63 | ErrorMessageMgt.GetErrors(TempErrorMessage);
64 | MyRecordRef.GetTable(TempErrorMessage);
65 | ErrorDesc := MyRecordRef.FIELD(5);
66 | ErrorRec := MyRecordRef.FIELD(10);
67 | if MyRecordRef.FINDSET(FALSE, FALSE) then begin
68 | repeat
69 | ErrorText := ErrorText + Format(ErrorRec.VALUE) + ': ' + Format(ErrorDesc.VALUE) + '\\';
70 | until MyRecordRef.NEXT = 0;
71 | end;
72 | ErrorText := 'Error Count: ' + Format(MyRecordRef.Count) + '\\Error Messages: ' + ErrorText;
73 |
74 | error(ErrorText);
75 | end;
76 | end;
77 |
78 | procedure GetBatchProcessor(var ResultBatchProcessingMgt: Codeunit "Batch Processing Mgt.")
79 | begin
80 | ResultBatchProcessingMgt := BatchProcessingMgt;
81 | end;
82 |
83 | procedure SetBatchProcessor(NewBatchProcessingMgt: Codeunit "Batch Processing Mgt.")
84 | begin
85 | BatchProcessingMgt := NewBatchProcessingMgt;
86 | end;
87 |
88 | procedure "Code"(var PurchaseHeader: Record "Purchase Header")
89 | var
90 | RecRef: RecordRef;
91 | begin
92 | if PostingCodeunitId = 0 then
93 | PostingCodeunitId := CODEUNIT::"Purch.-Post";
94 |
95 | RecRef.GetTable(PurchaseHeader);
96 |
97 | BatchProcessingMgt.SetProcessingCodeunit(PostingCodeunitId);
98 | BatchProcessingMgt.BatchProcess(RecRef);
99 |
100 | RecRef.SetTable(PurchaseHeader);
101 | end;
102 |
103 | local procedure PreparePurchaseHeader(var PurchaseHeader: Record "Purchase Header"; var BatchConfirm: Option)
104 | var
105 | BatchPostParameterTypes: Enum "Batch Posting Parameter Type";
106 | CalcInvoiceDiscont: Boolean;
107 | ReplacePostingDate: Boolean;
108 | PostingDate: Date;
109 | begin
110 | BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, BatchPostParameterTypes::"Calculate Invoice Discount", CalcInvoiceDiscont);
111 | BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, BatchPostParameterTypes::"Replace Posting Date", ReplacePostingDate);
112 | BatchProcessingMgt.GetDateParameter(PurchaseHeader.RecordId, BatchPostParameterTypes::"Posting Date", PostingDate);
113 |
114 | if CalcInvoiceDiscont then
115 | CalculateInvoiceDiscount(PurchaseHeader);
116 |
117 | PurchaseHeader.BatchConfirmUpdateDeferralDate(BatchConfirm, ReplacePostingDate, PostingDate);
118 |
119 | BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, BatchPostParameterTypes::Receive, PurchaseHeader.Receive);
120 | BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, BatchPostParameterTypes::Invoice, PurchaseHeader.Invoice);
121 | BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, BatchPostParameterTypes::Ship, PurchaseHeader.Ship);
122 | BatchProcessingMgt.GetBooleanParameter(
123 | PurchaseHeader.RecordId, BatchPostParameterTypes::Print, PurchaseHeader."Print Posted Documents");
124 |
125 | OnAfterPreparePurchaseHeader(PurchaseHeader);
126 | end;
127 |
128 | procedure SetPostingCodeunitId(NewPostingCodeunitId: Integer)
129 | begin
130 | PostingCodeunitId := NewPostingCodeunitId;
131 | end;
132 |
133 | local procedure CalculateInvoiceDiscount(var PurchaseHeader: Record "Purchase Header")
134 | var
135 | PurchaseLine: Record "Purchase Line";
136 | begin
137 | PurchaseLine.Reset();
138 | PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
139 | PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
140 | if PurchaseLine.FindFirst then begin
141 | CODEUNIT.Run(CODEUNIT::"Purch.-Calc.Discount", PurchaseLine);
142 | Commit();
143 | PurchaseHeader.Get(PurchaseHeader."Document Type", PurchaseHeader."No.");
144 | end;
145 | end;
146 |
147 | local procedure CanPostDocument(var PurchaseHeader: Record "Purchase Header"): Boolean
148 | var
149 | ApprovalsMgmt: Codeunit "Approvals Mgmt.";
150 | begin
151 | if ApprovalsMgmt.IsPurchaseApprovalsWorkflowEnabled(PurchaseHeader) then
152 | exit(false);
153 |
154 | if PurchaseHeader.Status = PurchaseHeader.Status::"Pending Approval" then
155 | exit(false);
156 |
157 | if not PurchaseHeader.IsApprovedForPostingBatch then
158 | exit(false);
159 |
160 | exit(true);
161 | end;
162 |
163 |
164 | [EventSubscriber(ObjectType::Codeunit, 1380, 'OnBeforeBatchProcessing', '', false, false)]
165 | local procedure PreparePurchaseHeaderOnBeforeBatchProcessing(var RecRef: RecordRef; var BatchConfirm: Option)
166 | var
167 | PurchaseHeader: Record "Purchase Header";
168 | begin
169 | RecRef.SetTable(PurchaseHeader);
170 | PreparePurchaseHeader(PurchaseHeader, BatchConfirm);
171 | RecRef.GetTable(PurchaseHeader);
172 | end;
173 |
174 | [EventSubscriber(ObjectType::Codeunit, 1380, 'OnVerifyRecord', '', false, false)]
175 | local procedure CheckPurchaseHeaderOnVerifyRecord(var RecRef: RecordRef; var Result: Boolean)
176 | var
177 | PurchaseHeader: Record "Purchase Header";
178 | begin
179 | RecRef.SetTable(PurchaseHeader);
180 | Result := CanPostDocument(PurchaseHeader);
181 | RecRef.GetTable(PurchaseHeader);
182 | end;
183 |
184 | [EventSubscriber(ObjectType::Codeunit, 1380, 'OnCustomProcessing', '', false, false)]
185 | local procedure HandleOnCustomProcessing(var RecRef: RecordRef; var Handled: Boolean; var KeepParameters: Boolean)
186 | var
187 | PurchaseHeader: Record "Purchase Header";
188 | PurchasesPayablesSetup: Record "Purchases & Payables Setup";
189 | PurchasePostViaJobQueue: Codeunit "Purchase Post via Job Queue";
190 | begin
191 | RecRef.SetTable(PurchaseHeader);
192 |
193 | PurchasesPayablesSetup.Get();
194 | if PurchasesPayablesSetup."Post with Job Queue" then begin
195 | PurchaseHeader."Print Posted Documents" :=
196 | PurchaseHeader."Print Posted Documents" and PurchasesPayablesSetup."Post & Print with Job Queue";
197 | PurchasePostViaJobQueue.EnqueuePurchDocWithUI(PurchaseHeader, false);
198 | if not IsNullGuid(PurchaseHeader."Job Queue Entry ID") then begin
199 | Commit();
200 | KeepParameters := true;
201 | end;
202 | PurchaseHeader."Print Posted Documents" := false;
203 | RecRef.GetTable(PurchaseHeader);
204 | Handled := true;
205 | end;
206 | end;
207 |
208 | [IntegrationEvent(false, false)]
209 | local procedure OnAfterPreparePurchaseHeader(var PurchaseHeader: Record "Purchase Header")
210 | begin
211 | end;
212 | }
213 |
--------------------------------------------------------------------------------