Get all columns of specific table

Today I needed to get all columns of specifict table. 

SQL which you can use for this purpose is the following:

SELECT COLUMN_NAME 'All_Columns' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='Specific table'

Screen Numbering in Acumatica

Hello everybody.

Today I want in short share screen numering in Acumatica.

Let's say we have screen number like this: xx.yy.zz.tt

in that case

yy is screen sequential number

zz is screen type: 10 - setup, 20 - Maintenance, 30 - data entry, 40 - inquiry, 50 - processing, 60 - reports.

tt is sub screen sequential number

 

Acumatica unit test

Hello readers of mine blog.

Today I want to share with everybody who wants to make unit test of Acumatica how I achieved it.

For unit testing I use NUnit. In order to start my work with Acumatica Unit testing I wrote the following class:

    [TestFixture]
    public class CATranEntryExtTest
    {
        [Test]
        public void TestAutonumber()
        {
            var gr = PXGraph.CreateInstance<CATranEntry>();
        }
    }

Now with help of Resharper let's start debugging:

And here we go, the first error message:

PX.Data.PXProviderException : Provider cannot be instantiated.

   at PX.Data.PXDatabase.get_Provider() in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Database\Provider.cs: line 388

   at PX.Data.PXDatabase.GetSlot(String key, Type[] tables) in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Database\Provider.cs: line 802

   at PX.Data.PXGraph.a(Type A_0) in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Graph\Graph.cs: line 2684

   at PX.Data.PXGraph.CreateInstance(Type graphType) in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Graph\Graph.cs: line 112

   at PX.Data.PXGraph.CreateInstance() in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Graph\Graph.cs: line 57

So, it means we need to add some connection string to the site.  How to add it exactly? What proper way? I tried two next options:

1.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <remove name="ProjectX" />
    <add name="ProjectX" providerName="System.Data.SqlClient" connectionString="Data Source=DIO222\DIO195;Initial Catalog=Ac20140117;Integrated Security=False;User ID=sa;Password=1234" />
  </connectionStrings>
</configuration>



This way also:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionString value="Data Source=DIO222\DIO195;Initial Catalog=Ac20140117;Integrated Security=False;User ID=sa;Password=1234"></connectionString>
</configuration>

and if you suppose, that error message changed, you are wrong. It didn't go away.

Then I addressed support of Acumatica, and here is the answer:

 you just need this config. That is not necessary to create and use real database. You just need connectionString specified.

In case if with answer you know how to add connectionString to app.config for unit test and it will work, let me congratulate you. For me you are genious. Sadly to admit, I'm not. After a while, I decided to do crazy idea - copy/paste web.config into App.config. Imagine scale of my surprise when I noticed, that error went away!!!!!!

Now I got the next error message:

PX.Data.PXNotLoggedInException : You are not currently logged in.

Do you have any idea how to log in? 

In order to understand this idea lets go to Login.aspx.cs, maybe we can locate there something. For example method NormalLogin:

    private void NormalLogin(string[] companies)
    {
        if (companies != null && companies.Length == 1)
        {
            cmbCompany.Items.Clear();
            cmbCompany.Items.Add(companies[0]);
        }

        string loginText = txtUser.Text.Trim();
        string userName = PXDatabase.Companies.Length > 0 ? loginText + "@" +
            (cmbCompany.SelectedIndex != -1 ? cmbCompany.SelectedItem.Value : PXDatabase.Companies[0]) : loginText;

        if (!PXLogin.LoginUser(ref userName, txtPass.Text))
        {
            // we will change password during next round-trip
            PXContext.Session.SetString("ChangingPassword", txtPass.Text);

            DisablingUserPassword();
            EnablingChangingPassword();

            this.Master.Message = string.Empty;
        }
        else
        {
            PXLogin.InitUserEnvironment(userName, cmbLang.SelectedValue);
        }
    }

I'm considered about mehtod PXLogin.LoginUser. Lets use reflector in order to look there:

 

using (PXLoginScope pxLoginScope = new PXLoginScope(userName, new string[0]))using (PXLoginScope pxLoginScope = new PXLoginScope(userName, new string[0]))

I just think what can mean PXLoginScope. But maybe name is self-explanatory. Some scope where some login considered as working?

Lets write code similar to what reflector showed:

[Test]
public void TestAutonumber()
{
     using (var pxLoginScope = new PXLoginScope("someuserName", new string[0]))
     {
          var gr = PXGraph.CreateInstance<CATranEntry>();
     }
}

and now error message is 

PX.Data.PXUndefinedCompanyException : Unable determine proper company id for the request.

At least we can see, that error message changes during our thinking process :). 

All other conclusions were built on this code:

        MembershipUser membershipUser = (MembershipUser) null;
        try
        {
          if (Membership.ValidateUser(pxLoginScope.UserName, password))
          {
            membershipUser = Membership.GetUser(pxLoginScope.UserName);
            if (membershipUser != null)
            {
              pxLoginScope.UserName = membershipUser.UserName;
              userName = PXContext.PXIdentity.User.Identity.Name;
              if (pxLoginScope.CompanyName != null)
              {
                string[] rolesForUser = System.Web.Security.Roles.GetRolesForUser(pxLoginScope.UserName);
                if (rolesForUser == null || rolesForUser.Length == 0)
                  throw new PXException("You are not allowed to login to the company {0}.", new object[1]
                  {
                    (object) pxLoginScope.CompanyName
                  });
                else if (!Enumerable.Contains<string>((IEnumerable<string>) PXDatabase.AvailableCompanies, pxLoginScope.CompanyName))
                  throw new PXException("You are not allowed to login to the company {0}.", new object[1]
                  {
                    (object) pxLoginScope.CompanyName
                  });
              }
              if (PXLogin.c(pxLoginScope.UserName))
                return false;
              PXLogin.a(pxLoginScope.UserName, false);
              PXLogin.SetBranchID(pxLoginScope.UserName, pxLoginScope.CompanyName, pxLoginScope.Branch);
              PXSessionContextFactory.AuthenticateRequest();
              PXLicenseHelper.OnAuthenticate();
              return true;
            }

The function which has name a if to trust to reflector just updates some info in audit journal, and updates some info in db, which IMHO is not usable for unit test.

So, code, which I use now for initiating Unit test now looks like this:

    [TestFixture]
    public class CATranEntryExtTest
    {
        [Test]
        public void TestAutonumber()
        {
            string userName = "some user name in db";
            using (var pxLoginScope = new PXLoginScope(userName, new string[0]))
            {
                var membershipUser = (MembershipUser) null;
                // Membership.ValidateUser(pxLoginScope.UserName, "123");

                membershipUser = Membership.GetUser(pxLoginScope.UserName);
                if (membershipUser != null)
                {
                    pxLoginScope.UserName = membershipUser.UserName;
                    userName = PXContext.PXIdentity.User.Identity.Name;
                    if (pxLoginScope.CompanyName != null)
                    {
                        string[] rolesForUser = System.Web.Security.Roles.GetRolesForUser(pxLoginScope.UserName);
                        if (rolesForUser == null || rolesForUser.Length == 0)
                            throw new PXException("You are not allowed to login to the company {0}.", new object[1]
                                {
                                    (object) pxLoginScope.CompanyName
                                });
                        else if (
                            !Enumerable.Contains<string>((IEnumerable<string>) PXDatabase.AvailableCompanies,
                                                         pxLoginScope.CompanyName))
                            throw new PXException("You are not allowed to login to the company {0}.", new object[1]
                                {
                                    (object) pxLoginScope.CompanyName
                                });
                    }
                    PXLogin.SetBranchID(pxLoginScope.UserName, pxLoginScope.CompanyName, pxLoginScope.Branch);
                    var gr = PXGraph.CreateInstance<CATranEntry>();
                }
            }
          }
    }

At the end of execution gr looks like this:

Lets continue our way of unit testing for creating instance of our extension. This can be achieved via following way:

var accountsManager = gr.GetExtension<CATranEntryExt>();

Screenshot shows that we created instance of extension successfully:

Now I can test methods, which are inside of the extension CATranEntryExt.

I think it's enough for this article. If you have any comments, requests, wishes, critics, you are wormly welcome to express them.

Acumatica security

Hello,

this post is dedicated to understanding how security in Acumatica works. If to be precisive security of accounts. 

Let's say you need in some way filter accounts for some user according to configuration at row level security screen ( GL104000 ).

In my case I had following records in database which correspondent to the following numbers:

Relation group mask : 16; 0; 0; 0

User group mask: 159; 96; 0; 0

Account group mask: 16; 0; 0; 0

How to join them? They are joined not by separated table, which has relations between groups and accounts or groups and users, but with usage of bit mask. It's very effective way to join and is much faster then holding adta in db. But the most complicated from viewpoint of understanding. Lets convert already mentioned numbers into bit masks:

Relation group mask :

00010000; 00000000; 00000000; 00000000

User group mask:

10011111; 11000000; 00000000; 00000000

Account group mask:

00010000; 00000000; 00000000; 00000000

From the bit mask you can notice that there is common bit between first byte in Account group mask and User group mask. Also there is common bit between "User group mask" and Relation group mask which means that user belongs to the group, and account belongs to the group. In order to work with them I wrote the following code:

 public List<Account> GetAvailableCashAccounts()
 {
     var result = new List<Account>();
     var userID = PXAccess.GetUserID();
     var user = GetUsers().First(u => u.PKID == userID);
     var allAccounts = GetAccounts();
     var groups = GetGroups();
     foreach (var account in allAccounts)
     {
           foreach (var relationGroup in groups)
           {
             for (var i = 0; i < relationGroup.GroupMask.Length && i < account.GroupMask.Length; i++)
               {
                  if ((relationGroup.GroupMask[i] & account.GroupMask[i]) == 0) continue;
                  if ((account.GroupMask[i] & user.GroupMask[i]) == 0 || result.Find(a => a.AccountCD.Equals(account.AccountCD)) != null) continue;
                  result.Add(account);
                 }
             }
       }
       return result;
}

As usually all your comments are welcomed, considered, premoderated, banned :)

Autonumbering in Acumatica second way

In one of my previous posts I described how to add autonumbering to acumatica. Described method will work pretty well, if you don't have any pop-ups which also need to have autonumbering. In case if you have such pop-ups, then it is different story.

My next assignment on the job was to add autonumbering to the screen "Fund Transfers" which is marked as "CA301000" to the field Document ref at three places:

There is a saying, that one image is better then thousands of words :).

Here is example of my code for OutExtRefNbr:

        protected void CATransfer_OutExtRefNbr_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
        {
            var row = e.Row as CATransfer;
            if (row == null)
                return;
            var refNbr = "001224";
            e.NewValue = refNbr;
        }

 

If you have a question why on earth code below needed:

                   var row = e.Row as "Class for which we will provide extension";

                   if( row == null )

                      return;

the answer is simple: because Acumatica for some unknown reason calls method FieldDefaulting and for mysterious reason passes into e.Row null. If you have any idea why, you are welcome to share them. I don't have and just used workaround ( don't say it to my boss ).

 

The second part of my task was to add some value to pop-up window. That can be done via the following template:

public class "Class Extention name" : PXGraphExtension<"Class for which we will provide extension">

{

      protected void "Class for which we will provide extension"_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)

      {

             Base.AddFilter.Current."Field in pop-up" = "some default value";

            Base.AddFilter.Update(Base.AddFilter.Current);

       }

"Field in pop-up" you can find also in Design mode of Acumatica forms.

Here is fragment of my source code for changes:

protected void CATransfer_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
     Base.AddFilter.Current.ExtRefNbr = "0012224";
     Base.AddFilter.Update(Base.AddFilter.Current);
}

In case if you have any comments, ideas don't hesitate to share them via comments line.

There is a saying, that one image is better then thousands of words :).

Here is example of my code for OutExtRefNbr:

        protected void CATransfer_OutExtRefNbr_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
        {
            var row = e.Row as CATransfer;
            if (row == null)
                return;
            var refNbr = "001224";
            e.NewValue = refNbr;
        }

 

If you have a question why on earth code below needed:

                   var row = e.Row as "Class for which we will provide extension";

                   if( row == null )

                      return;

the answer is simple: because Acumatica for some unknown reason calls method FieldDefaulting and for mysterious reason passes into e.Row null. If you have any idea why, you are welcome to share them. I don't have and just used workaround ( don't say it to my boss ).

 

The second part of my task was to add some value to pop-up window. That can be done via the following template:

public class "Class Extention name" : PXGraphExtension<"Class for which we will provide extension">

{

protected void "Class for which we will provide extension"_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
      Base.AddFilter.Current."Field in pop-up" = "some default value";
      Base.AddFilter.Update(Base.AddFilter.Current);
}

"Field in pop-up" you can find also in Design mode of Acumatica forms.

Here is fragment of my source code for changes:

protected void CATransfer_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
     Base.AddFilter.Current.ExtRefNbr = "0012224";
     Base.AddFilter.Update(Base.AddFilter.Current);
}

In case if you have any comments, ideas don't hesitate to share them via comments line.

 

Copy entry types via web services in Acumatica from one instance into another

Hello everybody.

Today I want to share how to copy Entty Types items in acumaticca from one instance into another instance.

The first step was to create import export settings in both instances of acumatica as described in acumatica manual similar to this screenshot:

The second step was to create project, which I decided to make as windows forms application with the following input fields: