Transformation code for sample data flow EDI

/*

 * transformFunction:

 *

 * This function transforms a set of invoice records into the desired EDI JSON format.

 *

 * The function is passed one ‘options’ argument with the following fields:

 *  ‘record’ – array [] representing a record set.

 *  ‘settings’ – all custom settings in scope for the transform currently running.

 *

 * The function returns the transformed EDI JSON object.

 * Throwing an exception will return an error for the record.

 */

function transform(options) {

  // Helper function to format dates as DDMMYY

  // Helper function to format dates as YYMMDD

function formatDateDDMMYY(dateStr) {

  if (!dateStr) return ”; // Return empty string if dateStr is falsy

  const [ month, day, year] = dateStr.split(‘/’); // Split the input DD/MM/YYYY

  if ( !month ||!day || !year) return ”; // Return empty string if any component is missing

  return `${year.slice(-2)}${month.padStart(2, ‘0’)}${day.padStart(2, ‘0’)}`; // Format as YYMMDD

}

function formatDateYYYYMMDD(dateStr) {

  if (!dateStr) return ”; // Return empty string if dateStr is falsy

  const [month, day, year] = dateStr.split(‘/’); // Split date into components

  if (!month || !day || !year) return ”; // Return empty string if any component is missing

  // Pad month and day with leading zeros if necessary

  const paddedMonth = month.padStart(2, ‘0’);

  const paddedDay = day.padStart(2, ‘0’);

  return `${year}${paddedMonth}${paddedDay}`; // Return formatted date as YYYYMMDD

}

  // Helper function to format time as HHMM in 24-hour format

  function formattedTime(timeStr, period) {

    if (!timeStr || !period) return ”; // Return empty string if timeStr or period is falsy

    let [hours, minutes] = timeStr.split(‘:’);

    // Convert 12-hour time to 24-hour time

    if (period.toLowerCase() === ‘pm’ && parseInt(hours) < 12) {

      hours = (parseInt(hours) + 12).toString().padStart(2, ‘0’);

    } else if (period.toLowerCase() === ‘am’ && hours === ’12’) {

      hours = ’00’;

    }

    return `${hours}${minutes}`;

  }

  // Helper function to extract and format date and time as per EDI standard

  function formatDateTime(dateTimeStr) {

     if (!dateTimeStr) return { date: ”, time: ” }; // Return empty if dateTimeStr is falsy

  const [datePart, timePart, period] = dateTimeStr.split(/[s:]+/);

  if (!datePart || !timePart || !period) return { date: ”, time: ” };

  return { 

    date: formatDateDDMMYY(datePart), // Use the updated date formatting function

    time: formattedTime(timePart, period) 

  };

  }

 

  // Helper function to remove % symbol from a tax rate string

function removePercentageSymbol(value) {

  if (!value) return ”; // Return empty string if value is falsy

  return value.replace(‘%’, ”); // Remove % symbol

}

// Helper function to adjust the customer name if it exceeds 35 characters

function adjustCustomerName(name) {

  if (!name) return ”; // Return empty string if the name is falsy

  if (name.length <= 35) return name; // Return the original name if within the limit

  return `${name.slice(0, 35)}:${name.slice(35)}`; // Insert ‘:’ at the 35th character

}

// Helper function to combine shipDate and time

function combineDateAndTime(updatedInvoiceDate, time) {

  if (!updatedInvoiceDate || !time) return ”; // Return empty string if any value is falsy

  return `${updatedInvoiceDate}${time}`; // Concatenate the date and time

}

  // Helper function to generate a message reference number

  function generateMessageReference(invoiceNumber, invoiceDate) {

    const formattedDate = formatDateDDMMYY(invoiceDate);

    return `${invoiceNumber}-${formattedDate}`; // Format: InvoiceNumber-DDMMYY

  }

  try {

    // Ensure the record is an array (recordSet)

    const recordSet = Array.isArray(options.record) ? options.record : [options.record];

    if (recordSet.length === 0) {

      throw new Error(‘Record set is empty.’);

    }

    // Identify the first record in the set, assuming it has the main invoice details

    const mainRecord = recordSet[0];

    // Retrieve necessary fields from the input data

    

    const invoiceNumber = mainRecord[“Document Number”] || ”;

    const poNumber = mainRecord[“PO/Cheque Number”] || ”;

    const invoiceDate = mainRecord[“Date”] || ”; // Invoice date in DD/MM/YYYY

    const updatedInvoiceDate = formatDateYYYYMMDD(invoiceDate);

    const shipDate = mainRecord[“ShipDate”] || ”;

    const time = “1012”;

    //const documentDateTime = mainRecord[“Document date”] || ”; // Document date and time in DD/MM/YYYY HH:MM AM/PM

    // Extract the formatted document date and time using our helper function

    const { date: formattedDocumentDate, time: formattedDocumentTime } = formatDateTime(invoiceDate);

     

     

    const numberOfItems = recordSet.length;

    const taxRate = removePercentageSymbol(mainRecord[“Tax Rate”]);

    // Prepare NAD Segment for the Buyer (Customer)

    const nadSegments = [

  {

    “Party Qualifier”: “BY”, // “BY” indicates Buyer

    “Party Identification Code”: mainRecord[“StoreCode”] || ”, // Unique Store Code

    “Name”: mainRecord[“ShipToName”] || ”, // ShipTo Name

    “Customer Ref number”: mainRecord[“StoreCode”] || ”, // Store Code as Reference

    “Code List Qualifier”: “160”,

    “Code List Responsible Agency”: “92”,

    “Street”: mainRecord[“ShipToAddress1″] || ”, // ShipTo Address Line 1

    “City”: mainRecord[“ShipToCity”] || ”, // ShipTo City

    “State”: mainRecord[“ShipToState”] || ”, // ShipTo State

    “Postal Code”: mainRecord[“ShipToZip”] || ”, // ShipTo Zip

    “Country”: mainRecord[“ShipToCountry”] || ” // ShipTo Country

  }

];

    // Prepare DTM segments (Date/Time/Period)

    const dtmSegments = [

      {

        “DATE/TIME/PERIOD”: {

          “Date qualifier 1″:”137”,

          “Date qualifier 2″:”2”,

          “Date/time/period qualifier”: “17”, // Invoice date qualifier

           

          “Date/time/period”: combineDateAndTime(updatedInvoiceDate,time),

          “Date/time/period 2”: shipDate,

          “Date/time/period format qualifier”: “203”,

          “Date/time/period format qualifier 2”: “102”

        }

      },

      

    ];

    // Prepare Segment Group 1 (References)

    const segmentGroup1 = [

      {

        “REFERENCE”: {

          “Reference qualifier”: “ON”, // Unique Invoice Reference

          “Reference number”: invoiceNumber

        },

        “DTM”: [

          {

            “DATE/TIME/PERIOD”: {

              “Date/time/period qualifier”: “35”, // Document creation date/time qualifier

              “Date/time/period”: formattedDocumentDate,

              “Date/time/period format qualifier”: “102”

            }

          }

        ]

      }

    ];

    // Prepare Segment Group 25 (Line Items)

    const segmentGroup25 = recordSet.map((item, index) => {

  // Format the amount for each line item

  const amount = parseFloat(item[“Amount”] || “0”).toFixed(2); // Parse and ensure two decimal places

  const taxRate = removePercentageSymbol(item[“Tax Rate”] || ”);

  return {

    “LINE ITEM NUMBER”: (index + 1).toString(),

    “ITEM NUMBER IDENTIFICATION”: {

      “Item number”: item[“Item”] || ”,

      “Item number type, coded”: “SRV”

    },

    “QTY”: [

      {

        

        “QUANTITY DETAILS”: {

          “Quantity qualifier”: “113”,

          “Quantity”: item[“Quantity”] || “0”,

          “Measure unit qualifier”: “EA” || ”

        }

      }

    ],

    “PIA”: [

      {

       “LINE ITEM NUMBER”: (index + 1).toString(),

        “ITEM NUMBER IDENTIFICATION”: {

          “Item number”: item[“Item”] || ”,

          “Item number type, coded”: “IN”

        },

        “PRODUCT ID. FUNCTION QUALIFIER”: “5”

      }

    ],

    “IMD”:[{

     “Item Description”: item[“ItemDescription”],

    }],

    “MONETARY AMOUNT”: {

      “Monetary amount type qualifier”: “128”,

      “Monetary amount”: amount, // Use parsed and formatted amount

    },

    “PRICE INFORMATION”: {

      “Price qualifier”: “AAA”,

      “Price”: item[“UnitPrice”] || “0.00”,

      “Price type, coded”: “CT”,

      “Price type qualifier”: “EA”

    },

    “DUTY/TAX/FEE”: {

      “DUTY/TAX/FEE FUNCTION QUALIFIER”: “7”,

      “Duty/tax/fee type, coded”: item[“Tax”] || ”,

      “Duty/tax/fee rate”: amount, // Use parsed and formatted amount

      “Duty/Tax/fee/ Rate”: taxRate || “0”

    }

  };

});

 // Prepare Separate MOA Segment for Tax Total

    const taxTotalSegment = {

      “MOA”: {

        “code”: “124”,

        “rate”: parseFloat(mainRecord[“Tax Total”] || “0”).toFixed(2)

      }

    };

    // Prepare Segment Group 48 (Transaction Total)

    const segmentGroup48 = [

      {

        “TRANSACTION TOTAL”: {

          “Monetary amount type qualifier”: “124”,

          “Monetary amount”: parseFloat(mainRecord[“Transaction Total”]).toFixed(2),

        }

      }

    ];

    // Function to count the total number of item lines

    function getTotalItemLines(recordSet) {

      return recordSet.length; // Count the number of line items

    }

    const totalItemLines = getTotalItemLines(segmentGroup25);

    // Generate the message reference number using the new function

    const messageReferenceNumber = generateMessageReference(invoiceNumber, invoiceDate);

    // Construct the final EDI JSON object

    const transformedRecord = {

      “SYNTAX IDENTIFIER”: {

        “Syntax identifier”: “UNOC”,

        “Syntax version number”: “3”

      },

      “INTERCHANGE SENDER”: {

        “Sender identification”: “OXTL”,

        “Partner identification code qualifier”: “ZZZ”

      },

      “INTERCHANGE RECIPIENT”: {

        “Recipient identification”: mainRecord.StoreCode,

        “Partner identification code qualifier”: “ZZZ”

      },

      “DATE/TIME OF PREPARATION”: {

        “Date of preparation”: formatDateDDMMYY(invoiceDate),

        “Time of preparation”: “1012” // Now dynamically fetched and formatted from input

      },

      “Interchange control reference”: “115883”,

      “Communications agreement ID”: “EANCOM”,

      “MESSAGE REFERENCE NUMBER”: messageReferenceNumber, // Updated

      “MESSAGE IDENTIFIER”: {

        “Message type identifier”: “ORDRSP”,

        “Message type version number”: “D”,

        “Message type release number”: “01B”,

        “Controlling agency”: “UN”,

        “Association assigned code”: “EAN008”

      },

      “DOCUMENT/MESSAGE NAME”: {

        “Document/message name, coded”: “231”

      },

      “DOCUMENT/MESSAGE NUMBER”: poNumber,

      “DTM”: dtmSegments,

      “NAD”: nadSegments, // Added the NAD segment for buyer/customer details

      “INVOICE NUMBER”: {

    “Invoice number”: invoiceNumber

  },

      “Segment Group 1”: segmentGroup1,

      “Segment Group 25”: segmentGroup25,

      “Tax Total MOA”: taxTotalSegment, 

      “Segment Group 48”: segmentGroup48,

      “SECTION IDENTIFICATION”: “S”,

      “CNT”: [

        {

          “CONTROL”: {

            “Control qualifier”: “2”,

            “Control value”: totalItemLines.toString() // Total number of item lines

          }

        }

      ],

      “Number of Items”:numberOfItems,

      “NUMBER OF SEGMENTS IN A MESSAGE”: (10 + (numberOfItems * 6)+2).toString(), // Adjust based on actual segment count

      “MESSAGE REFERENCE NUMBER(UNT020)”: messageReferenceNumber, // Updated

      “Interchange control count”: “1”,

      “Interchange control reference(UNZ020)”: “73920002”

    };

    // Return the transformed EDI JSON object

    return transformedRecord;

  } catch (error) {

    // Throw an exception with the error message

    throw new Error(`Transformation Error: ${error.message}`);

  }

}

Leave a comment

Your email address will not be published. Required fields are marked *