File upload: CSV import

This blog post is a code dump of a file upload dialog for D365 FO. There are various around, but I could not find a complete example so I decided to share my own. This is a single class extending the RunBase class, which has a file upload control and then parses the CSV file returned from the IO stream. No data entities are used although you can modify the code and use them.

D365 FO File Upload
public class ImportSalesOrderRunbase extends RunBase
{
    DialogRunbase dialog;
    private str availableTypes = ".csv";
    private const str OkButtonName = 'OkButton';
    private const str FileUploadName = 'FileUpload';
    private str textFile;

    public Object dialog()
    {
        DialogGroup      dialogGroup;
        FormBuildControl formBuildControl;
        FileUploadBuild  dialogFileUpload;
        Set              enumSet = new Set(Types::Enum);

        
        dialog = super();
        dialogGroup = dialog.addGroup("Import sales orders");
        formBuildControl = dialog.formBuildDesign().control(dialogGroup.name());
        
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), FileUploadName);
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileTypesAccepted(availableTypes);
        dialogFileUpload.fileNameLabel("@SYS308842");

        dialog.addText("CSV Columns \n1. External Sales Id \n2. Cust Account \n3. Item Id \n4. Unit Price \n5. Quantity \n6. Line Discount \n7. Line Amount");
    
        return dialog;
    }

    protected void setDialogOkButtonEnabled(DialogRunbase _dialog, boolean _isEnabled)
    {
        FormControl okButtonControl = this.getFormControl(_dialog, OkButtonName);

        if (okButtonControl)
        {
            okButtonControl.enabled(_isEnabled);
        }
    }

    protected FormControl getFormControl(DialogRunbase _dialog, str _controlName)
    {
        return _dialog.formRun().control(_dialog.formRun().controlId( _controlName));
    }

    protected void uploadCompleted()
    {
        FileUpload fileUpload = this.getFormControl(dialog, FileUploadName);
        fileUpload.notifyUploadCompleted -= eventhandler(this.UploadCompleted);
                
        textFile = fileUpload.fileName();

        this.setDialogOkButtonEnabled(dialog, true);
    }

    /// Disable the dialog Ok button until the file upload is complete.
    public void dialogPostRun(DialogRunbase _dialog)
    {
        FileUpload fileUpload = this.getFormControl(_dialog, FileUploadName);
        fileUpload.notifyUploadCompleted += eventhandler(this.uploadCompleted);
        this.setDialogOkButtonEnabled(_dialog, false);
    }

    public static void main(Args _args)
    {
        ImportSalesOrderRunbase importSO = new ImportSalesOrderRunbase();

        if (importSO.prompt())
        {
            importSO.run();
        }
    }

    public void run()
    {
        #File
        container               currentLine;
        int                     totalOfLines;
        CommaTextStreamIo       localStream;
        Num                     number;
            
       
        FileUpload fileUploadControl = this.getFormControl(dialog, FileUploadName);
        FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult();
        
        if (fileUploadResult != null && fileUploadResult.getUploadStatus())
        {
            textFile = fileUploadResult.getDownloadUrl();
        }
        
        localStream = CommaTextStreamIo::constructForRead(File::UseFileFromURL(textFile));
                 
        if (localStream.status() != IO_Status::Ok)
        {
            throw error('File cannot be opened');
        }
    
        localStream.inFieldDelimiter("\,");
        localStream.inRecordDelimiter("\n");
    
        currentLine = localStream.read();
        
        while(currentLine)
        {
            this.parseCSV(currentLine);

            currentLine = localStream.read();
        }
    }

    private void parseCSV(container _record)
    {
        str         externalSalesId = conPeek(_record, 1);
        str         custAccount = conPeek(_record, 2);
        str         itemId = conPeek(_record, 3);
        str         salesPrice = conPeek(_record, 4);
        str         salesQty = conPeek(_record, 5);
        str         lineDisc = conPeek(_record, 6);        
        str         lineAmount = conPeek(_record, 7);
        
        //Write your code to create Sales Orders and Lines
    }
}