web
You’re offline. This is a read only version of the page.
close
Skip to main content
Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Unanswered

extensibility of SalesFormLetter_Invoice

(0) ShareShare
ReportReport
Posted on by 21
Hello, 

I have a requirement to run my code after a sales order is invoiced, I have tried using SalesFormLetter_Invoice.afterOperationBody() this way
    protected void afterOperationBody()
    {
        CustInvoiceJour custInvoiceJour;
        ISTDParameters  parameters = ISTDParameters::find();

        next afterOperationBody();

        Set journalSet = Set::create(formletterOutputContract.parmAllJournalsPacked());
        SetEnumerator se = journalSet.getEnumerator();

        while (se.moveNext())
        {
            custInvoiceJour = se.current();

            if (ISTDParameters::isProduction() && !this.proforma() && custInvoiceJour && !formletterOutputContract.parmUpdateError())
            {
                ISTDProcessInvoice processISTDInvoice = new ISTDProcessInvoice();
                processISTDInvoice.parmCustInvoiceJour(custInvoiceJour);
                processISTDInvoice.run();
            }
        }
    }

in my class i call an API this way
 
/// <summary>
///    Contains the code that does the actual job of the class.
/// </summary>
private void processInvoice()
{
    System.Net.HttpWebRequest request;
    System.Net.WebResponse response;
    System.IO.Stream responseStream, requestStream;
    System.IO.StreamReader streamReader;
    System.Text.Encoding utf8;
    System.Byte[] bytes;
    System.Exception ex;
    Notes requestJson, responseJson, errorMessage;
    System.Net.WebException webException;
    ISTDInvoiceStatus invoiceStatus;
    ISTDGenerateInvoiceXML generateInvoiceXML;
    ISTDGenerateCreditNoteInvoiceXML generateCreditNoteInvoiceXML;
    ISTDLogTable logTable;

    try
    {
        System.Net.WebHeaderCollection httpHeader = new System.Net.WebHeaderCollection();
        new InteropPermission(InteropKind::ClrInterop).assert();

        request = System.Net.WebRequest::Create(parameters.URL);
        utf8 = System.Text.Encoding::get_UTF8();

        //fill log table
        logTable.clear();
        logTable.ProcessedDateTime = DateTimeUtil::utcNow();
        logTable.InvoiceId = custInvoiceJour.InvoiceId;
        logTable.InvoiceDate = custInvoiceJour.InvoiceDate;
        LogTable.custInvoiceJourRecId = custInvoiceJour.RecId;
        LogTable.InvoiceGUID = custInvoiceJour.ISTDGuid;

        if (custInvoiceJour.creditNote())
        {
            generateCreditNoteInvoiceXML = new ISTDGenerateCreditNoteInvoiceXML(custInvoiceJour);
            requestJson = generateCreditNoteInvoiceXML.returnXML();
        }
        else
        {
            generateInvoiceXML = new ISTDGenerateInvoiceXML(custInvoiceJour);
            requestJson = generateInvoiceXML.returnXML();
        }

        //fill request
        logTable.Request = requestJson;

        bytes = utf8.GetBytes(requestJson);
        httpHeader = request.Headers;

        httpHeader.Add('Client-Id', parameters.ClientId);
        httpHeader.Add('Secret-Key', parameters.SecretKey);

        request.set_Method('POST');
        request.set_Headers(httpHeader);
        request.ContentType = 'application/json';
        request.set_ContentLength(bytes.get_Length());
        requestStream = request.GetRequestStream();
        requestStream.Write(bytes, 0, bytes.get_Length());

        response = request.GetResponse();
        responseStream = response.GetResponseStream();
        streamReader = new System.IO.StreamReader(responseStream);
        responseJson = streamReader.ReadToEnd();

        logTable.Response = responseJson;
        logTable.IsProcessed = NoYes::Yes;

        invoiceStatus = ISTDInvoiceStatus::Sent;

        info('Invoice was sent successfully.');
    }
    catch (webException)
    {
        invoiceStatus = ISTDInvoiceStatus::Error;

        if (webException.get_Response() != null)
        {
            System.Net.HttpWebResponse httpWebResponse;
            Notes responseString;

            httpWebResponse = webException.get_Response() as System.Net.HttpWebResponse;
            responseStream = httpWebResponse.GetResponseStream();
            streamReader = new System.IO.StreamReader(responseStream);
            responseString = streamReader.ReadToEnd();

            logTable.Errors = responseString;
            logTable.IsProcessed = NoYes::No;

            streamReader.Close();
            responseStream.Close();
            httpWebResponse.Close();

            warning(strFmt('invoice %1 was not sent. Please check the log form for errors and try again.', custInvoiceJour.InvoiceId));
        }
        else
        {
            logTable.IsProcessed = NoYes::No;
            logTable.Errors = webException.get_Message();
        }

        //
        if (!logTable.Errors)
             logTable.Errors = webException.get_Message() + ' - block 1';
    }
    catch (Exception::Error)
    {
        logTable.IsProcessed = NoYes::No;
        logTable.Errors = con2Str(this.retreiveErrorsAndWarnings());
        invoiceStatus = ISTDInvoiceStatus::Error;
        this.clearInfologErrorAndWarnings();

        //
        if (!logTable.Errors)
             logTable.Errors = AifUtil::getClrErrorMessage() + ' - block 2';
    }
    catch (Exception::CLRError)
    {
        logTable.IsProcessed = NoYes::No;
        logTable.Errors = AifUtil::getClrErrorMessage();
        invoiceStatus = ISTDInvoiceStatus::Error;
    }
    catch
    {
        logTable.IsProcessed = NoYes::No;
        logTable.Errors = 'There was an unhandled error that occured. - ' + AifUtil::getClrErrorMessage();
        invoiceStatus = ISTDInvoiceStatus::Error;
    }
    finally
    {
        if (invoiceStatus == ISTDInvoiceStatus::Sent)
        {
            if (!custInvoiceJour.creditNote())
            {
                logTable.InvoiceAmount = generateInvoiceXML.parmInvoiceAmount();
            }
            else if (custInvoiceJour.creditNote())
            {
                logTable.InvoiceAmount = generateCreditNoteInvoiceXML.parmInvoiceAmount();
            }
        }

        if (invoiceStatus == ISTDInvoiceStatus::Error && !custInvoiceJour.creditNote())
        {
            ISTDLogLine logLine;

            delete_from logLine
                where logLine.custInvoiceJourRecId == custInvoiceJour.RecId;
        }
        
        ttsbegin;
        custInvoiceJour.selectForUpdate(true);
        custInvoiceJour.ISTDInvoiceStatus = invoiceStatus;
        custInvoiceJour.doUpdate();
        ttscommit;

        logTable.insert();
    }
}

and it works perfectly fine, although sometimes the invoice is not generated for some unknown reason since in my log table i can see the next number sequence of a sales invoice but its not actually used in the system so I'm assuming the invoice was not generated due to some errors, even though i made sure to use !formletterOutputContract.parmUpdateError() in my if statement but my class still gets called but the invoice is not generated, I have also tried using SalesInvoiceJournalPost.endUpdate(); but that didn't work since sometimes the API returns an exception and it would stop the sales order from being invoiced.

is there a place i can run my API after a sales order is completely invoiced with no errors so then it would be fine for me to call the API, Thanks a lot!
 
I have the same question (0)
  • Suggested answer
    Sagar121 Profile Picture
    652 on at
    extensibility of SalesFormLetter_Invoice
    Hi,
     
    As mentioned by Sohaib, EndPost is the perfect method to write the code.
     
    If you will go to SalesInvoiceJournalPostBase> end Post method then you can also see business event is also triggered inside this method when sales order is invoiced 
     
  • Sohaib Cheema Profile Picture
    48,219 User Group Leader on at
    extensibility of SalesFormLetter_Invoice
    Use, SalesInvoiceJournalPost[Class].EndPost[Method] if you have sales invoices only
    Use, SalesInvoiceJournalPostProj[Class].EndPost[Method] if you have project invoices
    You also have option to use the base SalesInvoiceJournalPostBase[Class].[EndPost] 

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Andrés Arias – Community Spotlight

We are honored to recognize Andrés Arias as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
CA Neeraj Kumar Profile Picture

CA Neeraj Kumar 895

#2
Sohaib Cheema Profile Picture

Sohaib Cheema 811 User Group Leader

#3
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 787 Super User 2025 Season 2

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans