"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 and "buy me a coffee" link.
Join us.