GRID => Properties
"Export Label" => "SalesReportMexico"
To get download file with custom naming.
Blog on Microsoft Dynamics AX/ D365
GRID => Properties
"Export Label" => "SalesReportMexico"
To get download file with custom naming.
validateExistCommonRecord(
RefTableId _refTableId,
RefRecId _refRecId)
{
boolean ret = true;
if (!_refTableId || !_refRecId)
{
ret = CheckFailed(strFmt("Incorrect parameter for the function called ", funcName()));
}
if (ret)
{
Common record = new DictTable(_refTableId).makeRecord();
select firstonly RecId from record
where record.RecId == _refRecId;
if (!record.RecId)
{
ret = checkFailed("Record not found");
}
}
return ret;
}
Content copied from AI.
Azure
Function Apps provide a serverless, event-driven compute service that lets
you run code in languages like C#, Python, JavaScript, and Java without
managing infrastructure. They scale automatically, offering a cost-effective
"pay-per-use" model suitable for processing data, integrating
systems, and building APIs.
Key
Aspects:
Prerequisites:
Azure Functions => Trigger types (Most commonly used triggers)
//Get or adjust tax calculation using TAXDOCUMENT framework (Tax calculation service)
TaxRegulation taxRegulationDetail;
TmpTaxRegulation tmpTaxRegulationDetail;
SalesTotals salesTotals;
salesTotals = SalesTotals::construct(SalesTable::find(salesLineParentPOl.SalesId), SalesUpdate::All);
salesTotals.calc();
taxRegulationDetail = TaxRegulation::newTaxRegulation(salesTotals.tax());
tmpTaxRegulationDetail.setTmpData(taxRegulationDetail.tmpTaxRegulation()); // Get all current tax by order wise
//Get this buffer "tmpTaxRegulationDetail" to get all tax related data
//To adjust
TaxTable taxTable;
select firstonly tmpTaxRegulationDetail
where tmpTaxRegulationDetail.TaxCode
join taxTable
where taxTable.TaxCode == 'SAN_IPI';
if(tmpTaxRegulationDetail)
{
taxRegulationDetail.updateTaxRegulationAmount(tmpTaxRegulationDetail, (<Updated tax amount after adjustment>), true); // to adjust use this call to do
taxRegulationDetail.saveTaxRegulation(); //
}
--Vendor default primary address
Select vt.AccountNum, vt.Party, vt.RecId, lpd.RECID, dpl.LOCATION, lpd.ADDRESS from VENDTABLE vt
join DirPartyLocation dpl on dpl.Party = vt.Party
join LogisticsPostalAddress lpd on dpl.LOCATION = lpd.LOCATION
where vt.DataAreaId = 'usrt' and dpl.ISPRIMARY =1 and lpd.VALIDTO = '2154-12-31 23:59:59.000'
--Warehouse default primary address
Select it.InventLocationId, it.INVENTSITEID, it.RecId, lpd.RECID, lpd.ADDRESS
from INVENTLOCATION it
join InventLocationLogisticsLocation illl on illl.INVENTLOCATION = it.RECID
join LogisticsPostalAddress lpd on lpd.LOCATION = illl.LOCATION
where it.DataAreaId = 'usrt' --and dpl.ISPRIMARY =1
and illl.IsPostalAddress =1 and illl.IsPrimary =1 and lpd.VALIDTO = '2154-12-31 23:59:59.000'
WMS Mobile app flow
=> Adding Detour fields for Process guided framework custom implementation
Before fix:
Adding code fix to get thos requires field.
/// <summary>
/// WHS APP FLOW Detour fields implementation SAN_WHSMobileAppFlowPOLMovementLPCreation
/// Run Create Default setup from Mobile device steps
/// </summary>
[WHSWorkExecuteMode(WHSWorkExecuteMode::SAN_MovementLP)]
class SAN_WHSMobileAppFlowPOLMovementLPCreation extends WHSMobileAppFlow
{
protected void initValues()
{
// add available fields
this.addAvailableField(extendedTypeNum(InventSerialId));
this.addAvailableField(extendedTypeNum(WHSLicensePlateId));
this.addAvailableField(extendedTypeNum(ItemId));
}
}
Post fix:
Reference class: RetailSyncOrdersSchedulerTask
Error readable:
private str generateHumanReadableErrorDetail(System.Exception _exception, str _errorDetail = '')
{
str errorDetail, exceptionType, stackTrace, exceptionMessage;
errorDetail = _errorDetail;
// When the CLR error encounters it gets the inner exception message, call stack and stores in Database.
if (_exception && _exception.InnerException)
{
if (_exception.InnerException.InnerException && _exception.InnerException.StackTrace)
{
// Use inner exception if it is available as it is often more descriptive.
errorDetail = errorDetail ? errorDetail +
_exception.InnerException.InnerException.Message : _exception.InnerException.InnerException.Message +
_exception.InnerException.StackTrace.ToString();
}
else if (_exception.InnerException.StackTrace)
{
errorDetail = _exception.InnerException.Message + _exception.InnerException.StackTrace.ToString();
}
else
{
// When the exeption not returns a call stack, we get the call stack from the <c>Xsession<c> object.
errorDetail = _exception.InnerException.Message + con2str(xSession::xppCallStack());
}
}
return errorDetail;
}
Replaces the value of the specified dimension attribute from source to target =>
LedgerDimensionDefaultFacade::serviceReplaceAttributeValue(<source dimension>, <target dimension>, DimensionAttribute::findByName("<Dimension name>").RecId);
/// <summary>
/// To check if user can get access to the Parameter form
/// </summary>
class SAN_ParamFormsAccessCtrl
{
protected void new()
{
super();
}
static SAN_ParamFormsAccessCtrl construct()
{
return new SAN_ParamFormsAccessCtrl();
}
public boolean validateUserRoleAccess()
{
#characters
UserId userId = curUserId();
container tmpValues;
SecurityRole securityRole;
SecurityUserRole securityUserRole;
int idx;
boolean isValidated = false;
Str secRoleList;
//Created new custom parameter to have which roles alone should have EDIT access, apart from this any roles would have only READ access even System admin
secRoleList = SAN_IntegrationParameters::find().ParametersAccessSecurityRole;
if(secRoleList)
{
tmpValues = str2con(secRoleList, #semicolon);
for(idx=1; idx<=conLen(tmpValues); idx++)
{
securityRole.clear();
select firstonly securityRole
where securityRole.Name == conPeek(tmpValues, idx);
if(securityRole.RecId && !isValidated)
{
securityUserRole.clear();
select firstonly RecId from securityUserRole
where securityUserRole.User == userId
&& securityUserRole.SecurityRole == securityRole.RecId;
if (securityUserRole.RecId)
{
isValidated = true;
}
}
}
}
return isValidated;
}
public void disableFormDataSources(FormRun _callingForm)
{
FormBuildDataSource frmBuildDS;
int i;
for(i = 1; i<= _callingForm.form().dataSourceCount(); i++)
{
frmBuildDS = _callingForm.form().dataSource(i);
frmBuildDS.allowEdit(false);
}
}
public boolean checkRoleCtrlAccess(FormRun _callingForm)
{
boolean userHasAccess = this.validateUserRoleAccess();
if(!userHasAccess)
{
this.disableFormDataSources(_callingForm);
}
return userHasAccess;
}
}
[ExtensionOf(formStr(LedgerParameters))]
final class LedgerParametersFrm_SAN_Extension
{
public void init()
{
next init();
SAN_ParamFormsAccessCtrl paramFormsAccessCtrl;
paramFormsAccessCtrl = SAN_ParamFormsAccessCtrl::construct();
if(!paramFormsAccessCtrl.checkRoleCtrlAccess(this))
{
this.san_lockControls();
}
}
void san_lockControls()
{
FormBuildControl formBuildControl;
int i;
for (i=1;i<=this.form().design().controlCount(); i++)
{
formBuildControl = this.form().design().controlNum(i);
this.control(formBuildControl.id()).enabled(false);
}
}
}
Requirement:
1. Override custom dimension value on posting sales invoice
2. Ledger posting type as "Cost of goods, invoiced" & "Sales revenue"
3. Reason: Requirement is to default for certain orders type, these account has to be changed.
4. Why can't we acheive in Customer or item level dimension. [Reason: Currently it was managed in item level, but requirement is to for same item if order type met certain criteria on posting, this need to defaulted with this dimension value for ledger reporting]
Class 1:
/// <summary>
/// The <c>LedgerVoucherTransObject</c> class represents a single transaction in an individual voucher. COC
/// </summary>
/// <remarks>
/// The transaction is stored in a temporary instance of a <see cref="T:LedgerTrans" /> record buffer.
/// The temporary transaction is inserted into the database during posting and made a permanent record.
/// </remarks>
[ExtensionOf(ClassStr(LedgerVoucherTransObject))]
final class LedgerVoucherTransObjectCls_SAN_Extension
{
/// <summary>
/// Initializes a new instance of the <c>LedgerVoucherTransObject</c> class by using a transaction COC POL
/// currency amount and a ledger posting reference for defaulting.
/// </summary>
/// <param name="_defaultLedgerPostingReference">
/// The ledger posting reference to use for defaulting.
/// </param>
/// <param name="_postingType">
/// The posting type of the general journal entry.
/// </param>
/// <param name="_ledgerDimensionId">
/// The dimension attribute value combination of the general journal entry.
/// </param>
/// <param name="_transactionCurrencyCode">
/// The currency code of the general journal entry.
/// </param>
/// <param name="_transactionCurrencyAmount">
/// The amount in the transaction currency.
/// </param>
/// <param name="_exchangeRateHelper">
/// The accounting currency amount and secondary currency amount exchange rates.
/// </param>
/// <returns>
/// A new instance of the <c>LedgerVoucherTransObject</c> class.
/// </returns>
/// <remarks>
/// The default ledger posting reference is used to set the transaction type and exchange rate date.
/// </remarks>
public static LedgerVoucherTransObject newTransactionAmountDefault(
LedgerVoucherObject _defaultLedgerPostingReference,
LedgerPostingType _postingType,
LedgerDimensionAccount _ledgerDimensionId,
CurrencyCode _transactionCurrencyCode,
Money _transactionCurrencyAmount,
CurrencyExchangeHelper _exchangeRateHelper)
{
LedgerVoucherTransObject polpostingTrans;
LedgerDimensionAccount ledgerDimensionAccount, tempLedgerDimenionAcc;
ledgerDimensionAccount = _ledgerDimensionId;
if(ledgerDimensionAccount && (_postingType == LedgerPostingType::SalesConsump
|| _postingType == LedgerPostingType::SalesRevenue))
{
SAN_SalesInvoiceDimensionMockContext contextCur = SAN_SalesInvoiceDimensionMockContext::current();
if(contextCur != null)
{
if(contextCur.isParameterActive && contextCur.isValidToOverride && contextCur.polproductLineToOverride)
{
tempLedgerDimenionAcc = _ledgerDimensionId;
ledgerDimensionAccount = SalesInvoiceJournalPost::SAN_buildDefaultAndLedgerDimension(tempLedgerDimenionAcc,contextCur.polproductLineToOverride);
}
}
}
polpostingTrans = next newTransactionAmountDefault(_defaultLedgerPostingReference, _postingType, ledgerDimensionAccount, _transactionCurrencyCode, _transactionCurrencyAmount, _exchangeRateHelper);
return polpostingTrans;
}
}
Class 2:
/// <summary>
/// To hold the value of SAN_SalesInvoiceDimensionMockContext through out the runtime.
/// </summary>
class SAN_SalesInvoiceDimensionMockContext implements System.IDisposable
{
public boolean isParameterActive;
public boolean isValidToOverride;
public SalesTable polsalesTable;
public str polsmmSegmentId;
public str polproductLineToOverride;
static SAN_SalesInvoiceDimensionMockContext instance;
protected void new ()
{
if (instance)
{
throw Error('Nesting of SAN_SalesInvoiceDimensionMockContext is not supported');
}
instance = this;
}
/// <summary>
/// To Create the instance wherever the method is called during the run time.
/// </summary>
/// <returns>current new instance</returns>
Public static SAN_SalesInvoiceDimensionMockContext createInstance()
{
SAN_SalesInvoiceDimensionMockContext newInstance = new SAN_SalesInvoiceDimensionMockContext();
instance = newInstance;
return instance;
}
/// <summary>
/// Dispose the instance once the Aging snapshot batch is run.
/// </summary>
public void dispose()
{
instance = null;
}
/// <summary>
/// To get the instance wherever the method is called during the run time.
/// </summary>
/// <returns>Current instance</returns>
public static SAN_SalesInvoiceDimensionMockContext current()
{
return instance;
}
}
Class 3:
/// <summary>
/// Extension of class SalesInvoiceJournalPost
/// </summary>
[Extensionof (classstr(SalesInvoiceJournalPost))]
Public Final class SalesInvoiceJournalPostCls_SAN_Extension
{
/// <summary>
/// Posts to inventory.
/// </summary>
protected void postInventory()
{
using(SAN_SalesInvoiceDimensionMockContext contextSet = SAN_SalesInvoiceDimensionMockContext::createInstance())
{
if(SalesParameters::find().SAN_OverrideDimensionValue)
{
contextSet.isParameterActive = true;
SalesTable salesTable;
salesTable = salesLine.SalesTable();
if(salesTable && salesLine)
{
contextSet.polsalesTable = salesTable;
contextSet.isValidToOverride = true;
contextSet.polproductLineToOverride = '09';
}
}
next postInventory();
}
}
/// <summary>
/// Posts one journal line.
/// </summary>
protected void postLine()
{
using(SAN_SalesInvoiceDimensionMockContext contextSet = SAN_SalesInvoiceDimensionMockContext::createInstance())
{
if(SalesParameters::find().SAN_OverrideDimensionValue)
{
contextSet.isParameterActive = true;
SalesTable salesTable;
salesTable = salesParmLine.SalesLine().SalesTable();
if(salesTable && salesParmLine )
{
contextSet.polsalesTable = salesTable;
contextSet.isValidToOverride = true;
contextSet.polproductLineToOverride = '09';
}
}
next postLine();
}
}
/// <summary>
/// buildDefaultAndLedgerDimension for govt and non-govt segment
/// </summary>
/// <param name = "_ledger">LedgerDimensionAccount</param>
/// <param name = "_overridePL">overridePL</param>
/// <returns>ledgerDimensionAccount</returns>
Static ledgerDimensionAccount SAN_buildDefaultAndLedgerDimension(LedgerDimensionAccount _ledger, str _overridePL)
{
DimensionAttributeValueSetStorage dimensionAttributeValueSetStorage;
DimensionAttributeValue dimensionAttributeValue;
DimensionDefault dimensionDefault;
LedgerDimensionAccount ledgerDimensionAccount;
DimensionAttributeLevelValueAllView dimAttrValueallview;
dimensionAttributeValueSetStorage = new DimensionAttributeValueSetStorage();
RefRecId mainAccountRecId, LedgerDimensionAcc;
mainAccountRecId = LedgerDimensionFacade::getMainAccountRecIdFromLedgerDimension(_ledger);
LedgerDimensionAcc = LedgerDefaultAccountHelper::getDefaultAccountFromMainAccountRecId(mainAccountRecId);
while select dimAttrValueallview
where dimAttrValueallview.ValueCombinationRecId == _ledger
{
if(DimensionAttribute::find(dimAttrValueallview.DimensionAttribute).Name != "MainAccount")
{
if(DimensionAttribute::find(dimAttrValueallview.DimensionAttribute).Name == "ProductLine")
{
dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(
DimensionAttribute::find(dimAttrValueallview.DimensionAttribute),
_overridePL, false, true);
}
else
{
dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(
DimensionAttribute::find(dimAttrValueallview.DimensionAttribute),
dimAttrValueallview.DisplayValue, false, true);
}
dimensionAttributeValueSetStorage.addItem(dimensionAttributeValue);
dimensionDefault = dimensionAttributeValueSetStorage.save();
}
}
ledgerDimensionAccount = LedgerDimensionFacade::serviceCreateLedgerDimension(LedgerDimensionAcc,dimensionDefault);
return ledgerDimensionAccount;
}
}
GRID => Properties "Export Label" => "SalesReportMexico" To get download file with custom naming.