Hi Gaurav,
Please find below what i did the customization.
I am created the two tables called salestotalssummary and SalesEncumbranceSummary with some fields related to summary of the sales order.
then i add two table in the form called salestotalssummarypart
in salestotalssummary datasource override the method execute query
public void executeQuery()
{
SalesTable salesTableParent;
salesTableParent = element.args().record() as SalesTable;
if(salesTableParent.RecId)
{
SalesTotalsSummaryController::updateTotals(salesTableParent, tableNum(SalesTotalsSummary));
super();
}
}
then i created new class called slaestotalssummarycontroller.
add the methods and code like this.
//class declaration
/// <summary>
/// This class is responsible for calculating and storing sales order totals and encumbrance summary amounts
/// in <c>SalesTotalsSummary</c> and <c>SalesEncumbranceSummary</c> tables respectively. These amounts are displayed on
/// Sales order details and list pages in factboxes.
/// </summary>
class SalesTotalsSummaryController
{
SalesId salesId;
boolean invalidateTotalsRecord;
}
//checkFields
/// <summary>
/// Checks if the fields that affect totals amounts have been updated and sets the result in a class level variable.
/// </summary>
/// <param name="_common">
/// Buffer for the record being updated
/// </param>
/// <remarks>
/// This class handles table record updates in two steps. First <c>checkFields()</c> is called from table <c>update()</c> method before the <c>super()</c> call
/// to check if any of the fields that affects sales order total amounts has been modified and a class level flag is set to indicate so.
/// Calling <c>checkFields()</c> before <c>super()</c> is needed becuase the <c>super()</c> call resets the original buffer. After the <c>super()</c> is called and
/// the updates have been written to the table a call to <c>onUpdate()</c> is made to write the class level varaible indicating the result from
/// <c>checkFields()</c> to <c>SalesTotalsSummary</c> table.
/// </remarks>
public void checkFields(Common _common)
{
SalesTable salesTable;
SalesLine salesLine;
MarkupTrans markupTrans;
if(!_common || !SalesParameters::find().AutomaticFactBoxUpdateOnSO_PSN)
{
return;
}
switch(_common.TableId)
{
case tableNum(SalesTable):
salesTable = _common as SalesTable;
invalidateTotalsRecord = invalidateTotalsRecord || (salesTable.orig().CurrencyCode != salesTable.CurrencyCode);
invalidateTotalsRecord = invalidateTotalsRecord || (salesTable.orig().InclTax != salesTable.InclTax);
if(TaxParameters::find().JournalInclTax)
{
invalidateTotalsRecord = invalidateTotalsRecord || (salesTable.orig().CashDisc != salesTable.CashDisc);
}
break;
case tableNum(SalesLine):
salesLine = _common as SalesLine;
invalidateTotalsRecord = invalidateTotalsRecord || (salesLine.orig().LineAmount != salesLine.LineAmount);
invalidateTotalsRecord = invalidateTotalsRecord || (salesLine.orig().SalesQty != salesLine.SalesQty);
invalidateTotalsRecord = invalidateTotalsRecord || (salesLine.orig().SalesPrice != salesLine.SalesPrice);
break;
case tableNum(MarkupTrans):
markupTrans = _common as MarkupTrans;
invalidateTotalsRecord = invalidateTotalsRecord || (markupTrans.orig().MarkupCategory != markupTrans.MarkupCategory);
invalidateTotalsRecord = invalidateTotalsRecord || (markupTrans.orig().Value != markupTrans.Value);
invalidateTotalsRecord = invalidateTotalsRecord || (markupTrans.orig().CurrencyCode != markupTrans.CurrencyCode);
break;
}
}
private void new(SalesId _salesId)
{
salesId = _salesId;
}
/// <summary>
/// This method will invalidate the totals record if it was marked to be invalidated from the checkFields() and
/// then notifies the calling datasource about the invalid totals record.
/// This method gets called after the update() is called on the table.
/// </summary>
/// <param name="_common">
/// Table buffer to notify about the invalidation of the record
/// </param>
public void onUpdate(Common _common)
{
SalesTable salesTable;
SalesLine salesLine;
if(!_common || !SalesParameters::find().AutomaticFactBoxUpdateOnSO_PSN)
{
return;
}
if(invalidateTotalsRecord)
{
SalesTotalsSummaryController::setValidFlag(salesId, tableNum(SalesTotalsSummary), false);
switch(_common.TableId)
{
case tableNum(SalesTable):
salesTable = _common as SalesTable;
SalesTotalsSummaryController::updateTotals(salesTable, tableNum(SalesTotalsSummary));
break;
case tableNum(SalesLine):
salesLine = _common as SalesLine;
SalesTotalsSummaryController::updateTotals(SalesTable::find(salesLine.SalesId), tableNum(SalesTotalsSummary));
break;
default:
break;
}
}
}
/// <summary>
/// Calculates or gets the totals for the sales order and inserts the data in the <c>SalesTotalsSummary</c> table.
/// </summary>
/// <param name="_salesTable">
/// <c>SalesTable</c> record buffer for which to update the totals.
/// </param>
/// <param name="_salesTotalsSummary">
/// <c>SalesTotalsSummary</c> record buffer that needs to be updated; optional.
/// </param>
/// <param name="_salesTotals">
/// <c>SalesTotals</c> object that carries the totals values calculated; optional.
/// </param>
/// <returns>
/// true - indiating that the <c>SalesTotalsSummary</c> record was updated.
/// </returns>
public server static boolean calculateAndUpdateTotalsSummary(SalesTable _salesTable, SalesTotalsSummary _salesTotalsSummary = null, SalesTotals _salesTotals = null)
{
ttsbegin;
if(!_salesTotals)
{
_salesTotals = SalesTotals::newSalesTable(_salesTable, SalesUpdate::All);
_salesTotals.calc();
}
if (!_salesTotalsSummary || !_salesTotalsSummary.selectForUpdate())
{
_salesTotalsSummary = SalesTotalsSummary::findBySalesId(_salesTable.SalesId,true);
}
_salesTotalsSummary.SalesId = _salesTable.SalesId;
_salesTotalsSummary.CurrencyCode = _salesTotals.salesCurrency();
_salesTotalsSummary.NetLines = _salesTotals.salesBalance();
_salesTotalsSummary.LineDiscount = _salesTotals.salesLineDisc();
_salesTotalsSummary.Discounts = _salesTotals.salesEndDisc();
_salesTotalsSummary.SalesTax = _salesTotals.salesTaxTotal();
_salesTotalsSummary.MiscCharges = _salesTotals.salesMarkup();
_salesTotalsSummary.RoundOff = _salesTotals.salesRoundOff();
_salesTotalsSummary.UseTax = _salesTotals.salesUseTax();
_salesTotalsSummary.OtherCharges = _salesTotals.salesOtherMiscCharges();
_salesTotalsSummary.TotalAmount = _salesTotals.salesTotalAmount();
_salesTotalsSummary.CashDiscount = _salesTotals.salesCashDiscAmount();
_salesTotalsSummary.IsValid = true;
if(!_salesTotalsSummary)
{
_salesTotalsSummary.insert();
}
else
{
_salesTotalsSummary.update();
}
ttscommit;
return true;
}
/// <summary>
/// Creates and returns an object of <c>SalesTotalsSummaryController</c> for the given sales order id.
/// </summary>
/// <param name="_salesId">
/// Sales order Id
/// </param>
/// <returns>
/// Object of <c>SalesTotalsSummaryController</c>
/// </returns>
public static SalesTotalsSummaryController construct(SalesId _salesId)
{
SalesTotalsSummaryController salesTotalsSummaryController = new SalesTotalsSummaryController(_salesId);
return salesTotalsSummaryController;
}
/// <summary>
/// Sets the <c>isValid</c> field of the <c>SalesEncumbranceSummary</c> table to false so
/// that the next time the <c>updateTotals</c> method is called the table will be updated.
/// </summary>
/// <param name="_salesId">
/// The <c>SalesId</c> value of the record to invalidate.
/// </param>
public static void invalidateEncumbranceSummaryRecord(SalesId _slaesId)
{
SalesTotalsSummaryController::setValidFlag(_slaesId, tableNum(SalesEncumbranceSummary), false);
}
/// <summary>
/// Checks the table buffer to see from which table record was deleted,
/// If a record is deleted from a table which affects totals then the totals record is invalidated.
/// </summary>
/// <param name="_common">
/// Buffer for delted record
/// </param>
public server static void onDelete(Common _common)
{
SalesTable salesTable;
SalesLine salesLine;
MarkupTrans markupTrans;
SalesTotalsSummary salesTotalsSummary;
if (!_common || !SalesParameters::find().AutomaticFactBoxUpdateOnSO_PSN)
{
return;
}
switch(_common.TableId)
{
case tableNum(SalesLine):
salesLine = _common as SalesLine;
salesTotalsSummary = SalesTotalsSummary::findBySalesId(salesLine.SalesId, true);
SalesTotalsSummaryController::setValidFlag(salesLine.SalesId, tableNum(SalesTotalsSummary), false, salesTotalsSummary);
SalesTotalsSummaryController::updateTotals(SalesTable::find(salesLine.SalesId), tableNum(SalesTotalsSummary), salesTotalsSummary);
break;
case tableNum(MarkupTrans):
markupTrans = _common as MarkupTrans;
salesTable = SalesTable::findRecId(markupTrans.TransRecId);
SalesTotalsSummaryController::setValidFlag(salesTable.SalesId, tableNum(SalesTotalsSummary), false);
break;
}
}
/// <summary>
/// Checks the table buffer to see in which table record was inserted.
/// If a record is inserted in SalesTable then records in totals tables are created,
/// otherwise records are invalidated if the insertion is in some other table that affects totals
/// </summary>
/// <param name="_common">
/// Buffer for new record
/// </param>
public server static void onInsert(Common _common)
{
SalesTable salesTable;
SalesLine salesLine;
MarkupTrans markupTrans;
SalesTotalsSummary salesTotalsSummary;
if (!_common || !SalesParameters::find().AutomaticFactBoxUpdateOnSO_PSN)
{
return;
}
switch(_common.TableId)
{
case tableNum(SalesTable):
salesTable = _common as SalesTable;
SalesTotalsSummary::createRecord(salesTable.SalesId, salesTable.CurrencyCode);
SalesEncumbranceSummary::createRecord(salesTable.SalesId, salesTable.CurrencyCode);
break;
case tableNum(SalesLine):
salesLine = _common as SalesLine;
SalesTotalsSummary = SalesTotalsSummary::findBySalesId(salesLine.SalesId, true);
SalesTotalsSummaryController::setValidFlag(salesLine.SalesId, tableNum(SalesTotalsSummary), false, salesTotalsSummary);
SalesTotalsSummaryController::updateTotals(SalesTable::find(salesLine.SalesId), tableNum(SalesTotalsSummary), salesTotalsSummary);
break;
case tableNum(MarkupTrans):
markupTrans = _common as MarkupTrans;
salesTable = SalesTable::findRecId(markupTrans.TransRecId);
SalesTotalsSummaryController::setValidFlag(salesTable.SalesId, tableNum(SalesTotalsSummary), false);
break;
}
}
/// <summary>
/// Invalidates the <c>SalesEncumbranceSummary</c> record if some document related to sales orders is posted.
/// </summary>
/// <param name="_postedJournalSet">
/// A <c>Set</c> object containing posted journal entries
/// </param>
public server static void onPostingSuccess(Set _postedJournalSet)
{
SetEnumerator enumerator;
Common commonBuffer;
CustInvoiceJour custInvoiceJourLocal;
CustConfirmJour custConfirmJourLocal;
if (!SalesParameters::find().AutomaticFactBoxUpdateOnSO_PSN)
{
return;
}
if (_postedJournalSet)
{
enumerator = _postedJournalSet.getEnumerator();
while (enumerator.moveNext())
{
commonBuffer = enumerator.current();
switch (commonBuffer.TableId)
{
case tableNum(CustConfirmJour):
custConfirmJourLocal = commonBuffer as CustConfirmJour;
SalesTotalsSummaryController::populateEncumbranceSummaryValues(custConfirmJourLocal.SalesId);
break;
case tableNum(CustInvoiceJour):
custInvoiceJourLocal = commonBuffer as CustInvoiceJour;
SalesTotalsSummaryController::populateEncumbranceSummaryValues(custInvoiceJourLocal.SalesId);
break;
}
}
}
}
/// <summary>
/// Populates the <c>SalesEncumbranceSummary</c> record with encumbrance and relieving amounts for the sales order.
/// </summary>
/// <param name="_salesId">
/// Sales order id for which to populate the record.
/// </param>
private server static void populateEncumbranceSummaryValues(SalesId _salesId)
{
SalesTable salesTable;
if (_salesId && SalesParameters::find().AutomaticFactBoxUpdateOnSO_PSN)
{
salesTable = SalesTable::find(_salesId);
SalesTotalsSummaryController::updateTotals(salesTable, tableNum(SalesEncumbranceSummary));
SalesTotalsSummaryController::setValidFlag(salesTable.SalesId, tableNum(SalesEncumbranceSummary), false);
}
}
/// <summary>
/// Sets the summary record's IsValid flag only if the new value is different from the one already stored.
/// </summary>
/// <param name="_salesId">
/// Sales order id for which to update the record
/// </param>
/// <param name="_tableId">
/// Table id of the summary table
/// </param>
/// <param name="_isValid">
/// Value for the IsValid flag
/// </param>
/// <param name="_salesSummary">
/// SalesTotalsSummary or SalesEncumbranceSummary table whose record needs to be updated
/// </param>
private server static void setValidFlag(SalesId _salesId, tableId _tableId, boolean _isValid = true, Common _salesSummary = null)
{
SalesTotalsSummary salesTotalsSummary;
SalesEncumbranceSummary salesEncumbranceSummary;
switch(_tableId)
{
case tableNum(SalesTotalsSummary):
salesTotalsSummary = _salesSummary as SalesTotalsSummary;
if (!salesTotalsSummary ||!salesTotalsSummary.selectForUpdate())
{
salesTotalsSummary = SalesTotalsSummary::findBySalesId(_salesid, true);
}
if(salesTotalsSummary && salesTotalsSummary.IsValid!=_isValid)
{
salesTotalsSummary.IsValid = _isValid;
ttsbegin;
salesTotalsSummary.update();
ttscommit;
}
break;
case tableNum(SalesEncumbranceSummary):
salesEncumbranceSummary = _salesSummary as SalesEncumbranceSummary;
if (!salesEncumbranceSummary ||!salesEncumbranceSummary.selectForUpdate())
{
salesEncumbranceSummary = SalesEncumbranceSummary::findBySalesId(_salesId, true);
}
if(salesEncumbranceSummary && salesEncumbranceSummary.IsValid!=_isValid)
{
salesEncumbranceSummary.IsValid = _isValid;
ttsbegin;
salesEncumbranceSummary.update();
ttscommit;
}
break;
}
}
/// <summary>
/// Updates the totals or encumbrance amounts for the sales order, if invalid, based on the table id passed.
/// </summary>
/// <param name="_salesTable">
/// <c>SalesTable</c> record buffer for which to update the totals
/// </param>
/// <param name="_tableId">
/// Table Id of the table whose record needs to be updated
/// </param>
/// <param name="_salesSummary">
/// SalesTotalsSummary or SalesEncumbranceSummary table whose record needs to be updated
/// </param>
/// <returns>
/// true if a summary record was updated, false otherwise
/// </returns>
public server static boolean updateTotals(SalesTable _salesTable, tableId _tableId, Common _salesSummary = null)
{
SalesTotalsSummary salesTotalsSummary;
AccountingDistributionOrderSummaryCalc accountingDistributionOrderSummaryCalc;
SalesEncumbranceSummary salesEncumbranceSummary;
boolean recordUpdated = false;
if (!SalesParameters::find().AutomaticFactBoxUpdateOnSO_PSN)
{
return recordUpdated;
}
switch(_tableId)
{
case tableNum(SalesTotalsSummary):
SalesTotalsSummary = _salesSummary as SalesTotalsSummary;
recordUpdated = SalesTotalsSummaryController::calculateAndUpdateTotalsSummary(_salesTable, salesTotalsSummary);
break;
case tableNum(SalesEncumbranceSummary):
salesEncumbranceSummary = _salesSummary as SalesEncumbranceSummary;
if (!salesEncumbranceSummary ||!salesEncumbranceSummary.selectForUpdate())
{
salesEncumbranceSummary = SalesEncumbranceSummary::findBySalesId(_salesTable.PurchId, true);
}
if(!salesEncumbranceSummary)
{
salesEncumbranceSummary = SalesEncumbranceSummary::createRecord(_salesTable.SalesId, _salesTable.CurrencyCode);
}
if(!salesEncumbranceSummary.IsValid)
{
accountingDistributionOrderSummaryCalc = new AccountingDistributionOrderSummaryCalc();
accountingDistributionOrderSummaryCalc.populateEncumbranceSummaryAmount(_salesTable.SalesId);
salesEncumbranceSummary.LastCalculatedOn = DateTimeUtil::getSystemDateTime();
salesEncumbranceSummary.CurrencyCode = _salesTable.CurrencyCode;
salesEncumbranceSummary.EncumberedAmount = accountingDistributionOrderSummaryCalc.parmTotalEncumbered();
salesEncumbranceSummary.RelievedAmount = accountingDistributionOrderSummaryCalc.parmTotalRelieved();
salesEncumbranceSummary.IsValid = true;
ttsbegin;
salesEncumbranceSummary.update();
ttscommit;
recordUpdated = true;
}
break;
}
return recordUpdated;
}