in Programming, Work&Life

Cashcard transaction history read software

Developed the software for reading the cash card transaction history, functions include read the balance, CAN no., issue date, expire date, expenses, and transaction history displayed in crystal report, and can print out in paper. The software screen shot is as,

Cashcard_read

Following are the work done for the software development,

1, cash card read APDU command,

00A40000020118 (select cashcard DF)

803200030400000000 (read the balance)

00B0810010 (read card information file 0001, includes CAN no., maximum transaction number, issue date, expire period, etc.)

00B0850010 (read cash card transaction history in file 0005, P2 is the offset, needs multiply by 4,  it’s a binary file, 10 bytes one transaction records.)

2, utilize the visual studio C#, and the Smart Card framework developed by Olivier Rouit, you can get the source codehere, pcsc based.

3, utilize the crystal report without database, but with the data source, by reading the maximum 25 transaction records from cash card, build up the data source by following code,

     DataSet1 ds = new DataSet1();
     DataTable t = ds.Tables.Add("Transactions");
     t.Columns.Add("item", Type.GetType("System.Int16"));
     t.Columns.Add("Date", Type.GetType("System.String"));
     t.Columns.Add("Time", Type.GetType("System.String"));
     t.Columns.Add("Type", Type.GetType("System.String"));
     t.Columns.Add("Amount", Type.GetType("System.Decimal"));
     t.Columns.Add("Merchant", Type.GetType("System.String"));
     DataRow r;

     for (int i = 1; i <= iCard.GetMaxTranLogNum(); i++)
     {
        r = t.NewRow();

        r["item"] = i;
        r["Date"] = trans[i - 1].TransactionTime.ToString("d", System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
        r["Time"] = trans[i - 1].TransactionTime.ToString("T", System.Globalization.CultureInfo.CreateSpecificCulture("en-us"));
        r["Type"] = trans[i - 1].TransactionType;
        r["Amount"] = trans[i - 1].TransactionAmount;
        r["Merchant"] = trans[i - 1].MerchantShortName;
        t.Rows.Add(r);
     }

4, set the dynamic TextObject in the Crystal report by following code,

     (objRpt.Section1.ReportObjects["Text9"] as TextObject).Text = ByteArrayToString(CanNo);
     (objRpt.Section1.ReportObjects["Text13"] as TextObject).Text = "S$ " + (num / 100).ToString("0.00");
     (objRpt.Section1.ReportObjects["Text15"] as TextObject).Text = dt.ToString("D");
     (objRpt.Section1.ReportObjects["Text17"] as TextObject).Text = expiredt.ToString("D");
     (objRpt.Section1.ReportObjects["Text19"] as TextObject).Text = "S$ " + iCard.GetExpenses().ToString("0.00");

5, the Julian date in cash card is from the date 1st Jan 1995 12:00 AM,

      public DateTime GetJuliaDateTime(byte [] input)
      {
         DateTime result = DateTime.Now;
         byte[] buffer = new byte[4];
         Array.Copy(input, 0, buffer, 0, 4);       

         if (BitConverter.IsLittleEndian)
            Array.Reverse(buffer); //need the bytes in the reverse order
         int year=1995, month=1;
         int value = BitConverter.ToInt32(buffer, 0);
         int duration = (value / 3600 / 24)+1;
         int[] daysOfMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
         while ((duration > 365 && year % 4 != 0) || (duration > 366 && year % 4 == 0))
         {
            if (year % 4 != 0) duration -= 365;
                else duration -= 366;
	    year++;
         }

         for (int i = 0; i < 12; i++)
         {
            if ((year % 4 != 0 && duration > daysOfMonth[i]) ||
            (year % 4 == 0 && i != 1 && duration > daysOfMonth[i]) ||
            (year % 4 == 0 && i == 1 && duration > 29))
            {
               if (year % 4 == 0 && i == 1) duration -= 29;
                 else duration -= daysOfMonth[i];
               month++;
            }
            else
            {
               break;
            }
        }

        result = new DateTime(year, month, duration, (value / 3600) % 24, (value / 60) % 60, value % 60, DateTimeKind.Local);
        return result;
     }

6, the merchant name is not stored in the cash card, only the short code available, have no idea where to get the merchant name, so have to get this information from  software downloaded from Nets website and read the real cash card to get the merchant name, and put in my software.

7, developed the CashCard class derived from CardNative and ICard from the Smart Card Framework, all the reading cash card implementation was put inside the CashCard class.

 

Write a Comment

Comment

two × 4 =

  1. Hi Eric,

    Are you able to send me the software? It will be good for me to extract my cashcash records for claim purposes