Does anyone know how to push a CREATE VIEW SQL statement into an Acumatica Customization Project?
I know how to do it in SQL Management Studio, but doing it through a Customization Project would be useful for Acumatica SaaS customers.
You should perform the following steps:
Create your SQL View in Management Studio (for demo purposes let me stick to a simple PositivePay view):
CREATE VIEW [dbo].[PositivePay] AS
SELECT
APPayment.RefNbr,
APPayment.ExtRefNbr,
APRegister.DocDate,
APRegister.OrigDocAmt,
CashAccount.ExtRefNbr BankAccountID
FROM APPayment
JOIN APRegister
ON APRegister.CompanyID = APPayment.CompanyID
AND APRegister.RefNbr = APPayment.RefNbr
JOIN CashAccount
ON APPayment.CashAccountID = CashAccount.AccountID
AND APPayment.CompanyID = CashAccount.CompanyID
WHERE APPayment.CompanyID = 2 AND APPayment.DocType= 'CHK'
GO
Open your customization project and click on Code, then generate new DAC based on your SQL view as shown in the screenshot below:
Define key fields for your new DAC and save changes. For PositivePay we set IsKey to true for the PXDBString attribute on top of the RefNbr field:
[PXDBString(15, IsUnicode = true, InputMask = "", IsKey = true)]
[PXUIField(DisplayName = "Ref Nbr")]
public string RefNbr { get; set; }
Click on DB Scripts, select your SQL view name in DBObject Name and put SQL script into the Custom Script control following the pattern below:
IF EXISTS
(
SELECT * FROM sys.views
WHERE name = 'PositivePay' AND schema_id = SCHEMA_ID('dbo')
)
DROP VIEW [dbo].[PositivePay]
GO
CREATE VIEW [dbo].[PositivePay] AS
SELECT
APPayment.RefNbr,
APPayment.ExtRefNbr,
APRegister.DocDate,
APRegister.OrigDocAmt,
CashAccount.ExtRefNbr BankAccountID
FROM APPayment
JOIN APRegister
ON APRegister.CompanyID = APPayment.CompanyID
AND APRegister.RefNbr = APPayment.RefNbr
JOIN CashAccount
ON APPayment.CashAccountID = CashAccount.AccountID
AND APPayment.CompanyID = CashAccount.CompanyID
WHERE APPayment.CompanyID = 2 AND APPayment.DocType= 'CHK'
GO
Related
I want to add files to salesorder line items in Acumatica using web services.
What endpoint should be used?
I want to add an image as shown in the screenshot above, using web service endpoint.
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.
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();
I have a customization to the Employee Timecard Entry screen (EP305000) which enables the Excel upload functionality into the Details tab grid. I did this by adding the attribute [PXImport(typeof(EPTimeCard))] to the 'Activities' view re-declaration in a TimeCardMaint BLC extension as follows:
[PXImport(typeof(EPTimeCard))]
[PXViewName(PX.Objects.EP.Messages.TimeCardDetail)]
public PXSelectJoin<EPTimecardDetail,
InnerJoin<CREmployee,
On<CREmployee.userID, Equal<EPTimecardDetail.ownerID>>,
LeftJoin<CRActivityLink,
On<CRActivityLink.noteID, Equal<EPTimecardDetail.refNoteID>>,
LeftJoin<CRCase,
On<CRCase.noteID, Equal<CRActivityLink.refNoteID>>,
LeftJoin<PX.Objects.AR.Customer,
On<PX.Objects.AR.Customer.bAccountID, Equal<CRCase.customerID>>,
LeftJoin<PX.Objects.EP.TimeCardMaint.ContractEx,
On<PX.Objects.EP.TimeCardMaint.ContractEx.contractID, Equal<CRCase.contractID>>,
LeftJoin<PMProject,
On<PMProject.contractID, Equal<EPTimecardDetail.projectID>>>>>>>>,
Where<CREmployee.bAccountID, Equal<Current<EPTimeCard.employeeID>>,
And<EPTimecardDetail.weekID, Equal<Current<EPTimeCard.weekId>>,
And<EPTimecardDetail.trackTime, Equal<True>,
And<EPTimecardDetail.approvalStatus, NotEqual<ActivityStatusListAttribute.canceled>,
And<Where<EPTimecardDetail.timeCardCD, IsNull, Or<EPTimecardDetail.timeCardCD, Equal<Current<EPTimeCard.timeCardCD>>>>>>>>>,
OrderBy<Asc<EPTimecardDetail.date>>> Activities;
I also set the 'AllowImport' property of the grid to 'True'. This seems to work ok, except that the 'ProjectTask' field of the upload does not allow mapping - i.e., if you go through the import process, when you get to the field mapping part, you can't map the Excel field for ProjectTask to the grid's ProjectTask. It just doesn't show up.
Would this be because the source BLC has as delegate method for 'activities' that I didn't reproduce in my extension?
What could be the reason for not allowing mapping to the ProjectTask field?
Since the ProjectTask field is disabled by default, this was solved by adding a parameter to the [ProjectTask] attribute, called "AlwaysEnabled" via the CacheAttached event, as shown below:
public class TimeCardMaint_Extension : PXGraphExtension<TimeCardMaint>
{
[PXDefault(typeof(Search<PMTask.taskID, Where<PMTask.projectID, Equal<Current<TimeCardMaint.EPTimecardDetail.projectID>>, And<PMTask.isDefault, Equal<True>>>>), PersistingCheck = PXPersistingCheck.Nothing)]
[ProjectTask(typeof(TimeCardMaint.EPTimecardDetail.projectID),
BatchModule.TA,
DisplayName = "Project Task",
BqlField = typeof(PMTimeActivity.projectTaskID),
AlwaysEnabled = true)]
protected virtual void EPTimecardDetail_ProjectTaskID_CacheAttached(PXCache cache)
{
}
Let's say that I have three database tables. Table1, Table2, Table3. I have created their DACs and their corresponding graph for each Graph1, Graph2, and Graph3.
Now I have created a screen for Graph1 which is showing data from Table1. But when a user clicks a particular Action Button in this screen, I want to save data in Tables 2 and 3. I want to insert multiple records in each table.
I don't think it makes sense to add Tables2 and Table 3 as Data Views (PXSelect properties) in Graph 1 because they will only be used when the user triggers the Action.
What's the recommended way to achieve this in Acumatica? For example, should I use PXDatabase.Update or should I create an instance of Graph2 and Graph3, call update on their Data Views and call PressSave? Also, would it be possible to wrap everything in a PXTransactionScope?
Please find below a code sample showing how to save changes in a single transaction from multiple BLC instances:
public class MyGraph1 : PXGraph<MyGraph1>
{
public PXAction<MyDAC> MultiGraphAction;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "My Magic Action")]
protected virtual void multiGraphAction()
{
using (var ts = new PXTransactionScope())
{
// To save changes made in MyGraph1
Actions.PressSave();
// To save changes in MyGraph2
var myGraph2 = PXGraph.CreateInstance<MyGraph2>();
// Place here data manipulation logic for myGraph2
myGraph2.Actions.PressSave();
// To save changes in MyGraph2
var myGraph3 = PXGraph.CreateInstance<MyGraph3>();
// Place here data manipulation logic for myGraph3
myGraph3.Actions.PressSave();
ts.Complete();
}
}
}
I am trying to set an extended field value for INRegister after I create and insert a new INKitRegister object into the KitAssemblyEntry graph. I understand that the INKitRegister, on save, has a method which creates the INRegister that is stored in the database for the kit. After the save, I have code that I want to execute that would set the extension field I added to the INRegister data table. When this code executes, I get the following error:
Error #78: Another process has updated the 'INRegister' record. Your changes will be lost.
I'm not sure why since I execute this edit after the data table entry is completed.
Here is my code:
...//Code to create component children
INKitRegister kitHeader = new INKitRegister
{
//set header fields
};
//I also have this extended field on the INKitRegister DAC
INKitRegisterExt kitHeaderExt = PXCache<INKitRegister>.GetExtension<INKitRegisterExt>(kitHeader);
kitHeaderExt.UsrWOID = CurrentDocument.Current.Id;
INTranSplit kitParentAssembly = new INTranSplit
{
//Making INTranSplit entry for kit
};
...
//Do I need to get the graph's extension? set register view? do I need to get kitHeader's inserted refNbr and forward that to function to set woid?
KitAssemblyEntry graphKAE = PXGraph.CreateInstance<KitAssemblyEntry>();
graphKAE.Document.Insert(kitHeader);
graphKAE.Document.Current.KitRevisionID = "1";
graphKAE.Actions.PressSave();
foreach (INComponentTran ch in kitChildren)
{
ch.RefNbr = kitHeader.RefNbr;
graphKAE.Components.Insert(ch);
}
graphKAE.Actions.PressSave();
//Code in which I get the newly created INRegister and set the extended field.
string refNbr = graphKAE.Document.Current.RefNbr;
INRegister reg = PXSelect<INRegister, Where<INRegister.refNbr, Equal<Required<INRegister.refNbr>>, And<INRegister.docType, Equal<Required<INRegister.docType>>>>>
.Select(this, refNbr, "P");
INRegisterExt regExt = PXCache<INRegister>.GetExtension<INRegisterExt>(reg);
regExt.UsrWOID = CurrentDocument.Current.Id;
INRegisters.Update(reg);
this.Actions.PressSave();
PXRedirectHelper.TryRedirect(graphKAE, PXRedirectHelper.WindowMode.Popup);
Any suggestions? I tried placing the code in a KitAssemblyEntry_Extension class under INKitRegister_RowPersisting and INKitRegister_RowUpdating. I've also looked into possibly executing the update when the popup window closes, but I do not know how to do that. Any help is welcome to point me in the correct direction.
That indicates the record you have is not the latest as it exists in the database. Try using PXSelectReadonly in place of PXSelect to get your INRegister (reg) object.
I assume it is the line "INRegisters.Update(reg);" then save that is failing?
I would also try to use the kit graph to update the INRegister and select the inregister. Try changing this one section...
//Code in which I get the newly created INRegister and set the extended field.
string refNbr = graphKAE.Document.Current.RefNbr;
INRegister reg = PXSelectReadOnly<INRegister,
Where<INRegister.refNbr, Equal<Required<INRegister.refNbr>>,
And<INRegister.docType, Equal<Required<INRegister.docType>>>>>
.Select(graphKAE, refNbr, "P");
INRegisterExt regExt = PXCache<INRegister>.GetExtension<INRegisterExt>(reg);
regExt.UsrWOID = CurrentDocument.Current.Id;
graphKAE.Caches[typeof(INRegister)].PersistUpdated(graphKAE.Caches[typeof(INRegister)].Update(reg));
We are working with Fast Search for Sharepoint 2010 and had some backend setup done with creating some managed properties e.g. BestBetDescription, keywords etc.
From the front-end part we are creating an application what will fetch all these properties and display in a grid.
However while querying the backend we are NOT getting these managed properties (BestBetDescription) along with other properties such as Title, URL etc.
Following is my source code:
settingsProxy = SPFarm.Local.ServiceProxies.GetValue<SearchQueryAndSiteSettingsServiceProxy>();
searchProxy = settingsProxy.ApplicationProxies.GetValue<SearchServiceApplicationProxy>("FAST Query SSA");
keywordQuery = new KeywordQuery(searchProxy);
keywordQuery.EnableFQL = true;
keywordQuery.QueryText = p;
keywordQuery.ResultsProvider = SearchProvider.FASTSearch;
keywordQuery.ResultTypes = ResultType.RelevantResults;
ResultTableCollection resultsTableCollection = keywordQuery.Execute();
ResultTable searchResultsTable = resultsTableCollection[ResultType.RelevantResults];
DataTable resultsDataTable = new DataTable();
resultsDataTable.TableName = "Results";
resultsDataTable.Load(searchResultsTable, LoadOption.OverwriteChanges);
return resultsDataTable;
The results are returned and I cannot see the Managed properties which we create in the resultDataTable.
Is there any property I missed or is this a backend issue ?
Thanks.
Hi if you are creating your custom Metadata Property then u should use this option to be selected
please check below link
http://screencast.com/t/SQdlarjhx4F
You can find this option in :
central admin:- services :- fast search :- Metadata Property :- your property
I was missing a property KeywordQuery.SelectProperties
So the code looks something like this
String[] arrSearchProperties = new String[] { "Title", "body", "url" };
KeywordQuery.SelectProperties(arrSearchProperties);
This will fetch you all the Managed Properties defined by you.