Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using PX.Api;
using PX.Data;
using PX.DataSync.Filter;
namespace PX.DataSync
{
public class My_CSV_Provider : IPXSYProvider
{
#region Consts
//Name of provider specific parameters
protected const String FILE_PARAM = "FileName";
protected const string DELIMITER_PARAMETER = "Delimiter";
protected const string QUOTEALL_PARAMETER = "QuoteAll";
protected const string CODE_PAGE_PARAMETER = "Encoding";
protected const String PROVIDER_NOTEID = "ProviderNoteID";
//Default values for some parameters
protected const char DEFAULT_DELIMITER = ',';
protected const bool DEFAULT_QUOTEALL = false;
//Encoding settings
protected static readonly string[] _codePages;
protected static readonly string[] _codePageNames;
protected static readonly string DEFAULT_CODE_PAGE = Encoding.ASCII.EncodingName;
#endregion
//Default extension for files created from provider
public string DefaultFileExtension
{
get
{
return ".csv";
}
}
//Provider description name
public string ProviderName
{
get
{
return PX.Data.PXMessages.Localize("My CSV Provider");
}
}
static My_CSV_Provider()
{
//Initializing codepages inside static constructor
var codePages = new List<string>();
var codePagesNames = new List<string>();
var infoList = new List<EncodingInfo>(Encoding.GetEncodings());
infoList.Sort((x, y) => string.Compare(x.DisplayName, y.DisplayName, true));
foreach (EncodingInfo info in infoList)
{
codePages.Add(info.Name);
codePagesNames.Add(info.DisplayName);
}
_codePages = codePages.ToArray();
_codePageNames = codePagesNames.ToArray();
}
#region Parameters
//variable for storing parameters
protected IEnumerable<PXSYParameter> _Parameters;
//returning description for parameters that is used by provider
public PXStringState[] GetParametersDefenition()
{
return FillParameters().ToArray();
}
//returning parameters values
public virtual PXSYParameter[] GetParameters()
{
return _Parameters.ToArray();
}
//setting parameter values from outside of provider
public virtual void SetParameters(PXSYParameter[] parameters)
{
_Parameters = parameters;
}
public List<PXStringState> FillParameters()
{
List<PXStringState> ret = new List<PXStringState>();
//Parameter for file name
PXStringState fileParam = CreateParameter(FILE_PARAM, Titles.FileName, InfoMessages.FileNameDefaultValue);
ret.Add(fileParam);
//Parameter for encoding
PXStringState codePageParam = CreateParameter(CODE_PAGE_PARAMETER, Titles.Encoding, DEFAULT_CODE_PAGE, null, _codePageNames, _codePages);
ret.Add(codePageParam);
//Parameter for delimeter
PXStringState delimiterParam = CreateParameter(DELIMITER_PARAMETER, PX.Data.PXMessages.Localize(Titles.DefaultDelimiter), new string(new[] { DEFAULT_DELIMITER }));
ret.Add(delimiterParam);
//Parameter for quote values
PXStringState quoteAllParam = CreateParameter(QUOTEALL_PARAMETER, PX.Data.PXMessages.Localize(Titles.QuoteAll), DEFAULT_QUOTEALL.ToString());
ret.Add(quoteAllParam);
return ret;
}
#endregion
#region Schema
//Returning Provider Objects
public virtual String[] GetSchemaObjects()
{
//Reading file from database before processing
InitialiseFile(GetParameter(FILE_PARAM), false);
List<String> ret = new List<String>();
//For csv file we don't have any objects, so we will use file name
ret.Add(_file.Name);
return ret.ToArray();
}
//Returning Provider Fields for specific Provider Object
public virtual PXFieldState[] GetSchemaFields(String objectName)
{
//Reading file from database before processing
InitialiseFile(GetParameter(FILE_PARAM), false);
List<PXFieldState> ret = new List<PXFieldState>();
//Initialising delimeter
String separator = GetParameter(DELIMITER_PARAMETER);
if (String.IsNullOrEmpty(separator)) separator = new String(new[] { DEFAULT_DELIMITER });
//Getting Encoding
Int32 codePage = Encoding.GetEncoding(GetParameter(CODE_PAGE_PARAMETER) ?? DEFAULT_CODE_PAGE).CodePage;
//Opening CSV Reader with all parameters
using (CSVReader reader = new CSVReader(_file.BinData, codePage) { Separator = separator })
{
//Reading firs row (there should be column definitions)
reader.Reset();
if (reader.MoveNext())
{
Int32 index = 0;
foreach (KeyValuePair<int, string> indexKeyPair in reader.IndexKeyPairs)
{
if (!String.IsNullOrEmpty(indexKeyPair.Value))
{
//Creating description class for all columns in the file
PXFieldState fs = CreateFieldState(new SchemaFieldInfo(index, indexKeyPair.Value));
ret.Add(fs);
}
index++;
}
}
}
return ret.ToArray();
}
#endregion
#region Import
public virtual PXSYTable Import(String objectName, String[] fieldNames, PXSYFilterRow[] filters, String lastTimeStamp, PXSYSyncTypes syncType)
{
//Reading file from database before processing
InitialiseFile(GetParameter(FILE_PARAM), false);
//Getting fields form file
PXFieldState[] fields = GetSchemaFields(objectName);
//initialising return table
PXSYTable table = new PXSYTable(fieldNames);
table.ObjectName = objectName;
table.Description = String.Format(PXMessages.Localize(Messages.ImportedComment), _file.OriginalName);
table.TimeStamp = _file.RevisionId != null ? _file.RevisionId.ToString() : null;
//Initialising delimeter
String separator = GetParameter(DELIMITER_PARAMETER);
if (String.IsNullOrEmpty(separator)) separator = new String(new[] { DEFAULT_DELIMITER });
//Getting Encoding
Int32 codePage = Encoding.GetEncoding(GetParameter(CODE_PAGE_PARAMETER) ?? DEFAULT_CODE_PAGE).CodePage;
//Opening CSV Reader with all parameters
using (CSVReader reader = new CSVReader(_file.BinData, codePage) { Separator = separator })
{
reader.Reset();
//Reading lines one by one
while (reader.MoveNext())
{
PXSYRow row = table.CreateRow();
for (int i = 0; i < row.Count; i++)
{
Int32 index = -1;
//Columns set in the file and provider can be diferent, so we need to match indexes.
for (int j = 0; j < fields.Length; j++)
{
if (String.Compare(fields[j].Name, table.Columns.ElementAt(i), true) == 0) index = j;
}
//If column not found that throwing an exception.
if (index < 0)
throw new PXException(Messages.ColumnNotFound, table.ObjectName, table.Columns.ElementAt(i));
//setting value
PXSYItem value = new PXSYItem(reader.GetValue(index));
row.SetItem(i, value);
}
table.Add(row);
}
}
return table;
}
#endregion
#region Export
public virtual void Export(String objectName, PXSYTable table, Boolean breakOnError, Action<SyProviderRowResult> callback)
{
//Reading file from database before processing, if file does not exists, we have to crete new one.
InitialiseFile(GetParameter(FILE_PARAM), true);
//Initialising delimeter and quoting
string separator = GetParameter(DELIMITER_PARAMETER);
Encoding encoding = Encoding.GetEncoding(GetParameter(CODE_PAGE_PARAMETER) ?? DEFAULT_CODE_PAGE);
bool quoteAll = false;
if (!bool.TryParse(GetParameter(QUOTEALL_PARAMETER), out quoteAll))
throw new PXException(Messages.StringToBoolError);
Byte[] data = null;
//Opening csv data writer
using (My_CSV_Writer writer = new My_CSV_Writer(separator, encoding, quoteAll))
{
writer.Write(table.Columns);
//Writing data row by row.
foreach (PXSYRow row in table)
writer.Write(row);
data = writer.BinData;
}
//saving file to the database.
SetFile(data);
//informing sytem that data have been processed.
InvokeCallback(table, callback);
}
#endregion
#region Auxiliary File
protected PX.SM.FileInfo _file;
protected virtual void InitialiseFile(String fileName, Boolean create)
{
if (_file == null)
{
//serching for file in the database.
PX.SM.FileInfo file = GetFile(fileName);
//If file does not exist than trow and error.
if ((file == null || file.BinData == null) && !create) throw new PXException(Messages.FileNotFound, fileName);
//creating new file if needed
if (file == null)
{
//Searching for specific provider in the database
SYProvider prov = GetProvider();
//Generation name
String filename = fileName ?? String.Concat(prov.Name, DefaultFileExtension);
//creating file
file = new PX.SM.FileInfo(filename, filename, null);
}
_file = file;
}
}
protected virtual PX.SM.FileInfo GetFile(String fileName)
{
PX.SM.FileInfo file;
//creating special graph for managing files
PX.SM.UploadFileMaintenance upload = new PX.SM.UploadFileMaintenance();
//searching for file
file = upload.GetFile(fileName);
return file;
}
protected virtual PX.SM.FileInfo SetFile(Byte[] bytes)
{
Boolean notexist = _file.BinData == null;
//initialisubg files data.
_file.Comment = String.Format(Messages.ExportedComment, this.ProviderName);
_file.BinData = bytes;
//creating special graph for managing files
PX.SM.UploadFileMaintenance upload = new PX.SM.UploadFileMaintenance();
//saiving file to the database
upload.SaveFile(_file, PX.SM.FileExistsAction.CreateVersion);
//attaching new file to current provider.
if (notexist) AttachFile((Guid)_file.UID);
return _file;
}
protected virtual void AttachFile(Guid file)
{
//searching for current provider.
SYProvider prov = GetProvider();
try
{
//inserting reference between file and provider to the database
PXDatabase.Insert(typeof(NoteDoc),
new PXDataFieldAssign(typeof(NoteDoc.noteID).Name, PXDbType.BigInt, 8, prov.NoteID),
new PXDataFieldAssign(typeof(NoteDoc.fileID).Name, PXDbType.UniqueIdentifier, file),
PXDataFieldAssign.OperationSwitchAllowed
);
}
catch (PXDatabaseException ex)
{
if (ex.ErrorCode == PXDbExceptions.OperationSwitchRequired)
{
//if table is shared we need to check different way
PXDatabase.Update<NoteDoc>(
new PXDataFieldAssign(typeof(NoteDoc.noteID).Name, PXDbType.BigInt, 8, prov.NoteID),
new PXDataFieldAssign(typeof(NoteDoc.fileID).Name, PXDbType.UniqueIdentifier, file),
new PXDataFieldRestrict(typeof(NoteDoc.noteID).Name, PXDbType.BigInt, 8, prov.NoteID),
new PXDataFieldRestrict(typeof(NoteDoc.fileID).Name, PXDbType.UniqueIdentifier, file)
);
}
else
{
throw;
}
}
}
protected virtual SYProvider GetProvider()
{
//getting provider note id from parameters
String notestring = GetParameter(PROVIDER_NOTEID, false);
Int32 noteid;
if (!Int32.TryParse(notestring, out noteid))
throw new PXException(Messages.ProviderNoteIDNotFound);
//searching fo providers by note id
SYProviderMaint graph = new SYProviderMaint();
SYProvider provider = PXSelect<SYProvider, Where<SYProvider.noteID, Equal<Required<SYMapping.noteID>>>>.Select(graph, noteid);
if (provider == null) throw new PXException(Messages.ProviderNotFound, noteid);
return provider;
}
#endregion
#region Auxiliary Methods
//Searching for specific parameter in parameters collection
protected String GetParameter(String paremeter, Boolean checkEmpty = true, Boolean checkExistanse = true)
{
foreach (PXSYParameter pr in _Parameters)
{
if (String.Compare(pr.Name, paremeter, true) == 0)
{
if (checkEmpty && String.IsNullOrEmpty(pr.Value)) throw new PXException(Messages.ParameterIsEmpty, paremeter);
return pr.Value;
}
}
if (checkExistanse) throw new PXException(Messages.ParameterNotFound, paremeter);
return null;
}
//Creating definition class for the known parameter
protected PXStringState CreateParameter(String name, String displayName, String value = null, String mask = null, String[] alowedLabels = null, String[] alowedValues = null)
{
PXStringState param = (PXStringState)PXStringState.CreateInstance(
value,
null,
false,
name,
null,
1,
String.IsNullOrEmpty(mask) ? null : mask,
alowedValues == null ? null : alowedValues,
alowedLabels == null ? null : alowedLabels,
null,
String.IsNullOrEmpty(value) ? null : value);
if (!String.IsNullOrEmpty(displayName)) param.DisplayName = displayName;
return param;
}
//create difinition class for provider field.
protected PXFieldState CreateFieldState(SchemaFieldInfo fieled)
{
PXFieldState fieldState = PXStringState.CreateInstance(
null, //value
fieled.DataType, //dataType
false, //isKey
true, //nullable
null, //required
null, //precision
fieled.Length, //length
null, //defaultValue
fieled.Name, //fieldName
fieled.Name, //descriptionName
fieled.Name, //displayName
null, //error
PXErrorLevel.Undefined, //errorLevel
null, //enabled
null, //visible
null, //readOnly
PXUIVisibility.Undefined, //visibility
null, //viewName
null, //fieldList
null //headerList
);
return fieldState;
}
//invoking callback for all rows in table.
protected virtual void InvokeCallback(PXSYTable table, Action<SyProviderRowResult> callback)
{
for (int i = 0; i < table.Count; i++)
{
callback.Invoke(new SyProviderRowResult(i));
}
}
#endregion
}
#region CsvWriter
//Specila class that can write data in to CSV format.
public class My_CSV_Writer : BaseWriter
{
private const string _DEF_DELIMITER = ",";
private readonly char[] _DEPRICATED_SYMBOLS = new char[] { '\"', '\x0A', '\x0D' };
private readonly char[] _QUOTED_SYMBOLS = new char[] { '\"', '\x0A', '\x0D' };
private readonly string _delimiter;
private readonly bool _quoteAll;
public My_CSV_Writer(string delimiter, Encoding encoding, bool quoteAll)
: base(encoding)
{
if (delimiter.IndexOfAny(_DEPRICATED_SYMBOLS) >= 0)
throw new PXException(Messages.DelimiterError, String.Join("', '", _DEPRICATED_SYMBOLS.Select(c => c.ToString()).ToArray()));
_delimiter = delimiter;
_quoteAll = quoteAll;
}
public void Write(IEnumerable<object> values)
{
Write(values.Select(o => o.ToString()));
}
public void Write(IEnumerable<string> values)
{
int valuesCount = values.Count();
string[] converted = new string[valuesCount];
int i = 0;
foreach (string item in values)
{
string value = item ?? String.Empty;
if (_quoteAll || (value.IndexOfAny(_QUOTED_SYMBOLS) >= 0) || value.Contains(_delimiter))
value = QuoteItem(value);
converted[i++] = value;
}
WriteLine(String.Join(_delimiter, converted.ToArray()));
}
private string QuoteItem(string item)
{
return String.Format("\"{0}\"", item.Replace("\"", "\"\""));
}
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.