I want to create a time field which displays and allows user to select only Time. I have tried setting it some properties (TimeMode=True, DisplayFormat=hh:mm, EditFormat=hh:mm) but while the format remains as hh:mm but dropdown still has default date in it (see below screenshots).
Please suggest.
I have used some time only datetime fields... here is a quick sample:
On your DAC field, set it to use the PXDBTime attribute type as shown below...
[PXDBTime(DisplayMask = "t", UseTimeZone = false)]
[PXUIField(DisplayName = "My Time")]
public virtual DateTime? MyTime
{
get { return this._MyTime; }
set { this._MyTime = value; }
}
In your page, use the following...
<px:PXDateTimeEdit ID="edMyTime" runat="server" DataField="MyTime" DisplayFormat="t" EditFormat="t" TimeMode="True" SuppressLabel="True"/>
Related
I'm trying to change the logic that enables the "PO Link" action/button on the Sales Order lines. I'm not finding where the code that controls the enable/disable lives. Is it controlled by a workflow? If so, where?
I've tried the below but the SetEnable() is being overridden, apparently.
public class MySOOrderEntryExt :
PXGraphExtension<PX.Objects.SO.GraphExtensions.SOOrderEntryExt.POLinkDialog,
PX.Objects.SO.GraphExtensions.SOOrderEntryExt.PurchaseSupplyBaseExt, SOOrderEntry>
{
public void _(Events.RowSelected<SOOrder> e)
{
//Base.Actions["pOSupplyOK"].SetEnabled(false); //Doesn't work.
Base.Actions["pOSupplyOK"].SetVisible(false);
}
}
Any ideas would be great.
TIA!
The control consists of 2 components. In the ASPX in the ActionBar of the grid, teh button is defined as:
<px:PXToolBarButton Text="PO Link" DependOnGrid="grid" StateColumn="IsPOLinkAllowed">
<AutoCallBack Command="POSupplyOK" Target="ds" ></AutoCallBack>
</px:PXToolBarButton>
The StateColumn refers to the field that determines if the action/button is enabled or not. This is defined in SOLine in the field IsPOLinkAllowed as:
#region IsPOLinkAllowed
public abstract class isPOLinkAllowed : PX.Data.BQL.BqlBool.Field<isPOLinkAllowed> { }
[PXFormula(typeof(Switch<Case<Where<SOLine.pOCreate, Equal<True>, And<SOLine.operation, Equal<SOOperation.issue>>>, True>, False>))]
[PXUIField(DisplayName = "", Visibility = PXUIVisibility.Invisible, Visible = false, Enabled = false)]
[PXBool]
public virtual bool? IsPOLinkAllowed
{
get;
set;
}
#endregion
The PXFormula indicates that the POCreate field must be true and the operation of the Sales Order be an Issue.
The simplest way to modify this behavior likely is to change the attributes on the field via a DAC extension or CacheAttached in the graph to result in true when you want it enabled.
I am building a simple time clock screen. Employee number is entered; using the FieldUpdated event the employee name is filled out, along with the current time (PX.Common.PXTimeZoneInfo.Now) in the Clock Time field. Clicking SAVE puts the data in the table and as you can see it is correct.
Also on the Acumatica screen UPTO this point, the time displayed is correct.
Upon refresh of the screen the time displayed is wrongly shown as 12:00.
My DAC code for the ClockTime looks like:
#region ClockTime
[PXDBDate()]
[PXUIField(DisplayName = "Clock Time")]
public virtual DateTime? ClockTime { get; set; }
public abstract class clockTime : PX.Data.BQL.BqlDateTime.Field<clockTime> { }
#endregion
And my event handler:
protected virtual void _(Events.FieldUpdated<EMPTimeEntries, EMPTimeEntries.employeeID> e)
{
EMPTimeEntries row = e.Row;
if (row.EmployeeID != null)
{
EPEmployee employeeCard = PXSelectorAttribute.Select<EMPTimeEntries.employeeID>(e.Cache, row) as EPEmployee;
row.EmployeeName = employeeCard.AcctName;
row.ClockTime = PX.Common.PXTimeZoneInfo.Now;
}
}
Any thoughts on why this is happening?
Let me know if you need any further information.
I think I have it. I added to my DAC attribute:
[PXDBDate(PreserveTime = true)]
Please advice if there is a more proper way, or if this is the way.
We have a customer who has requested to have the "Duration" or "End Time" field rounded up to the nearest quarter hour in Service Appointment entry (whichever makes the most sense) Service Appointment Entry screen
With the service appointments there's alot going on. Does anyone have any thoughts on where would be the best way to approach this? There are a lot of events going on that modify the duration and end time and I wouldn't want to have to modify all of them. I'm wondering if its possible to just modify something on the DAC to automatically round the end time up to the quarter hour.
Got Pretty far with modifying the DAC. No errors in the code and as I step through it I can see its rounding the time like I want it to. However the field isnt setting in the screen. Am i missing something silly?
namespace PX.Objects.FS
{
public class FSAppointmentDetServiceExt : PXCacheExtension<PX.Objects.FS.FSAppointmentDetService>
// public class FSAppointmentDetServiceExt : PXCacheExtension<PX.Objects.FS.FSAppointmentDetService>
{
#region ActualDateTimeEnd
[PXDBDateAndTime(UseTimeZone = true, PreserveTime = true, DisplayNameDate = "Actual Date End", DisplayNameTime = "Actual Time End - Nicole")]
[PXUIField(DisplayName = "Actual Date", Visibility = PXUIVisibility.SelectorVisible)]
public virtual DateTime? ActualDateTimeEnd
{
get
{
return this._ActualDateTimeEnd;
}
set
{
this._ActualDateTimeEnd = RoundUp(value, TimeSpan.FromMinutes(15));
}
}
#pragma warning disable PX1026 // Underscores cannot be used in DAC declarations
public DateTime? _ActualDateTimeEnd;
#pragma warning restore PX1026 // Underscores cannot be used in DAC declarations
public static DateTime? RoundUp(DateTime? dt, TimeSpan d)
{
DateTime nt = Convert.ToDateTime(dt);
if (nt != null)
{
return new DateTime((nt.Ticks + d.Ticks - 1) / d.Ticks * d.Ticks, nt.Kind);
}
else
{
return nt;
}
}
#endregion
}
}
I'm wondering if its possible to just modify something on the DAC to
automatically round the end time up to the quarter hour.
Yes this is possible and I would recommend it since it's the easiest (perhaps not best) approach.
Create a DAC extension in CODE section, override (replace) the field dates you need to round. Add a backing field to the property and modify the setter property to round the time.
Example:
[PXDBDateAndTime(UseTimeZone = true, PreserveTime = true, DisplayNameDate = "Actual Date Time Begin", DisplayNameTime = "Actual Start Time")]
[PXUIField(DisplayName = "Actual Date", Visibility = PXUIVisibility.SelectorVisible)]
public virtual DateTime? ActualDateTimeBegin
{
get { return _ActualDateTimeBegin; }
set
{
_ActualDateTimeBegin = RoundTime(value);
}
}
public DateTime? _ActualDateTimeBegin;
public DateTime? RoundTime(DateTime? dateTime)
{
// return the rounded datetime
}
We have a button "Start" that populates the dateStarted field to DateTime.Now..
When retrieving datetime, it always shows the server's date/time instead of user's local timezone version. How do i make it work like lastModifiedDateTime/CreatedDateTime that whenever we view it it's formatted as user's local timezone. I tried UseTimeZone = true/false but nothing is working
Here is my code that is not working
#region DateStarted
public abstract class dateStarted : PX.Data.IBqlField
{
}
protected DateTime? _DateStarted;
[PXDBDateAndTime(DisplayNameDate = "Date Started", DisplayNameTime = "Time", UseTimeZone = true)]
public virtual DateTime? DateStarted
{
get
{
return this._DateStarted;
}
set
{
this._DateStarted = value;
}
}
#endregion
It sounds like just using PX.Common.PXTimeZoneInfo.Now is enough to do the job.
PX.Common.PXTimeZoneInfo also has UtcNow, UtcToday, and Today if needed
Look up the code of class PXDBDateAndTime in Source Code screen SM204570. For debugging purpose you can copy the whole attribute and rename it to something else like PXDBDateAndTimeDebug:
[PXDBDateAndTimeDebug(DisplayNameDate = "Date Started", DisplayNameTime = "Time", UseTimeZone = true)]
With that approach you can debug SetUseTimeZone and GetTimeZone methods. The time zone used is coming from LocaleInfo.GetTimeZone method and you should debug that too:
public static PXTimeZoneInfo GetTimeZone()
{
if (!PXContext.PXIdentity.IsAnonymous() && PXContext.PXIdentity.TimeZone != null)
{
return PXContext.PXIdentity.TimeZone;
}
return PXTimeZoneInfo.Invariant;
}
The issue here is that from your question we can't tell if there's actually a problem with Acumatica time zone handling or if the user profile time zone is properly configured in your instance or if the result you're expecting is actually a valid ISO conversion as done by the DotNet framework. Debugging step by step should reveal what's going on.
After analyzing how CreatedDateTime and LastModifiedDatetime and other dates behave the same, the problem is in the input. So i created the following code to save the correct datetime with regards to the current user's timezone.
public static class DateTimeHelper
{
public static DateTime? Now()
{
var test = LocaleInfo.GetTimeZone();
PXTimeZoneInfo timezone = LocaleInfo.GetTimeZone();
DateTime dt = DateTime.UtcNow;
dt = PXTimeZoneInfo.ConvertTimeFromUtc(dt, timezone);
return dt;
}
}
and the implementation:
public PXAction<CQLMChecklists> startButton;
[PXUIField(DisplayName = "Start", Visible = true)]
[PXButton()]
public virtual void StartButton()
{
if (Document.Current != null)
{
CQLMChecklists doc = Document.Current;
Actions.PressSave();
CommenceChecklist(DateTimeHelper.Now(), DateTimeHelper.Now().Value, ref doc);
Document.Update(doc);
}
Actions.PressSave();
}
In Sales Order documents grid footer. It displays the product's availability.
How to do the same in Opportunity products grid ?
More so, how do you enforce it to be displayed at the footer
instead of a simple grid column ? Is there such attribute ?
Thanks for the replies.
If we compare to sales order, the sales order line gets its value from LSSOLine during Availabilty_FieldSelecting. The wire-up on the page is on the tab via StatusField="Availability". We can do something similar by adding an unbound extension field and then during a field selecting fill in the value. An alternative would be to implement an LSCROpportunityProducts class that is inherits LSSelect similar to LSSoLine (a better preferred solution). To keep this simple and focus on just getting the field to display text, I will use an extension field and a simple field selecting in the extension graph for opportunity.
(1) In a dac extension, create an unbound field (MyAvailability is the example field):
[PXTable(typeof(CROpportunityProducts.cROpportunityID), typeof(CROpportunityProducts.cROpportunityProductID), IsOptional = true)]
[Serializable]
public class CROpportunityProductsMyExtension : PXCacheExtension<CROpportunityProducts>
{
#region MyAvailability
public abstract class myAvailability : PX.Data.IBqlField
{
}
protected string _MyAvailability;
[PXString(IsUnicode = true)]
[PXUIField(DisplayName = "Product Availability", Enabled = false)]
public virtual string MyAvailability
{
get
{
return this._MyAvailability;
}
set
{
this._MyAvailability = value;
}
}
#endregion
}
(2) On the opportunity products tab, wire up the new field as the grid status value by setting property StatusField. The page needs modified to add this value and should look something like this when added (requires screen customization in your project -> actions edit ASPX and locate ProductsGrid to paste in your StatusField and value):
<px:PXGrid ID="ProductsGrid" SkinID="Details" runat="server" Width="100%"
Height="500px" DataSourceID="ds" ActionsPosition="Top" BorderWidth="0px"
SyncPosition="true" StatusField="MyAvailability">
(3) Now in a graph extension populate the field:
Edit: The use of Current<> does not always contain the correct currently highlighted row in the UI. Switched to Required<> based on the PXFieldSelectingEventArgs.Row and the results are correct for multiple rows in the products tab.
public class CROpportunityMaintMyExtension : PXGraphExtension<OpportunityMaint>
{
public virtual void CROpportunityProducts_MyAvailability_FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
{
var row = (CROpportunityProducts) e.Row;
if (row == null)
{
e.ReturnValue = string.Empty;
return;
}
INLocationStatus locationStatus = PXSelectGroupBy<INLocationStatus,
Where<INLocationStatus.inventoryID, Equal<Required<CROpportunityProducts.inventoryID>>,
And2<Where<INLocationStatus.subItemID, Equal<Required<CROpportunityProducts.subItemID>>,
Or<Not<FeatureInstalled<PX.Objects.CS.FeaturesSet.subItem>>>>,
And<Where<INLocationStatus.siteID, Equal<Required<CROpportunityProducts.siteID>>,
Or<Required<CROpportunityProducts.siteID>, IsNull>>>>>,
Aggregate<Sum<INLocationStatus.qtyOnHand, Sum<INLocationStatus.qtyAvail>>>
>.Select(sender.Graph, row.InventoryID, row.SubItemID, row.SiteID, row.SiteID);
// Need to convert to transaction UOM... (this is always base units)
decimal? qtyOnHand = locationStatus?.QtyOnHand;
decimal? qtyAvail = locationStatus?.QtyAvail;
e.ReturnValue = $"Qty On hand = {qtyOnHand.GetValueOrDefault()} ; Qty Avail = {qtyAvail.GetValueOrDefault()}";
}
}
The results: