Is it possible to customize the Task & Activities pop up screen that shows when you click the Activities button on the top right of most screens in Acumatica?
We have a request to add the task owner field to the list view.
I've tried searching the source code, but I have not been able to figure out how to modify the popup.
I found this in the code, but not sure what page (if any) is linked to this.
[PXUIField(Visible = false, MapEnableRights = PXCacheRights.Select)]
[PXButton(OnClosingPopup = PXSpecialButtonType.Refresh)]
public virtual IEnumerable ViewAllActivities(PXAdapter adapter)
{
var gr = new ActivitiesMaint();
gr.Filter.Current.NoteID = ((PXCache<TActivity>)_Graph.Caches[typeof(TActivity)]).InitNewRow().RefNoteID;
throw new PXPopupRedirectException(gr, string.Empty, true);
}
The code which creates the grid and adds column definitions is in:
PX.Web.UI.PXActivityBox class (see full method below).
Unfortunately this can't be changed, it is outside the reach of customization because:
The grid is defined in C# source code instead of being declared in an ASPX file.
The grid is defined in compiled code which can't be extended, it's not in a graph.
The only workaround I can think of is to create your own action that opens ActivitiesMaint graph (EP405000). This is not the same thing as the ActivityBox and the action would have to be placed outside the main (topmost) toolbar.
private void CreateActivityGrid(WebControl div)
{
var grid = new PXGrid()
{
ID = _CONTENT_ID,
Width = Unit.Percentage(100),
AllowSearch = true,
SkinID = "Inquire",
AllowPaging = true,
MatrixMode = true
};
grid.Levels.Add(new PXGridLevel() { DataMember = "Activity" });
grid.DataMember = "Activity";
grid.ActionBar.ActionsText = ActionsTextVisible.True;
grid.ActionBar.PagerVisible = ActionVisible.False;
grid.ActionBar.DefaultAction = "cmdViewActivity";
grid.ActionBar.Position = ActionsPosition.Top;
grid.CallbackCommands.Refresh.CommitChanges = true;
grid.CallbackCommands.Refresh.PostData = PostDataMode.Page;
grid.Mode.AllowAddNew = false;
grid.Mode.AllowUpdate = false;
grid.Mode.AllowDelete = false;
grid.Mode.AllowFormEdit = false;
grid.Mode.AllowUpload = false;
grid.AutoSize.Enabled = true;
grid.Columns.Add(new PXGridColumn() { DataField = "IsCompleteIcon", Width = Unit.Pixel(21), AllowShowHide = AllowShowHide.False, ForceExport = true });
grid.Columns.Add(new PXGridColumn() { DataField = "PriorityIcon", Width = Unit.Pixel(21), AllowShowHide = AllowShowHide.False, AllowResize = false, ForceExport = true });
grid.Columns.Add(new PXGridColumn() { DataField = "ReminderIcon", Width = Unit.Pixel(21), AllowShowHide = AllowShowHide.False, AllowResize = false, ForceExport = true });
grid.Columns.Add(new PXGridColumn() { DataField = "ClassIcon", Width = Unit.Pixel(31), AllowShowHide = AllowShowHide.False, ForceExport = true });
grid.Columns.Add(new PXGridColumn() { DataField = "ClassInfo", });
grid.Columns.Add(new PXGridColumn() { DataField = "Subject", LinkCommand = "ViewActivity", Width = Unit.Pixel(297), });
grid.Columns.Add(new PXGridColumn() { DataField = "UIStatus" });
grid.Columns.Add(new PXGridColumn() { DataField = "MPStatus" });
grid.Columns.Add(new PXGridColumn() { DataField = "Released", Width = Unit.Pixel(80) });
grid.Columns.Add(new PXGridColumn() { DataField = "StartDate", Width = Unit.Pixel(120), DisplayFormat = "g" });
grid.Columns.Add(new PXGridColumn() { DataField = "CategoryID" });
div.Controls.Add(grid);
grid.ApplyStyleSheetSkin(this.Page);
_content = grid;
}
Related
I need a help with a issue in tabulator.
I have placed an fa icon to hide and particular column. The icon is placed in an header in table and on click of the icon the entire column should be hidden but i am unable to do so.
Using headerClick function i an able to hide the column but i need to have the function on the icon click not on header click in tabulator.
this is the code which is working but we need to enable click on the Fa icon not on header click.
var showHideButtonFormatter = function(cell, formatterParams, onRendered){
var btn = document.createElement("i");
btn.classList.add("pull-right","fa","fa-eye-slash","btn");
btn.setAttribute('type', 'button');
var title = document.createElement("span");
title.appendChild(btn);
var textnode = document.createTextNode(formatterParams["titleName"]);
title.appendChild(textnode);
title.style.css ="text-align:center"
$(btn).on('click', function (e) {
});
return title;
}
//PriceBreakup Table --START
var priceBreakupTablejsondata = [[${rfxForm.itemSupplierDetails}]];
if(priceBreakupTablejsondata == "{}" || priceBreakupTablejsondata == null){
priceBreakupTablejsondata = priceBreakupTablejsondata;
}else{
priceBreakupTablejsondata = JSON.parse(priceBreakupTablejsondata);
}
var columnsObjects =[]
function showAllColumns(){
columnsObjects.forEach(function(value, index, array) {
value.show();
});
}
var priceBreakupTable = new Tabulator("#priceBreakupTable", {
height:310,
data:[],
layout:"fitColumns",
placeholder:"",
columnVertAlign:"bottom",
columns:[
//{title:"#", field:"rownum ", widthGrow:1, formatter:"rownum"},
{title:"Item", field:"item", widthGrow:2, headerSort:false},
{title:"Quantity", field:"quantity", widthGrow:1, headerSort:false},
{title:"UOM", field:"uom", align:"center", widthGrow:1, headerSort:false},
],
});
//column definition in the columns array
if(priceBreakupTablejsondata!=null){
for(i=0; i<Object.keys(priceBreakupTablejsondata).length; i++){
var itemsArray = priceBreakupTablejsondata[i];
var supplierArray = itemsArray.supplierList;
for (var s = 0; s < supplierArray.length; s++) {
if (i==0) {
priceBreakupTable.addColumn(
{ title:supplierArray[s].supplierName,align:"center",
headerClick:function(e, column){
//e - the click event object
//column - column component
columnsObjects.push(column);
column.hide();
},
titleFormatter:showHideButtonFormatter, titleFormatterParams:{"titleName":supplierArray[s].supplierName},
columns:[
{title:"Unit Rate", field:"unitRate_"+s, headerSort:false, align:"center", widthGrow:2},
{title:"Tax Amount", field:"taxAmount_"+s, headerSort:false, align:"center", widthGrow:2},
{title:"Total Amount", field:"totalAmount_"+s, headerSort:false, align:"center", widthGrow:2.2},
],
}
,false);
}
}
}
}
function reformatData(itemJSON){
var output = [];
var totalSuppliers;
var headersRow = {
item: "",
quantity: "",
uom: "",
}
var itemsLength = Object.keys(itemJSON).length;
for(i=0; i < itemsLength; i++){
var row = {
item:itemJSON[i].item,
quantity:itemJSON[i].quantity,
uom:itemJSON[i].uom,
}
var supplierArray = itemJSON[i].supplierList;
for(s=0; s < itemJSON[i].supplierList.length; s++){
totalSuppliers = itemJSON[i].supplierList.length
var supplierName = supplierArray[s].supplierName;
row["unitRate_"+s] = supplierArray[s].unitRate;
row["taxAmount_"+s] = supplierArray[s].taxAmount ;
row["totalAmount_"+s] = supplierArray[s].totalAmount ;
}
output.push(row);
}
for(hid=0; hid < totalSuppliers; hid++){
headersRow["unitRate_"+hid] = "Unit Rate";
headersRow["taxAmount_"+hid] = "Tax Amt.";
headersRow["totalAmount_"+hid] = "Total Amt.";
}
//alert(JSON.stringify(headersRow));
output.unshift(headersRow)
return output;
}
if(priceBreakupTablejsondata!=null){
priceBreakupTable.setData(reformatData(priceBreakupTablejsondata));
}
//PriceBreakup Table --END
The click event listener for your btn in your header formatter should be should be:
btn.addEventListener("click", function(e){
cell.getColumn().hide();
});
I am performing CRUD operations for products of e-commerce site in kentico 10.I can add and update products using below API
SKUInfoProvider.SetSKUInfo(updateProduct);
Also there is an API for deleting product
SKUInfoProvider.DeleteSKUInfo(updateProduct);
But I do not wish to delete the product from database,rather just disable them so that they do not show up to the end users and still stay in the database .
I tried to set SKUEnabled as false but still user can see the product.So, I used below code to hide the products
ProductNode.SetValue("DocumentPublishTo", DateTime.Now.AddDays(-1));
But my code setup adds a new product with above disabled property.Here is my code
foreach (DataRow dr in dt.Rows)
{
manufacturer = GetManufacturer(Convert.ToString(dr["MANUFACTURER_NAME"]));
department = GetDepartment(Convert.ToString(dr["CATEGORY_OF_PRODUCT_1"]));
var sku = new SKUInfo
{
SKUNumber = Convert.ToString(dr["MANUFACTURER_PART_NUMBER"]),
SKUName = Convert.ToString(dr["MANUFACTURER_PART_NUMBER"]),
SKUDescription = Convert.ToString(dr["TECHNICAL_SPECIFICATIONS"]).Trim('"'),
SKUShortDescription = Convert.ToString(dr["SHORT_DESCRIPTION"]).Trim('"'),
SKUPrice = ValidationHelper.GetDouble(dr["RESELLER_BUY_INC"], 0),
SKURetailPrice = ValidationHelper.GetDouble(dr["RRP_INC"], 0),
SKUEnabled = false,
SKUSiteID = siteId,
SKUProductType = SKUProductTypeEnum.Product,
SKUManufacturerID = manufacturer.ManufacturerID,
SKUDepartmentID = department.DepartmentID,
SKUHeight = ValidationHelper.GetDouble(dr["HEIGHT"], 0),
SKUWidth = ValidationHelper.GetDouble(dr["WIDTH"], 0),
SKUWeight = ValidationHelper.GetDouble(dr["WEIGHT"], 0),
SKUDepth = ValidationHelper.GetDouble(dr["LENGTH"], 0),
SKUAvailableItems = 1,
SKUSellOnlyAvailable = true
};
try
{
SKUInfo updateProduct = SKUInfoProvider.GetSKUs()
.WhereEquals("SKUNumber", sku.SKUNumber)
.FirstObject;
sku.SKUPrice += sku.SKUPrice * 0.015;
if (updateProduct != null)
{
updateProduct.SKUNumber = sku.SKUNumber; updateProduct.SKUName = sku.SKUName;
SKUInfoProvider.SetSKUInfo(updateProduct);
}
else
{
SKUInfoProvider.SetSKUInfo(sku);
}
if (!sku.SKUEnabled)
{
SKUTreeNode productDoc = (SKUTreeNode)SKUTreeNode.New(productDocumentType.ClassName, tree);
if (sku.SKUEnabled == false)
{
productDoc.DocumentPublishTo = DateTime.Now.AddDays(-1);
}
productDoc.DocumentSKUName = Convert.ToString(dr["MANUFACTURER_PART_NUMBER"]);
productDoc.DocumentSKUDescription = sku.SKUDescription;
productDoc.NodeSKUID = sku.SKUID;
productDoc.DocumentCulture = cultureCode;
productDoc.DocumentName = Convert.ToString(dr["MANUFACTURER_PART_NUMBER"]);
}
}
catch (Exception ex)
{
error += "error";
}
}
Please provide the possible solution.There ain't no property such as DocumentPublishTo in SKUInfo,hence I used it with SKUTreeNode which you can find in code setup.
SKUTreeNode productDoc = (SKUTreeNode)SKUTreeNode.New(productDocumentType.ClassName, tree);
if (sku.SKUEnabled == false)
{
productDoc.DocumentPublishTo = DateTime.Now.AddDays(-1);
}
You need to get the node for the SKU, not create a new one. from the documentation :
SKUTreeNode productDoc = (SKUTreeNode)tree.SelectNodes()
.Path("/Products/NewProduct")
.OnCurrentSite()
.CombineWithDefaultCulture()
.FirstObject;
productDoc.DocumentPublishTo = DateTime.Now.AddDays(-1)
I need to grab the batch bill submission id (from different vendors) of the object from netsuite.Does anyone know how to do this?
TransactionSearchBasic transSearch = new TransactionSearchBasic();
SearchResult resVendorBill = service.search(transSearch);
resVendorBill.pageSize = 25;
resVendorBill.pageSizeSpecified = true;
resVendorBill.totalRecords = SearchRecentTransCount;
resVendorBill.totalRecordsSpecified = true;
transSearch.recordType = new SearchStringField() { #operator = SearchStringFieldOperator.#is, searchValue = "vendorpayment", operatorSpecified = true };
SearchResult resVendorPayment = service.search(transSearch);
if (resVendorPayment.status.isSuccess)
{
Record[] searchPaymentRecords = resVendorPayment.recordList;
if (searchPaymentRecords != null && searchPaymentRecords.Length >= 1)
{
List<VendorPayment> lstVendorPayments = searchPaymentRecords.Select(ep => (VendorPayment)ep).OrderByDescending(epo => epo.createdDate).Take(SearchRecentTransCount).ToList();
}
}
I have create a group in phaserjs
this.fruitsOutline = this.game.add.group();
After that I have added few sprites in it. Everything is working correctly. Now if want to access this.fruitsOutline, from inside of a onDragStart event handler, it is giving undefined
var GameState = {
init:function(){
this.physics.startSystem(Phaser.Physics.ARCADE);
},
create: function () {
var innerImgPos = {x:150,y:200};
var outlineImgPos = {x:460,y:200};
var FIXED_DISTANCE_Y = 150;
var gameData = [
//...some data
];
this.background = this.game.add.sprite(0, 0, 'background');
this.overlapHappen = false;
this.startPos = {x:150,y:197};
this.fruitsOutline = this.game.add.group();
this.fruitsInner = this.game.add.group();
for(var i=0; i<gameData.length; i++){
fruitOuter = this.fruitsOutline.create(outlineImgPos.x,((outlineImgPos.y+25)*i)+FIXED_DISTANCE_Y,gameData[i].fruit_outline.img);
fruitOuter.name = gameData[i].fruitName;
fruitOuter.anchor.setTo(.5);
fruitOuter.customParams = {myName:gameData[i].fruit_outline.name};
this.game.physics.arcade.enable(fruitOuter);
fruitOuter.body.setSize(100,100,50,50);
fruitInner = this.fruitsInner.create(innerImgPos.x,((innerImgPos.y+25)*i)+FIXED_DISTANCE_Y,gameData[i].fruit_inner.img);
fruitInner.name = gameData[i].fruitName;
fruitInner.anchor.setTo(0.5);
fruitInner.inputEnabled = true;
fruitInner.input.enableDrag();
fruitInner.input.pixelPerfectOver = true;
fruitInner.originalPos = {x:fruitInner.position.x,y:fruitInner.position.y};
this.game.physics.arcade.enable(fruitInner);
fruitInner.body.setSize(100,100,50,50);
fruitInner.customParams = {myName:gameData[i].fruit_inner.name,targetKey:fruitOuter,targetImg:gameData[i].fruit_outline.name};
fruitInner.events.onDragStart.add(this.onDragStart);
fruitInner.events.onDragStop.add(this.onDragStop,this);
}
},
update: function () {
},
onDragStart:function(sprite,pointer){
console.log(this.fruitsInner) //this gives undefined I expect an array
},
onDragStop:function(sprite,pointer){
var endSprite = sprite.customParams.targetKey;
console.log(endSprite);
this.stopDrag(sprite,endSprite)
},
stopDrag:function(currentSprite,endSprite){
var currentSpriteRight = currentSprite.position.x + (currentSprite.width / 2);
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
var currentSpriteTarget = currentSprite.customParams.targetImg;
var endSpriteName = endSprite.customParams.myName;
console.log(currentSpriteTarget,endSpriteName);
if(currentSpriteTarget === endSpriteName){
currentSprite.input.draggable = false;
currentSprite.position.copyFrom(endSprite.position);
currentSprite.anchor.setTo(endSprite.anchor.x, endSprite.anchor.y);
}
console.log(currentSprite.width);
})) {
//currentSprite.position.copyFrom(currentSprite.originalPosition);
currentSprite.position.x = currentSprite.originalPos.x;
currentSprite.position.y = currentSprite.originalPos.y;
}
},
render:function(){
game.debug.body(this.fruitsInner);
//game.debug.body(this.orange_outline);
}
}
You're missing the context when adding the drag callback.
Try that (adding this as the second argument):
fruitInner.events.onDragStart.add(this.onDragStart, this);
Oh, and inside the callback (or anywhere in the state) this.fruitsInner will be an instance of Phaser.Group, not an array like that comment says. The array you're looking for is probably this.fruitsInner.children.
I'm using the SuiteTalk (API) service for NetSuite to retrieve a list of Assemblies. I need to load the InventoryDetails fields on the results to view the serial/lot numbers assigned to the items. This is the current code that I'm using, but the results still show those fields to come back as NULL, although I can see the other fields for the AssemblyBuild object. How do I get the inventory details (serials/lot#'s) to return on a transaction search?
public static List<AssemblyBuildResult> Get()
{
var listAssemblyBuilds = new List<AssemblyBuildResult>();
var service = Service.Context();
var ts = new TransactionSearch();
var tsb = new TransactionSearchBasic();
var sfType = new SearchEnumMultiSelectField
{
#operator = SearchEnumMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new string[] { "_assemblyBuild" }
};
tsb.type = sfType;
ts.basic = tsb;
ts.inventoryDetailJoin = new InventoryDetailSearchBasic();
// perform the search
var response = service.search(ts);
response.pageSizeSpecified = true;
// Process response
if (response.status.isSuccess)
{
// Process the records returned in the response
// Get more records with pagination
if (response.totalRecords > 0)
{
for (var x = 1; x <= response.totalPages; x++)
{
var records = response.recordList;
foreach (var t in records)
{
var ab = (AssemblyBuild) t;
listAssemblyBuilds.Add(GetAssemblyBuildsResult(ab));
}
if (response.pageIndex < response.totalPages)
{
response = service.searchMoreWithId(response.searchId, x + 1);
}
}
}
}
// Parse and return NetSuite WorkOrder into assembly WorkOrderResult list
return listAssemblyBuilds;
}
After much pain and suffering, I was able to solve this problem with the following code:
/// <summary>
/// Returns List of AssemblyBuilds from NetSuite
/// </summary>
/// <returns></returns>
public static List<AssemblyBuildResult> Get(string id = "", bool getDetails = false)
{
// Object to populate and return results
var listAssemblyBuilds = new List<AssemblyBuildResult>();
// Initiate Service and SavedSearch (TransactionSearchAdvanced)
var service = Service.Context();
var tsa = new TransactionSearchAdvanced
{
savedSearchScriptId = "customsearch_web_assemblysearchmainlist"
};
// Filter by ID if specified
if (id != "")
{
tsa.criteria = new TransactionSearch()
{
basic = new TransactionSearchBasic()
{
internalId = new SearchMultiSelectField
{
#operator = SearchMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new[] {
new RecordRef() {
type = RecordType.assemblyBuild,
typeSpecified = true,
internalId = id
}
}
}
}
};
}
// Construct custom columns to return
var tsr = new TransactionSearchRow();
var tsrb = new TransactionSearchRowBasic();
var orderIdCols = new SearchColumnSelectField[1];
var orderIdCol = new SearchColumnSelectField();
orderIdCols[0] = orderIdCol;
tsrb.internalId = orderIdCols;
var tranDateCols = new SearchColumnDateField[1];
var tranDateCol = new SearchColumnDateField();
tranDateCols[0] = tranDateCol;
tsrb.tranDate = tranDateCols;
var serialNumberCols = new SearchColumnStringField[1];
var serialNumberCol = new SearchColumnStringField();
serialNumberCols[0] = serialNumberCol;
tsrb.serialNumbers = serialNumberCols;
// Perform the Search
tsr.basic = tsrb;
tsa.columns = tsr;
var response = service.search(tsa);
// Process response
if (response.status.isSuccess)
{
var searchRows = response.searchRowList;
if (searchRows != null && searchRows.Length >= 1)
{
foreach (SearchRow t in searchRows)
{
var transactionRow = (TransactionSearchRow)t;
listAssemblyBuilds.Add(GetAssemblyBuildsResult(transactionRow, getDetails));
}
}
}
// Parse and return NetSuite WorkOrder into assembly WorkOrderResult list
return listAssemblyBuilds;
}
private static string GetAssemblyBuildLotNumbers(string id)
{
var service = Service.Context();
var serialNumbers = "";
var tsa = new TransactionSearchAdvanced
{
savedSearchScriptId = "customsearch_web_assemblysearchlineitems"
};
service.searchPreferences = new SearchPreferences { bodyFieldsOnly = false };
tsa.criteria = new TransactionSearch()
{
basic = new TransactionSearchBasic()
{
internalId = new SearchMultiSelectField
{
#operator = SearchMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new[] {
new RecordRef() {
type = RecordType.assemblyBuild,
typeSpecified = true,
internalId = id
}
}
}
}
};
// Construct custom columns to return
var tsr = new TransactionSearchRow();
var tsrb = new TransactionSearchRowBasic();
var orderIdCols = new SearchColumnSelectField[1];
var orderIdCol = new SearchColumnSelectField();
orderIdCols[0] = orderIdCol;
tsrb.internalId = orderIdCols;
var serialNumberCols = new SearchColumnStringField[1];
var serialNumberCol = new SearchColumnStringField();
serialNumberCols[0] = serialNumberCol;
tsrb.serialNumbers = serialNumberCols;
tsr.basic = tsrb;
tsa.columns = tsr;
var response = service.search(tsa);
if (response.status.isSuccess)
{
var searchRows = response.searchRowList;
if (searchRows != null && searchRows.Length >= 1)
{
foreach (SearchRow t in searchRows)
{
var transactionRow = (TransactionSearchRow)t;
if (transactionRow.basic.serialNumbers != null)
{
return transactionRow.basic.serialNumbers[0].searchValue;
}
}
}
}
return serialNumbers;
}
private static AssemblyBuildResult GetAssemblyBuildsResult(TransactionSearchRow tsr, bool getDetails)
{
if (tsr != null)
{
var assemblyInfo = new AssemblyBuildResult
{
NetSuiteId = tsr.basic.internalId[0].searchValue.internalId,
ManufacturedDate = tsr.basic.tranDate[0].searchValue,
SerialNumbers = tsr.basic.serialNumbers[0].searchValue
};
// If selected, this will do additional NetSuite queries to get detailed data (slower)
if (getDetails)
{
// Look up Lot Number
assemblyInfo.LotNumber = GetAssemblyBuildLotNumbers(tsr.basic.internalId[0].searchValue.internalId);
}
return assemblyInfo;
}
return null;
}
What I learned about pulling data from NetSuite:
Using SavedSearches is the best method to pull data that doesn't automatically come through in the API objects
It is barely supported
Don't specify an ID on the SavedSearch, specify a criteria in the TransactionSearch to get one record
You will need to specify which columns to actually pull down. NetSuite doesn't just send you the data from a SavedSearch automatically
You cannot view data in a SavedSearch that contains a Grouping
In the Saved Search, use the Criteria Main Line = true/false to read data from the main record (top of UI screen), and line items (bottom of screen)