eConnect - Copy a SOP document using reflection

I have the task today of copying a SOP Order. The user supplies the order that needs to be copied, I need to make a complete copy.

I have the standard SOP code documented here but I know that there is going to be a ton of manual typing to get all the 150 or so fields in each of the SOP header and lines eConnect documents populated. So, in order to avoid that hour of work, I spend a day working on .NET Reflection. <smiles>

My initial foray into reflection is here. The code is simpler and easier to understand if all you're looking for is Reflection.

The resulting code is below. Basically, we get a query of the SOP Header and then (using Reflection) loop through the eConnect taSOPHdrIvcInsert object and populate all the fields with the data from the order to be copied.

Then we repeat that with all the lines, and create the order.

 Send comments!

 This is the .NET code, the two stored procedures are below that.

 

Private Sub CopySuborder(strSopnumber As String, intSoptype As Int16)
        Try
            'get an instances of the eConnect classes that we'll need
            Dim oeConnectType As New Microsoft.Dynamics.GP.eConnect.Serialization.eConnectType
            Dim otaSopHdrIvcInsert As New Microsoft.Dynamics.GP.eConnect.Serialization.taSopHdrIvcInsert
            Dim oSOPTransactionType As New Microsoft.Dynamics.GP.eConnect.Serialization.SOPTransactionType
 
            'this class is documented here: http://dyndeveloper.com/thread.aspx?Threadid=1117
            Dim oeConnectFunctions As New eConnectFunctions(App.SQLServer, App.Database)
 
            Dim intCurrentLine As Int32
 
            'get a sopnumber for the new document
            Dim strSopnumberNew As String = oeConnectFunctions.GetNextSOPNumber(Microsoft.Dynamics.GP.eConnect.IncrementDecrement.Increment, "stdord", Microsoft.Dynamics.GP.eConnect.SopType.SOPOrder)
 
            'get a datatable that has data from live dynamics data, we'll get all the fields from a SOP10100 order
            'this stored procedure is documented below
            Dim oDT As DataTable = SPs.FP_taSopHdrIvcInsert(intSoptype, strSopnumber, App.Database).getTable
 
            'this data table will only ever have one row, get a reference to the first row.
            Dim oRow As DataRow = oDT.Rows(0)
 
            'edit the sop number, replace the old one with the new one
            oRow("sopnumbe") = strSopnumberNew
 
            '======================================================================================
            ' header
            '======================================================================================
            'using Reflection, get a 'FieldInfo' object for the taSopHdrIvcInsert.SOPNUMBE field
            'this will loop through the entire taSopHdrIvcInsert object and populate all the fields
            'cool, right?
            For Each oFieldInfo As FieldInfo In otaSopHdrIvcInsert.GetType().GetFields
 
                'using Reflection, populate that field with the data from the data table.
                oFieldInfo.SetValue(otaSopHdrIvcInsert, Convert.ChangeType(oRow(oFieldInfo.Name), oFieldInfo.FieldType))
 
            Next
 
            'assign the header to the master
            oSOPTransactionType.taSopHdrIvcInsert = otaSopHdrIvcInsert
 
            '======================================================================================
            ' lines
            '======================================================================================
            'this stored procedure is documented below, it retrieves all the lines on the order
            Dim oDT2 As DataTable = SPs.FP_taSopLineIvcInsert(intSoptype, strSopnumber, App.Database).getTable
 
            'loop through the lines in the current order.
            For Each oRow In oDT2.Rows
                Dim otaSopLineIvcInsert As New Microsoft.Dynamics.GP.eConnect.Serialization.taSopLineIvcInsert_ItemsTaSopLineIvcInsert
                'edit the sop number, replace the old one with the new one
                oRow("sopnumbe") = strSopnumberNew
 
                'loop through all the fields in the eConnect document
                For Each oFieldInfo As FieldInfo In otaSopLineIvcInsert.GetType().GetFields
                    'using Reflection, populate that field with the data from the data table.
                    Select Case oFieldInfo.Name
                        'eConnect doesn't want us to send these fields.
                        Case "SLSINDX", "MKDNINDX", "RTNSINDX", "INUSINDX", "INSRINDX", "DMGDINDX", "INVINDX", "CSLSINDX"
                            Continue For
                    End Select
                    oFieldInfo.SetValue(otaSopLineIvcInsert, Convert.ChangeType(oRow(oFieldInfo.Name), oFieldInfo.FieldType))
                Next
 
                'assign the line to the eConnect line collection
                ReDim Preserve oSOPTransactionType.taSopLineIvcInsert_Items(intCurrentLine)
                oSOPTransactionType.taSopLineIvcInsert_Items(intCurrentLine) = otaSopLineIvcInsert
                intCurrentLine += 1
            Next
 
            '======================================================================================
            ' send to dynamics
            '======================================================================================
            ReDim Preserve oeConnectType.SOPTransactionType(0)
            oeConnectType.SOPTransactionType(0) = oSOPTransactionType
            'this class is documented here: http://dyndeveloper.com/thread.aspx?Threadid=1117
            oeConnectFunctions.CreateTransactionEntity(oeConnectType)
 
        Catch ex As Exception
            ErrorHandler.globalErrorHandler(ex, True)
        End Try
 
    End Sub

  

IF EXISTS (SELECT name
    FROM   sysobjects
    WHERE  name = N'FP_taSopHdrIvcInsert'
        AND type = 'P')
    DROP PROCEDURE FP_taSopHdrIvcInsert
GO
 
 
CREATE PROCEDURE FP_taSopHdrIvcInsert
--  FP_taSopHdrIvcInsert 2, 'STD00582719'
 
@SOPTYPE smallint,
@SOPNUMBE char(21)
 
AS
 
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
 
Declare @CalculateTaxes as bit
select @CalculateTaxes = 1
 
SELECT SOPTYPE,DOCID,SOPNUMBE,ORIGNUMB,ORIGTYPE,TAXSCHID,FRTSCHID,MSCSCHID,SHIPMTHD,
        --taxes
        case when @CalculateTaxes = 1 then 0 else TAXAMNT end as TAXAMNT,
        @CalculateTaxes as CREATETAXES,
        subtotal as DOCAMNT,
 
        LOCNCODE,DOCDATE,
        h.FRTAMNT as FREIGHT,MISCAMNT,
        TRDISAMT,
        case when TRDISAMT > 0 then 1 else 0 end as TRDISAMTSpecified,
        h.TRDISPCT as TRADEPCT,
        case when TRDISPCT > 0 then 1 else 0 end as TRADEPCTSpecified,
        DISTKNAM,MRKDNAMT,CUSTNMBR,CUSTNAME,CSTPONBR,ShipToName,ADDRESS1,ADDRESS2,
        ADDRESS3,CNTCPRSN,FAXNUMBR,CITY,STATE,ZIPCODE,COUNTRY,PHNUMBR1,PHNUMBR2,
        h.PHONE3 as PHNUMBR3,SUBTOTAL,
        PYMTRCVD,SALSTERR,SLPRSNID,UPSZONE,USER2ENT,BACHNUMB,PRBTADCD,PRSTADCD,FRTTXAMT,MSCTXAMT,ORDRDATE,MSTRNUMB,
        PYMTRMID,DUEDATE,DISCDATE,REFRENCE,
        0 as USINGHEADERLEVELTAXES,
        '' as BatchCHEKBKID,
        0 as CREATECOMM,COMMAMNT,
        0 as COMPRCNT,
        0 as CREATEDIST,
        0 as DEFTAXSCHDS,
        CURNCYID,XCHGRATE,RATETPID,
        '1/1/1900' as EXPNDATE,EXCHDATE,
        '' as EXGTBDSC,
        '' as EXTBLSRC,
        0 as RATEEXPR,DYSTINCR,
        0 as RATEVARC,
        0 as TRXDTDEF,RTCLCMTD,
        0 as PRVDSLMT,
        0 as DATELMTS,TIME1,
        DISAVAMT,
        case when DISAVAMT > 0 then 1 else 0 end as DISAVAMTSpecified,
        DSCDLRAM,
        case when DSCDLRAM > 0 then 1 else 0 end as DSCDLRAMSpecified,
        DSCPCTAM,
        case when DSCPCTAM > 0 then 1 else 0 end as DSCPCTAMSpecified,
        0 as FREIGTBLE,
        0 as MISCTBLE,COMMNTID,
        '' as COMMENT_1,
        '' as COMMENT_2,
        '' as COMMENT_3,
        '' as COMMENT_4,GPSFOINTEGRATIONID,INTEGRATIONSOURCE,INTEGRATIONID,
        ReqShipDate,
        0 as RequesterTrx,
        0 as CKCreditLimit,
        0 as CKHOLD,
        0 as UpdateExisting,
        QUOEXPDA,QUOTEDAT,INVODATE,BACKDATE,RETUDATE,
        '' as CMMTTEXT,PRCLEVEL,
        0 as DEFPRICING,TAXEXMT1,TAXEXMT2,TXRGNNUM,REPTING,TRXFREQU,TIMETREP,
        0 as QUOTEDYSTINCR,
        '' as NOTETEXT,
        '' as USRDEFND1,'' as USRDEFND2,'' as USRDEFND3,'' as USRDEFND4,'' as USRDEFND5
    FROM SOP10100 h
    WHERE
        SOPTYPE = @SOPTYPE
        and SOPNUMBE = @SOPNUMBE
 
GO
grant exec on FP_taSopHdrIvcInsert to public
--sp_sps
 
 
--select REPLACE(PARAMETER_NAME,'@I_v','') + ',' from INFORMATION_SCHEMA.PARAMETERS c where c.SPECIFIC_NAME = 'tasophdrivcinsert'

 

 

IF EXISTS (SELECT name
    FROM   sysobjects
    WHERE  name = N'FP_taSopLineIvcInsert'
        AND type = 'P')
    DROP PROCEDURE FP_taSopLineIvcInsert
GO
 
 
CREATE PROCEDURE FP_taSopLineIvcInsert
--  FP_taSopLineIvcInsert 2, 'STD00582719'
 
@SOPTYPE smallint,
@SOPNUMBE char(21)
 
AS
 
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
 
SELECT
        l.SOPTYPE,l.SOPNUMBE,h.CUSTNMBR,h.DOCDATE,
        h.docdate as USERDATE,l.LOCNCODE,l.ITEMNMBR,
        0 as AutoAssignBin,l.UNITPRCE,l.XTNDPRCE,l.QUANTITY,
        l.MRKDNAMT,
        case when l.MRKDNAMT > 0 then 1 else 0 end as MRKDNAMTSpecified,
        l.MRKDNPCT,
        case when l.MRKDNPCT > 0 then 1 else 0 end as MRKDNPCTSpecified,
        l.COMMNTID,
        '' as COMMENT_1,
        '' as COMMENT_2,
        '' as COMMENT_3,
        '' as COMMENT_4,
        CASE when h.soptype = 4 then l.UNITCOST else 0 end as UNITCOST,
        case when CASE when h.soptype = 4 then l.UNITCOST else 0 end > 0 then 1 else 0 end as UNITCOSTSpecified,
        l.PRCLEVEL,l.ITEMDESC,l.TAXAMNT,l.QTYONHND,l.QTYRTRND,l.QTYINUSE,l.QTYINSVC,l.QTYDMGED,l.NONINVEN,l.LNITMSEQ,l.DROPSHIP,l.QTYTBAOR,h.DOCID,l.SALSTERR,
        l.SLPRSNID,l.ITMTSHID,l.IVITMTXB,l.TAXSCHID,l.PRSTADCD,l.ShipToName,l.CNTCPRSN,l.ADDRESS1,l.ADDRESS2,l.ADDRESS3,l.CITY,l.STATE,l.ZIPCODE,l.COUNTRY,l.PHONE1,l.PHONE2,l.PHONE3,l.FAXNUMBR,
        l.EXCEPTIONALDEMAND,l.ReqShipDate,l.FUFILDAT,l.ACTLSHIP,l.SHIPMTHD,l.INVINDX,l.CSLSINDX,l.SLSINDX,l.MKDNINDX,l.RTNSINDX,l.INUSINDX,l.INSRINDX,l.DMGDINDX,
        0 as AUTOALLOCATESERIAL,
        0 as AUTOALLOCATELOT,
        l.GPSFOINTEGRATIONID,l.INTEGRATIONSOURCE,l.INTEGRATIONID,
        0 as RequesterTrx,l.QTYCANCE,
        l.QTYFULFI,
        case when l.QTYFULFI > 0 then 1 else 0 end as QTYFULFISpecified,
        0 as ALLOCATE,
        0 as UpdateIfExists,
        0 as RecreateDist,
        0 as QUOTEQTYTOINV,
        0 as TOTALQTY,
        '' as CMMTTEXT,
        0 as KitCompMan,
        0 as DEFPRICING,
        0 as DEFEXTPRICE,
        '' as CURNCYID,l.UOFM,
        0 as IncludePromo,
        0 as CKCreditLimit,
        2 as QtyShrtOpt,
        '' as USRDEFND1,
        '' as USRDEFND2,
        '' as USRDEFND3,
        '' as USRDEFND4,
        '' as USRDEFND5
    FROM sop10100 h
        join SOP10200 l on h.SOPNUMBE = l.SOPNUMBE and h.SOPTYPE = l.soptype
    WHERE
        h.SOPTYPE = @SOPTYPE
        and h.SOPNUMBE = @SOPNUMBE
 
GO
grant exec on FP_taSopLineIvcInsert to public
 
 
--select 'l.' + REPLACE(PARAMETER_NAME,'@I_v','') + ',' from INFORMATION_SCHEMA.PARAMETERS c where c.SPECIFIC_NAME = 'taSopLineIvcInsert'

 

 

 

 

 

 

 


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