Here is an example of correct conversion between UTCDateTime value and Date and Time value which is associated with user preferred time zone: public static void testDateTimeConversion() { utcDateTime dateTime; date dateInUserTimeZone; TimeOfDay timeInUserTimeZone; dateTime = DateTimeUtil::utcNow(); dateInUserTimeZone = DateTimeUtil::date(DateTimeUtil::applyTimeZoneOffset(dateTime, DateTimeUtil::getUserPreferredTimeZone())); timeInUserTimeZone = DateTimeUtil::time(DateTimeUtil::applyTimeZoneOffset(dateTime, DateTimeUtil::getUserPreferredTimeZone())); dateTime = DateTimeUtil::newDateTime(dateInUserTimeZone, timeInUserTimeZone, DateTimeUtil::getUserPreferredTimeZone()); }
This blog is contains coding reference related to Microsoft AX 2012 and D365 finance and operations and Power platform
Friday, April 30, 2021
Conversion from UTCDateTime to Date or Time in AX
Monday, April 26, 2021
UserConnection in D365fo
Its used when we need to commit our transaction wehen standared code doesn't Commit.
example :SalesQuotationEditLinesForm_Sales_Send > checkSales() , COC and try to write
custom insert or update operation here while validation is failed our transactions doesn't commit
static void KlForRecordInserted(Args _args) { UserConnection userConnection; CustTable custTable; ; ttsbegin; userConnection = new userConnection(); custTable.clear(); custTable.initValue(); custTable.AccountNum = "000020"; custTable.Name = "My Test Customer"; custTable.setConnection(userConnection); // set userconnection custTable.insert(); throw error("An error that causes a rollback"); ttscommit; }
Saturday, April 24, 2021
Query with join with multiple data sources in AX (Inner join, not exists join)
public void initializeQueryDS() { query = new Query(); QueryBuildDataSource qbds; QueryBuildDataSource qbdsSessionLine; switch(routing) { case Routing::Sales: qbds = query.addDataSource(tableNum(SalesLine)); qbdsSessionLine = qbds.addDataSource(tableNum(WorkbenchSessionLine)); qbdsSessionLine.joinMode(JoinMode::NoExistsJoin); qbdsSessionLine.relations(true); qbdsSessionLine.fetchMode(QueryFetchMode::One2One); TblNum = tableNum(SalesLine); break; case Routing::Return: qbds = query.addDataSource(tableNum(SalesLine)); TblNum = tableNum(SalesLine); break; } } public void initializeQueryRange() { if(inventLocationId != strMin()) { QueryBuildDataSource qbdsSalesLine,qbdsInventDim; qbdsSalesLine = query.dataSourceTable(tableNum(SalesLine)); qbdsInventDim = qbdsSalesLine.addDataSource(tableNum(InventDim)); qbdsInventDim.joinMode(JoinMode::InnerJoin); qbdsInventDim.relations(true); qbdsInventDim.fetchMode(QueryFetchMode::One2One); qbdsInventDim.addRange(fieldNum(InventDim, InventLocationId)).value(inventLocationId); } if(shipDate != dateNull()) { QueryBuildDataSource qbds; qbds = query.dataSourceTable(tableNum(SalesLine)); qbds.addRange(fieldNum(SalesLine, ShippingDateConfirmed)).value(SysQuery::value(shipDate)); } if(dlvModeFrom.elements()) { container conMOD; Enumerator enumerator = dlvModeFrom.getEnumerator(); while (enumerator.moveNext()) { conMOD += enumerator.current(); } QueryBuildDataSource qbds; qbds = query.dataSourceTable(tableNum(SalesLine)); qbds.addRange(fieldNum(SalesLine, DlvMode)).value(con2Str(conMOD)); } } public WorkbenchSessionLine initFromCommon(Common _callerTable) { WorkbenchSessionLine line; switch (_callerTable.TableId) { case tableNum(SalesLine): line.RefRecId = _callerTable.(fieldNum(SalesLine, RecId)); line.RefTableId = _callerTable.TableId; line.InventTransId = _callerTable.(fieldNum(SalesLine, InventTransId)); if(routing == Routing::Sales) { line.ReferenceType = RefType::SalesOrder; } else if(routing == Routing::Return) { line.ReferenceType = RefType::ReturnOrder; } break; default: break; } return line; } public void createWorkbenchSession(WorkbenchSessionContract _contract) { WorkbenchSessionTable header; WorkbenchSessionLine line; RecordInsertList lineRecordList = new RecordInsertList(tableNum(WorkbenchSessionLine), true, true, true, false, true, line); contract = _contract; this.initializeParameters(); this.initializeQueryDS(); this.initializeQueryRange(); try { ttsbegin; NumberSeq numberSeq = NumberSeq::newGetNum(TMSParameters::numRefInternalSessionID()); header.initValue(); header.DynamicsInternalSessionID = numberSeq.num(); numberSeq.used(); header.SessionStatus = SessionStatus::Open; header.LE_ID = curExt(); if (routing == Routing::Sales || routing == Routing::Return) { header.CombineOrders = true; } header.insert(); queryRun = new QueryRun(query); while(queryRun.next()) { Common common = queryRun.get(TblNum); line = this.initFromCommon(common); line.WorkbenchSessionTable = header.RecId; lineRecordList.add(line); } lineRecordList.insertDatabase(); ttscommit; this.openWorkbenchSessionForm(header); } catch { } }
Sysoperations frameworks Tips and tricks in AX
protected ClassDescription defaultCaption() { return "@CashManagement:CashFlowTimeSeriesInitializeControllerCaption"; } public ClassDescription caption() { return this.defaultCaption(); } /// <summary> /// Indicates if the class must run in batch or not. /// </summary> /// <returns> /// Always returns false. /// </returns> /// <remarks> /// This method must be in this class because it is called from the <c>dialogRunbase</c> class. /// </remarks> public boolean mustGoBatch() { return false; } /// <summary> /// Determines whether the job can be executed in batch. /// </summary> /// <returns> /// false if the job cannot be executed in batch; otherwise, true. /// </returns> public boolean canGoBatch() { return false; } /// <summary> /// Sets whether to show the batch tab or not. /// </summary> /// <param name = "_showBatchTab">Flag to identify whether to show the batch tab or not.</param> /// <returns>False for batch tab to be invisible</returns> public boolean showBatchTab(boolean _showBatchTab = showBatchTab) { return false; } public boolean showBatchRecurrenceButton(boolean _showBatchRecurrenceButton = showBatchRecurrenceButton) { return false; }
Thursday, April 22, 2021
How to get the number of elements in the list in AX
{ List il = new List(Types::Integer); il.addStart(1); il.addStart(2); il.addStart(3); if (il.elements() != 3) { print "Something is wrong..."; } }
Friday, April 16, 2021
Data entities method calling sequence in D365FO
EXPORT: Entity- postLoad() staging - insert() Entity- postLoad() - depends on records IMPORT: staging - postLoad() Entity - postLoad() Entity - initValue() Entity - validateField() - depends on no of fields Entity - validateWrite() Entity - insert() / update() Entity - persistEntity() Entity - initializeEntityDataSource() Entity - mapEntityToDataSource() Entity - insertEntityDataSource() / updateEntityDataSource() Entity - mapDataSourceToEntity() staging - postLoad()
Tuesday, April 13, 2021
How to create a collapsible section in Blogger
Add CSS
Add a unique name for each new post eg: collapsible1 or collapsible2 etc add at the start of the HTML code after <HTML> tag <style> .collapsible { background-color: #777; color: white; cursor: pointer; padding: 18px; border: none; text-align: left; outline: none; font-size: 15px; } .active, .collapsible:hover { background-color: #555; } .content1 { padding: 0 18px; display: none; overflow: hidden; background-color: #f1f1f1; } </style>
Apply CSS to div and Paragragh
add these classes in the paragrah and the div at the start of the tag <p title="UIBuilder" class="collapsible">UIBuilder class</p> <div class="content1"></div>
Javascript
add at the end of the HTML code before </HTML> tag <script> var coll = document.getElementsByClassName("collapsible"); var i; for (i = 0; i < coll.length; i++) { coll[i].addEventListener("click", function() { this.classList.toggle("active"); var content = this.nextElementSibling; if (content.style.display === "block") { content.style.display = "none"; } else { content.style.display = "block"; } }); } </script>
How to use RecordInsertList in AX
/// <summary> /// The <c>BankCheckStubDP</c> class declares the variables and tables that are required for the /// <c>BankCheckStub</c> report. /// </summary> [ SRSReportParameterAttribute(classStr(BankCheckStubContract)) ] public class BankCheckStubDP extends SRSReportDataProviderBase { BankCheckStubTmp BankCheckStubTmp; /// <summary> /// Fetches the <c>BankCheckStubTmp</c> temporary table. /// </summary> /// <returns> /// The <c>BankCheckStubTmp</c> temporary table. /// </returns> [ SRSReportDataSetAttribute(tablestr(BankCheckStubTmp)) ] public BankCheckStubTmp getBankCheckStubTmp() { select BankCheckStubTmp; return BankCheckStubTmp; } /// <summary> /// Fetches the required data for the <c>BankCheckStub</c> report. /// </summary> public void processReport() { RecordInsertList tmpTableRecordList; BankTrans BankTrans; BankChequeTable bankChequeTable; CompanyBankAccountId curBankAccountIdGroup; BankChequeNum curChequeNumGroup; int lineNumInCheck; RefRecId SSNType; HcmIdentificationNumber BankSSN; BankCheckStubContract contract = this.parmDataContract() as BankCheckStubContract; BankChequeNum chequeNum = contract.parmChequeNum(); TransDate transDate = contract.parmChequeDate(); CompanyBankAccountId bankAccountId = contract.parmBankAccountId(); ShowSSN showSSN = contract.parmShowSSN(); tmpTableRecordList = new RecordInsertList(tableNum(BankCheckStubTmp), true, true, true, false, true, BankCheckStubTmp); SSNType = BankAccountingParameters::find().SSNIdentificationType; if (!Global::hasTableAccess(tableNum(HcmPersonIdentificationNumber)) || !Global::hasFieldAccess(tableNum(HcmPersonIdentificationNumber), fieldNum(HcmPersonIdentificationNumber, IdentificationNumber))) { showSSN = false; } while select BankTrans order by BankAccountId, BankChequeNum where (BankTrans.JournalEntryType == JournalEntryType::Refund || BankTrans.JournalEntryType == JournalEntryType::Stipend || BankTrans.JournalEntryType == JournalEntryType::SubsidiaryRefund) && BankTrans.SISPaymentType == SISPaymentType::Check && BankTrans.BankChequeNum && (!chequeNum || (chequeNum && BankTrans.BankChequeNum == chequeNum)) && (!bankAccountId || (bankAccountId && BankTrans.BankAccountId == bankAccountId)) join TransDate from bankChequeTable where bankChequeTable.AccountID == BankTrans.BankAccountId && bankChequeTable.ChequeNum == BankTrans.BankChequeNum && (!transDate || (transDate && bankChequeTable.TransDate == transDate)) { if (curBankAccountIdGroup != BankTrans.BankAccountId || curChequeNumGroup != BankTrans.BankChequeNum) { curBankAccountIdGroup = BankTrans.BankAccountId; curChequeNumGroup = BankTrans.BankChequeNum; lineNumInCheck = 1; } BankSSN = ""; if (showSSN) { BankSSN = HcmPersonIdentificationNumber::findByPersonAndType(Bank::find(BankTrans.Bank).Person, SSNType).IdentificationNumber; } BankCheckStubTmp.BankAccountId = BankTrans.BankAccountId; BankCheckStubTmp.ChequeNum = BankTrans.BankChequeNum; BankCheckStubTmp.ChequeDate = bankChequeTable.TransDate; BankCheckStubTmp.LineNum = strFmt('%1', lineNumInCheck); BankCheckStubTmp.BankId = strFmt('%1', BankTrans.BankIdInSIS); BankCheckStubTmp.BankName = BankTrans.BankName(); BankCheckStubTmp.BankSSN = BankSSN; BankCheckStubTmp.FundSource = FundSource::findByRecId(BankTrans.FundSource).Description; BankCheckStubTmp.Amount = BankTrans.AmountCur; tmpTableRecordList.add(BankCheckStubTmp); lineNumInCheck++; } tmpTableRecordList.insertDatabase(); } }
How to create RunBaseBatch class in AX : Sample code
See the code
/// <summary> /// The <c>LedgerJournalEntryPost</c> class creates and posts to general ledger transactions specified in /// the <c>LedgerJournalEntryContract</c> contract class. /// </summary> class LedgerJournalEntryPost extends RunBaseBatch { LedgerJournalEntryContract ledgerJournalEntryContract; LedgerJournalEntryPostStatusContract ledgerJournalEntryPostStatusContract; Set studentTransRecIdPostedSet; #IntegrationServiceFaults /// <summary> /// Checks if the Ledger journal can be posted or not. /// </summary> /// <param name="_ledgerJournalTable"> /// Record of the <c>LedgerJournalTable</c> table to verify. /// </param> /// <returns> /// True if Ledger journal can be posted; otherwise, false. /// </returns> protected boolean canPostLedgerJournal(LedgerJournalTable _ledgerJournalTable) { LedgerJournalTrans ledgerJournalTrans; VendPaymModeTable vendPaymModeTable; select firstOnly RecId from ledgerJournalTrans where ledgerJournalTrans.JournalNum == _ledgerJournalTable.JournalNum; if (!ledgerJournalTrans.RecId) { return false; } if (_ledgerJournalTable.JournalType == LedgerJournalType::Payment) { select firstOnly RecId from ledgerJournalTrans where ledgerJournalTrans.JournalNum == _ledgerJournalTable.JournalNum && ledgerJournalTrans.AccountType == LedgerJournalACType::Vend && ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Bank && (!ledgerJournalTrans.BankChequeNum || ledgerJournalTrans.PaymentStatus != CustVendPaymStatus::Sent) exists join vendPaymModeTable where vendPaymModeTable.PaymMode == ledgerJournalTrans.PaymMode && vendPaymModeTable.PaymentType == PaymentType::Check; if(ledgerJournalTrans.RecId) { return false; } } return true; } /// <summary> /// Creates a ledger journal for the specified ledger journal entry. /// </summary> /// <param name="_ledgerJourEntryLines"> /// List of <c>LedgerJournalEntryLineContract</c> contract classes. /// </param> /// <param name="_journalEntryType"> /// The type of the journal to create. /// </param> /// <returns> /// Created <c>LedgerJournalTable</c> table. /// </returns> protected LedgerJournalTable createJournal(List _ledgerJourEntryLines, JournalEntryType _journalEntryType) { LedgerJournalTable ledgerJournalTable; LedgerJournalCreate ledgerJournalCreate; LedgerJournalEntryContract entryContract; entryContract = new LedgerJournalEntryContract(); entryContract.parmLedgerJourEntryLines(_ledgerJourEntryLines); ledgerJournalCreate = LedgerJournalCreate::construct(entryContract, _journalEntryType); ledgerJournalCreate.run(); ledgerJournalTable = ledgerJournalCreate.parmLedgerJournalTable(); return ledgerJournalTable; } /// <summary> /// Finds or creates a ledger journal for the specified ledger journal entry. /// </summary> /// <param name="_ledgerJourEntryLines"> /// List of <c>LedgerJournalEntryLineContract</c> contract classes. /// </param> /// <param name="_journalEntryType"> /// The type of the journal entry. /// </param> /// <param name="_paymentType"> /// The payment type of the journal entry. /// </param> /// <returns> /// Found or created <c>LedgerJournalTable</c> table. /// </returns> protected LedgerJournalTable findOrCreateJournal(List _ledgerJourEntryLines, JournalEntryType _journalEntryType, SISPaymentType _paymentType) { LedgerJournalTable ledgerJournalTable; ledgerJournalTable = this.findRelatedJournal(_ledgerJourEntryLines, _journalEntryType, _paymentType); if (!ledgerJournalTable) { ledgerJournalTable = this.createJournal(_ledgerJourEntryLines, _journalEntryType); } return ledgerJournalTable; } /// <summary> /// Finds the ledger journal for the specified ledger journal entry. /// </summary> /// <param name="_ledgerJourEntryLines"> /// List of <c>LedgerJournalEntryLineContract</c> contract classes. /// </param> /// <param name="_journalEntryType"> /// The type of the journal entry. /// </param> /// <param name="_paymentType"> /// The payment type of the journal entry. /// </param> /// <returns> /// Found <c>LedgerJournalTable</c> table. /// </returns> protected LedgerJournalTable findRelatedJournal(List _ledgerJourEntryLines, JournalEntryType _journalEntryType, SISPaymentType _paymentType) { LedgerJournalEntryLineContract ledgerJournalEntryLineContract; ListEnumerator ledgerJourEntryLinesEnum; LedgerJournalTable ledgerJournalTable; if (StudentTrans::isBankChequeProcess(_journalEntryType, _paymentType)) { ledgerJourEntryLinesEnum = _ledgerJourEntryLines.getEnumerator(); while (ledgerJourEntryLinesEnum.moveNext()) { ledgerJournalEntryLineContract = ledgerJourEntryLinesEnum.current(); //if (ledgerJournalEntryLineContract.parmBankChequeNum()) //{ ledgerJournalTable = ledgerJournalTable.FindByStudentTransIdInSIS(ledgerJournalEntryLineContract.parmTransIdInSIS(), ledgerJournalEntryLineContract.parmJournalEntryType()); if (ledgerJournalTable) { return ledgerJournalTable; } //} } } return ledgerJournalTable; } /// <summary> /// Initializes the map of transaction types and transactions from /// the <c>LedgerJournalEntryContract</c> contract class. /// </summary> /// <returns> /// An instance of the map of transaction types and transactions. /// </returns> public Map getJournalEntryLinesMap() { List entryLineList; ListEnumerator ledgerJournalEntryLinesEnum; LedgerJournalEntryLineContract entryLineContract; container entryTypeKeyCon; int transGroupCounter; Map entryLinesMap = new Map(Types::Container, Types::Class); #define.TransGroupUniqueIdentifier("TransGroupUniqueIdentifier") ledgerJournalEntryLinesEnum = ledgerJournalEntryContract.parmLedgerJourEntryLines().getEnumerator(); while (ledgerJournalEntryLinesEnum.moveNext()) { entryLineContract = ledgerJournalEntryLinesEnum.current(); if (StudentTrans::isBankChequeProcess(entryLineContract.parmJournalEntryType(), entryLineContract.parmSISPaymentType()) && entryLineContract.parmMasterChequeGroup()) { entryTypeKeyCon = [entryLineContract.parmJournalEntryType(), entryLineContract.parmSISPaymentType(), entryLineContract.parmMasterChequeGroup()]; } else { transGroupCounter++; entryTypeKeyCon = [entryLineContract.parmJournalEntryType(), entryLineContract.parmSISPaymentType(), strFmt("%1%2", #TransGroupUniqueIdentifier, transGroupCounter)]; } if (!entryLinesMap.exists(entryTypeKeyCon)) { entryLineList = new List(Types::Class); entryLineList.addEnd(entryLineContract); entryLinesMap.insert(entryTypeKeyCon, entryLineList); } else { entryLineList = entryLinesMap.lookup(entryTypeKeyCon); entryLineList.addEnd(entryLineContract); entryLinesMap.insert(entryTypeKeyCon, entryLineList); } } return entryLinesMap; } /// <summary> /// Gets student transaction SIS Ids. /// </summary> /// <param name="_ledgerJourEntryLines"> /// List of <c>LedgerJournalEntryLineContract</c> contract classes. /// </param> /// <returns> /// Container of student transaction SIS Ids. /// </returns> protected container getStudentTransIds(List _ledgerJourEntryLines) { LedgerJournalEntryLineContract ledgerJournalEntryLineContract; container ret; ListEnumerator ledgerJournalEntryLinesEnum = _ledgerJourEntryLines.getEnumerator(); while (ledgerJournalEntryLinesEnum.moveNext()) { ledgerJournalEntryLineContract = ledgerJournalEntryLinesEnum.current(); ret += ledgerJournalEntryLineContract.parmTransIdInSIS(); } return ret; } /// <summary> /// Initializes <c>LedgerJournalEntryPostStatusContract</c> contract class. /// </summary> protected void initEntryPostStatusContract() { ledgerJournalEntryPostStatusContract = new LedgerJournalEntryPostStatusContract(); ledgerJournalEntryPostStatusContract.parmPostedJournals(new List(Types::String)); ledgerJournalEntryPostStatusContract.initializeMessages(); } public static void markPostedTrans(Map _postedTransMap) { new SISIntegrationServiceAdapter().sendPostedStudentTrans(_postedTransMap); } public void new() { super(); studentTransRecIdPostedSet = new Set(Types::Int64); } /// <summary> /// Gets or sets the value of the <c>LedgerJournalEntryContract</c> class parameter. /// </summary> /// <param name="_ledgerJournalEntryContract"> /// The new value of the <c>LedgerJournalEntryContract</c> class parameter; optional. /// </param> /// <returns> /// The current value of the <c>LedgerJournalEntryContract</c> class parameter. /// </returns> public LedgerJournalEntryContract parmLedgerJournalEntryContract(LedgerJournalEntryContract _ledgerJournalEntryContract = ledgerJournalEntryContract) { ledgerJournalEntryContract = _ledgerJournalEntryContract; return ledgerJournalEntryContract; } /// <summary> /// Gets or sets the value of the <c>LedgerJournalEntryPostStatusContract</c> class parameter. /// </summary> /// <param name="_ledgerJournalEntryPostStatusContract"> /// The new value of the <c>LedgerJournalEntryPostStatusContract</c> class parameter; optional. /// </param> /// <returns> /// The current value of the <c>LedgerJournalEntryPostStatusContract</c> class parameter. /// </returns> public LedgerJournalEntryPostStatusContract parmLedgerJournalEntryPostStatusContract(LedgerJournalEntryPostStatusContract _ledgerJournalEntryPostStatusContract = ledgerJournalEntryPostStatusContract) { ledgerJournalEntryPostStatusContract = _ledgerJournalEntryPostStatusContract; return ledgerJournalEntryPostStatusContract; } /// <summary> /// Gets or sets the value of the <c>studentTransRecIdPostedSet</c> parameter. /// </summary> /// <param name="_studentTransRecIdPostedSet"> /// The new value of the <c>studentTransRecIdPostedSet</c> parameter; optional. /// </param> /// <returns> /// The current value of the <c>studentTransRecIdPostedSet</c> parameter. /// </returns> public Set parmStudentTransRecIdPostedSet(Set _studentTransRecIdPostedSet = studentTransRecIdPostedSet) { studentTransRecIdPostedSet = _studentTransRecIdPostedSet; return studentTransRecIdPostedSet; } /// <summary> /// Posts the ledger journal. /// </summary> /// <param name="_ledgerJournalTable"> /// Ledger journal to post. /// </param> protected void postJournal(LedgerJournalTable _ledgerJournalTable) { LedgerJournalCheckPost ledgerJournalCheckPost; LedgerJournalTable ledgerJournalTable; if (!_ledgerJournalTable) { throw error("@1401"); } ledgerJournalCheckPost = LedgerJournalCheckPost::newLedgerJournalTable(_ledgerJournalTable, NoYes::Yes); if (this.canPostLedgerJournal(_ledgerJournalTable)) { ledgerJournalCheckPost.parmSkipBlockedForManualEntryCheck(true); ledgerJournalCheckPost.runOperation(); } ledgerJournalTable = ledgerJournalTable::find(_ledgerJournalTable.JournalNum); if (!ledgerJournalTable.Posted) { throw error("@1402"); } } /// <summary> /// Posts student transactions. /// </summary> /// <param name="_journalNum"> /// Ledger journal Id. /// </param> /// <param name="_ledgerJourEntryLines"> /// List of <c>LedgerJournalEntryLineContract</c> contract classes. /// </param> protected void postStudentTrans(LedgerJournalId _journalNum, List _ledgerJourEntryLines) { LedgerJournalEntryLineContract ledgerJournalEntryLineContract; StudentTrans studentTrans; container mapKey; ListEnumerator ledgerJournalEntryLinesEnum = _ledgerJourEntryLines.getEnumerator(); Map transLedgerJournalIdMap = new Map(Types::Container, Types::Class); Set journalNumSet = new Set(Types::String); journalNumSet.add(_journalNum); while (ledgerJournalEntryLinesEnum.moveNext()) { ledgerJournalEntryLineContract = ledgerJournalEntryLinesEnum.current(); mapKey = [ledgerJournalEntryLineContract.parmTransIdInSIS(), ledgerJournalEntryLineContract.parmJournalEntryType()]; transLedgerJournalIdMap.insert(mapKey, journalNumSet); studentTrans = StudentTrans::find(ledgerJournalEntryLineContract.parmTransIdInSIS(), ledgerJournalEntryLineContract.parmJournalEntryType(), true); studentTrans.Posted = true; if(studentTrans.SISPaymentType == SISPaymentType::Check) studentTrans.PendingChequeInSIS = false; if (!studentTrans.validateWrite()) { throw error("@SYS18447"); } studentTrans.updateSkipDatabaseLog(true); if (studentTrans.isValidForFundSourceTrans()) { if (FundSourceTrans::findByStudentTrans(studentTrans.RecId)) { FundSourceTrans::updateExist(studentTrans); } else { FundSourceTrans::create(studentTrans); } } if (StudentAccountingParameters::isCampusNexusMode()) { LedgerJournalEntryPost::markPostedTrans(transLedgerJournalIdMap); } studentTransRecIdPostedSet.add(studentTrans.RecId); } } /// <summary> /// Executes business logic of the class. /// </summary> public void run() { LedgerJournalTable ledgerJournalTable; JournalEntryType journalEntryType; SISPaymentType paymentType; AifInfoLog aifInfoLog; List ledgerJourEntryLines; Name groupName; boolean exceptionThrown; MapEnumerator entryLinesMapEnum; this.initEntryPostStatusContract(); entryLinesMapEnum = this.getJournalEntryLinesMap().getEnumerator(); while (entryLinesMapEnum.moveNext()) { [journalEntryType, paymentType, groupName] = entryLinesMapEnum.currentKey(); ledgerJourEntryLines = entryLinesMapEnum.currentValue(); aifInfoLog = new AifInfoLog(); try { ttsBegin; this.validateLedgerJourEntryLines(ledgerJourEntryLines); ledgerJournalTable = this.findOrCreateJournal(ledgerJourEntryLines, journalEntryType, paymentType); this.postJournal(ledgerJournalTable); this.postStudentTrans(ledgerJournalTable.JournalNum, ledgerJourEntryLines); ttsCommit; if (ledgerJournalTable.Posted) { ledgerJournalEntryPostStatusContract.parmPostedJournals().addEnd(ledgerJournalTable.JournalNum); } } catch (Exception::Error) { exceptionThrown = true; this.updateEntryPostStatus(aifInfoLog, LedgerJournalCreatePostStatus::Error, this.getStudentTransIds(ledgerJourEntryLines)); } catch (Exception::CLRError) { exceptionThrown = true; error(AifUtil::getClrErrorMessage()); this.updateEntryPostStatus(aifInfoLog, LedgerJournalCreatePostStatus::Error, this.getStudentTransIds(ledgerJourEntryLines)); } catch { exceptionThrown = true; this.updateEntryPostStatus(aifInfoLog, LedgerJournalCreatePostStatus::Error, this.getStudentTransIds(ledgerJourEntryLines)); } } if (!exceptionThrown && !ledgerJournalEntryPostStatusContract.parmPostedJournals().empty()) { ledgerJournalEntryPostStatusContract.parmStatus(LedgerJournalCreatePostStatus::Posted); } } /// <summary> /// Updates <c>LedgerJournalEntryPostStatusContract</c> contract class. /// </summary> /// <param name="_aifInfoLog"> /// An object of <c>AifInfoLog</c> class. /// </param> /// <param name="_postStatus"> /// Operation status. /// </param> /// <param name="_studentTransIdCon"> /// Container of student transaction SIS Ids. /// </param> protected void updateEntryPostStatus(AifInfoLog _aifInfoLog, LedgerJournalCreatePostStatus _postStatus, container _studentTransIdCon) { SysInfologEnumerator infologEnum; if (!ledgerJournalEntryPostStatusContract) { this.initEntryPostStatusContract(); } ledgerJournalEntryPostStatusContract.parmStatus(_postStatus); AifFault::fault(strFmt("@1403", "@141", con2str(_studentTransIdCon, ', ')), #LedgerJournalTableCreationFailed); infologEnum = SysInfologEnumerator::newData(_aifInfoLog.getInfoLogData()); while (infologEnum.moveNext()) { ledgerJournalEntryPostStatusContract.addMessage(IntegrationServiceProvider::trimLeadingTabs(infologEnum.currentMessage())); } } /// <summary> /// Validates ledger journal entry lines. /// </summary> /// <param name="_ledgerJourEntryLines"> /// List of <c>LedgerJournalEntryLineContract</c> contract classes. /// </param> protected void validateLedgerJourEntryLines(List _ledgerJourEntryLines) { LedgerJournalEntryLineContract ledgerJournalEntryLineContract; StudentTrans studentTrans; ListEnumerator ledgerJournalEntryLinesEnum = _ledgerJourEntryLines.getEnumerator(); while (ledgerJournalEntryLinesEnum.moveNext()) { ledgerJournalEntryLineContract = ledgerJournalEntryLinesEnum.current(); studentTrans = StudentTrans::find(ledgerJournalEntryLineContract.parmTransIdInSIS(), ledgerJournalEntryLineContract.parmJournalEntryType()); if (studentTrans.Posted) { throw error(strfmt("@1399", studentTrans.description())); } if (StudentTrans::isBankChequeProcess(studentTrans.JournalEntryType, studentTrans.SISPaymentType) && !studentTrans.BankChequeNum) { throw error(strFmt("@1400", studentTrans.description())); } } } /// <summary> /// Creates a new instance of the <c>LedgerJournalEntryPost</c> class. /// </summary> /// <param name="_ledgerJournalEntryContract"> /// Value of the <c>LedgerJournalEntryContract</c> contract class. /// </param> /// <returns> /// Created instance of the <c>LedgerJournalEntryPost</c> class. /// </returns> public static server LedgerJournalEntryPost construct(LedgerJournalEntryContract _ledgerJournalEntryContract) { LedgerJournalEntryPost ledgerJournalEntryPost = new LedgerJournalEntryPost(); ledgerJournalEntryPost.parmLedgerJournalEntryContract(_ledgerJournalEntryContract); return ledgerJournalEntryPost; } /// <summary> /// Creates an object of <c>LedgerJournalEntryContract</c> contract class. /// </summary> /// <param name="_studentTransRecIdPacked"> /// Packed set of <c>StudentTrans</c> record Ids. /// </param> /// <returns> /// An object of <c>LedgerJournalEntryContract</c> contract class. /// </returns> public static server LedgerJournalEntryContract createJournalEntryContractList(container _studentTransRecIdPacked) { StudentTrans studentTrans; StudentTrans studentTransMasterCheque; LedgerJournalEntryContract ledgerJournalEntryContract = new LedgerJournalEntryContract(); Set masterChequeGroup = new Set(Types::String); Set studentTransRecIdSet = Set::create(_studentTransRecIdPacked); SetEnumerator se = studentTransRecIdSet.getEnumerator(); ledgerJournalEntryContract.parmLedgerJourEntryLines(new List(Types::Class)); while (se.moveNext()) { studentTrans = StudentTrans::findRecId(se.current()); if (studentTrans.MasterChequeGroup && !masterChequeGroup.in(studentTrans.MasterChequeGroup)) { masterChequeGroup.add(studentTrans.MasterChequeGroup); while select studentTransMasterCheque where studentTransMasterCheque.MasterChequeGroup == studentTrans.MasterChequeGroup { ledgerJournalEntryContract.parmLedgerJourEntryLines().addEnd(studentTransMasterCheque.ledgerJournalEntryLineContract()); } } else if (!studentTrans.MasterChequeGroup) { ledgerJournalEntryContract.parmLedgerJourEntryLines().addEnd(studentTrans.ledgerJournalEntryLineContract()); } } return ledgerJournalEntryContract; } /// <summary> /// Performs transaction posting from user interface. /// </summary> /// <param name="_args"> /// Parameters object. /// </param> public static void main(Args _args) { LedgerJournalEntryPost ledgerJournalEntryPost; StudentTrans studentTrans; FormDataSource ds; Set studentTransRecIdSet = new Set(Types::Int64); if (!_args || !_args.dataset()) { throw Error(Error::wrongUseOfFunction(funcName())); } if (FormDataUtil::isFormDataSource(_args.record())) { ds = FormDataUtil::getFormDataSource(_args.record()); studentTrans = ds.getFirst(true) ? ds.getFirst(true) : ds.cursor(); while (studentTrans) { studentTransRecIdSet.add(studentTrans.RecId); studentTrans = ds.getNext(); } } else { studentTrans = _args.record(); studentTransRecIdSet.add(studentTrans.RecId); } ledgerJournalEntryPost = LedgerJournalEntryPost::newFromLedgerJournalEntryContract(LedgerJournalEntryPost::createJournalEntryContractList(studentTransRecIdSet.pack())); ledgerJournalEntryPost.runOperation(); info(strFmt("@561", ledgerJournalEntryPost.parmStudentTransRecIdPostedSet().elements())); if (ds) { ds.research(true); } } /// <summary> /// Creates a new instance of the <c>LedgerJournalEntryPost</c> class and initilizes its parameters. /// </summary> /// <param name="_ledgerJournalEntryContract"> /// Value of the <c>LedgerJournalEntryContract</c> contract class. /// </param> /// <returns> /// Created instance of the <c>LedgerJournalEntryPost</c> class. /// </returns> public static server LedgerJournalEntryPost newFromLedgerJournalEntryContract(LedgerJournalEntryContract _ledgerJournalEntryContract) { LedgerJournalEntryPost ledgerJournalEntryPost = new LedgerJournalEntryPost(); LedgerJournalEntryPost::validateLedgerJournalEntryContract(_ledgerJournalEntryContract); ledgerJournalEntryPost.parmLedgerJournalEntryContract(_ledgerJournalEntryContract); return ledgerJournalEntryPost; } /// <summary> /// Validates the <c>LedgerJournalEntryContract</c> contract class. /// </summary> /// <param name="_ledgerJournalEntryContract"> /// An instance of the <c>LedgerJournalEntryContract</c> contract class. /// </param> public static void validateLedgerJournalEntryContract(LedgerJournalEntryContract _ledgerJournalEntryContract) { if (!_ledgerJournalEntryContract) { throw error(strFmt("@35", classStr(LedgerJournalEntryContract))); } if (!_ledgerJournalEntryContract.parmLedgerJourEntryLines() || _ledgerJournalEntryContract.parmLedgerJourEntryLines().empty()) { throw error("@36"); } } protected boolean canRunInNewSession() { return false; } }
How to pass marked records from grid to sysoperations framework in AX
Controller class
/// <summary> /// /// </summary> class Sales_UpdateMoDSalesOrderController extends SysOperationServiceController { public static Sales_UpdateMoDSalesOrderController construct(Args _args) { Sales_UpdateMoDSalesOrderController controller = new Sales_UpdateMoDSalesOrderController(classStr( Sales_UpdateMoDSalesOrderService ), methodStr( Sales_UpdateMoDSalesOrderService, updateMoDSalesOrder ), SysOperationExecutionMode::Synchronous); controller.parmArgs( _args ); return controller; } public static void main(Args _args) { Set recordSet; SalesTable salesTable; MultiSelectionHelper multiselectionHelper; Sales_UpdateMoDSalesOrderContract dataContract; Sales_UpdateMoDSalesOrderController controller; controller = Sales_UpdateMoDSalesOrderController::construct( _args ); // Get marked records from calling form if (_args && _args.caller() is FormRun) { recordSet = new Set(Types::Record); multiselectionHelper = MultiSelectionHelper::createFromCaller(_args.caller()); salesTable = multiselectionHelper.getFirst(); while (salesTable) { recordSet.add(salesTable); salesTable = multiselectionHelper.getNext(); } } // Put records from calling datasource into dataContract dataContract = controller.getDataContractObject(); if (dataContract is Sales_UpdateMoDSalesOrderContract) { dataContract.parmRecordCon(recordSet.pack()); } controller.startOperation(); } }
Contract class
/// <summary> /// The data contract for Intercompany update of Mode of delivery /// </summary> [ DataContract, SysOperationGroup('GeneralGroup',"@SYS81043",'1',FormArrangeMethod::Vertical) ] class Sales_UpdateMoDSalesOrderContract implements SysOperationInitializable, SysOperationValidatable { UpsModeOfDelivery upsModeOfDelivery; container recordCon; /// <summary> /// Indicates whether the contract is valid. /// </summary> /// <returns> /// A Boolean value that indicates whether the contract is valid. /// </returns> public boolean validate() { boolean isValid = true; return isValid; } /// <summary> /// Initailizes the default values to parameters. /// </summary> public void initialize() { } /// <summary> /// Method used to specify the data memmber attribute /// </summary> /// <param> /// <name>parmShipmentDate</name>is used to set and get the shipmentDate /// </param> [ DataMember, SysOperationGroupMember('GeneralGroup'), SysOperationDisplayOrder('1'), SysOperationLabelAttribute(literalstr("@Warehouse:UpsModeOfDelivery")) ] public UpsModeOfDelivery parmUpsModeOfDelivery( UpsModeOfDelivery _upsModeOfDelivery = upsModeOfDelivery ) { upsModeOfDelivery = _upsModeOfDelivery; return upsModeOfDelivery; } /// <summary> /// Method used to specify the data memmber attribute /// </summary> /// <param name = "_recordCon"></param> /// <returns></returns> [DataMemberAttribute, SysOperationControlVisibilityAttribute(false)] public container parmRecordCon(container _recordCon = recordCon) { recordCon = _recordCon; return recordCon; } }
Service class
class Sales_UpdateMoDSalesOrderService { /// <summary> /// Creates transfer order for from and to wareshouse combination /// </summary> /// <param name = "_contract">TransferOrderCreateContract from dialog</param> public void updateMoDSalesOrder(Sales_UpdateMoDSalesOrderContract _contract) { Set recordSet; Common record; SalesTable salesTable; SetEnumerator se; ModeOfDeliverySetup smModeOfDeliverySetup; // Process records if (conLen(_contract.parmRecordCon()) > 0) { recordSet = Set::create(_contract.parmRecordCon()); se = recordSet.getEnumerator(); while (se.moveNext()) { record = se.current(); switch (record.TableId) { case tableNum(SalesTable): salesTable = record; salesTable.DlvMode = _contract.parmUpsModeOfDelivery(); info(strFmt("%1 %2", salesTable.SalesId, salesTable.DlvMode)); break; default: break; } } } } }
Sysoperations framework sample
UIBuilder class
/// <summary> /// The <c>TransferOrderCreateProposalUIBuilder</c> The data contract for Transfer order creation. /// </summary> class TransferOrderCreateProposalUIBuilder extends SysOperationAutomaticUIBuilder { DialogField toDate; DialogField timeFence; DialogField fromSite; DialogField fromWarehouse,toWarehouses; DialogField proposalModel; DialogField recalculateQuantities; DialogField replaceCurrentProposals; SysLookupMultiSelectCtrl ctrlSources; /// <summary> /// /// </summary> public void postBuild() { TransferOrderCreateProposalContract contract = this.dataContractObject() as TransferOrderCreateProposalContract; toDate = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmToDate)); timeFence = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmTimeFence)); fromSite = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmInventSiteId)); fromWarehouse = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmInventLocationIdFrom)); toWarehouses = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmInventLocationIdTo)); proposalModel = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmProposalModel)); recalculateQuantities = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmRecalculateQuantities)); replaceCurrentProposals = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmReplaceCurrentProposal)); replaceCurrentProposals.allowEdit(false); recalculateQuantities.visible(false); toWarehouses.lookupButton(FormLookupButton::Always); switch (this.controller().parmArgs().menuItemName()) { case menuItemActionStr(TransferOrderCreateProposal): replaceCurrentProposals.value(true); recalculateQuantities.value(false); toDate.value(DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone())); break; case menuItemActionStr(TransferOrderEditProposal): TransferOrderProposal transferOrderProposal = this.controller().parmArgs().record(); fromSite.allowEdit(false); fromWarehouse.allowEdit(false); proposalModel.allowEdit(false); recalculateQuantities.value(false); replaceCurrentProposals.value(false); toDate.value(transferOrderProposal.ToDate); fromSite.value(transferOrderProposal.InventSiteIdFrom); timeFence.value(transferOrderProposal.timeFence); proposalModel.value(transferOrderProposal.ProposalModel); fromWarehouse.value(transferOrderProposal.InventLocationIdFrom); break; case menuItemActionStr(TransferOrderRecalculateQty): toDate.visible(false); fromSite.visible(false); fromWarehouse.visible(false); timeFence.visible(false); toWarehouses.visible(false); replaceCurrentProposals.visible(false); recalculateQuantities.value(true); replaceCurrentProposals.value(false); break; default: break; } } /// <summary> /// /// </summary> public void postRun() { if ( this.controller().parmArgs().menuItemName() == menuItemActionStr(TransferOrderCreateProposal) ) { this.WarehouseLookup(false); } else if ( this.controller().parmArgs().menuItemName() == menuItemActionStr(TransferOrderEditProposal) ) { this.WarehouseLookup(true); } } /// <summary> /// Multi select lookup for warehouse /// </summary> /// <param name = "_preselectValues">true for preselect lookup values</param> public void WarehouseLookup(boolean _preselectValues) { Query query = new Query(); QueryBuildDataSource qbdsWarehouses = query.addDataSource(tablenum(InventLocation)); container selectedFields = [tableNum(InventLocation), fieldNum(InventLocation, InventLocationId)]; qbdsWarehouses.fields().addField(fieldNum(InventLocation, InventLocationId)); qbdsWarehouses.fields().addField(fieldNum(InventLocation, Name)); ctrlSources = SysLookupMultiSelectCtrl::constructWithQuery(this.dialog().formRun(), toWarehouses.control(), query, true, selectedFields); if (_preselectValues) { TransferOrderProposal transferOrderProposal, transferOrderProposalLoc = this.controller().parmArgs().record(); InventLocation inventLocation; container selectedRecIds; container selectedValues; while select InventLocationIdTo from transferOrderProposal group by InventLocationIdTo where transferOrderProposal.ProposalModel == transferOrderProposalLoc.ProposalModel { inventLocation = InventLocation::find(transferOrderProposal.InventLocationIdTo); selectedRecIds += inventLocation.RecId; selectedValues += inventLocation.InventLocationId; } ctrlSources.set([selectedRecIds, selectedValues]); } } }
Service class
/// <summary> /// The <c>TransferOrderCreationProposalService</c> is used to create Transfer order proposals /// for planned orders. /// </summary> class TransferOrderCreateProposalService { List toWareHouse; Query query; counter timeFence, lineNum; boolean replaceCurrentProposal; String20 proposalModel; TransDate fromDate,toDate; InventTable inventTable; InventSiteId fromInventSite; InventLocationId fromWarehouse; Enumerator enumerator; TransferOrderCreateProposalContract contract; /// <summary> /// Entry point for creating Transfer order propsal lines based on proposal model /// </summary> /// <param name = "_contract">TransferOrderCreateProposalContract passed from dialog</param> public void createTransferOrderProposal(TransferOrderCreateProposalContract _contract) { contract = _contract; this.initializeQuery(); this.initializeParameters(); ttsbegin; this.deleteTranferProposalsLines(proposalModel, replaceCurrentProposal); this.createTransferOrderProposalLines(); ttscommit; } /// <summary> /// Method is used to delete the Transfer order propsal lines based on proposal model /// </summary> /// <param name = "_proposalModel">from dialog</param> /// <param name = "_replaceCurrentProposal">true if creating new transfer order proposal</param> public void deleteTranferProposalsLines(ProposalModelId _proposalModel, boolean _replaceCurrentProposal) { if (_replaceCurrentProposal) { TransferOrderProposal transferOrderProposal; delete_from transferOrderProposal where transferOrderProposal.ProposalModel == _proposalModel; } } /// <summary> /// intilalize parameters /// </summary> public void initializeParameters() { toDate = contract.parmToDate(); timeFence = contract.parmTimeFence(); fromDate = contract.parmToDate() - timeFence; toWareHouse = contract.parmInventLocationIdTo(); fromWarehouse = contract.parmInventLocationIdFrom(); proposalModel = contract.parmProposalModel(); fromInventSite = contract.parmInventSiteId(); replaceCurrentProposal = contract.parmReplaceCurrentProposal(); } /// <summary> /// initialize query object /// </summary> public void initializeQuery() { query = contract.parmQuery(); } /// <summary> /// Method is used to create the Transfer order propsal lines based on proposal model /// </summary> public void createTransferOrderProposalLines() { Real workingdays; InventLocation inventLocation; InventQtyTotal inventQty; RecordInsertList transferOrderProposalInsertList = null; TransferOrderProposal transferOrderProposal; QueryRun queryRun = new QueryRun(query); while (queryRun.next()) { transferOrderProposalInsertList = new RecordInsertList(tablenum(TransferOrderProposal)); inventTable = queryRun.get(tablenum(InventTable)); enumerator = toWareHouse.getEnumerator(); try { ttsbegin; while (enumerator.moveNext()) { if (!replaceCurrentProposal) { if (TransferOrderProposal::exist(inventTable.ItemId, enumerator.current(), proposalModel)) { lineNum++; continue; } } transferOrderProposal.clear(); lineNum++; transferOrderProposal.LineNum = lineNum; transferOrderProposal.ItemId = inventTable.ItemId; transferOrderProposal.ItemName = inventTable.itemName(); transferOrderProposal.ToDate = toDate; transferOrderProposal.TimeFence = timeFence; transferOrderProposal.InventSiteIdFrom = fromInventSite; inventLocation = InventLocation::find(fromWarehouse); transferOrderProposal.InventLocationIdFrom = inventLocation.InventLocationId; transferOrderProposal.InventLocationIdFromName = inventLocation.Name; transferOrderProposal.InventSiteIdTo = fromInventSite; inventLocation = InventLocation::find(enumerator.current()); transferOrderProposal.InventLocationIdTo = inventLocation.InventLocationId; transferOrderProposal.InventLocationIdToName = inventLocation.Name; transferOrderProposal.ProposalModel = proposalModel; transferOrderProposal.CoverageGroup = inventTable.ReqGroupId; transferOrderProposal.RefillAvailablePhysical = this.getRefillItemAvailPhysicalBySiteAndWarehouse(transferOrderProposal.ItemId, transferOrderProposal.InventSiteIdFrom, transferOrderProposal.InventLocationIdFrom); inventQty = 0; inventQty = this.getItemTotalSalesBySiteAndWarehouse(transferOrderProposal.ItemId, transferOrderProposal.InventSiteIdFrom, transferOrderProposal.InventLocationIdFrom, fromDate, toDate); workingdays = 0; workingdays = this.getNumOfWorkingdays(transferOrderProposal.InventLocationIdFrom, fromDate, toDate); transferOrderProposal.RefillSalesPerDay = workingdays ? inventQty / workingdays : 0; transferOrderProposal.RefillCoverageDays = transferOrderProposal.RefillSalesPerDay ? transferOrderProposal.RefillAvailablePhysical / transferOrderProposal.RefillSalesPerDay : 0; transferOrderProposal.DCAvailablePhysical = this.getDCItemAvailPhysicalBySiteAndWarehouse(transferOrderProposal.ItemId, transferOrderProposal.InventSiteIdTo, transferOrderProposal.InventLocationIdTo); inventQty = 0; inventQty = this.getItemTotalSalesBySiteAndWarehouse(transferOrderProposal.ItemId, transferOrderProposal.InventSiteIdTo, transferOrderProposal.InventLocationIdTo, fromDate, toDate); workingdays = 0; workingdays = this.getNumOfWorkingdays(transferOrderProposal.InventLocationIdTo,fromDate, toDate); transferOrderProposal.DCSalesPerDay = workingdays ? inventQty / workingdays : 0; transferOrderProposal.DCCoverageDays = transferOrderProposal.DCSalesPerDay ? transferOrderProposal.DCAvailablePhysical / transferOrderProposal.DCSalesPerDay : 0; transferOrderProposalInsertList.add(transferOrderProposal); } transferOrderProposalInsertList.insertDatabase(); ttscommit; } catch(Exception::Error) { throw error( "@Planning:TransferOrderPropsalCreationError"); } catch(Exception::Deadlock ) { if(xSession::currentRetryCount() >= Planning_Constants::MaxOCCRetryCount) { throw Exception::Deadlock; } else { retry; } } catch(Exception::UpdateConflict) { if (appl.ttsLevel() == 0) { if (xSession::currentRetryCount() >= Planning_Constants::MaxOCCRetryCount) { throw Exception::UpdateConflictNotRecovered; } else { retry; } } else { throw Exception::UpdateConflict; } } info(strFmt("@Planning:TransferOrderProposalCreationSuccess", lineNum, proposalModel)); } } /// <summary> /// Calculate total sales between daterange for each item based on site and warehouse /// </summary> /// <param name = "_itemId"></param> /// <param name = "_inevntSiteId"></param> /// <param name = "_inventLocationId"></param> /// <returns></returns> public InventQtyTotal getItemTotalSalesBySiteAndWarehouse(ItemId _itemId, InventSiteId _inventSiteId, InventLocationId _inventLocationId, FromDate _fromDate, ToDate _toDate) { InventDim inventDim; InventTrans inventTrans; InventTransOrigin inventTransOrigin; select sum(Qty) from inventTrans where inventTrans.ItemId == _itemId && inventTrans.DatePhysical >= _fromDate && inventTrans.DatePhysical <= _toDate exists join inventTransOrigin where inventTransOrigin.RecId == inventTrans.InventTransOrigin && inventTransOrigin.ReferenceCategory == InventTransType::Sales exists join inventDim where inventDim.inventDimId == inventTrans.inventDimId && inventDim.InventSiteId == _inventSiteId && inventDim.InventLocationId == _inventLocationId; return abs(inventTrans.Qty); } /// <summary> /// calculates number of working days based on warehouse or Legal entity base calender /// </summary> /// <param name = "_inventLocationId"></param> /// <returns></returns> public Real getNumOfWorkingdays(InventLocationId _inventLocationId, FromDate _fromDate, ToDate _toDate) { Real workingdays; CalendarId calenderId; WorkCalendarDate WorkCalendarDate; if (InventLocation::find(_inventLocationId).ReqCalendarId) { calenderId = InventLocation::find(_inventLocationId).ReqCalendarId; } else { calenderId = CompanyInfo::find().ShippingCalendarId; } select count(RecId) from WorkCalendarDate where WorkCalendarDate.CalendarId == calenderId && (WorkCalendarDate.TransDate >= _fromDate && WorkCalendarDate.TransDate <= _toDate) && WorkCalendarDate.WorkTimeControl == WorkTimeControl::Open; workingdays = any2Real(WorkCalendarDate.RecId); if (!calenderId) { Real noOfDays = _toDate - _fromDate; //Formula for calculating working days if No base calender is present workingdays = (abs(noOfDays) / Planning_Constants::NumOfDaysInAWeek ) * Planning_Constants::MinWorkingDaysInAWeek; } return abs(workingdays); } /// <summary> /// Calculate avaialable physical inventory for each item based on site and warehouse /// </summary> /// <param name = "_itemId"></param> /// <param name = "_inevntSiteId"></param> /// <param name = "_inventLocationId"></param> /// <returns>Refill warehouse avail physical</returns> public InventQtyAvailPhysical getRefillItemAvailPhysicalBySiteAndWarehouse(ItemId _itemId, InventSiteId _inventSiteId, InventLocationId _inventLocationId) { InventDim inventDim; InventDimParm inventDimParm; inventDim = this.initInventDim(_inventSiteId, _inventLocationId); inventDimParm.initFromInventDim(inventDim); return abs(InventOnhand::newParameters(_itemId, inventDim, inventDimParm).availPhysical()); } /// <summary> /// Calculate avaialable physical inventory for each item based on site and warehouse /// </summary> /// <param name = "_itemId"></param> /// <param name = "_inevntSiteId"></param> /// <param name = "_inventLocationId"></param> /// <returns>DC warehouse avail physical</returns> public InventQtyAvailPhysical getDCItemAvailPhysicalBySiteAndWarehouse(ItemId _itemId, InventSiteId _inventSiteId, InventLocationId _inventLocationId) { InventDim inventDim; InventTrans inventTrans; InventDimParm inventDimParm; inventTransOrigin InventTransOrigin; InventQty totalAvailPhysical; inventDim = this.initInventDim(_inventSiteId, _inventLocationId); inventDimParm.initFromInventDim(inventDim); totalAvailPhysical = abs(InventOnhand::newParameters(_itemId, inventDim, inventDimParm).availPhysical()); inventDim.clear(); select sum(Qty) from inventTrans where inventTrans.ItemId == _itemId && inventTrans.DatePhysical == dateNull() && inventTrans.StatusIssue == StatusIssue::ReservPhysical exists join inventTransOrigin where inventTransOrigin.RecId == inventTrans.InventTransOrigin && (inventTransOrigin.ReferenceCategory == InventTransType::TransferOrderShip || inventTransOrigin.ReferenceCategory == InventTransType::TransferOrderReceive) exists join inventDim where inventDim.inventDimId == inventTrans.inventDimId && inventDim.InventSiteId == _inventSiteId && inventDim.InventLocationId == _inventLocationId; return totalAvailPhysical + abs(inventTrans.Qty); } /// <summary> /// Initilalize InevntDim by site and warehouse /// </summary> /// <param name = "_inevntSiteId">SiteId from proposal line</param> /// <param name = "_inventLocationId">LocationId from proposal line</param> /// <returns>InventDim buffer</returns> public InventDim initInventDim(InventSiteId _inevntSiteId, InventLocationId _inventLocationId) { InventDim inventDim; inventDim.InventSiteId = _inevntSiteId; inventDim.InventLocationId = _inventLocationId; inventDim = InventDim::findOrCreate(inventDim); return inventDim; } /// <summary> /// Recalculates and updates avail physical quanties /// </summary> /// <param name = "_contract">TransferOrderCreateProposalContract from dialog</param> public void recalculateQuanties(TransferOrderCreateProposalContract _contract) { TransferOrderProposal transferOrderProposal; InventQtyTotal inventQty; Real workingdays; while select forupdate transferOrderProposal where transferOrderProposal.ProposalModel == _contract.parmProposalModel() { try { ttsbegin; transferOrderProposal.RefillAvailablePhysical = this.getRefillItemAvailPhysicalBySiteAndWarehouse(transferOrderProposal.ItemId, transferOrderProposal.InventSiteIdFrom, transferOrderProposal.InventLocationIdFrom); inventQty = 0; inventQty = this.getItemTotalSalesBySiteAndWarehouse(transferOrderProposal.ItemId, transferOrderProposal.InventSiteIdFrom, transferOrderProposal.InventLocationIdFrom, transferOrderProposal.ToDate - transferOrderProposal.TimeFence, transferOrderProposal.ToDate); workingdays = 0; workingdays = this.getNumOfWorkingdays(transferOrderProposal.InventLocationIdFrom, transferOrderProposal.ToDate - transferOrderProposal.TimeFence, transferOrderProposal.ToDate); transferOrderProposal.RefillCoverageDays = transferOrderProposal.RefillSalesPerDay ? transferOrderProposal.RefillAvailablePhysical / transferOrderProposal.RefillSalesPerDay : 0; transferOrderProposal.DCAvailablePhysical = this.getDCItemAvailPhysicalBySiteAndWarehouse(transferOrderProposal.ItemId, transferOrderProposal.InventSiteIdTo, transferOrderProposal.InventLocationIdTo); inventQty = 0; inventQty = this.getItemTotalSalesBySiteAndWarehouse(transferOrderProposal.ItemId, transferOrderProposal.InventSiteIdTo, transferOrderProposal.InventLocationIdTo, transferOrderProposal.ToDate - transferOrderProposal.TimeFence, transferOrderProposal.ToDate); workingdays = 0; workingdays = this.getNumOfWorkingdays(transferOrderProposal.InventLocationIdFrom, transferOrderProposal.ToDate - transferOrderProposal.TimeFence, transferOrderProposal.ToDate); transferOrderProposal.DCCoverageDays = transferOrderProposal.DCSalesPerDay ? transferOrderProposal.DCAvailablePhysical / transferOrderProposal.DCSalesPerDay : 0; transferOrderProposal.update(); ttscommit; } catch(Exception::Error) { throw error( "@Planning:TransferOrderPropsalCreationError"); } catch(Exception::Deadlock ) { if(xSession::currentRetryCount() >= Planning_Constants::MaxOCCRetryCount) { throw Exception::Deadlock; } else { retry; } } catch(Exception::UpdateConflict) { if (appl.ttsLevel() == 0) { if (xSession::currentRetryCount() >= Planning_Constants::MaxOCCRetryCount) { throw Exception::UpdateConflictNotRecovered; } else { retry; } } else { throw Exception::UpdateConflict; } } } } }
Controller class
/// <summary> /// The controller for handling bulk Transfer order proposal creation. /// </summary> class TransferOrderCreateProposalController extends SysOperationServiceController { /// <summary> /// Constructs a new instance of the <c>TransferOrderCreateProposalController</c>. /// </summary> /// <param name = "_args">A set of arguments that is used for Transfer order proposal creation.</param> /// <returns>A new instance of the <c>TransferOrderCreateProposalController</c>.</returns> public static TransferOrderCreateProposalController construct(Args _args) { TransferOrderCreateProposalController controller; switch (_args.menuItemName()) { case menuItemActionStr(TransferOrderEditProposal): case menuItemActionStr(TransferOrderCreateProposal): controller = new TransferOrderCreateProposalController(classStr( TransferOrderCreateProposalService ), methodStr( TransferOrderCreateProposalService, createTransferOrderProposal ), SysOperationExecutionMode::Synchronous); break; case menuItemActionStr(TransferOrderRecalculateQty): controller = new TransferOrderCreateProposalController(classStr( TransferOrderCreateProposalService ), methodStr( TransferOrderCreateProposalService, recalculateQuanties ), SysOperationExecutionMode::Synchronous); break; default: break; } controller.parmArgs( _args ); return controller; } public static void main(Args _args) { TransferOrderCreateProposalController controller = TransferOrderCreateProposalController::construct( _args ); controller.startOperation(); //Only run if in Non batch mode if (controller.startResult == SysOperationStartResult::Started) { controller.RefreshCallingForm(_args); } } /// <summary> /// Refresh TransferOrderProposal from when not running in batch /// </summary> /// <param name = "_args"></param> private void RefreshCallingForm(args _args) { if (_args && _args.caller() && _args.caller() is formRun) { TransferOrderCreateProposalContract contract = this.getDataContractObject(); FormStringControl proposalModel; FormRun callerFormRun = _args.caller() as formRun; proposalModel = callerFormRun.design().controlName(formControlStr(TransferOrderProposal, ProposalModel)); proposalModel.Text(contract.parmProposalModel()); proposalModel.modified(); callerFormRun.dataSource(1).research(true); callerFormRun.dataSource(1).refresh(); callerFormRun.dataSource(2).research(true); callerFormRun.dataSource(2).refresh(); } } protected boolean canRunInNewSession() { return true; } }
Contract class
/// <summary> /// The data contract for Transfer order creation. /// </summary> [ DataContract, SysOperationGroup("HistoricalHorizoGroup","@:HistoricalHorizon","1",FormArrangeMethod::Vertical), SysOperationGroup("ReplaceCurrentProposalGroup","@:ReplaceCurrentProposal","2",FormArrangeMethod::Vertical), SysOperationContractProcessing(classStr(TransferOrderCreateProposalUIBuilder)) ] public class TransferOrderCreateProposalContract implements SysOperationInitializable, SysOperationValidatable { Query query; str packedQuery; TransDate fromDate,toDate; NoYesId replaceCurrentProposal; NoYesId recalculateQuantities; InventSiteId inventSiteId; InventLocationId inventLocationIdFrom; Integer timeFence; ProposalModelId proposalModel; List inventLocationIdTo; /// <summary> /// Indicates whether the contract is valid. /// </summary> /// <returns> /// A Boolean value that indicates whether the contract is valid. /// </returns> public boolean validate() { boolean isValid = true; if (!proposalModel) { isValid = checkFailed(strFmt("@SYS135209", "@:ProposalModel")); } else if (!this.confirmReplaceCurrentProposal(proposalModel, replaceCurrentProposal) && !recalculateQuantities) { isValid = false; } if (!replaceCurrentProposal && !recalculateQuantities) { isValid = this.checkProposalExists(); } return isValid; } /// <summary> /// check for transfer order proposals exists /// </summary> /// <returns>A Boolean value that indicates whether the contract is valid</returns> public boolean checkProposalExists() { Query queryVal; Counter lineNum; container results; Enumerator enumerator; InventTable inventTable; boolean isValid = true; if (query == null && packedQuery) { queryVal = new Query( SysOperationHelper::base64Decode( packedQuery ) ); } else { queryVal = query; } QueryRun queryRun = new QueryRun(queryVal); while (queryRun.next()) { inventTable = queryRun.get(tablenum(InventTable)); enumerator = inventLocationIdTo.getEnumerator(); while (enumerator.moveNext()) { if (TransferOrderProposal::exist(inventTable.ItemId, enumerator.current(), proposalModel)) { lineNum++; results += strFmt("@:ProposalExistsValidation", inventTable.ItemId, enumerator.current()); if (lineNum >= 100) { break; } } } } if (conLen(results) > 0) { warning(con2Str(results)); DialogButton diagBut; str strMessage = "@:TransferOrderAddlinesConfirmation"; str strTitle = "@ApplicationPlatform:SystemNotificationTitle"; diagBut = Box::okCancel(strMessage, DialogButton::Cancel, // Initial focus is on the Cancel button. strTitle); if (diagBut == DialogButton::Cancel) { isValid = false; } else { isValid = true; } } return isValid; } /// <summary> /// confirm from user to replace Marked/modifeied transfer order proposals /// </summary> /// <param name = "_proposalModel">user selected value</param> /// <param name = "_replaceCurrentProposal">true</param> /// <returns>A Boolean value that indicates whether the contract is valid </returns> public boolean confirmReplaceCurrentProposal(ProposalModelId _proposalModel, boolean _replaceCurrentProposal) { boolean ret = true; if(_proposalModel && _replaceCurrentProposal) { TransferOrderProposal transferOrderProposal; select firstonly RecId from transferOrderProposal where transferOrderProposal.ProposalModel == _proposalModel && (transferOrderProposal.AddToShipment == NoYes::Yes || transferOrderProposal.CaseQty != 0); if (transferOrderProposal.RecId) { DialogButton diagBut; str strMessage = "@:PropsalReplaceConfirmationText"; str strTitle = "@ApplicationPlatform:SystemNotificationTitle"; diagBut = Box::okCancel(strMessage, DialogButton::Cancel, // Initial focus is on the Cancel button. strTitle); if (diagBut == DialogButton::Cancel) { ret = false; } else { ret = true; } } } else { ret = true; } return ret; } /// <summary> /// Initailizes the default values to parameters. /// </summary> public void initialize() { query = new Query( queryStr( InventTableQuery ) ); } /// <summary> /// load query from syslast value /// </summary> /// <param name = "_packedQuery"></param> /// <returns> packed query string</returns> [ DataMember, AifQueryTypeAttribute('_packedQuery', queryStr( InventTableQuery ) ) ] public str parmPackedQuery( str _packedQuery = packedQuery) { packedQuery = _packedQuery; return packedQuery; } /// <summary> /// Encode/decode the query and set or get /// </summary> /// <param name = "_query"></param> /// <returns>query object</returns> public Query parmQuery( Query _query = query ) { if ( prmisDefault( _query ) && query == null ) { query = new Query( SysOperationHelper::base64Decode( packedQuery ) ); } else { packedQuery = SysOperationHelper::base64Encode( _query.pack() ); query = _query; } return query; } /// <summary> /// Method used to specify the data memmber attribute /// </summary> /// <param> /// <name>parmFromDate</name>is used to set and get the FromDate /// </param> [ DataMember, SysOperationGroupMember("HistoricalHorizoGroup"), SysOperationDisplayOrder("1"), SysOperationLabelAttribute(literalstr("@:TransferProposalModel")) ] public ProposalModelId parmProposalModel( ProposalModelId _proposalModel = proposalModel ) { proposalModel = _proposalModel; return proposalModel; } /// <summary> /// Method used to specify the data member attribute /// </summary> /// <param> /// <name>parmTimeFence</name>is used to set and get the historical time /// </param> [ DataMember, SysOperationGroupMember("HistoricalHorizoGroup"), SysOperationDisplayOrder("2"), SysOperationLabelAttribute(literalstr("@SYS315566")) ] public Integer parmTimeFence(Integer _timeFence = timeFence ) { timeFence = _timeFence; return timeFence; } /// <summary> /// Method used to specify the data member attribute /// </summary> /// <param> /// <name>parmToDate</name>is used to set and get the ToDate /// </param> [ DataMember, SysOperationGroupMember("HistoricalHorizoGroup"), SysOperationDisplayOrder("3"), SysOperationLabelAttribute(literalstr("@:ToDate")) ] public TransDate parmToDate( TransDate _toDate = toDate ) { toDate = _toDate; return toDate; } /// <summary> /// Method used to specify the data member attribute /// </summary> /// <param> /// <name>parmReplaceCurrentProposal</name>is used to set and get the parameter value /// </param> [ DataMember, SysOperationGroupMember("ReplaceCurrentProposalGroup"), SysOperationDisplayOrder("4"), SysOperationLabelAttribute(literalstr("@:ReplaceCurrentProposal")) ] public NoYesId parmReplaceCurrentProposal( NoYesId _replaceCurrentProposal = replaceCurrentProposal ) { replaceCurrentProposal = _replaceCurrentProposal; return replaceCurrentProposal; } /// <summary> /// Method used to specify the data memmber attribute /// </summary> /// <param> /// <name>parmToDate</name>is used to set and get the ToDate /// </param> [ DataMember, SysOperationGroupMember("ReplaceCurrentProposalGroup"), SysOperationDisplayOrder("5"), SysOperationLabelAttribute(literalstr("@SYS106955")) ] public InventSiteId parmInventSiteId( InventSiteId _inventSiteId = inventSiteId ) { inventSiteId = _inventSiteId; return inventSiteId; } /// <summary> /// Method used to specify the data memmber attribute /// </summary> /// <param> /// <name>parmToDate</name>is used to set and get the ToDate /// </param> [ DataMember, SysOperationGroupMember("ReplaceCurrentProposalGroup"), SysOperationDisplayOrder("6"), SysOperationLabelAttribute(literalstr("@SYS25253")) ] public InventLocationId parmInventLocationIdFrom( InventLocationId _inventLocationIdFrom = inventLocationIdFrom ) { inventLocationIdFrom = _inventLocationIdFrom; return inventLocationIdFrom; } /// <summary> /// Method used to specify the data memmber attribute /// </summary> /// <param> /// <name>parmToDate</name>is used to set and get the ToDate /// </param> [ DataMember, SysOperationGroupMember("ReplaceCurrentProposalGroup"), SysOperationDisplayOrder("7"), SysOperationLabelAttribute(literalstr("@SYS8519")), AifCollectionType('return', Types::String) ] public List parmInventLocationIdTo( List _inventLocationIdTo = inventLocationIdTo ) { inventLocationIdTo = _inventLocationIdTo; return inventLocationIdTo; } /// <summary> /// Method used to specify the data memmber attribute /// </summary> /// <param> /// <name>parmReplaceCurrentProposal</name>is used to set and get the parameter value /// </param> [ DataMember, SysOperationGroupMember("ReplaceCurrentProposalGroup"), SysOperationDisplayOrder("8"), SysOperationLabelAttribute(literalstr("@SYS40695")) ] public NoYesId parmRecalculateQuantities( NoYesId _recalculateQuantities = recalculateQuantities ) { recalculateQuantities = _recalculateQuantities; return recalculateQuantities; } }
Subscribe to:
Posts (Atom)