├── .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 | ![increment](https://i.imgur.com/nGg8btl.gif) 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 | --------------------------------------------------------------------------------