"DAT","FA000014VK","file2.txt" "DAT","FA000015VK","file3.txt" "DAT","FA000016VK","file4.txt"
using System.IO.Compression; /// <summary> /// Multi-attachment upload from ZIP archive /// </summary> class VKAttachmentUpload extends RunBaseBatch implements BatchRetryable { DialogRunbase dialog; Filename filename; protected str availableTypes = '.zip'; protected const str OkButtonName = 'OkButton'; protected const str FileUploadName = 'FileUpload'; protected const str FileCSVMain = 'main.csv'; protected Map entryMapping = new Map(Types::String, Types::Class); ZipArchive zipArchive; str textFile; Set set = new Set(Types::Record); SetEnumerator setEnumerator; int fileLineNumber; container currentLine; container storageResult; #define.CurrentVersion(1) #localmacro.CurrentList filename, storageResult #endmacro public boolean canGoBatch() { return true; } protected boolean canGoBatchJournal() { return true; } public Object dialog() { DialogGroup dialogGroup; FormBuildControl formBuildControl; FileUploadBuild dialogFileUpload; dialog = new DialogRunbase(VKAttachmentUpload::description(), this); dialogGroup = dialog.addGroup(VKAttachmentUpload::description()); formBuildControl = dialog.formBuildDesign().control(dialogGroup.name()); dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), FileUploadName); dialogFileUpload.style(FileUploadStyle::Standard); dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy)); dialogFileUpload.fileTypesAccepted(availableTypes); dialogFileUpload.fileNameLabel("@SYS308842"); return dialog; } public void dialogPostRun(DialogRunbase _dialog) { FileUpload fileUpload = this.getFormControl(_dialog, FileUploadName); fileUpload.notifyUploadCompleted += eventhandler(this.uploadCompleted); this.setDialogOkButtonEnabled(_dialog, false); } /// <summary> /// To handle file upload event and enable OK dialog button /// </summary> protected void uploadCompleted() { FileUpload fileUpload = this.getFormControl(dialog, FileUploadName); FileUploadTemporaryStorageResult uploadResult = fileUpload.getFileUploadResult(); storageResult = uploadResult.pack(); if (uploadResult.getUploadStatus()) { fileUpload.notifyUploadCompleted -= eventhandler(this.UploadCompleted); filename = fileUpload.fileName(); this.setDialogOkButtonEnabled(dialog, true); } else { warning(uploadResult.getLogMessage()); } } 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)); } public void run() { #File System.IO.MemoryStream memoryStream; FileUpload fileUploadControl; FileUploadTemporaryStorageResult fileUploadResult = new FileUploadTemporaryStorageResult(); if(this.isInBatch()) { fileUploadResult.unpack(storageResult); } else { fileUploadControl = this.getFormControl(dialog, FileUploadName); fileUploadResult = fileUploadControl.getFileUploadResult(); } if (fileUploadResult != null && fileUploadResult.getUploadStatus()) { textFile = fileUploadResult.getDownloadUrl(); } memoryStream = File::UseFileFromURL(textFile); zipArchive = new ZipArchive(memoryStream); this.readCSVFile(); this.processAttachments(); } /// <summary> /// Fetches attachment files from ZIP archive and attaches them to relevant records. /// </summary> protected void processAttachments() { ZipArchiveEntry entry; System.IO.MemoryStream stream; VKAttachmentContract attachmentContract; var enumerator = zipArchive.Entries.GetEnumerator(); while (enumerator.MoveNext()) { entry = enumerator.Current; if (entry.Name != FileCSVMain) { if (entryMapping.exists(entry.Name)) { attachmentContract = entryMapping.lookup(entry.Name); Common record = this.findEntityRecord(attachmentContract); if (record) { stream = new System.IO.MemoryStream(); var unzippedStream = entry.Open(); unzippedStream.CopyTo(stream); // required as otherwise file with zero content will be attached if (stream.CanSeek) { stream.Position = 0; } //System.IO.StreamReader sreader = new System.IO.StreamReader(stream, System.Text.Encoding::UTF8, true); //info(strFmt('File content: %1', sreader.ReadToEnd())); DocumentManagement::attachFileForRecord(record, 'File', stream, entry.Name, entry.Name); } else { warning(strFmt("Was not able to find entry with key %1, skipping.", attachmentContract.parmKey())); } } else { warning(strFmt("File name %1 not found, skipping.", entry.Name)); } } } } /// <summary> /// Finds entity record by the key to attach the file. /// </summary> /// <param name = "_attachmentContract">VKAttachmentContract</param> /// <returns>Entity record</returns> protected Common findEntityRecord(VKAttachmentContract _attachmentContract) { AssetTable assetTable; changecompany(_attachmentContract.parmCompany()) { assetTable = null; assetTable = AssetTable::find(_attachmentContract.parmKey()); } return assetTable; } /// <summary> /// Reads CSV file from ZIP archive /// </summary> protected void readCSVFile() { #File #OCCRetryCount #define.delimiterField(',') ZipArchiveEntry entry; System.IO.MemoryStream csvStream = new System.IO.MemoryStream(); var enumerator = zipArchive.Entries.GetEnumerator(); while (enumerator.MoveNext()) { entry = enumerator.Current; if (entry.Name == FileCSVMain) { break; } } if (!entry || entry.Name != FileCSVMain) { throw error(strFmt("Was not able to find %1 file.", FileCSVMain)); } var unzippedStream = entry.Open(); unzippedStream.CopyTo(csvStream); CommaTextStreamIo commaTextStreamIo = CommaTextStreamIo::constructForRead(csvStream); commaTextStreamIo.inFieldDelimiter(#delimiterField); commaTextStreamIo.inRecordDelimiter(#delimiterCRLF); if (commaTextStreamIo.status() != IO_Status::Ok) { throw error(strfmt("Not possible to open the file. Error: %1", enum2str(commaTextStreamIo.status()))); } str attachFileName; str recordKey; str company; VKAttachmentContract attachmentContract = new VKAttachmentContract(); while (!commaTextStreamIo.status()) { currentLine = commaTextStreamIo.read(); fileLineNumber++; if (conlen(currentLine) < 3) { warning(strFmt("Line %1, incorrect column count. Skipping.", fileLineNumber)); continue; } company = conPeek(currentLine, 1); recordKey = conPeek(currentLine, 2); attachFileName = conPeek(currentLine, 3); attachmentContract = new VKAttachmentContract(); attachmentContract.parmFileName(attachFileName); attachmentContract.parmKey(recordKey); attachmentContract.parmCompany(company); if (!entryMapping.exists(attachFileName)) { entryMapping.insert(attachFileName, attachmentContract); } } } public boolean runsImpersonated() { return true; } public container pack() { return [#CurrentVersion, #CurrentList]; } public boolean unpack(container _packedClass) { Integer version = conPeek(_packedClass, 1); switch (version) { case #CurrentVersion: [version, filename, storageResult] = _packedClass; break; default: return false; } return true; } public boolean validate(Object _calledFrom = null) { boolean ret = true; if (!filename) { ret = checkFailed("@SYS18624"); } return ret; } public static VKAttachmentUpload construct() { return new VKAttachmentUpload(); } /// <summary> /// Description of the job /// </summary> /// <returns>Description of the job</returns> public static ClassDescription description() { return "Multi-attachment upload."; } public static void main(Args args) { VKAttachmentUpload attachmentUpload; attachmentUpload = VKAttachmentUpload::construct(); if (attachmentUpload.prompt()) { attachmentUpload.runOperation(); } } protected boolean canRunInNewSession() { return false; } [Hookable(false)] public final boolean isRetryable() { return true; } }
/// <summary> /// Contract with information about attachment. /// </summary> class VKAttachmentContract { Filename fileName; DataAreaId company; str key; public Filename parmFileName(Filename _fileName = fileName) { fileName = _fileName; return fileName; } public DataAreaId parmCompany(DataAreaId _company = company) { company = _company; return company; } public str parmKey(str _key = key) { key = _key; return key; } }
DaxOnline.org is free platform that allows you to quickly store and reuse snippets, notes, articles related to Dynamics AX.
Authors are allowed to set their own AdSense units.
Join us.