eConnect - Handling tax details when the source data does not include any

When doing an eConnect integration, it is common to get data from a web site that includes only the header level taxes.

eConnect requires that we provide taxes on a detail level, so the technique is to back into the line item taxes and tax details. Since we'll be dividing and rounding to do that, there will be rounding errors at the end; we'll make a final 'adjustment' in the tax amounts to deal with the errant pennies.

The problem:

The web site sends you 'MyTaxSchedule' and the header level tax of $xx.xx, the tax rate is 8.5%

We know that MyTaxSchedule is made up of:

  • MyStateDetail (6%)
  • MyCountyDetail (1%)
  • MyCityDetail (.5%)

For each line in the order, we have to figure what the tax should be for each of the three tax details (so, for a two line order, we have six tax detail lines).

Then, at the end, we sum up our work and make a correction to deal with the pennies.

The code below is straight out of production; the data source that was used was an XML file that was serialized into a Class (a very cool technique); the main class is called oGreatPlainsIntegration. The GreatPlainsIntegration class contains a Batch class. That class has a Customer class, the Customer class has the DocumentHeader class; the DocumentHeader class contains the DocumentLines class. I didn't invent that; that's the way the web site sends it.

 

 

    Sub importOrder(ByVal oGreatPlainsIntegration As GreatPlainsIntegration)
        Dim oBatch As Batch = oGreatPlainsIntegration.Batch
        Dim oCustomer As Customer = oBatch.Customer
        Dim oDocumentHeader As DocumentHeader = oCustomer.DocumentHeader
        Dim strLocationCode As String = ""
        Dim decSubtotal As Decimal = 0
        Dim decLineTaxAmount As Decimal
 
        Try
            'get the server and database from the config
            Dim strServer As String = System.Configuration.ConfigurationManager.AppSettings("SQLServer")
            Dim strDocID As String = System.Configuration.ConfigurationManager.AppSettings("DOCID")
            Dim strDatabase As String = oBatch.TargetCatalog
 
            Dim intCurrentLine As Int16 = 0
            Dim intCurrentTaxLine As Int16 = 0
 
            'declare our eConnect classes
            Dim oeConnectType As New Microsoft.Dynamics.GP.eConnect.Serialization.eConnectType
            Dim oSOPTransactionType As New Microsoft.Dynamics.GP.eConnect.Serialization.SOPTransactionType
            'this is a reference to our eConnectHelper class, found here: http://dyndeveloper.com/thread.aspx?Threadid=1117
            Dim oeConnectFunctions As New eConnectFunctions(strServer, strDatabase)
 
            'massage some data
            oDocumentHeader.DocumentDate = Replace(oDocumentHeader.DocumentDate, "Z""")
            Dim strTaxScheduleID As String = oDocumentHeader.TaxScheduleId
 
 
            'get the tax rate by looping through the details and getting the total...
            For Each oDocumentLine As DocumentLine In oDocumentHeader.DocumentLine
                decSubtotal += oDocumentLine.Quantity * oDocumentLine.UnitPrice
            Next
 
            'and doing some math
            Dim decTaxRate As Decimal = oDocumentHeader.TaxAmount / decSubtotal
 
            Dim decSalesTaxTotal As Decimal = 0
 
            'validation
            If strTaxScheduleID.Trim = "" And oDocumentHeader.TaxAmount > 0 Then
                Throw New Exception(String.Format("Document {0} has a tax amount, but no Tax Schedule ID, unable to process", oDocumentHeader.DocumentNumber))
            End If
 
            'create the document details
            'loop through the detail lines
            For Each oDocumentLine As DocumentLine In oDocumentHeader.DocumentLine
                decLineTaxAmount = 0
 
                'this query gets the tax details for the tax schedule. We use the 'zDP' stored proc
                'that is native to Dynamics. You'll have to grant permissions to use it.
                Dim oDTTaxDetails As DataTable = SPs.zDP_TX00102SS_2(strTaxScheduleID).getTable
                For Each oRow As DataRow In oDTTaxDetails.Rows
                    If decTaxRate = 0 Then
                        Exit For
                    End If
 
                    'get the tax amount
                    Dim strTaxDetailID As String = oRow("taxdtlid")
 
                    'again, we're using a 'zDP' native Dynamics stored proc
                    Dim oDTTaxDetail As DataTable = SPs.zDP_TX00201SS_1(strTaxDetailID).getTable
                    If oDTTaxDetail.Rows.Count = 0 Then
                        Throw New Exception("Unable to locate the tax detail lines")
                    End If
 
                    Dim decTaxPercentage As Decimal = oDTTaxDetail.Rows(0)("txdtlpct") / 100
 
                    ' handle sales taxes
                    ' we know the amount of the taxes at the order level, we'll back into the taxes
                    Dim otaSopLineIvcTaxInsert As New Microsoft.Dynamics.GP.eConnect.Serialization.taSopLineIvcTaxInsert_ItemsTaSopLineIvcTaxInsert
                    With otaSopLineIvcTaxInsert
                        .SOPNUMBE = oDocumentHeader.DocumentNumber
                        .SOPTYPE = oDocumentHeader.SopType
                        .LNITMSEQ = oDocumentLine.LineNumber
                        .CUSTNMBR = oCustomer.CustomerNumber
                        .TAXDTLID = strTaxDetailID
 
                        .SALESAMT = oDocumentLine.Quantity * oDocumentLine.UnitPrice
                        .STAXAMNT = Math.Round(decTaxPercentage * .SALESAMT, 2, MidpointRounding.AwayFromZero)
                        decSalesTaxTotal += .STAXAMNT
                        decLineTaxAmount += .STAXAMNT
                    End With
                    ReDim Preserve oSOPTransactionType.taSopLineIvcTaxInsert_Items(intCurrentTaxLine)
                    oSOPTransactionType.taSopLineIvcTaxInsert_Items(intCurrentTaxLine) = otaSopLineIvcTaxInsert
                    intCurrentTaxLine += 1
                Next
 
 
                '
                'handle the lines
                '
                'declare an object for the detail line
                Dim oItemsTaSopLineIvcInsert As New Microsoft.Dynamics.GP.eConnect.Serialization.taSopLineIvcInsert_ItemsTaSopLineIvcInsert
 
                'populate the detail line
                oItemsTaSopLineIvcInsert.SOPNUMBE = oDocumentHeader.DocumentNumber
                oItemsTaSopLineIvcInsert.SOPTYPE = oDocumentHeader.SopType
                oItemsTaSopLineIvcInsert.ITEMNMBR = oDocumentLine.ItemNumber
                oItemsTaSopLineIvcInsert.QUANTITY = oDocumentLine.Quantity
                oItemsTaSopLineIvcInsert.CUSTNMBR = oCustomer.CustomerNumber
                oItemsTaSopLineIvcInsert.DOCDATE = oDocumentHeader.DocumentDate
                oItemsTaSopLineIvcInsert.LOCNCODE = oDocumentLine.Location
                If oDocumentLine.UOFM = "Each" Then
                    oDocumentLine.UOFM = "Ea"
                End If
                oItemsTaSopLineIvcInsert.UOFM = oDocumentLine.UOFM
 
 
                oItemsTaSopLineIvcInsert.UNITPRCE = oDocumentLine.UnitPrice
                oItemsTaSopLineIvcInsert.LNITMSEQ = oDocumentLine.LineNumber
                oItemsTaSopLineIvcInsert.TAXAMNT = decLineTaxAmount
                oItemsTaSopLineIvcInsert.XTNDPRCE = oDocumentLine.Quantity * oDocumentLine.UnitPrice
                strLocationCode = oDocumentLine.Location
 
                ReDim Preserve oSOPTransactionType.taSopLineIvcInsert_Items(intCurrentLine)
                oSOPTransactionType.taSopLineIvcInsert_Items(intCurrentLine) = oItemsTaSopLineIvcInsert
 
                intCurrentLine += 1
            Next
 
            'fix the last line
            If oDocumentHeader.TaxAmount > 0 Then
                oSOPTransactionType.taSopLineIvcTaxInsert_Items(intCurrentTaxLine - 1).STAXAMNT += (oDocumentHeader.TaxAmount - decSalesTaxTotal)
                oSOPTransactionType.taSopLineIvcInsert_Items(intCurrentLine - 1).TAXAMNT += (oDocumentHeader.TaxAmount - decSalesTaxTotal)
                'decLineTaxAmount += (oDocumentHeader.TaxAmount - decSalesTaxTotal)
                'throw an error if the last line is negative
                If oSOPTransactionType.taSopLineIvcTaxInsert_Items(intCurrentTaxLine - 1).STAXAMNT < 0 Then
                    Throw New Exception("Error computing taxes")
                End If
            End If
 
            'taCreateSopPaymentInsertRecord
            Dim otaCreateSopPaymentInsertRecord As New Microsoft.Dynamics.GP.eConnect.Serialization.taCreateSopPaymentInsertRecord_ItemsTaCreateSopPaymentInsertRecord
            With otaCreateSopPaymentInsertRecord
                .SOPNUMBE = oDocumentHeader.DocumentNumber
                .SOPTYPE = oDocumentHeader.SopType
                .CUSTNMBR = oCustomer.CustomerNumber
                .DOCDATE = oDocumentHeader.DocumentDate
                .Action = 1
                .ActionSpecified = True
                .PYMTTYPE = 6
                .DOCAMNT = oDocumentHeader.DocumentPayment.Amount
                .CARDNAME = "VISA"
            End With
            ReDim Preserve oSOPTransactionType.taCreateSopPaymentInsertRecord_Items(0)
            oSOPTransactionType.taCreateSopPaymentInsertRecord_Items(0) = otaCreateSopPaymentInsertRecord
 
            '
            '
            'create the document header
            '
            '
            Dim otaSopHdrIvcInsert As New Microsoft.Dynamics.GP.eConnect.Serialization.taSopHdrIvcInsert
 
            'populate the header
            With otaSopHdrIvcInsert
                .SOPNUMBE = oDocumentHeader.DocumentNumber
                .SOPTYPE = oDocumentHeader.SopType
                .DOCID = strDocID
                .CUSTNMBR = oCustomer.CustomerNumber
                .BACHNUMB = "WEB" & Now.ToString("yyyyMMdd")
                .DOCDATE = oDocumentHeader.DocumentDate
 
                .ReqShipDate = Now.ToShortDateString
                .FREIGHT = oDocumentHeader.FreightAmount
                .MISCAMNT = oDocumentHeader.MiscAmount
                .TRDISAMT = oDocumentHeader.TradeDiscountAmount
                If .TRDISAMT <> 0 Then
                    .TRDISAMTSpecified = 1
                End If
                .TAXAMNT = oDocumentHeader.TaxAmount
                .TAXSCHID = strTaxScheduleID
 
                .ADDRESS1 = oDocumentHeader.ShippingAddress1
                .ADDRESS2 = oDocumentHeader.ShippingAddress2
                .ADDRESS3 = oDocumentHeader.ShippingAddress3
                .CITY = oDocumentHeader.ShippingCity
                .STATE = oDocumentHeader.ShippingState
                .ZIPCODE = oDocumentHeader.ShippingZip
                .COUNTRY = oDocumentHeader.ShippingCountry
                .LOCNCODE = strLocationCode
 
                .SUBTOTAL = decSubtotal
                .DOCAMNT = .FREIGHT + .MISCAMNT + decSubtotal - .TRDISAMT + .TAXAMNT
                .PYMTRCVD = oDocumentHeader.DocumentPayment.Amount
 
            End With
 
            'assign the header to the master
            oSOPTransactionType.taSopHdrIvcInsert = otaSopHdrIvcInsert
 
            'create the document header user def fields
            Dim otaSopUserDefined As New Microsoft.Dynamics.GP.eConnect.Serialization.taSopUserDefined
 
            'populate the header
            With otaSopUserDefined
                .SOPNUMBE = oDocumentHeader.DocumentNumber
                .SOPTYPE = oDocumentHeader.SopType
                .USRDAT01 = oDocumentHeader.UserDate1
                .USRDAT02 = oDocumentHeader.UserDate2
                .USERDEF1 = oDocumentHeader.UserDefined1
                .USERDEF2 = oDocumentHeader.UserDefined2
                .USRDEF03 = oDocumentHeader.UserDefined3
                .USRDEF04 = oDocumentHeader.UserDefined4
                .USRDEF05 = oDocumentHeader.UserDefined5
            End With
 
            'assign the header to the master
            oSOPTransactionType.taSopUserDefined = otaSopUserDefined
 
            ReDim Preserve oeConnectType.SOPTransactionType(0)
            oeConnectType.SOPTransactionType(0) = oSOPTransactionType
            'this is a reference to our eConnectHelper class, found here: http://dyndeveloper.com/thread.aspx?Threadid=1117
            oeConnectFunctions.CreateTransactionEntity(oeConnectType)
 
        Catch ex As Exception
            Throw ex
        End Try
 
    End Sub

RealWorldCode gives developers practical, real‑world solutions with clean, working code — no fluff, no theory, just answers.
Links
Home
Knowledge Areas
Sitemap
Contact
Et cetera
Privacy Policy
Terms and Conditions
Cookie Preferences