Upload CSV/TXT using SysOperation X++
Contract:
/// <summary>
/// Contract class upload through excel for PO inbound journals
/// </summary>
[DataContractAttribute,
SysOperationContractProcessingAttribute(classStr(SAN_POImportUIBuilder))]
public class SAN_POImportContract extends SysOperationDataContractBase
Implements SysOperationInitializable, SysOperationValidatable
{
FileName fileName;
private System.IO.Stream inputDataStream;
NoYes hasColumnNames;
Str1260 layout;
/// <summary>
/// Validates the parameters.
/// </summary>
/// <returns>
/// true if successful; otherwise, false.
/// </returns>
public boolean validate()
{
return true;
}
public void initialize()
{
hasColumnNames = NoYes::Yes;
}
/// <summary>
/// Gets or sets the value of the data contract parameter fileName.
/// </summary>
/// <param name="_fileName">
/// The new value of the data contract parameter fileName.
/// </param>
/// <returns>
/// Returns the current value of data contract parameter fileName.
/// </returns>
public Filename parmFileName(FileName _fileName = fileName)
{
fileName = _fileName;
return fileName;
}
/// <summary
/// Gets or sets the value of the data contract parameter hasColumnNames.
/// </summary>
/// <param name = "_hasColumnNames">
/// The new value of the data contract parameter hasColumnNames.
/// </param>
/// <returns>
/// Returns the current value of data contract parameter hasColumnNames.
/// </returns>
[DataMemberAttribute,
SysOperationLabelAttribute("File has header column") ]
public NoYes parmHasColumnNames(NoYes _hasColumnNames = hasColumnNames)
{
hasColumnNames = _hasColumnNames;
return hasColumnNames;
}
/// <summary>
/// Set or get Input file data stream
/// </summary>
/// <param name = "_value">current value of stream</param>
/// <returns>file memory stream to process</returns>
[Hookable(false)]
public System.IO.Stream parmInputDataStream(System.IO.Stream _value = inputDataStream)
{
inputDataStream = _value;
return inputDataStream;
}
/// <summary>
/// Gets or sets the value of the data contract parameter fileLayout.
/// </summary>
/// <param name="_layout">
/// The new value of the data contract parameter fileLayout.
/// </param>
/// <returns>
/// Returns the current value of data contract parameter fileLayout.
/// </returns>
[DataMemberAttribute,
SysOperationLabelAttribute("File layout") ]
public Str1260 parmLayout(Str1260 _layout = layout)
{
layout = '';
layout = 'TXT/CSV File delimited as |' + '\n';
layout += strfmt("%1 | %2 : %3\n", '1', 'A', 'Column1');
layout += strfmt("%1 | %2 : %3\n", '2', 'B', 'Column2');
layout += strfmt("%1 | %2 : %3\n", '3', 'C', 'Column3');
layout += strfmt("%1 | %2 : %3\n", '4', 'D', 'Column4');
layout += strfmt("%1 | %2 : %3\n", '5', 'E', 'Column5');
return layout;
}
}
UI Builder:
/// <summary>
/// Class is to upload through excel for PO inbound substitution journals to handle run time contract operations
/// </summary>
class SAN_POImportUIBuilder extends SysOperationAutomaticUIBuilder
{
#define.commandButton('CommandButton')
#define.fileUpload('FileUpload')
#define.fileTypesAccepted('.txt,.csv')
SAN_POImportContract contract;
/// <summary>
/// Adds a button to the dialog to import a file.
/// </summary>
[Hookable(false)]
public void build()
{
DialogGroup dialogGroup;
DialogTabPage dialogTabPage;
Dialog dlg;
FormBuildControl formBuildControl;
FileUploadBuild dialogFileUpload;
DialogField dialogLayout;
FormBuildTabPageControl parametersTabPage;
FormBuildTabPageControl layoutTabPage;
dlg = this.dialog();
contract = this.dataContractObject() as SAN_POImportContract;
dialogTabPage = dlg.addTabPage("@SYS7764");
dialogTabPage.columns(2);
parametersTabPage = dlg.formBuildDesign().control(dialogTabPage.name());
parametersTabPage.fastTabExpanded(FastTabExpanded::Yes);
dialogGroup = dlg.addGroup('Upload file');
formBuildControl = dlg.formBuildDesign().control(dialogGroup.name());
dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), #fileUpload);
dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
dialogFileUpload.fileTypesAccepted(#fileTypesAccepted);
dialogFileUpload.fileNameLabel("@SYS308842");
dlg.addGroup("@SYS339526");
this.addDialogField(methodStr(SAN_POImportContract, parmHasColumnNames), contract);
dialogTabPage = dlg.addTabPage("@Polaris:FileLayout");
layoutTabPage = dlg.formBuildDesign().control(dialogTabPage.name());
layoutTabPage.fastTabExpanded(FastTabExpanded::Yes);
dialogLayout = this.addDialogField(methodStr(SAN_POImportContract, parmLayout), contract);
dialogLayout.showLabel(false);
dialogLayout.enabled(false);
dialogLayout.widthMode(1);
dialogLayout.displayHeight(15);
}
/// <summary>
/// Handles dialog closing events.
/// </summary>
/// <param name = "sender">
/// xFormRun class.
/// </param>
/// <param name = "e">
/// FormEventArgs class.
/// </param>
[SuppressBPWarningAttribute('BPParametersNotUsed', 'This event parameter is not used')]
private void dialogClosing(xFormRun sender, FormEventArgs e)
{
FormEventArgs formEventArgs;
formEventArgs = e;
this.dialogEventsUnsubscribe(sender as FormRun);
}
/// <summary>
/// Handles dialog events.
/// </summary>
/// <param name = "_formRun">
/// FormRun class type.
/// </param>
private void dialogEventsSubscribe(FormRun _formRun)
{
FileUpload fileUpload = _formRun.control(_formRun.controlId(#fileUpload));
fileUpload.notifyUploadCompleted += eventhandler(this.uploadCompleted);
fileUpload.notifyUploadAttemptStarted += eventhandler(this.uploadStarted);
_formRun.onClosing += eventhandler(this.dialogClosing);
}
/// <summary>
/// Handles dialog event.
/// </summary>
/// <param name = "_formRun">
/// FormRun class type.
/// </param>
private void dialogEventsUnsubscribe(FormRun _formRun)
{
FileUpload fileUpload = _formRun.control(_formRun.controlId(#fileUpload));
fileUpload.notifyUploadCompleted -= eventhandler(this.uploadCompleted);
fileUpload.notifyUploadAttemptStarted -= eventhandler(this.uploadStarted);
_formRun.onClosing -= eventhandler(this.dialogClosing);
}
/// <summary>
/// Handles dialog event post run.
/// </summary>
[Hookable(false)]
public void postRun()
{
super();
FormRun formRun = this.dialog().dialogForm().formRun();
this.dialogEventsSubscribe(formRun);
this.setDialogOkButtonEnabled(formRun, false);
}
/// <summary>
/// Enables or disables the dialog Ok button.
/// </summary>
/// <param name = "_formRun">
/// The <c>FormRun</c> object.
/// </param>
/// <param name = "_isEnabled">
/// Indicates to enable or disable the Ok button.
/// </param>
protected void setDialogOkButtonEnabled(FormRun _formRun, boolean _isEnabled)
{
FormControl okButtonControl = _formRun.control(_formRun.controlId(#commandButton));
if (okButtonControl)
{
okButtonControl.enabled(_isEnabled);
}
}
/// <summary>
/// After the file has been uploaded, the Ok button is enabled.
/// </summary>
protected void uploadCompleted()
{
contract = this.dataContractObject() as SAN_POImportContract;
var formRun = this.dialog().dialogForm().formRun();
FileUpload fileUpload = formRun.control(formRun.controlId(#fileUpload));
contract.parmFileName(fileUpload.fileName());
using (System.IO.Stream stream = fileUpload.getUploadedFile(true))
{
if (stream)
{
System.IO.MemoryStream copiedStream = new System.IO.MemoryStream();
stream.CopyTo(copiedStream);
contract.parmInputDataStream(copiedStream);
}
}
this.setDialogOkButtonEnabled(formRun, contract.parmInputDataStream() != null);
}
/// <summary>
/// During file upload, the Ok button is disabled.
/// </summary>
private void uploadStarted()
{
var formRun = this.dialog().dialogForm().formRun();
this.setDialogOkButtonEnabled(formRun, false);
}
}
Controller:
/// <summary>
/// Class is to handle controller logic to upload PO journals
/// </summary>
class SAN_POImportController extends SysOperationServiceController
{
public ClassDescription caption()
{
return "Upload Purchase Journals";
}
/// <summary>
/// Provides entry point for the instance of <c>SAN_POImportController</c>.
/// </summary>
/// <param name = "_args">
/// The arguments passed to the class <c>SAN_POImportController</c>.
/// </param>
public static void main(Args _args)
{
SAN_POImportController controller;
controller = SAN_POImportController::construct();
controller.showBatchTab(false);
controller.parmArgs(_args);
controller.startOperation();
}
/// <summary>
/// Initializes new instance of <c>SAN_POImportController</c>.
/// </summary>
/// <returns>
/// Return object of <c>SAN_POImportController</c>.
/// </returns>
public static SAN_POImportController construct()
{
SAN_POImportController controller;
controller = new SAN_POImportController(classStr(SAN_POImportService),
methodStr(SAN_POImportService, Run),
SysOperationExecutionMode::Synchronous);
return controller;
}
}
Service:
/// <summary>
/// Class is to upload through excel for PO upload journals to handle service operations
/// </summary>
class SAN_POImportService extends SysOperationServiceBase
{
System.IO.Stream stream;
int totalLinesProcessed = 0;
SAN_POImportContract contract;
str filename, journalProcessId;
/// <summary>
/// process file to upload WG purchase line item substitution journals
/// </summary>
/// <param name = "_contract">
/// Contract class.
/// </param>
public void run(SAN_POImportContract _contract)
{
contract = _contract;
stream = _contract.parmInputDataStream();
filename = _contract.parmFileName();
this.processFile(_contract);
}
/// <summary>
/// Processing excel file input
/// </summary>
/// <param name = "_contract">
/// Contract class.
/// </param>
protected void processFile(SAN_POImportContract _contract)
{
#File
TextStreamIo inFile = TextStreamIo::constructForRead(stream);
inFile.inFieldDelimiter('|'); //TODO delimiter used
inFile.inRecordDelimiter('\r\n');
container recordContainer;
str item;
boolean isFirstLine = true;
recordContainer = inFile.read();
if(_contract.parmHasColumnNames())
{
recordContainer = inFile.read();
}
ttsbegin;
while (inFile.status() == IO_Status::OK)
{
if(isFirstLine)
{
journalProcessId = '';
//Header record creation logic
isFirstLine= false;
}
//line record creation logic
//Read the next line
recordContainer = inFile.read();
}
ttscommit;
info(strFmt("Journal - %2 Total record lines created %1",totalLinesProcessed, journalProcessId));
}
}