'Add Files to Salesorder line item

I want to add files to salesorder line items in Acumatica using web services. What endpoint should be used? enter image description here

I want to add an image as shown in the screenshot above, using web service endpoint.



Solution 1:[1]

REST API needs to reference the detail line in the body. Since the body is used to pass the binary data of the attachment REST API can't be used to attach files to detail line.

Below is a screen based API snippet that creates a new master/detail document and attach images to the detail line. If you choose to use the screen based API you will need to adapt the snippet for sales order ASMX screen and fetch sales order with expanded details SOLine. The pattern to attach file will be the same:

string[] detailDescription = "Test";
List<string> filenames = "image.jpg";
List<byte[]> images = new byte[] { put_image_binary_data_here } ;

ServiceReference1.Screen context = new ServiceReference1.Screen();
context.CookieContainer = new System.Net.CookieContainer();
context.Url = "http://localhost/Demo/Soap/XYZ.asmx";
context.Login("admin@CompanyLoginName", "admin");

ServiceReference1.XY999999Content content = PX.Soap.Helper.GetSchema<ServiceReference1.XY999999Content>(context);

List<ServiceReference1.Command> cmds = new List<ServiceReference1.Command>
{
    // Insert Master
    new ServiceReference1.Value { Value="<NEW>", LinkedCommand = content.Document.KeyField},
    new ServiceReference1.Value { Value="Description", LinkedCommand = content.Document.Description},

    // Insert Detail
    content.DataView.ServiceCommands.NewRow,
        new ServiceReference1.Value { Value = noteDetail[0], LinkedCommand = content.DataView.Description },

    // Attaching a file to detail
    new ServiceReference1.Value
    {
        Value = Convert.ToBase64String(images[0]),
        FieldName = filenames[0],
        LinkedCommand = content.DataView.ServiceCommands.Attachment
    },
    content.Actions.Save,
    content.Document.KeyField
};

var returnValue = context.PP301001Submit(cmds.ToArray());
context.Logout();

Solution 2:[2]

This is an old question, but I just came across this same issue while assisting a customer with a third-party integration. The third-party developers were adamant that they could only use the REST service, as they had already built the rest of their integration around it before realizing they couldn't attach files to sales order lines.

I was able to build a workaround using a customization. The issue at hand is that the way Acumatica's REST API attaches files is only accessible for Top-Level entities - which means there has to be a screen that uses the object as a primary DAC.

The workaround is to do just that, create a new custom screen that uses the SOLine object as it's primary DAC. In order to make the selectors available, I had to remove and replace a couple attributes on the key fields so that they could be visible and enabled. Here is the graph code - it's very simple, as this is basically just the bare minimum needed to be able to create a custom endpoint that uses the SOLine DAC as a top-level entity.

public class SOLineAttachmentEntry : PXGraph<SOLineAttachmentEntry, SOLine>
{
    public PXSelect<SOLine> SOLineDetail;
    
    [PXMergeAttributes(Method = MergeMethod.Append)]
    [PXRemoveBaseAttribute(typeof(PXUIFieldAttribute))]
    [PXUIField(DisplayName = "Order Type", Visible=true, Enabled = true)]
    protected virtual void SOLine_OrderType_CacheAttached(PXCache sender) { }
      
    [PXMergeAttributes(Method = MergeMethod.Append)]
    [PXRemoveBaseAttribute(typeof(PXUIFieldAttribute))]
    [PXUIField(DisplayName = "Order Nbr", Visible=true, Enabled = true)]
    protected virtual void SOLine_OrderNbr_CacheAttached(PXCache sender) { }
      
    [PXMergeAttributes(Method = MergeMethod.Append)]
    [PXRemoveBaseAttribute(typeof(PXUIFieldAttribute))]
    [PXRemoveBaseAttribute(typeof(PXLineNbrAttribute))]
    [PXUIField(DisplayName = "Line Nbr", Visible=true, Enabled = true)]
    protected virtual void SOLine_LineNbr_CacheAttached(PXCache sender) { }      

}

The custom screen layout should be a simple Form with just these three key fields, OrderType, OrderNbr, LineNbr. In the Screen Editor of the customization, you'll want to set CommitChanges=true in the Layout Properties tab for each field.

Once the screen is published, you can use it to create a new custom endpoint and add a single entity by selecting the SOLine view from the custom screen. I named the endpoint "SalesOrderDetailAttach", assigned the endpoint version to be 1.0, and named the new entity "SalesOrderDetail". Using those names, the file attachment request should be a PUT request with the binary file data in the request body, using the url format:

[AcumaticaBaseUrl]/entity/SalesOrderDetailAttach/1.0/SalesOrderDetail/[OrderType]/[OrderNbr]/[LineNbr]/files/[Desired filename in Acumatica]

This worked for this one very specific case, attaching a file to the SOLine object. The screen and the endpoint should really never be used for anything else, and the custom screen should not be accessible to any users other than the administrator and the API user. Ultimately I would recommend using the Screen-Based method from the other answer, but if using the REST API is an absolute must-have, this is a potential workaround.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Bob Voorheis