Posts tagged with: Technical

Date Lookup in a String Control

Sometimes, you may need to lookup the date calendar in a string control. This was easily possible by overriding the lookup function and call the below method in the AX older versions.

public void lookup()
{
    ;

    this.performFormLookup(SysLookup::LookupDate());
}

But in AX2012R2 you cannot use the lookupDate function like this because it is made protected and can only be used by functions in the classes which are derived from SysLookup.

Its work around is to directly call the SysDateLookup form.

The code is as below.

public void lookup() // Form control lookup
{
    FormRun formRun;
    Args    args;
    ;

    args        = new Args(formStr(SysDateLookup));
    args.caller(element);
    formRun     = classfactory.formRunClass(args);
    formRun.init();
    this.performFormLookup(formRun);
}

Happy DAXing!


Calling table insert stops the AX service AX2012

Recently, I faced an issue when calling table insert from code. Every time I executed the statement table.insert() the service of dynamics AX2012 was stopped.

There may be two reasons of this issue.

1-      The RecIds of that particular table tables is getting duplicated, in case if you inserted the data to  that particular table from SQL and it picked the old RecId that are not generated by your current AOS.

2-      The table is not well synchronized.

In my case, synchronizing the table resolved the problem.

Happy DAXing!


Exchange Currency Service Provider

Exchange currency service provider is OOTB available in MS Dynamics AX and by default three AX provide three service exchange provider i.e. Central Bank of the Russian Federal, Central bank of Europe and Lithuanian Bank.

Following is the below screen for Exchange Rate provider which is Available in General Ledger Module

Path: General ledger /setup /Configure exchange rate providers

You must first set up the exchange rate provider you want to use, and AX 2012 R2 comes with 3 providers ready to use in General Ledger -> Setup -> Currency -> Configure Exchange Rate Providers:

fk

fk01

There is reset value option also available to restore default value.

After adding exchange rate provider run this service through batch Job exchange service as shown in below screen

Path: General ledger / Periodic / Import currency exchange rates

Import currency exchange rates batch job take Exchange rate type and exchange rate provider. If exchange rate type is not created then create it from General ledger / setup / Exchange rate type.

Prerequisite:

Before going to run Currency exchange batch job, make sure that all mentioned Exchange currency must create once in exchange rate type.

fk02

Run this batch job

fk03

After running Service provider batch job see today’s exchange currency rate in General ledger / setup / Exchange rate type.

fk04


Delete All the Transactions in a Company by keeping the Master Data intact Dynamics AX

Sometimes, you may have a requirement to delete all the transactions in a company while keeping the Master data as it is.
In order to achieve this you can duplicate the company and run SysDatabaseTransDelete class, which will delete all the transactions in the related company while keep the master data intact.

1. Press Ctrl + D.
2. Open Class node in AOT.
3. Find SysDatabaseTransDelete class, right click open, it will show the related company from which you want to delete the transactions.

transactions

Note : Before performing the above steps on production please do it in test so you can come to know what exactly you achieve.


Usage Data User Specific Report Error Dynamics AX 2012

th3Sometimes, you might face the error in which some reports like “Summary trial balance” report in general ledger will not execute.

In order to resolve this error you need to delete the related records from SysLastValue table. You cannot find this table in AOT so go to SysLastValue form, open data source node, right click and browse table data.

Filter the table with the UserId who is facing the above error, the ElementName with the related element in error and the related company name.

Delete that particular record by Alt+F9 and restart the client.

You can take the backup of the SysLastValue table if you are performing the above actions in production environment.

Note : This table contains the usage data and deleting the records unnecessarily can reset the user saved settings.

Happy DAXing!


Region as an Internal Organisation

System should allow users to create Region within the internal organization hierarchy. For this we have to do some customization

First create new operating unit type element in OMOperatingUnitType base enum

f1

OMOperatingUnitType is used in OMOperatingUnit tables so we need to Restore OMOperatingUnit tables.

Create new View which named as DimAttributeOMRegion as shown in below screen

f2

 Create Internal Region Organization type

Organization Administration > Common > Organization > Internal Organization

Create new region from Internal Organization action pane button as shown in below screen

f3

Click Ok

f4

General Ledger > Setup > Financial Dimensions > Financials Dimensions

Newly created organization should appear within Financial Dimension Form and could be used throughout AX.

f5


Customize Existing Number Sequence to Fiscal Year Number Sequence

Here we are customizing existing Number sequence and convert it in to Fiscal year number sequence Many customer demands for Purchase order creation with automatic year means how to add year to a number sequence in AX2012, e.g. to generate IDs such as 2013-xxxxx and 2014-xxxxx, that would automatically use the current year. Some people understand that number sequence scopes should allow that, but they don’t know how, from very little bit of customization we can automate purchase order number sequence with year

Customize Purchase order Number Sequence Class:

Add fiscal calendar parameter in NumberSeqModulePurchaseIOrder (LoadModule) method as shown in below screen

 datatype.addParameterType(NumberSeqParameterType::FiscalCalendarPeriod, true, true);
fk1

Load NumberSeqModulePurchaseIOrder (Load Module) method Through Job

 NumberSeqModulePurchaseOrder NumberSeqModulePurchaseOrder = new NumberSeqModulePurchaseOrder();
NumberSeqModulePurchaseOrder.load();
fk2

Before going to run the Job, Remove purchase order existing scope parameter record in NumberSequenceDatatype table, if we don’t remove previous Purchase order scope parameter record it will not effect in Segment configuration as shown below

CEU/Organization administration/Number Sequence/ Segment configuration

fk3

Add Fiscal Year Relation to PurchParamater Table:

CEU/Procurement and sourcing/procurement and Sourcing parameters

fk4

We have customized procurement and Sourcing parameters form for Purchase order Fiscal Number sequence, because we need to select which Fiscal year the purchase order is created every year.

Add fiscal year table relation to PurchParamter table

fk5

Add a fiscal year Field on Procurement and Sourcing parameters form

fk6

Customize Purchase Order Number Sequence Table (PurchParameter):

Add following code in Purchase order Number sequence Parameter table method (numRefPurchId), in this existing method we have change code according to fiscal year.

static client server NumberSequenceReference  numRefPurchId(TransDate _date = systemdateget())
{
   //
   PurchParameters PurchParameters;
   NumberSeqScope  scope;

select firstOnly PurchParameters; // get Selected fiscal year in 
                                  // procurement and    Sourcing parameters Form 

   scope = NumberSeqScopeFactory::CreateDataAreaFiscalCalendarPeriodScope
                            (curext(),FiscalCalendars::findPeriodByPeriodCodeDate(FiscalCalendar::findByCalendarId(PurchParameters.FiscalCalendar).RecId, _date).RecId);
   //

     return NumberSeqReference::findReference(extendedTypeNum(PurchId),scope);
}
fk7

Fiscal Year Number Sequence Configuration

 

General ledger -> Setup -> Fiscal calendars.

Create a new Fiscal year or use existing Fiscal year, but In our case we have created our own Fiscal year for Ten years because we need to create Purchase order automated for Ten years

fk8

If you want to add more years follow below screen.

fk9

Click the Calendar -> Calendar year -> New fiscal year button.

Change Copy from last fiscal year from ‘true’ to ‘false’.

Change Unit from ‘Months’ to ‘Years’.

Click the Create button.

Close the Fiscal calendars form.

Number sequences creation

 

fk10

 

Click Area Page node: Organization administration -> Common -> Number sequences -> Number sequences. Click the Number sequence -> New -> Number sequence button.

fk11

Change Number sequence code from ” to ‘POFiscal’.

Change Name from ” to ‘2013’.

Change Scope from ‘Shared’ to ‘Company and Fiscal calendar period’.

Change Company from ” to ‘ceu’.

Change Calendar from ” to ‘FiscalYear’.

Change Fiscal year from ” to ‘2013’.

Change Period name from ” to ‘Period 1′.

fk12

 

Make it very clear that we are creating PO number sequence for the year 2013 and we have to create PO number sequence again for Year 2014, 2015, 2016.xxxxxx 2023 with same Number sequence Code i.e. ‘POFiscal’  as shown in below screen for Year 2014

fk13

 

Creating Purchase orders:

Before going to create Purchase order make sure that Fiscal year must be selected in Procurement and sourcing Parameter form which we have customized earlier above

fk14

 

This selected Fiscal year must be same which we have selected in creating Purchase order Fiscal year Number Sequence.


Consuming External Web Service through a .Net Class Library Wrapper in Microsoft Dynamics AX 2009

Direct referencing a web service in AOT may lead to different issues some times when it comes to use service reference in the x++ code.

I will show you a simple recipe of how we can consume an external web service in AX2009 by wrapping this web service into a .net assembly wrapper.

Open a visual studio, create a new project.
Select the .net class library as template.
Give it a meaning full name so it can be accessed from x++ code.

th1

th2

Add a web service reference, I’m using a public WSDL of the currency convert.
Click Ok and build the project.
Now right click on the project and go to the project directory.
Copy the dll from bin and rename app.config file to AX32Srv.exe and AX32.exe.
Copy these files to the directory of AOS server and the bin of client if needed.
Restart the AOS.
Now you can consume this webservice from x++ code.
ServiceWrapper.ServiceReference .
If you don’t copy the config file to AOS bin you face this error because It does not read the end points from configuration file when instantiating the service client.

 System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.InvalidOperationException: Could not find default endpoint element that references contract ‘ServiceReference1.ICyclelutionService’ in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.

 at System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName)

 at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName, Configuration configuration)

 at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName)

 at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)

 at System.ServiceModel.ChannelFactory`1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress)

at System.ServiceModel.ConfigurationEndpointTrait`1.CreateSimplexFactory()

at System.ServiceModel.ConfigurationEndpointTrait`1.CreateChannelFactory()

 at System.ServiceModel.ClientBase`1.CreateChannelFactoryRef(EndpointTrait`1 endpointTrait)

 at System.ServiceModel.ClientBase`1.InitializeChannelFactoryRef()

 at System.ServiceModel.ClientBase`1..ctor()

 at ServiceRef.ServiceReference1.CyclelutionServiceClient..ctor()

— End of inner exception stack trace —

 at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)

 at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)

at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)

 at System.Activator.CreateInstance(Type type, Boolean nonPublic)

at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)

 at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)

at System.Activator.CreateInstance(Type type, Object[] args)

at Microsoft.Dynamics.AX.ManagedInterop.ClrBridgeImpl.NewClrObject(ClrBridgeImpl* , Char* pszClassName, Char* assemblyName, Int32 argsLength, ObjectWrapper** arguments, Boolean* isException

Another way to wrap the web service is to wrap it in a web service project in VS. But for that, the web service must be hosted to IIS.

 


Import ledger, AP and AR invoice journal lines

Recently, I came across a requirement in which users want to import the ledger, AP and AR invoice journal lines from a pre-defined excel format in general journal AX2012R2. So I developed a functionality hope that helps you

Below snap shot shows the flat list of all objects in this project.

t1

 Below snap shot shows the UI.

t2

Below is the list of all functions created in a class.

t3

class SLSalesPurchLedgerJourLinesImport extends RunBase
{
    int                                 row;
    int                                 col;
    LedgerJournalId                     journalNum;
    DialogRunbase                       dialog;
    DialogGroup                         dialogGrp;
    FilePath                            filePath;
    DialogField                         dialogFieldsalesPurchLedger,
                                        dialogFieldFilePath;
    SLSalesPurLedger                    salesPurLedger;

    SysExcelApplication                 application;
    SysExcelWorkbooks                   workbooks;
    SysExcelWorkbook                    workbook;
    SysExcelWorksheets                  worksheets;
    SysExcelWorksheet                   worksheet;
    SysExcelCells                       cells;
    COMVariantType                      type;
    str                                 mainAccount;
    LedgerJournalTrans                  ledgerJournalTrans;
    LedgerJournalACType                 accountType;
    LedgerDimensionAccount              ledgerDim;
    DimensionStorage                    dimensionStorage;
    DimensionServiceProvider            dimensionServiceProvider;
    LedgerAccountContract               LedgerAccountContract;
    DimensionAttributeValueContract     ValueContract;
    List                                ListValueContract;

    #DEFINE.CurrentVersion(1)
    #LOCALMACRO.CurrentList
        filePath,
        salesPurLedger
    #ENDMACRO
}

private void clearList(List _list)
{
    ListIterator iterator;
    str          value;

    iterator = new ListIterator(_list);

    while (iterator.more())
    {
        value = iterator.value();

        if (true) // check value
        {
            iterator.delete();
        }
        else
        {
            iterator.next();
        }
    }
}

str COMVariant2Str(COMVariant _cv, int _decimals = 0, int _characters = 0, int _separator1 = 0, int _separator2 = 0)
{
    switch (_cv.variantType())
    {
        case (COMVariantType::VT_BSTR):
        return _cv.bStr();

        case (COMVariantType::VT_R4):
        return num2str(_cv.float(),_characters,_decimals,_separator1,_separator2);

        case (COMVariantType::VT_R8):
        return num2str(_cv.double(),_characters,_decimals,_separator1,_separator2);

        case (COMVariantType::VT_DECIMAL):
        return num2str(_cv.decimal(),_characters,_decimals,_separator1,_separator2);

        case (COMVariantType::VT_DATE):
        return date2str(_cv.date(),123,2,1,2,1,4);

        case (COMVariantType::VT_EMPTY):
        return "";

        default:
        throw error(strfmt("@SYS26908", _cv.variantType()));
    }
    return "";
}

private void createCustInvoiceJourLines()
{
    this.initilizeExcel();

    try
    {
        ttsbegin;
        do
        {
            row++;

            ledgerJournalTrans.clear();
            ledgerJournalTrans.initValue();
            ledgerJournalTrans.JournalNum = this.parmJournalNum();
            ledgerJournalTrans.Voucher = this.generateVoucherNum();
            if(!ledgerJournalTrans.Voucher)
                throw error('Voucher number is missing.');
            ledgerJournalTrans.TransDate = cells.item(row, 1).value().date();
            ledgerJournalTrans.Invoice = this.COMVariant2Str(cells.item(row, 2).value());
            ledgerJournalTrans.Txt = this.COMVariant2Str(cells.item(row, 3).value());
            ledgerJournalTrans.AmountCurDebit = cells.item(row, 4).value().double();
            ledgerJournalTrans.AmountCurCredit = cells.item(row, 5).value().double();
            ledgerJournalTrans.AccountType = str2enum(accountType, this.COMVariant2Str(cells.item(row,6).value()));
            if(ledgerJournalTrans.AccountType != LedgerJournalACType::Cust)
            {
                throw error('The sheet does not only contain the customer invoice journal lines.');
            }
            ledgerJournalTrans.OffsetAccountType = str2enum(accountType, this.COMVariant2Str(cells.item(row,18).value()));

            ledgerDim = 0;
            ledgerDim = DimensionStorage::getDynamicAccount(this.COMVariant2Str(cells.item(row,7).value()), LedgerJournalACType::Cust);
            ledgerJournalTrans.LedgerDimension = ledgerDim;

            ledgerDim = 0;
            if(ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Cust)
            {
                ledgerDim = DimensionStorage::getDynamicAccount(this.COMVariant2Str(cells.item(row,19).value()), LedgerJournalACType::Cust);
                ledgerJournalTrans.OffsetLedgerDimension = ledgerDim;
            }

            ledgerDim = 0;
            if(ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Vend)
            {
                ledgerDim = DimensionStorage::getDynamicAccount(this.COMVariant2Str(cells.item(row,19).value()), LedgerJournalACType::Vend);
                ledgerJournalTrans.OffsetLedgerDimension = ledgerDim;
            }

            if(ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Ledger)
            {
                col = 18;
                if(!ListValueContract.empty())
                    this.clearList(ListValueContract);
                do
                {
                    col ++;

                    if(cells.item(row, col).value().bStr() == '')
                    {
                        continue;
                    }

                    ValueContract = new DimensionAttributeValueContract();
                    ValueContract.parmName(this.COMVariant2Str(cells.item(1 , col).value()));
                    ValueContract.parmValue(this.COMVariant2Str(cells.item(row , col).value()));
                    ListValueContract.addEnd(ValueContract);

                    mainAccount = this.COMVariant2Str(cells.item(1, col + 1).value());
                }
                while (mainAccount != 'MainAccount');

                ledgerAccountContract.parmMainAccount(this.COMVariant2Str(cells.item(row, col + 1).value()));
                LedgerAccountContract.parmValues(ListValueContract);

                dimensionStorage =  DimensionServiceProvider::buildDimensionStorageForLedgerAccount(LedgerAccountContract);
                ledgerJournalTrans.OffsetLedgerDimension = DimensionAttributeValueCombination::find(dimensionStorage.save()).RecId;
            }

            if(ledgerJournalTrans.validateWrite())
            {
                ledgerJournalTrans.insert();
            }

            type = cells.item(row+1, 1).value().variantType();
        }
        while (type != COMVariantType::VT_EMPTY);

        application.quit();
        ttscommit;
    }
    catch
    {
        Error('Import Failed.');
    }
}

private void createLedgerInvoiceJourLines()
{
    int     dynamicCol;
    this.initilizeExcel();

    try
    {
        ttsbegin;
        do
        {
            row++;

            ledgerJournalTrans.clear();
            ledgerJournalTrans.initValue();
            ledgerJournalTrans.JournalNum = this.parmJournalNum();
            ledgerJournalTrans.Voucher = this.generateVoucherNum();
            if(!ledgerJournalTrans.Voucher)
                throw error('Voucher number is missing.');
            ledgerJournalTrans.TransDate = cells.item(row, 1).value().date();
            ledgerJournalTrans.Invoice = this.COMVariant2Str(cells.item(row, 2).value());
            ledgerJournalTrans.Txt = this.COMVariant2Str(cells.item(row, 3).value());
            ledgerJournalTrans.AmountCurDebit = cells.item(row, 4).value().double();
            ledgerJournalTrans.AmountCurCredit = cells.item(row, 5).value().double();
            ledgerJournalTrans.AccountType = str2enum(accountType, this.COMVariant2Str(cells.item(row, 6).value()));
            if(ledgerJournalTrans.AccountType != LedgerJournalACType::Ledger)
            {
                throw error('The sheet does not contain only the ledger invoice journal lines.');
            }
            ledgerJournalTrans.OffsetAccountType = str2enum(accountType, this.COMVariant2Str(cells.item(row, 18).value()));

            ledgerDim = 0;

            col = 6;
            mainAccount = '';
            if(!ListValueContract.empty())
                this.clearList(ListValueContract);
            do
            {
                col ++;

                if(cells.item(row, col).value().bStr() == '')
                {
                    continue;
                }

                ValueContract = new DimensionAttributeValueContract();
                ValueContract.parmName(this.COMVariant2Str(cells.item(1 , col).value()));
                ValueContract.parmValue(this.COMVariant2Str(cells.item(row , col).value()));
                ListValueContract.addEnd(ValueContract);

                mainAccount = this.COMVariant2Str(cells.item(1 , col + 1).value());
            }
            while (mainAccount != 'MainAccount');

            dynamicCol = col + 9;
            ledgerAccountContract.parmMainAccount(this.COMVariant2Str(cells.item(row, col + 1).value()));
            LedgerAccountContract.parmValues(ListValueContract);

            dimensionStorage =  DimensionServiceProvider::buildDimensionStorageForLedgerAccount(LedgerAccountContract);
            ledgerJournalTrans.LedgerDimension = DimensionAttributeValueCombination::find(dimensionStorage.save()).RecId;

            ledgerDim = 0;
            if(ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Cust)
            {
                ledgerDim = DimensionStorage::getDynamicAccount(this.COMVariant2Str(cells.item(row,18).value()), LedgerJournalACType::Cust);
                ledgerJournalTrans.OffsetLedgerDimension = ledgerDim;
            }

            ledgerDim = 0;
            if(ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Vend)
            {
                ledgerDim = DimensionStorage::getDynamicAccount(this.COMVariant2Str(cells.item(row,18).value()), LedgerJournalACType::Vend);
                ledgerJournalTrans.OffsetLedgerDimension = ledgerDim;
            }

            if(ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Ledger)
            {
                col = dynamicCol;
                mainAccount = '';
                if(!ListValueContract.empty())
                    this.clearList(ListValueContract);
                do
                {
                    col ++;
                    if(cells.item(row, col).value().bStr() == '')
                    {
                        continue;
                    }
                    ValueContract = new DimensionAttributeValueContract();
                    ValueContract.parmName(this.COMVariant2Str(cells.item(1 , col).value()));
                    ValueContract.parmValue(this.COMVariant2Str(cells.item(row , col).value()));
                    ListValueContract.addEnd(ValueContract);

                    mainAccount = this.COMVariant2Str(cells.item(1, col + 1).value());
                }
                while (mainAccount != 'MainAccount');

                ledgerAccountContract.parmMainAccount(this.COMVariant2Str(cells.item(row, col + 1).value()));
                LedgerAccountContract.parmValues(ListValueContract);

                dimensionStorage =  DimensionServiceProvider::buildDimensionStorageForLedgerAccount(LedgerAccountContract);
                ledgerJournalTrans.OffsetLedgerDimension = DimensionAttributeValueCombination::find(dimensionStorage.save()).RecId;
            }

            if(ledgerJournalTrans.validateWrite())
            {
                ledgerJournalTrans.insert();
            }

            type = cells.item(row + 1, 1).value().variantType();
        }
        while (type != COMVariantType::VT_EMPTY);

        application.quit();
        ttscommit;
    }
    catch
    {
        Error('Import Failed.');
    }
}

private void createVendInvoiceJourLines()
{
    this.initilizeExcel();

    try
    {
        ttsbegin;
        do
        {
            row++;

            ledgerJournalTrans.clear();
            ledgerJournalTrans.initValue();
            ledgerJournalTrans.JournalNum = this.parmJournalNum();
            ledgerJournalTrans.Voucher = this.generateVoucherNum();
            if(!ledgerJournalTrans.Voucher)
                throw error('Voucher number is missing.');
            ledgerJournalTrans.TransDate = cells.item(row, 1).value().date();
            ledgerJournalTrans.Invoice = this.COMVariant2Str(cells.item(row, 2).value());
            ledgerJournalTrans.Txt = this.COMVariant2Str(cells.item(row, 3).value());
            ledgerJournalTrans.AmountCurDebit = cells.item(row, 4).value().double();
            ledgerJournalTrans.AmountCurCredit = cells.item(row, 5).value().double();
            ledgerJournalTrans.AccountType = str2enum(accountType, this.COMVariant2Str(cells.item(row,6).value()));
            if(ledgerJournalTrans.AccountType != LedgerJournalACType::Vend)
            {
                throw error('The sheet does not contain only the vendor invoice journal lines.');
            }
            ledgerJournalTrans.OffsetAccountType = str2enum(accountType, this.COMVariant2Str(cells.item(row,18).value()));

            ledgerDim = 0;

            ledgerDim = DimensionStorage::getDynamicAccount(this.COMVariant2Str(cells.item(row,7).value()), LedgerJournalACType::Vend);
            ledgerJournalTrans.LedgerDimension = ledgerDim;

            ledgerDim = 0;
            if(ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Cust)
            {
                ledgerDim = DimensionStorage::getDynamicAccount(this.COMVariant2Str(cells.item(row,19).value()), LedgerJournalACType::Cust);
                ledgerJournalTrans.OffsetLedgerDimension = ledgerDim;
            }

            if(ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Vend)
            {
                ledgerDim = DimensionStorage::getDynamicAccount(this.COMVariant2Str(cells.item(row,19).value()), LedgerJournalACType::Vend);
                ledgerJournalTrans.OffsetLedgerDimension = ledgerDim;
            }

            if(ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Ledger)
            {
                col = 18;
                if(!ListValueContract.empty())
                    this.clearList(ListValueContract);
                do
                {
                    col ++;

                    if(cells.item(row, col).value().bStr() == '')
                    {
                        continue;
                    }

                    ValueContract = new DimensionAttributeValueContract();
                    ValueContract.parmName(this.COMVariant2Str(cells.item(1 , col).value()));
                    ValueContract.parmValue(this.COMVariant2Str(cells.item(row , col).value()));
                    ListValueContract.addEnd(ValueContract);

                    mainAccount = this.COMVariant2Str(cells.item(1, col + 1).value());
                }
                while (mainAccount != 'MainAccount');

                ledgerAccountContract.parmMainAccount(this.COMVariant2Str(cells.item(row, col + 1).value()));
                LedgerAccountContract.parmValues(ListValueContract);

                dimensionStorage =  DimensionServiceProvider::buildDimensionStorageForLedgerAccount(LedgerAccountContract);
                ledgerJournalTrans.OffsetLedgerDimension = DimensionAttributeValueCombination::find(dimensionStorage.save()).RecId;
            }

            if(ledgerJournalTrans.validateWrite())
            {
                ledgerJournalTrans.insert();
            }

            type = cells.item(row+1, 1).value().variantType();
        }
        while (type != COMVariantType::VT_EMPTY);

        application.quit();
        ttscommit;
    }
    catch
    {
        Error('Upload Failed.');
    }
}

public Object dialog()
{
    FormBuildControl    setupGroupControl;
    FormRun             formRun;
    #Excel
    dialog = super();

    dialog.alwaysOnTop(true);
    dialog.windowType(FormWindowType::Standard);
    dialogGrp = dialog.addGroup('Import journal lines');
    dialogFieldFilePath = dialog.addFieldValue(extendedTypeStr(FilenameOpen), filePath,  "File path",    "");
    dialog.filenameLookupFilter(["@SYS28576",#XLSX]);
    dialog.filenameLookupTitle("Upload from EXCEL");

    dialogFieldsalesPurchLedger = dialog.addFieldValue(extendedTypeStr(SLSalesPurLedger), salesPurLedger,  "Account Type",    "");

    return dialog;

}

private Num generateVoucherNum()
{
    LedgerJournalName   ledgerJournalName;
    NumberSeq           numberseq;
    select firstOnly ledgerJournalName
        where ledgerJournalName.JournalType == LedgerJournalType::Daily;

    return new JournalVoucherNum(JournalTableData::newTable(LedgerJournalTable::find(journalNum))).getNew(true);

}

public boolean getFromDialog()
{
    boolean ret;

    ret = super();

    salesPurLedger = dialogFieldsalesPurchLedger.value();
    filePath       = dialogFieldFilePath.value();

    return ret;
}

public boolean init()
{
    boolean ret;

    ret = super();

    row                             =    1;
    application                     =    SysExcelApplication::construct();
    workbooks                       =    application.workbooks();

    return ret;
}
private void initilizeExcel()
{
    try
    {
        workbooks.open(filePath);
    }
    catch (Exception::Error)
    {
        throw error('File cannot be opened.');
    }

    workbook            =   workbooks.item(1);
    worksheets          =   workbook.worksheets();
    worksheet           =   worksheets.itemFromNum(1);
    cells               =   worksheet.cells();
}

public void new()
{
    super();

    dimensionServiceProvider = new DimensionServiceProvider();
    LedgerAccountContract    = new LedgerAccountContract();
    ListValueContract        = new List(Types::Class);
}

container pack()
{
    return [#CurrentVersion,#CurrentList];
}

public LedgerJournalId parmJournalNum(LedgerJournalId _journalNum = journalNum)
{
    journalNum = _journalNum;

    return journalNum;
}

public void run()
{
    super();

    switch (salesPurLedger)
    {
        case SLSalesPurchLedger::Customer :
            this.createCustInvoiceJourLines();
            break;

        case SLSalesPurchLedger::Vendor :
            this.createVendInvoiceJourLines();
            break;

        case SLSalesPurchLedger::Ledger :
            this.createLedgerInvoiceJourLines();
            break;
    }

}

boolean unpack(container _packedClass)
{
    Integer     version = conpeek(_packedClass,1);

    switch (version)
    {
        case #CurrentVersion:
            [version,#CurrentList] = _packedClass;
            break;
        default :
            return false;
    }

    return true;
}

public static void main(Args args)
{
    SLSalesPurchLedgerJourLinesImport   salesPurchLedgerJourLinesImport;
    LedgerJournalTable                  ledgerJournalTable;

    if (args && args.record())
    {
        ledgerJournalTable = args.record();
        salesPurchLedgerJourLinesImport = new SLSalesPurchLedgerJourLinesImport();
        salesPurchLedgerJourLinesImport.init();
        salesPurchLedgerJourLinesImport.parmJournalNum(ledgerJournalTable.JournalNum);
        if(salesPurchLedgerJourLinesImport.prompt())
        {
            salesPurchLedgerJourLinesImport.run();
        }
    }
    else
    {
        throw error('arguments are missing');
    }
}

t4The above snap shot method must be written to the import button click event.

Now I’m going to show you the predefined excel templates these templates can accommodate up to 10 ledger dimensions for the account type ledger. Make sure that when you create the excel template the data is defined on the correct alphabetical columns and the dimension column names must be the same as the dimensions you created in the system and they should be in reverse order than you enter it in segmented entry field in the system as below.

 Customer Template

t5

Ledger Template

t6

Vendor Template

t7

 


Find All AOT Object Layers

Sometimes you might need to know the total objects on different layers in AOT.

The below job that I wrote will show all the tables exist on different layers you can copy and paste it to excel from the data in the infolog after the job has been executed.

In order to know about the other objects than the tables just change “#TablesPath” macro which are available in #AOT.

static void displayAOTObjLayers(Args _args)

{

#AOT

#Properties

#define.LayerCount(16)

str                     layers;

str                     aotObjName;

int                     i, j, objectLayers;

str                     total;

TreeNode        treeNode, treeNodeInLayer;

Array               layerArray;

DictEnum        dictEnum;

UtilElements   utilElements;

TreeNode        baseTreeNode;

;

layerArray = new Array(Types::String);

dictEnum = new DictEnum(enumNum(UtilEntryLevel));

//#TablesPath is the path of tables in AOT. Look other object paths in #AOT macro.

baseTreeNode = TreeNode::findNode(#TablesPath);

treeNode = BaseTreeNode.AOTfirstChild();

while(treeNode)

{

for (i = 0; i < dictEnum.values(); i++)

{

layerArray.value(i+1, dictEnum.value2Name(i));

}

objectLayers = treeNode.applObjectLayerMask();

for (i = 0; i < #LayerCount; i++)

{

j = objectLayers;

j = j & power(2, i);

 

if (j)

{

aotObjName = TreeNode.AOTname();

layers += layerArray.value(i + 1)+’ ‘;

}

}

info(strfmt(‘%1 || %2′, aotObjName, layers));

treeNode = treeNode.AOTnextSibling();

aotObjName = ”;

layers = ”;

}

}