We have a list of stock items in Acumatica and now want to upload their pictures.
Is there any way to mass upload images of stock items to Acumatica cloud platform?
Thanks
My suggestion for mass uploading of images to Stock or Non-stock items would be to use the built in Contract API, I have created the following sample code project that will use the in built "Default - 6.00.001" end point in version 6.1 or greater.
namespace MassInventoryItemImageUpload
{
class Program
{
static void Main(string[] args)
{
//List of inventory Item CD's and associated file to upload.
List<Tuple<string, string>> itemsToUpdate = new List<Tuple<string, string>>() { new Tuple<string, string>("InventoryItemCD", #"fileUrl") };
Console.WriteLine("Updateing : " + itemsToUpdate.Count + " Inventory Items, press enter to begin");
Console.ReadLine();
AcumaticaProcessor processor = new AcumaticaProcessor();
processor.Login();
processor.UploadImages(itemsToUpdate);
Console.WriteLine("Updates complete, press enter to exit program");
Console.ReadLine();
}
}
public class AcumaticaProcessor
{
DefaultSoapClient client = new DefaultSoapClient();
public void Login()
{
client.Login("username", "password", "Company", "branch", null);
}
public void UploadImages(List<Tuple<string, string>> updateItems)
{
//Foreach Inventory Item in the list we are going to upload a files
foreach(Tuple<string,string> updateItem in updateItems)
{
UploadImage(updateItem);
}
}
private void UploadImage(Tuple<string, string> updateItem)
{
try
{
//Finds the StockItem with the given InventoryCD
StockItem itemToUpdate = new StockItem()
{
InventoryID = new StringSearch() { Value = updateItem.Item1 }
};
itemToUpdate = client.Get(itemToUpdate) as StockItem;
//Updates found StockItem to include associated files
client.PutFiles(itemToUpdate, FileData(updateItem.Item2));
}
catch(Exception e)
{
}
}
//Creates Acumatica File object from filestream and return File[] for uplaod
private Acumatica.File[] FileData(string url)
{
byte[] fileData;
using (FileStream file = System.IO.File.Open(url, System.IO.FileMode.Open))
{
fileData = new byte[file.Length];
file.Read(fileData, 0, fileData.Length);
}
return new Acumatica.File[1] { new Acumatica.File() { Name = url.Substring(url.LastIndexOf('\\') + 1), Content = fileData } };
}
}
}
Additional documentation : http://asiablog.acumatica.com/2016/02/contract-based-web-services-api.html
Related
Suppose I have thousands of files in Azure blob Storage and I want to get one page at a time (it is not good idea to load entire pages). But I couldn't get any idea how to proceed.
I tried like this : List blobs with Azure Storage client libraries.
This is my code :
public async Task<BlobPageDto> GetBlobPageAsync
(string containerName, int? segmentSize, string? continuationToken)
{
var blobPage = new BlobPageDto();
try
{
BlobClient? blobClient = null;
var client = new BlobContainerClient(_connectionString, containerName);
await client.CreateIfNotExistsAsync();
// Call the listing operation and return pages of the specified size.
var resultSegment = client.GetBlobsAsync()
.AsPages(continuationToken, segmentSize);
await foreach (var page in resultSegment)
{
var blobItems = new List<BlobItemDto>();
foreach (var item in page.Values)
{
blobClient = client.GetBlobClient(item.Name);
string blobUrl = blobClient.Uri.ToString();
blobItems.Add(
new()
{
Name = item.Name,
Url = blobUrl
});
}
blobPage = new() { BlobItems = blobItems, ContinuationToken = page.ContinuationToken };
break; //to get one page
}
}
catch (RequestFailedException e)
{
}
return blobPage;
}
BlobItemDto.cs
public class BlobItemDto
{
public string Name { get; set; } = default!;
public string Url { get; set; } = default!;
}
BlobPageDto.cs
public class BlobPageDto
{
public IEnumerable<BlobItemDto>? BlobItems { get; set; }
public string? ContinuationToken { get; set; }
}
Update:
From above code How I can achieve the pagination like this (since by using ContinuationToken I can only move forward):
I'm using Azure Notification Hub with Firebase Cloud Messaging and Xamarin. When I have the app in the background or in use, I can receive notifications. But when I kill the app from the Android current app list, I'm able to receive one notification but after that, I have the error "my_app stopped (close the application)". Any idea why ? I don't have error log because it happens when the app is killed.
This is my code, from the documentation
using System;
using System.Collections.Generic;
using System.Text;
using Android.App;
using Android.Content;
using Android.Util;
using WindowsAzure.Messaging;
using Gcm.Client;
[assembly: Permission(Name = "#PACKAGE_NAME#.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "#PACKAGE_NAME#.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name ="com.google.android.c2dm.permission.RECEIVE")]
//GET_ACCOUNTS is needed only for Android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
namespace Waka.Droid
{
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE },
Categories = new string[] { "#PACKAGE_NAME#" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK },
Categories = new string[] { "#PACKAGE_NAME#" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY },
Categories = new string[] { "#PACKAGE_NAME#" })]
public class MyBroadcastReceiver : GcmBroadcastReceiverBase<PushHandlerService>
{
public static string[] SENDER_IDS = new string[] { Constants.SenderID };
public const string TAG = "MyBroadcastReceiver-GCM";
}
[Service] // Must use the service tag
public class PushHandlerService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
private NotificationHub Hub { get; set; }
public PushHandlerService() : base(Constants.SenderID)
{
}
protected override void OnRegistered(Context context, string registrationId)
{
RegistrationID = registrationId;
Hub = new NotificationHub(Constants.NotificationHubName, Constants.ListenConnectionString,
context);
try
{
Hub.UnregisterAll(registrationId);
}
catch (Exception ex)
{
Log.Error(MyBroadcastReceiver.TAG, ex.Message);
}
//var tags = new List<string>() { "falcons" }; // create tags if you want
var tags = new List<string>() { };
try
{
var hubRegistration = Hub.Register(registrationId, tags.ToArray());
}
catch (Exception ex)
{
Log.Error(MyBroadcastReceiver.TAG, ex.Message);
}
}
protected override void OnMessage(Context context, Intent intent)
{
var msg = new StringBuilder();
if (intent != null && intent.Extras != null)
{
foreach (var key in intent.Extras.KeySet())
msg.AppendLine(key + "=" + intent.Extras.Get(key).ToString());
}
string messageText = intent.Extras.GetString("message");
if (!string.IsNullOrEmpty(messageText))
{
createNotification("Shotgun!", messageText);
}
else
{
createNotification("Undefined", msg.ToString());
}
}
void createNotification(string title, string desc)
{
//Create notification
var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
//Create an intent to show UI
var uiIntent = new Intent(this, typeof(MainActivity));
PendingIntent resultPendingIntent =
PendingIntent.GetActivity(
this,
0,
uiIntent,
0
);
Notification noti = new Notification.Builder(this)
.SetContentTitle("" + title)
.SetContentText(desc)
.SetSmallIcon(Android.Resource.Drawable.SymActionEmail)
.SetContentIntent(resultPendingIntent)
.SetDefaults(NotificationDefaults.All)
.Build();
//Show the notification
notificationManager.Notify(1, noti);
dialogNotify(title, desc);
}
protected void dialogNotify(String title, String message)
{
MainActivity.instance.RunOnUiThread(() =>
{
AlertDialog.Builder dlg = new AlertDialog.Builder(MainActivity.instance);
AlertDialog alert = dlg.Create();
alert.SetTitle(title);
alert.SetButton("Ok", delegate
{
alert.Dismiss();
});
alert.SetMessage(message);
alert.Show();
});
}
protected override void OnUnRegistered(Context context, string registrationId)
{
}
protected override bool OnRecoverableError(Context context, string errorId)
{
return base.OnRecoverableError(context, errorId);
}
protected override void OnError(Context context, string errorId)
{
}
}
}
MainActivity.cs:
using System;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Util;
using Gcm.Client;
namespace Waka.Droid
{
[Activity(Label = "Waka.Droid", Icon = "#drawable/icon", Theme = "#style/MyTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity instance;
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
instance = this;
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
RegisterWithGCM();
}
private void RegisterWithGCM()
{
// Check to ensure everything's set up right
GcmClient.CheckDevice(this);
GcmClient.CheckManifest(this);
// Register for push notifications
GcmClient.Register(this, Constants.SenderID);
}
}
}
I have tried first time Azure push notifications, now after implementation, i'm get stuck on onMessage receive. OnMessage receive is not getting hit. App getting register successfully. I did not made any change in AndroidManifest file, I'm uploading the code. Few settings below:-
Package name:- pACKAGE_NAME
[assembly: Permission(Name = "pACKAGE_NAME.permission.C2D_MESSAGE")] [assembly: UsesPermission(Name = "pACKAGE_NAME.permission.C2D_MESSAGE")] [assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")] [assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")] [assembly: UsesPermission(Name = "android.permission.INTERNET")] [assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
namespace App1.Droid
{
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE },
Categories = new string[] { "pACKAGE_NAME" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK },
Categories = new string[] { "pACKAGE_NAME" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY },
Categories = new string[] { "pACKAGE_NAME" })]
public class MyBroadcastReceiver : GcmBroadcastReceiverBase<PushHandlerService>
{
public static string[] SENDER_IDS = new string[] { Constants.SenderID };
public const string TAG = "MyBroadcastReceiver-GCM";
}
[Service] // Must use the service tag
public class PushHandlerService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
private NotificationHub Hub { get; set; }
public PushHandlerService() : base(Constants.SenderID)
{
Log.Info(MyBroadcastReceiver.TAG, "PushHandlerService() constructor");
}
protected override void OnRegistered(Context context, string registrationId)
{
Log.Verbose(MyBroadcastReceiver.TAG, "GCM Registered: " + registrationId);
RegistrationID = registrationId;
createNotification("PushHandlerService-GCM Registered...",
"The device has been Registered!");
Hub = new NotificationHub(Constants.NotificationHubName, Constants.ListenConnectionString,
context);
try
{
Hub.UnregisterAll(registrationId);
}
catch (Exception ex)
{
Log.Error(MyBroadcastReceiver.TAG, ex.Message);
}
//var tags = new List<string>() { "falcons" }; // create tags if you want
var tags = new List<string>() { };
try
{
var hubRegistration = Hub.Register(registrationId, tags.ToArray());
}
catch (Exception ex)
{
Log.Error(MyBroadcastReceiver.TAG, ex.Message);
}
}
protected override void OnMessage(Context context, Intent intent)
{
Log.Info(MyBroadcastReceiver.TAG, "GCM Message Received!");
var msg = new StringBuilder();
if (intent != null && intent.Extras != null)
{
foreach (var key in intent.Extras.KeySet())
msg.AppendLine(key + "=" + intent.Extras.Get(key).ToString());
}
string messageText = intent.Extras.GetString("message");
if (!string.IsNullOrEmpty(messageText))
{
createNotification("New hub message!", messageText);
}
else
{
createNotification("Unknown message details", msg.ToString());
}
}
void createNotification(string title, string desc)
{
//Create notification
var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
//Create an intent to show UI
var uiIntent = new Intent(this, typeof(MainActivity));
//Create the notification
var notification = new Notification(Android.Resource.Drawable.SymActionEmail, title);
//Auto-cancel will remove the notification once the user touches it
notification.Flags = NotificationFlags.AutoCancel;
//Set the notification info
//we use the pending intent, passing our ui intent over, which will get called
//when the notification is tapped.
notification.SetLatestEventInfo(this, title, desc, PendingIntent.GetActivity(this, 0, uiIntent, 0));
//Show the notification
notificationManager.Notify(1, notification);
dialogNotify(title, desc);
}
protected void dialogNotify(String title, String message)
{
MainActivity.instance.RunOnUiThread(() => {
AlertDialog.Builder dlg = new AlertDialog.Builder(MainActivity.instance);
AlertDialog alert = dlg.Create();
alert.SetTitle(title);
alert.SetButton("Ok", delegate {
alert.Dismiss();
});
alert.SetMessage(message);
alert.Show();
});
}
protected override void OnUnRegistered(Context context, string registrationId)
{
Log.Verbose(MyBroadcastReceiver.TAG, "GCM Unregistered: " + registrationId);
createNotification("GCM Unregistered...", "The device has been unregistered!");
}
protected override bool OnRecoverableError(Context context, string errorId)
{
Log.Warn(MyBroadcastReceiver.TAG, "Recoverable Error: " + errorId);
return base.OnRecoverableError(context, errorId);
}
protected override void OnError(Context context, string errorId)
{
Log.Error(MyBroadcastReceiver.TAG, "GCM Error: " + errorId);
}
}
}
I've prepared a XAMARIN forums sample APP with Notification Hub. Here is link: https://1drv.ms/u/s!AuKd5Hvq8SOlo8Fukh4KcX6GtIoPmQ.
Compare with your code and see if you missed anything. This App uses the Xamarin.GooglePlayServices.Gcm package version 25.0.0 (instead of latest version: 29.0.0.2).
Thanks,
Sateesh
Currently my app returns data by MemoryStream, the problem is
the size of data could be large than 500MB, and that takes up much memory before return.
I am seeking for a way to return the data progressively.
For example, flush the output for every 1MB.
First I tried IPartialWriter
public class ViewRenderResult : IPartialWriter
{
public void WritePartialTo(IResponse response)
{
response.Write("XXX");
}
public bool IsPartialRequest { get { return true; } }
}
response.Write can only be called for one time.
Then I found IStreamWriter
public interface IStreamWriter
{
void WriteTo(Stream responseStream);
}
I doubt it caches all data before returining.
Please can anyone clarify it?
This previous answer shows different response types ServiceStack supports, e.g. you can just return a Stream or write to the base.Response.OutputStream directly from within your Service.
These ImageServices also shows the different ways you can write a binary response like an Image to the response stream, e.g. here's an example of using a custom IStreamWriter which lets you control how to write to the Response OutputStream:
//Your own Custom Result, writes directly to response stream
public class ImageResult : IDisposable, IStreamWriter, IHasOptions
{
private readonly Image image;
private readonly ImageFormat imgFormat;
public ImageResult(Image image, ImageFormat imgFormat = null)
{
this.image = image;
this.imgFormat = imgFormat ?? ImageFormat.Png;
this.Options = new Dictionary<string, string> {
{ HttpHeaders.ContentType, this.imgFormat.ToImageMimeType() }
};
}
public void WriteTo(Stream responseStream)
{
using (var ms = new MemoryStream())
{
image.Save(ms, imgFormat);
ms.WriteTo(responseStream);
}
}
public void Dispose()
{
this.image.Dispose();
}
public IDictionary<string, string> Options { get; set; }
}
Which you can return in your Service with:
public object Any(ImageAsCustomResult request)
{
var image = new Bitmap(100, 100);
using (var g = Graphics.FromImage(image))
{
g.Clear(request.Format.ToImageColor());
return new ImageResult(image, request.Format.ToImageFormat());
}
}
I have this base class structure:
Base:
public abstract class BackgroundTask
{
protected readonly Logger Logger = LogManager.GetCurrentClassLogger();
protected virtual void Initialize()
{
// initialize database access
}
public void Run()
{
Initialize();
try
{
Execute();
// insert to database or whatever
}
catch (Exception ex)
{
Logger.ErrorException(string.Format("Error proccesing task: {0}\r\n", ToString()), ex);
Exceptions.Add(ex);
}
finally
{
TaskExecuter.Discard();
}
}
protected abstract void Execute();
public abstract override string ToString();
public IList<Exception> Exceptions = new List<Exception>();
}
Task executor:
public static class TaskExecuter
{
private static readonly ThreadLocal<IList<BackgroundTask>> TasksToExecute
= new ThreadLocal<IList<BackgroundTask>>(() => new List<BackgroundTask>());
public static void ExecuteLater(BackgroundTask task)
{
TasksToExecute.Value.Add(task);
}
public static void StartExecuting()
{
foreach (var backgroundTask in TasksToExecute.Value)
{
Task.Factory.StartNew(backgroundTask.Run);
}
}
public static void Discard()
{
TasksToExecute.Value.Clear();
TasksToExecute.Dispose();
}
}
FileTask:
public class FileTask : BackgroundTask
{
protected static string BaseFolder = #"C:\ASCII\";
private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
private readonly string _folder;
private IHistoryRepository _historyRepository;
public string Folder
{
get { return _folder; }
}
public FileTask(string folder)
{
_folder = string.Format("{0}{1}", BaseFolder, folder);
}
protected override void Initialize()
{
_historyRepository = new HistoryRepository();
}
protected override void Execute()
{
// todo: Get institute that are active,
var institute = MockInstitute(); // todo: uncomment _historyRepository.FindInstituteByFolderName(Folder);
// todo: Update institute, lastupdate - [date] | [files amount] | [phonenumbers amount]
if (institute == null)
{
Logger.Warn("Not found data", Folder);
return;
}
// todo: read file get encoding | type and parse it
Task.Factory.StartNew(ReadFile);
}
private void ReadFile()
{
var list = GetFilesByFolder();
StreamReader sr = null;
try
{
Lock.EnterReadLock();
foreach (var fi in list)
{
var fileName = fi.FullName;
Logger.Info("Line: {0}:=> Content: {1}", fileName, Thread.CurrentThread.ManagedThreadId);
sr = new StreamReader(fileName, DetectEncoding(fileName));
string currentLine;
while ((currentLine = sr.ReadLine()).ReturnSuccess())
{
if (string.IsNullOrEmpty(currentLine)) continue;
Logger.Info("Line: {0}:=> Content: {1}", fileName, currentLine);
}
}
Lock.ExitReadLock();
}
finally
{
if (sr != null) sr.Dispose();
Logger.Info("Finished working" + Folder);
}
}
protected IEnumerable<FileInfo> GetFilesByFolder()
{
return Directory.GetFiles(Folder).Select(fileName => new FileInfo(fileName));
}
protected Encoding DetectEncoding(string file)
{
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
var cdet = new Ude.CharsetDetector();
cdet.Feed(fs);
cdet.DataEnd();
return cdet.With(x => x.Charset)
.Return(x => Encoding.GetEncoding(cdet.Charset),
Encoding.GetEncoding("windows-1255"));
}
}
private Institute MockInstitute()
{
return new Institute
{
FromFolderLocation = string.Format("{0}{1}", BaseFolder, Folder)
};
}
public override string ToString()
{
return string.Format("Folder: {0}", Folder);
}
}
When don't read the file every thing ok, the Log is populated and every thing runs smooth,
but when i attach the Task.Factory.StartNew(ReadFile); method i have an exception.
Exception:
Cannot access a disposed object.
Object name: 'The ThreadLocal object has been disposed.'.
How do i solve that issue? might i need to change the LocalThread logic, or what - i have been trying to handle that issue, for almost a day.
BTW: It's an MVC4 project, and C# 5.0 and i'm trying to TDD it all.
You shouldn't be calling TasksToExecute.Dispose();
there.