Marking when a SO is printed - Acumatica - acumatica

I'm interested in hooking into the print report action on a Sales Order to mark the SO "Traveler Printed" when someone has printed that particular report. Suggestions for how to accomplish this? I know it's done on the PO but I'm struggling to parse out the where and how of it.

In Customization Project Editor Code section, create a graph extension for SOOrderEntry.
Customization Project Editor has an Override Method feature that is handy for generating the event handler prototype:
You can then edit the generated stub definition like this:
namespace PX.Objects.SO
{
public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry>
{
#region Event Handlers
public delegate IEnumerable ReportDelegate(PXAdapter adapter, String reportID);
[PXOverride]
public IEnumerable Report(PXAdapter adapter, String reportID, ReportDelegate baseMethod)
{
if (reportID == "SO641010")
{
PXTrace.WriteInformation("I'm doing my things here, after report action has been invoked, just before report is actually launched.");
}
return baseMethod(adapter,reportID);
}
#endregion
}
}

Related

Create missing data on RowSelected

We have a graph extension that manages the tab we added to a screen. The tab displays data from our own DAC. We do not use a DAC extension, not going to go into the reasons right now.
When a user opens the main screen I want to create a record of our data if it does not exist, with some defaulting business logic.
I added a RowSelected event handler on the main DAC and it fires as I expect it to. When I add the code to create our missing record in the event handler Acuminator gives me error "PX1044 Changes to PXCache cannot be performed in event handlers."
I understand the error that Acuminator is raising, but I'm not sure where else to create our record. I cannot remember a section of the university specifically addressing this scenario.
Can anyone tell me how I would handle this scenario? And if possible, point me at the learning material that covers this scenario for broader information.
Unfortunatly there are only a few OK ways to do this and make Acuminator happy. You will risk data inconsistency.
https://github.com/Acumatica/Acuminator/blob/master/docs/diagnostics/PX1044.md
I would reccomend putting your data insertion code in Row Updated and hope the user updates something
I got a reply from Acumatica support, you can do this in a view select delegate.
Here's some example code, I haven't tested it though:
public class InventoryItemMaintExtension : PXGraphExtension<InventoryItemMaint>
{
public SelectFrom<MyCustomTable>.
Where<MyCustomTable.inventoryID.IsEqual<
InventoryItem.inventoryID.FromCurrent>>.
View AdditionalItemData;
public static bool IsActive() { return true; }
public IEnumerable additionalItemData()
{
var data = AdditionalItemData.SelectSingle();
if (data is null)
{
data = new MyCustomTable();
AdditionalItemData.Insert(data);
}
return AdditionalItemData.Select();
}
}
[PXCacheName("Additional Item Data")]
[Serializable]
public class MyCustomTable : IBqlTable
{
#region CashAccountID
[Inventory]
[PXDefault]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : PX.Data.BQL.BqlInt.Field<inventoryID> { }
#endregion
#region Required
[PXDBBool()]
[PXDefault(false)]
[PXUIField(DisplayName = "Required")]
public virtual bool? Required { get; set; }
public abstract class required : PX.Data.BQL.BqlBool.Field<required> { }
#endregion
}

How to customize the approval button on the Expense Claim screen

I am trying to customize the approve button and I can't find the right method to do it.
Could you tell me how I can manipulate that event.
Thanks in advance.
button to customize
Method
I looked around at the ExpenseClaimEntry, and the approval is added from the class ExpenceClaimApproval. You can browse the code through the Code Library in an extension Library under the folder App_Data\CodeRepository\PX.Objects\EP\ExpenseClaimEntry.cs. The derived type is declared in the Descriptor\Attribute.cs file. There is a StatusHandler you can set that is executed upon approval/denial.
I built this test graph and was able to break in the middle of the approval process:
public class ExpenseClaimEntry_Extension : PXGraphExtension<ExpenseClaimEntry>
{
public void CustomApprovalAction(EPExpenseClaim item)
{
//do something
}
public override void Initialize()
{
base.Initialize();
Base.Approval.StatusHandler += CustomApprovalAction;
}
}

Acumatica - Remove RowSelected Event for Service Order Screen

I would like to override the standard method of the RowSelected event on the Service Orders screen. Specifically, the DocDesc field gets populated when you select a row item for the Labor tab. It will set the TranDesc to the DocDesc and I would like to keep this from happening. I am using Acumatica 6.1 which means that the Service Management Module is not standard in Acumatica during this time. I would like the method that populates this field to not run when the labor line is populated, so the DocDesc field would remain null or blank, this way the user can input their own description.
You should be able to customize the ServiceOrderEntry graph like any other graph :
protected virtual void FSServiceOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected bs)
{
...
}
See https://help.acumatica.com/(W(3))/Main?ScreenId=ShowWiki&pageid=4a05d4c2-cd8b-4131-bf3b-d05861de3ae6
You could override the method if it is virtual, like this :
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate baseMethod)
{
...
baseMethod();
...
}
See https://help.acumatica.com/(W(3))/Main?ScreenId=ShowWiki&pageid=635c830e-4617-4d5c-9fa5-035952311aa9
You could also modify the base customization, but since you are not the owner it could get difficult to maintain and track the changes.

Adding search function to the AlternateID on the Sales Order Line Grid

I want to add a pxselector to the AlternateID field on the Sales Order Line grid to search multiple alternate id's for a single item for the customer identified on the SOHeader. I added the following code:
namespace PX.Objects.SO {
public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry> {
#region Event Handlers
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXSelector(typeof(Search<INItemXRef.alternateID,
Where<INItemXRef.inventoryID, Equal<Current<SOLine.inventoryID>>,
And<INItemXRef.bAccountID, Equal<Current<SOOrder.customerID>>>>>),
typeof(INItemXRef.alternateID),
typeof(INItemXRef.inventoryID),
typeof(INItemXRef.bAccountID)
)]
public void SOLine_AlternateID_CacheAttributeCacheAttached() {}
#endregion
}
}
I also deleted the text control from the Transactions grid and re-added it as a selector.
My selector shows up on the AlternateID field on as expected but when the selector is clicked the error "Error #107: View doesn't exist" is displayed.
This was an example Ruslan from Acumatica went over with us at Framework training last week in Ohio, but I obviously missed a step. Any help would be appreciated.
George, you put a wrong name for your event handler and that causes the error. Try replacing your handler with the code snippet below:
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXSelector(typeof(Search<INItemXRef.alternateID>),
typeof(INItemXRef.alternateID),
typeof(INItemXRef.inventoryID),
typeof(INItemXRef.bAccountID))]
public void SOLine_AlternateID_CacheAttached(PXCache sender)
{
}

Adding additional filter field on process shipments

I have added a new custom field to SOShipment and SOShipmentFilter. I am trying to use it to filter the grid for Process Shipments and I am having problems with the code. I have done other customizations where I have extended code but I was able to call the baseHandler first and then execute my snippet when it returned. However when I override the delegate function, it just sets up a template with a return to baseMethod. When I put my code in to include the new filter field, I get compile errors for undefined fields/references. Do I need to copy all of the original code from the original delegate and include it in my override function? Below is my current override code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using PX.Data;
using PX.Objects.CS;
using PX.Objects.IN;
using PX.Objects.AR;
using PX.Objects.CM;
using POReceipt = PX.Objects.PO.POReceipt;
using POReceiptLine = PX.Objects.PO.POReceiptLine;
using POLineType = PX.Objects.PO.POLineType;
using PX.Objects;
using PX.Objects.SO;
namespace PX.Objects.SO
{
public class SOInvoiceShipment_Extension:PXGraphExtension<SOInvoiceShipment>
{
#region Event Handlers
public delegate IEnumerable ordersDelegate();
[PXOverride]
public IEnumerable orders(ordersDelegate baseMethod)
{
if (filter.usrTruckNbr != null)
{
((PXSelectBase<SOShipment>)cmd).WhereAnd<Where<SOShipment.usrTruckNbr, GreaterEqual<Current<SOShipmentFilter.usrTruckNbr>>>>();
}
return baseMethod();
}
protected virtual void SOShipmentFilter_UsrTruckNbr_CacheAttached(PXCache cache)
{
}
#endregion
}
}
cmd is a location variable and you cannot access it from your extension. I see two ways you could achieve the result you want:
Copy the whole delegate function to your extension. This is not ideal because it will have to be verified and updated with every new version of Acumatica.
Filter data on the client side after it is returned from the original delegate but before it is displayed on screen. This is not as efficient as filtering on SQL but at least would remove the need to copy too much code to your extension. Here's a complete sample which will filter the list of shipments to return only documents where shipment quantity is even:
public class SOInvoiceShipment_Extension : PXGraphExtension<SOInvoiceShipment>
{
[PXFilterable]
public PXFilteredProcessing<SOShipment, SOShipmentFilter> Orders;
protected IEnumerable orders()
{
// Filter the list of shipments to return only documents where shipment quantity is even
foreach (SOShipment shipment in Base.Orders.Select())
{
if(shipment.ShipmentQty % 2 == 0)
{
yield return shipment;
}
}
}
public void SOShipmentFilter_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
if (e.Row == null) return;
SOShipmentFilter filter = e.Row as SOShipmentFilter;
if (filter != null && !string.IsNullOrEmpty(filter.Action))
{
Dictionary<string, object> parameters = Base.Filter.Cache.ToDictionary(filter);
Orders.SetProcessTarget(null, null, null, filter.Action, parameters);
}
}
}
In all cases, you should not use PXOverride to override the view delegate; the customization tools unfortunately generate the wrong method signature when you try to override a delegate, and this will be improved. You should refer to the T300 training available here for more information on this type of customization (look for "Declaring or Altering a BLC Data View Delegate).

Resources