Skip to main content
March 17, 2011
Question

Customer received wrong transaction number

  • March 17, 2011
  • 4 replies
  • 2664 views

Hi all,

I encountered a strange problem with our shopping cart today.  We had two transactions that occured around the same time.  Let's say, customer A was assigned transaction number 100 and customer B transaction number 101.  Both transactions were saved into the database correctly.  However, customer B received an email confirmation stating that his transaction number is 100.  The details of his transaction in the email are correct, only the transaction number is mixed up.

Here's roughly the code:

// get transaction number

transNum = salesCFC.createTransactionNumber()

// save shopping cart into db

salesCFC.saveTransaction( transNum, session.shoppingBagObj)

// email customer
<cfmail from="" to="" subject="Transaction Number #transNum#">

     // shopping bag printout

</cfmail>

transNum is a local-scoped variable.

I have been scratching my head to understand how this happened.  We only discovered this issue because customer B wanted to cancel his transaction and he gave the transaction number belonging to customer A.  We checked our sent mail folder and sure enough both customers received confirmation emails with the same transaction number.

Is it possible that customer B's transNum variable got corrupted and crossed with customer A's transNum?

    This topic has been closed for replies.

    4 replies

    Inspiring
    March 17, 2011

    Here's roughly the code:

    Can you post the actual code.  Including the code for createTransactionNumber().  Snip out anything that's not relevant (so code that does not use or influence the transaction number in any way... and excise any mark-up ;-), but include any branching and looping logic, and the relationship between any different files involved, incuding how each is called from other files.

    It sounds like the transaction number is correct when you call saveTransaction(), but it gets overwritten between there and the CFMAIL call.  To state what is probably obvious.

    Perhaps at some point you are inadvertantly putting the transaction number in some shared-scope variable which is being accessed by reference rather than value, eg one can have two requests doing this:

    variables.myStruct = application.myStruct;

    Which might look like variables.myStruct is local, but all it is is a reference to the shared scope variable.  So if one then does this:

    variables.myStruct.someVariable = "some request-specific value";

    Then all requests accessing variables.myStruct.someVariable will be accessing the same variable (the one in the application scope), and that variable will have a request-specific value.  Bad.  This will be the case for any complex objects in CF, except for arrays.  I only mention this because we've quite often been caught out by this.

    --

    Adam

    March 17, 2011

    Hi,

    Thank you all for your comments.  Below is the code on createTransactionNumber.  Basically, the function queries the database for the most recent transaction number, and return the next number.  The whole function is enclosed within <cftransaction> to ensure that both queries are run together.

        <cffunction name="createTransactionNumber" returntype="numeric">
           
            <cfquery name="getCurrentTransactionNum">
                select CurrentValue
                from Setting
                where VariableName = 'TransactionNum';
            </cfquery>
            <cfquery name="updateNextTransactionNumber">
                update Setting
                set CurrentValue = CurrentValue + 1
                where VariableName = 'TransactionNum';
            </cfquery>


            <cfreturn getCurrentTransactionNum.currentValue + 1 />


        </cffunction>

    I am going through the codes carefully to see if that there is any problem with variables scoping and the variable referencing as suggested by Chiwi8888 and  Adam.  I'll report back if I find anything.

    Thanks again.

    Owainnorth
    Inspiring
    March 17, 2011

    From the look of that, there's no need for you to go and get the ID upfront. Can you not just scrap the first function, run the inserts in a transaction and select back the @@IDENTITY or whatever it's called in SQL Server? You can then just pass that to your email function.

    I'm pretty sure all database engines have sequencing capability, no point reinventing the wheel.

    March 17, 2011

    I would also look into possible variable scoping issues.  Do you use something like http://varscoper.riaforge.org/ to check all your code?

    If there was one thing I don't like about CF, it would be the fact that variables are not local to functions by default.  I can't think of any other language I have used that does this.

    You say that transNum is a locally scoped variable, but you don't illustrate that in your example code.  For example in CF9 prefixing all local varaibles with "local.", when accessing and assigning.  How are you doing this currently?

    Cheers

    March 17, 2011

    Dave's comment reminded me that I do enclose both createTransactionNumber() and saveTransaction() functions inside <cftransaction>.

    So the code is (sorry I mixed in cfscript formats for readability)

    // get transaction number

    <cftransaction>

    transNum =  salesCFC.createTransactionNumber()

    </cftransaction>

    // save shopping cart  into db

    <cftransaction>

    salesCFC.saveTransaction( transNum,  session.shoppingBagObj)

    </cftransaction>

    // email customer
    <cfmail  from="" to="" subject="Transaction Number #transNum#">

         //  shopping bag printout

    </cfmail>

    Owainnorth
    Inspiring
    March 17, 2011

    You are aware that any processes that rely on the transaction need to be within the *same* cftransaction tag?

    Obviously I can't see what's going on inside your cfcs, but simply wrapping each query in its own transaction achieves nothing.

    Community Expert
    March 17, 2011

    My guess would be that you have a concurrency problem in salesCFC.

    Dave Watts, CTO, Fig Leaf Software

    http://www.figleaf.com/

    http://training.figleaf.com/

    Dave Watts, Eidolon LLC
    March 17, 2011

    Do you mind elaborating what you meant by "concurrency problem"?  The two transactions were recorded in the database with the correct transaction numbers, so I know that salesCFC.createTransactionNumber() and salesCFC.saveTransaction() are doing their jobs.

    My guess would be that you have a concurrency problem in salesCFC.