protected virtual void _(Events.FieldDefaulting <CROpportunityProducts, FSxCROpportunityProducts.billingRule> e) { if (e.Row == null) { return; } CROpportunityProducts crOpportunityProductsRow = (CROpportunityProducts)e.Row; FSxCROpportunityProducts fsxCROpportunityProductsRow = e.Cache.GetExtension <FSxCROpportunityProducts>(crOpportunityProductsRow); if (crOpportunityProductsRow.InventoryID != null) { InventoryItem inventoryItemRow = SharedFunctions.GetInventoryItemRow(Base, crOpportunityProductsRow.InventoryID); if (inventoryItemRow.ItemType == INItemTypes.ServiceItem) { FSxService fsxServiceRow = PXCache <InventoryItem> .GetExtension <FSxService>(inventoryItemRow); e.NewValue = fsxServiceRow?.BillingRule; e.Cancel = true; } else { e.NewValue = ID.BillingRule.FLAT_RATE; e.Cancel = true; } } }
protected virtual void _(Events.FieldDefaulting <CROpportunityProducts, FSxCROpportunityProducts.estimatedDuration> e) { if (e.Row == null) { return; } CROpportunityProducts crOpportunityProductsRow = (CROpportunityProducts)e.Row; FSxCROpportunityProducts fsxCROpportunityProductsRow = e.Cache.GetExtension <FSxCROpportunityProducts>(crOpportunityProductsRow); if (fsxCROpportunityProductsRow != null) { InventoryItem inventoryItemRow = SharedFunctions.GetInventoryItemRow(Base, crOpportunityProductsRow.InventoryID); if (inventoryItemRow != null) { FSxService fsxServiceRow = PXCache <InventoryItem> .GetExtension <FSxService>(inventoryItemRow); if (inventoryItemRow.ItemType == INItemTypes.ServiceItem || inventoryItemRow.ItemType == INItemTypes.NonStockItem) { e.NewValue = fsxServiceRow?.EstimatedDuration; e.Cancel = true; } } } }
/// <summary> /// Enable/Disable the ActionType field for a Service depending on the appointments related to that service. /// </summary> public virtual void EnableDisableActionType(PXCache cache, InventoryItem inventoryItemRow) { bool enableActionType = true; FSxService fsxServiceRow = PXCache <InventoryItem> .GetExtension <FSxService>(inventoryItemRow); if (cache.GetStatus(inventoryItemRow) != PXEntryStatus.Inserted) { int rowCount = PXSelect <FSAppointmentDet, Where < FSAppointmentDet.lineType, Equal <ListField_LineType_Pickup_Delivery.Pickup_Delivery>, And <FSAppointmentDet.pickupDeliveryServiceID, Equal <Required <FSAppointmentDet.pickupDeliveryServiceID> > > > > .SelectSingleBound(cache.Graph, null, inventoryItemRow.InventoryID).Count; enableActionType = rowCount == 0; } PXUIFieldAttribute.SetEnabled <FSxService.actionType>(cache, inventoryItemRow, enableActionType); if (enableActionType == false) { cache.RaiseExceptionHandling <FSxService.actionType>(inventoryItemRow, null, new PXSetPropertyException( PXMessages.LocalizeFormatNoPrefix(TX.Warning.CANNOT_MODIFY_FIELD, "Appoinments", "Service"), PXErrorLevel.Warning)); } }
/// <summary> /// Enable/Disable the PickUp/Delivery Grid for a Service if the ActionType is No Items Related or another option. /// </summary> public virtual void EnableDisablePickUpDelivery(PXCache cache, InventoryItem inventoryItemRow) { FSxService fsxServiceRow = PXCache <InventoryItem> .GetExtension <FSxService>(inventoryItemRow); if (fsxServiceRow != null) { bool enable = fsxServiceRow.ActionType != ID.Service_Action_Type.NO_ITEMS_RELATED; ServiceInventoryItems.Cache.AllowInsert = enable; ServiceInventoryItems.Cache.AllowUpdate = enable; ServiceInventoryItems.Cache.AllowDelete = enable; } }
protected virtual void _(Events.RowPersisting <InventoryItem> e) { if (e.Row == null) { return; } InventoryItem item = (InventoryItem)e.Row; PXCache cache = e.Cache; InventoryItem oldItem = SharedFunctions.GetInventoryItemRow(cache.Graph, item.InventoryID); if (oldItem != null && e.Operation == PXDBOperation.Update && item.BaseUnit?.Equals(oldItem.BaseUnit) == false && SharedFunctions.IsServiceRelatedToAnyContract(cache, item.InventoryID) == true) { if (WebDialogResult.Yes == ServiceInventoryItems.Ask(TX.WebDialogTitles.CONFIRM_CHANGE_FSSALESPRICE_UOM, TX.Messages.ASK_CONFIRM_CHANGE_UOM_FSSALESPRICE, MessageButtons.YesNo)) { baseUnitChanged = true; } } if (item.ItemType == INItemTypes.ServiceItem) { FSxService service = cache.GetExtension <FSxService>(e.Row); if (service.EstimatedDuration == null || service.EstimatedDuration == 0) { cache.RaiseExceptionHandling <FSxService.estimatedDuration>(e.Row, service.EstimatedDuration, new PXSetPropertyException(TX.Warning.INVALID_SERVICE_DURATION, PXErrorLevel.Error)); } if (PXAccess.FeatureInstalled <FeaturesSet.distributionModule>()) { if (item.ItemClassID == null) { cache.RaiseExceptionHandling <InventoryItem.itemClassID>(e.Row, null, new PXSetPropertyException <InventoryItem.itemClassID>(TX.Error.FIELD_EMPTY, PXErrorLevel.Error)); } } } }
/// <summary> /// Assign the default Billing Rule set in the ItemClass. /// </summary> public virtual void SetDefaultBillingRule(PXCache cache, InventoryItem nonStockItemRow) { if (nonStockItemRow == null || nonStockItemRow.ItemClassID == null) { return; } if (nonStockItemRow.ItemType == INItemTypes.ServiceItem) { INItemClass inItemClassRow = PXSelect <INItemClass, Where < INItemClass.itemClassID, Equal <Required <InventoryItem.itemClassID> > > > .Select(Base, nonStockItemRow.ItemClassID); FSxServiceClass fsxServiceClassRow = PXCache <INItemClass> .GetExtension <FSxServiceClass>(inItemClassRow); FSxService service = cache.GetExtension <FSxService>(nonStockItemRow); service.BillingRule = fsxServiceClassRow.DfltBillingRule; } }
protected virtual void _(Events.FieldUpdated <InventoryItem, FSxService.estimatedDuration> e) { if (e.Row == null) { return; } InventoryItem inventoryItemRow = (InventoryItem)e.Row; FSxService fsxServiceRow = PXCache <InventoryItem> .GetExtension <FSxService>(inventoryItemRow); PXSetPropertyException exception = null; if (fsxServiceRow.EstimatedDuration < 1) { exception = new PXSetPropertyException(TX.Warning.INVALID_SERVICE_DURATION, PXErrorLevel.Error); } e.Cache.RaiseExceptionHandling <FSxService.estimatedDuration>(inventoryItemRow, fsxServiceRow.EstimatedDuration, exception); }
/// <summary> /// Create a Service Order from a TimeSlot. /// </summary> protected void CreateServiceOrder(TimeSlot timeSlotServiceOrder, bool createAppointmentFlag = false, bool appointmentsBelongToRoute = false) { // This action allows to avoid errors related to cache if (graphServiceOrderEntry != null) { graphServiceOrderEntry.Clear(PXClearOption.ClearAll); } else { graphServiceOrderEntry = PXGraph.CreateInstance <ServiceOrderEntry>(); graphServiceOrderEntry.DisableServiceOrderUnboundFieldCalc = true; } FSSchedule fsScheduleRow = ScheduleSelected.Select(timeSlotServiceOrder.ScheduleID); FSServiceContract fsServiceContractRow = ServiceContractSelected.Select(fsScheduleRow.EntityID); bool isPrepaidContract = fsServiceContractRow.BillingType == ID.Contract_BillingType.STANDARDIZED_BILLINGS; //Services from the Schedule var fsScheduleDetSet = ScheduleLinesSelected.Select(timeSlotServiceOrder.ScheduleID); //Templates from the Schedule var fsScheduleDetTemplateSet = ScheduleTemplatesSelected.Select(timeSlotServiceOrder.ScheduleID); FSServiceOrder fsServiceOrderRow = new FSServiceOrder(); fsServiceOrderRow.SrvOrdType = fsScheduleRow.SrvOrdType; graphServiceOrderEntry.ServiceOrderRecords.Insert(fsServiceOrderRow); fsServiceOrderRow = graphServiceOrderEntry.ServiceOrderRecords.Cache.CreateCopy(graphServiceOrderEntry.ServiceOrderRecords.Current) as FSServiceOrder; fsServiceOrderRow.BranchID = fsScheduleRow.BranchID; fsServiceOrderRow.BranchLocationID = fsScheduleRow.BranchLocationID; fsServiceOrderRow.OrderDate = timeSlotServiceOrder.DateTimeBegin.Date; fsServiceOrderRow.CustomerID = fsServiceContractRow.CustomerID; fsServiceOrderRow.LocationID = fsScheduleRow.CustomerLocationID; graphServiceOrderEntry.ServiceOrderRecords.Update(fsServiceOrderRow); fsServiceOrderRow = graphServiceOrderEntry.ServiceOrderRecords.Cache.CreateCopy(graphServiceOrderEntry.ServiceOrderRecords.Current) as FSServiceOrder; // Currently Service-Management's contracts DO NOT support multi-currency specification // therefore their ServiceOrders MUST be created in customer base currency if (PXAccess.FeatureInstalled <FeaturesSet.multicurrency>()) { string curyID = null; Customer customer = (Customer)PXSelect <Customer, Where <Customer.bAccountID, Equal <Required <Customer.bAccountID> > > > .Select(this, fsServiceContractRow.CustomerID); if (customer != null) { curyID = customer.CuryID; } if (string.IsNullOrEmpty(curyID) == true) { curyID = this.Accessinfo.BaseCuryID ?? new PXSetup <PX.Objects.GL.Company>(this).Current?.BaseCuryID; } fsServiceOrderRow.CuryID = curyID; } fsServiceOrderRow.DocDesc = timeSlotServiceOrder.Descr; fsServiceOrderRow.BillCustomerID = fsServiceContractRow.BillCustomerID; fsServiceOrderRow.BillLocationID = fsServiceContractRow.BillLocationID; fsServiceOrderRow.ServiceContractID = fsServiceContractRow.ServiceContractID; fsServiceOrderRow.ProjectID = fsServiceContractRow.ProjectID; fsServiceOrderRow.DfltProjectTaskID = fsServiceContractRow.DfltProjectTaskID; if (isPrepaidContract == true && graphServiceOrderEntry.BillingCycleRelated.Current != null && graphServiceOrderEntry.BillingCycleRelated.Current.BillingBy == ID.Billing_By.SERVICE_ORDER) { fsServiceOrderRow.BillServiceContractID = fsServiceContractRow.ServiceContractID; } fsServiceOrderRow.ScheduleID = timeSlotServiceOrder.ScheduleID; fsServiceOrderRow.ServiceContractID = fsServiceContractRow.ServiceContractID; fsServiceOrderRow.GenerationID = timeSlotServiceOrder.GenerationID; fsServiceOrderRow.SalesPersonID = fsServiceContractRow.SalesPersonID; fsServiceOrderRow.Commissionable = fsServiceContractRow.Commissionable; fsServiceOrderRow = graphServiceOrderEntry.ServiceOrderRecords.Update(fsServiceOrderRow); if (fsServiceOrderRow.SalesPersonID == null) { object salesPersonID; graphServiceOrderEntry.ServiceOrderRecords.Cache.RaiseFieldDefaulting <FSServiceOrder.salesPersonID>(fsServiceOrderRow, out salesPersonID); fsServiceOrderRow.SalesPersonID = (int?)salesPersonID; object commissionable; graphServiceOrderEntry.ServiceOrderRecords.Cache.RaiseFieldDefaulting <FSServiceOrder.commissionable>(fsServiceOrderRow, out commissionable); fsServiceOrderRow.Commissionable = (bool?)commissionable; } graphServiceOrderEntry.Answers.CopyAllAttributes(fsServiceOrderRow, fsScheduleRow); #region Setting Service Order Details foreach (FSScheduleDet fsScheduleDetRow in fsScheduleDetSet) { if (fsScheduleDetRow.LineType == ID.LineType_ServiceContract.SERVICE_TEMPLATE) { foreach (FSScheduleDet fsScheduleDetLocalRow in fsScheduleDetTemplateSet.Where(x => ((FSScheduleDet)x).ServiceTemplateID == fsScheduleDetRow.ServiceTemplateID)) { var fsServiceTemplateDetSet_Service = ServiceTemplateSelected.Select(fsScheduleDetRow.ServiceTemplateID); foreach (FSServiceTemplateDet fsServiceTemplateDetRow_Service in fsServiceTemplateDetSet_Service) { FSSODet fsSODetRow = new FSSODet(); // Insert the new row with key fields fsSODetRow.ScheduleID = fsScheduleDetLocalRow.ScheduleID; fsSODetRow.ScheduleDetID = fsScheduleDetLocalRow.ScheduleDetID; fsSODetRow.LineType = fsServiceTemplateDetRow_Service.LineType; fsSODetRow = graphServiceOrderEntry.ServiceOrderDetails.Insert(fsSODetRow); fsSODetRow.InventoryID = fsServiceTemplateDetRow_Service.InventoryID; fsSODetRow = graphServiceOrderEntry.ServiceOrderDetails.Update(fsSODetRow); PXNoteAttribute.CopyNoteAndFiles(ScheduleLinesSelected.Cache, fsScheduleDetLocalRow, graphServiceOrderEntry.ServiceOrderDetails.Cache, fsSODetRow, copyNotes: true, copyFiles: true); // Create a copy to update the other fields fsSODetRow = (FSSODet)graphServiceOrderEntry.ServiceOrderDetails.Cache.CreateCopy(fsSODetRow); fsSODetRow.TranDesc = fsServiceTemplateDetRow_Service.TranDesc; InventoryItem inventoryItemRow = SharedFunctions.GetInventoryItemRow(this, fsServiceTemplateDetRow_Service.InventoryID); if (inventoryItemRow != null) { FSxService fsxServiceRow = PXCache <InventoryItem> .GetExtension <FSxService>(inventoryItemRow); if (fsxServiceRow != null && fsxServiceRow.BillingRule == ID.BillingRule.TIME) { int?estimatedDuration = CalculateEstimatedDuration(fsSODetRow, fsServiceTemplateDetRow_Service.Qty); fsSODetRow.EstimatedDuration = estimatedDuration; } else { fsSODetRow.EstimatedQty = fsServiceTemplateDetRow_Service.Qty; } } if (fsServiceContractRow.SourcePrice == ID.SourcePrice.CONTRACT) { fsSODetRow.ManualPrice = true; // TODO: Check where is assigned the contract price? } if (createAppointmentFlag) { fsSODetRow.Scheduled = true; fsSODetRow.Status = ID.Status_SODet.SCHEDULED; } fsSODetRow.EquipmentAction = fsScheduleDetRow.EquipmentAction; fsSODetRow.SMEquipmentID = fsScheduleDetRow.SMEquipmentID; fsSODetRow.ComponentID = fsScheduleDetRow.ComponentID; fsSODetRow.EquipmentLineRef = fsScheduleDetRow.EquipmentLineRef; fsSODetRow.ProjectTaskID = fsScheduleDetRow.ProjectTaskID; fsSODetRow.CostCodeID = fsScheduleDetRow.CostCodeID; if (fsSODetRow.InventoryID != null) { fsSODetRow.ProjectTaskID = fsScheduleDetRow.ProjectTaskID; fsSODetRow.CostCodeID = fsScheduleDetRow.CostCodeID; } graphServiceOrderEntry.ServiceOrderDetails.Update(fsSODetRow); } } } else { FSSODet fsSODetRow = new FSSODet(); // Insert the new row with key fields fsSODetRow.ScheduleID = fsScheduleDetRow.ScheduleID; fsSODetRow.ScheduleDetID = fsScheduleDetRow.ScheduleDetID; fsSODetRow.LineType = fsScheduleDetRow.LineType; fsSODetRow = graphServiceOrderEntry.ServiceOrderDetails.Insert(fsSODetRow); fsSODetRow.InventoryID = fsScheduleDetRow.InventoryID; fsSODetRow = graphServiceOrderEntry.ServiceOrderDetails.Update(fsSODetRow); PXNoteAttribute.CopyNoteAndFiles(ScheduleLinesSelected.Cache, fsScheduleDetRow, graphServiceOrderEntry.ServiceOrderDetails.Cache, fsSODetRow, copyNotes: true, copyFiles: true); // Create a copy to update the other fields fsSODetRow = (FSSODet)graphServiceOrderEntry.ServiceOrderDetails.Cache.CreateCopy(fsSODetRow); fsSODetRow.TranDesc = fsScheduleDetRow.TranDesc; fsSODetRow.BillingRule = fsScheduleDetRow.BillingRule; if (fsSODetRow.BillingRule == ID.BillingRule.TIME) { int?estimatedDuration = CalculateEstimatedDuration(fsSODetRow, fsScheduleDetRow?.Qty); fsSODetRow.EstimatedDuration = estimatedDuration; } else { fsSODetRow.EstimatedQty = fsScheduleDetRow.Qty; } if (fsServiceContractRow.SourcePrice == ID.SourcePrice.CONTRACT) { fsSODetRow.ManualPrice = true; // TODO: AC-142850 Check where is assigned the contract price? } if (createAppointmentFlag) { fsSODetRow.Scheduled = true; fsSODetRow.Status = ID.Status_SODet.SCHEDULED; } fsSODetRow.EquipmentAction = fsScheduleDetRow.EquipmentAction; fsSODetRow.SMEquipmentID = fsScheduleDetRow.SMEquipmentID; fsSODetRow.ComponentID = fsScheduleDetRow.ComponentID; fsSODetRow.EquipmentLineRef = fsScheduleDetRow.EquipmentLineRef; fsSODetRow.ProjectTaskID = fsScheduleDetRow.ProjectTaskID; fsSODetRow.CostCodeID = fsScheduleDetRow.CostCodeID; if (fsSODetRow.InventoryID != null) { fsSODetRow.ProjectTaskID = fsScheduleDetRow.ProjectTaskID; fsSODetRow.CostCodeID = fsScheduleDetRow.CostCodeID; } graphServiceOrderEntry.ServiceOrderDetails.Update(fsSODetRow); } } if (fsScheduleRow.VendorID != null) { FSSOEmployee fsSOEmployeeRow = new FSSOEmployee(); fsSOEmployeeRow.EmployeeID = fsScheduleRow.VendorID; graphServiceOrderEntry.ServiceOrderEmployees.Insert(fsSOEmployeeRow); } #endregion graphServiceOrderEntry.Save.Press(); if (createAppointmentFlag) { string origStatus = graphServiceOrderEntry.ServiceOrderRecords.Current.Status; if (origStatus != ID.Status_ServiceOrder.OPEN) { //Due to FSAppointment.sORefNbr selector, Service Order status must be OPEN to allow the SetValueExt<SORefNbr> inside createAppointment() work properly. //PXUpdate is used to avoid raising any ServiceOrderEntry event. PXUpdate < Set <FSServiceOrder.status, FSServiceOrder.status.Open>, FSServiceOrder, Where < FSServiceOrder.sOID, Equal <Required <FSServiceOrder.sOID> > > > .Update(this, graphServiceOrderEntry.ServiceOrderRecords.Current.SOID); } CreateAppointment(graphServiceOrderEntry.ServiceOrderRecords.Current, timeSlotServiceOrder, fsScheduleRow, true, appointmentsBelongToRoute, isPrepaidContract); if (origStatus != ID.Status_ServiceOrder.OPEN) { PXUpdate < Set <FSServiceOrder.status, Required <FSServiceOrder.status> >, FSServiceOrder, Where < FSServiceOrder.sOID, Equal <Required <FSServiceOrder.sOID> > > > .Update(this, origStatus, graphServiceOrderEntry.ServiceOrderRecords.Current.SOID); } } }
public static void X_InventoryID_FieldUpdated <DAC, SubItemID, SiteID, SiteLocationID, UOM, EstimatedDuration, EstimatedQty, BillingRule, ActualDuration, ActualQty>( PXCache cache, PXFieldUpdatedEventArgs e, int?branchLocationID, Customer billCustomerRow, bool useActualFields) where DAC : class, IBqlTable, IFSSODetBase, new() where SubItemID : class, IBqlField where SiteID : class, IBqlField where SiteLocationID : class, IBqlField where UOM : class, IBqlField where EstimatedDuration : class, IBqlField where EstimatedQty : class, IBqlField where BillingRule : class, IBqlField where ActualDuration : class, IBqlField where ActualQty : class, IBqlField { if (e.Row == null) { return; } var row = (DAC)e.Row; // This is required in Inventory FieldUpdated events if (e.ExternalCall) { row.CuryUnitPrice = 0m; } if (IsInventoryLine(row.LineType) == false || (row.InventoryID == null && row.LineType != ID.LineType_All.PICKUP_DELIVERY)) { // Clear fields for non-inventory lines row.IsBillable = false; row.ManualPrice = false; row.TranDesc = null; row.SubItemID = null; row.SiteID = null; row.SiteLocationID = null; cache.SetDefaultExt <FSSODet.uOM>(e.Row); cache.RaiseExceptionHandling <UOM>(e.Row, null, null); row.SetDuration(FieldType.EstimatedField, 0, cache, false); row.SetQty(FieldType.EstimatedField, 0, cache, false); if (useActualFields == true) { row.SetDuration(FieldType.ActualField, 0, cache, false); row.SetQty(FieldType.ActualField, 0, cache, false); } row.BillingRule = ID.BillingRule.NONE; return; } InventoryItem inventoryItemRow = SharedFunctions.GetInventoryItemRow(cache.Graph, row.InventoryID); row.TranDesc = null; if (inventoryItemRow != null) { row.TranDesc = PXDBLocalizableStringAttribute.GetTranslation(cache.Graph.Caches[typeof(InventoryItem)], inventoryItemRow, "Descr", billCustomerRow?.LocaleName); } // UOM is assigned to null here to avoid price calculation while duration and qty fields are defaulted. row.UOM = null; cache.RaiseExceptionHandling <UOM>(e.Row, null, null); cache.SetDefaultExt <SubItemID>(e.Row); cache.SetDefaultExt <SiteID>(e.Row); if (inventoryItemRow != null) { if (row.SiteID == null) { row.SiteID = inventoryItemRow.DfltSiteID; } if (row.SiteID == null) { //TODO: this query may return multiple records INItemSite inItemSiteRow = PXSelect <INItemSite, Where < INItemSite.inventoryID, Equal <Required <INItemSite.inventoryID> > > > .Select(cache.Graph, inventoryItemRow.InventoryID); if (inItemSiteRow != null) { row.SiteID = inItemSiteRow.SiteID; } } } cache.SetDefaultExt <SiteLocationID>(e.Row); if (inventoryItemRow != null) { if (row.SiteLocationID == null && row.LineType == ID.LineType_All.INVENTORY_ITEM) { row.SiteLocationID = inventoryItemRow.DfltShipLocationID; } } int? defaultSubItemID = row.SubItemID; object newValue = null; cache.RaiseFieldDefaulting <UOM>(e.Row, out newValue); string defaultUOM = (string)newValue; int? defaultSiteID = row.SiteID; CompleteItemInfoUsingBranchLocation( cache.Graph, branchLocationID, inventoryItemRow != null ? inventoryItemRow.DefaultSubItemOnEntry : false, ref defaultSubItemID, ref defaultUOM, ref defaultSiteID); row.SubItemID = defaultSubItemID; if (defaultSiteID != null) { cache.SetValueExt <SiteID>(e.Row, defaultSiteID); } cache.SetValueExt <UOM>(e.Row, defaultUOM); row.SetDuration(FieldType.EstimatedField, 0, cache, false); // EstimatedQty MUST be assigned after BillingRule BUT before EstimatedDuration. if (row.LineType == ID.LineType_All.SERVICE && inventoryItemRow != null) { FSxService fsxServiceRow = PXCache <InventoryItem> .GetExtension <FSxService>(inventoryItemRow); cache.SetValueExt <BillingRule>(e.Row, fsxServiceRow.BillingRule); cache.SetDefaultExt <EstimatedQty>(e.Row); cache.SetValueExt <EstimatedDuration>(e.Row, fsxServiceRow.EstimatedDuration ?? 0); } else { cache.SetValueExt <BillingRule>(e.Row, ID.BillingRule.FLAT_RATE); cache.SetDefaultExt <EstimatedQty>(e.Row); } if (useActualFields == true) { cache.SetDefaultExt <ActualQty>(e.Row); cache.SetDefaultExt <ActualDuration>(e.Row); } }