I am currently working on a project in which I am using the Quartz Scheduler.
I've been working on a feature that displays different details about jobs that are currently active, using the following method.
public IEnumerable<ActiveScheduleJob> GetAllActiveScheduls()
{
var activeScheduls = new List<ActiveScheduleJob>();
try
{
IList<string> jobGroups = scheduler.GetJobGroupNames();
// IList<string> triggerGroups = scheduler.GetTriggerGroupNames();
ActiveScheduleJob ASJ;
foreach (string group in jobGroups)
{
var groupMatcher = GroupMatcher<JobKey>.GroupContains(group);
var jobKeys = scheduler.GetJobKeys(groupMatcher);
foreach (var jobKey in jobKeys)
{
var detail = scheduler.GetJobDetail(jobKey);
var triggers = scheduler.GetTriggersOfJob(jobKey);
foreach (ITrigger trigger in triggers)
{
ASJ = new ActiveScheduleJob();
ASJ.Group = group;
ASJ.Name = jobKey.Name;
ASJ.Description = detail.Description;
ASJ.TriggerKeyName = trigger.Key.Name;
ASJ.TriggerKeyGroup = trigger.Key.Group;
ASJ.TriggerGetTypeName = trigger.GetType().Name;
ASJ.TriggerState = scheduler.GetTriggerState(trigger.Key);
ASJ.NextFireTime = trigger.GetNextFireTimeUtc();
if (ASJ.NextFireTime.HasValue)
{
ASJ.NextFireTimeString = ASJ.NextFireTime.Value.LocalDateTime.ToString();
}
ASJ.PreviousFireTime = trigger.GetPreviousFireTimeUtc();
if (ASJ.PreviousFireTime.HasValue)
{
ASJ.PreviousFireTimeString = ASJ.PreviousFireTime.Value.LocalDateTime.ToString();
}
ASJ.FullJobString = $"Trigger Name: {ASJ.TriggerKeyName} | Trigger Group: {ASJ.TriggerKeyGroup} | Trigger State: {ASJ.TriggerState} | Trigger Get Type: {ASJ.TriggerGetTypeName} | Job Name: {ASJ.Name} | Job Group: {ASJ.Group} | Next Fire Time: {ASJ.NextFireTimeString} | Previous Fire Time: {ASJ.PreviousFireTimeString} | Description: {ASJ.Description}";
activeScheduls.Add(ASJ);
}
}
}
}
catch (Exception ex)
{
logging.WriteLog(1, "JobScheduler", "GetAllActiveScheduls", "Hent alle aktive job+triggers", $"EXCEPTION MESSAGE: {ex.Message} | EXCEPTION INNER: {ex.InnerException}", LogType.Exception, "");
}
return activeScheduls;
}
The method in it self works just fine, my problems lies in the fact that the GetNextFireTime() method, gives it in UTC which is an hour behind my GMT+1 / UTC+1.
When it displays: 10-01-2018 07:00:00 +00:00
It should display: 10-01-2018 08:00:00 +01:00
I've looked at the following link: Working With DateTimeOffset
and tried to work with what Marko Lahma mentioned could work in converting the DateTimeOffset. But I've run into a wall where I can't convert it, because GetNextFireTime() returns a DataTimeOffset? and what I've tried, can't convert something thats Nullable. So I am abit stumped in what to do
You can convert the DateTimeOffset to a local DateTimeOffset and that to a DateTime.
var nextFireDateTime = trigger.GetNextFireTimeUtc()?.ToLocalTime().DateTime;
Please note that nextFireDateTime could be null.
Related
I'm trying to update two entities at the same time but the change is not applying and I think that when I try to return the update entity it doesn't even found it.
Here is my Razor view:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
repositorioFamiliar.Actualizar(Familiar);
return RedirectToPage("/Familiares/DetalleFamiliar", new { IdPaciente = Familiar.IdPaciente });
}
Here is my update function:
public FamiliaresPer Actualizar(FamiliaresPer familiar)
{
var familiarActualizar = (from f in _context.Familiars.Where(p => p.IdFamiliar == familiar.IdFamiliar) select f).FirstOrDefault();
if (familiarActualizar != null)
{
familiarActualizar.Correo = familiar.Correo;
_context.Update(familiarActualizar);
_context.SaveChanges();
}
var personaActualizar = (from p in _context.Personas.Where(p => p.Id == familiar.IdPersona) select p).FirstOrDefault();
if (personaActualizar != null)
{
personaActualizar.Telefono = familiar.Telefono;
_context.Update(personaActualizar);
_context.SaveChanges();
}
var familiares = from p in _context.Familiars
from p1 in _context.Personas
where p.IdPaciente == familiar.IdPaciente
where p.IdPersona == p1.IdPersona
select new FamiliaresPer()
{
IdFamiliar = p.IdFamiliar,
IdPaciente = p.IdPaciente,
IdPersona = p1.IdPersona,
Id = p1.Id,
Nombres = p1.Nombres,
Apellidos = p1.Apellidos,
Genero = p1.Genero,
Telefono = p1.Telefono,
Parentesco = p.Parentesco,
Correo = p.Correo,
};
FamiliaresPer familiaresPer = familiares.FirstOrDefault();
return familiaresPer;
}
When I submit the form I get an error
NullReferenceException: Object reference not set to an instance of an object
And the link shows the IdPaciente = 0 when it should use the same IdPaciente of the updated entity (which the Id never changes).
In your OnPost( ) Action Method, you used repositorioFamiliar.Actualizar(Familiar);
but it looks like you didn't define 'Familiar'.
In addition, when I look at your code. I can give you an advice. Let's say your first update was done correctly and you got an error in the second update case. But you want both to be updated at the same time. Assume that the first object is updated in the database but the second one isn't. This is a problem, right? Unit of Work design pattern is very useful to solve this.
In brief, The approach should be to do SaveChanges() after both update processes are completed so there will be no changes in the database until both updates are completed.
I have a custom PXbutton called UploadRecords, when I click this button I should populate the grid with records and release the records.
Release Action is pressed in the UploadRecords action delegate. The problem I get with this code is, the code here function properly for less records by release action but when passes thousands of records to release, it takes huge time(> 30 min.) and show the error like Execution timeout.
suggest me to avoid more execution time and release the records fastly.
namespace PX.Objects.AR
{
public class ARPriceWorksheetMaint_Extension : PXGraphExtension<ARPriceWorksheetMaint>
{
//public class string_R112 : Constant<string>
//{
// public string_R112()
// : base("4E5CCAFC-0957-4DB3-A4DA-2A24EA700047")
// {
// }
//}
public class string_R112 : Constant<string>
{
public string_R112()
: base("EA")
{
}
}
public PXSelectJoin<InventoryItem, InnerJoin<CSAnswers, On<InventoryItem.noteID, Equal<CSAnswers.refNoteID>>,
LeftJoin<INItemCost, On<InventoryItem.inventoryID, Equal<INItemCost.inventoryID>>>>,
Where<InventoryItem.salesUnit, Equal<string_R112>>> records;
public PXAction<ARPriceWorksheet> uploadRecord;
[PXUIField(DisplayName = "Upload Records", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
[PXButton]
public IEnumerable UploadRecord(PXAdapter adapter)
{
using (PXTransactionScope ts = new PXTransactionScope())
{
foreach (PXResult<InventoryItem, CSAnswers, INItemCost> res in records.Select())
{
InventoryItem invItem = (InventoryItem)res;
INItemCost itemCost = (INItemCost)res;
CSAnswers csAnswer = (CSAnswers)res;
ARPriceWorksheetDetail gridDetail = new ARPriceWorksheetDetail();
gridDetail.PriceType = PriceTypeList.CustomerPriceClass;
gridDetail.PriceCode = csAnswer.AttributeID;
gridDetail.AlternateID = "";
gridDetail.InventoryID = invItem.InventoryID;
gridDetail.Description = invItem.Descr;
gridDetail.UOM = "EA";
gridDetail.SiteID = 6;
InventoryItemExt invExt = PXCache<InventoryItem>.GetExtension<InventoryItemExt>(invItem);
decimal y;
if (decimal.TryParse(csAnswer.Value, out y))
{
y = decimal.Parse(csAnswer.Value);
}
else
y = decimal.Parse(csAnswer.Value.Replace(" ", ""));
gridDetail.CurrentPrice = y; //(invExt.UsrMarketCost ?? 0m) * (Math.Round(y / 100, 2));
gridDetail.PendingPrice = y; // (invExt.UsrMarketCost ?? 0m)* (Math.Round( y/ 100, 2));
gridDetail.TaxID = null;
Base.Details.Update(gridDetail);
}
ts.Complete();
}
Base.Document.Current.Hold = false;
using (PXTransactionScope ts = new PXTransactionScope())
{
Base.Release.Press();
ts.Complete();
}
List<ARPriceWorksheet> lst = new List<ARPriceWorksheet>
{
Base.Document.Current
};
return lst;
}
protected void ARPriceWorksheet_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (ARPriceWorksheet)e.Row;
uploadRecord.SetEnabled(row.Status != SPWorksheetStatus.Released);
}
}
}
First, Do you need them all to be in a single transaction scope? This would revert all changes if there is an exception in any. If you need to have them all committed without any errors rather than each record, you would have to perform the updates this way.
I would suggest though moving your process to a custom processing screen. This way you can load the records, select one or many, and use the processing engine built into Acumatica to handle the process, rather than a single button click action. Here is an example: https://www.acumatica.com/blog/creating-custom-processing-screens-in-acumatica/
Based on the feedback that it must be all in a single transaction scope and thousands of records, I can only see two optimizations that may assist. First is increasing the Timeout as explained in this blog post. https://acumaticaclouderp.blogspot.com/2017/12/acumatica-snapshots-uploading-and.html
Next I would load all records into memory first and then loop through them with a ToList(). That might save you time as it should pull all records at once rather than once for each record.
going from
foreach (PXResult<InventoryItem, CSAnswers, INItemCost> res in records.Select())
to
var recordList = records.Select().ToList();
foreach (PXResult<InventoryItem, CSAnswers, INItemCost> res in recordList)
I am facing this seem to be famous issue by setting a timestamp binding against postgres.
#Test
public void testGetCurrentDate() {
NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(datasources.get(dbType));
PlatformTransactionManager manager = new DataSourceTransactionManager(datasources.get(dbType));
final Timestamp ts = new Timestamp(System
.currentTimeMillis());
new TransactionTemplate(manager).execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
template.update("create table test_timestamp (col timestamp)", Collections.emptyMap());
template.update("insert into test_timestamp (col) values (:TS) ", Collections.singletonMap("TS", ts));
}
});
Assert.assertEquals((Integer) 1, new TransactionTemplate(manager).execute(new TransactionCallback<Integer>() {
#Override
public Integer doInTransaction(TransactionStatus status) {
MapSqlParameterSource paramsSource = new MapSqlParameterSource();
paramsSource.addValue("TS", ts, Types.TIMESTAMP, "timestamp");
return template.queryForObject("select 1 from test_timestamp where :TS is not null and col=:TS ", paramsSource,
Integer.class);
}
}));
}
This test fails with ERROR: could not determine data type of parameter $1
See here the discution with postgres about that:
http://www.postgresql-archive.org/quot-could-not-determine-data-type-of-parameter-quot-with-timestamp-td5995489.html
I already have a workaround for that (Setting a PGTimestamp instance instead of Timestamp). I was wondering if it is something that could benefits to Spring JDBC to increase portability accross multiple databases.
In this case the workaround would be something like this in org.springframework.jdbc.core.StatementCreatorUtils ( around line 380):
else if (sqlType == Types.TIMESTAMP &&
"PostgreSQL".equals(ps.getConnection().getMetaData().getDatabaseProductName()))) {
Class<?> pgTimestampClass = Class.forName("org.postgresql.util.PGTimestamp");
Timestamp ts = (Timestamp)pgTimestampClass.getConstructor(long.class).newInstance(javaValue.getTime());
ps.setTimestamp(paramIndex, ts);
If you think that it something that makes sense, I could propose a pull request.
Arnaud
I have been using the same script to import appointments to Calendar for 2 years with no issues. All of a sudden today, I am getting an error code that reads TypeError: Cannot find function createAllDayEvent in object Calendar. (line 35, file "Code")
Why is this happening?? We use this script to schedule company deliveries, so I really need it to work. Any help would be greatly appreciated!!
This is the script I have been using...
function importCalendar() {
var sheet = SpreadsheetApp.getActiveSheet();
var headerRows = 1; // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getValues();
var calId = "CALENDAR ID HERE";
var cal = CalendarApp.getCalendarById(calId);
for (i=0; i<data.length; i++) {
if (i < headerRows) continue; // Skip header row(s)
var row = data[i];
var startDate = row[3]; // Fourth column
var title = row[1]; // Second column
var location = row[2];
var description = row[4];
var id = row[6]; // Seventh column == eventId
var advancedArgs ={description: description, location: location};
// Check if event already exists, update it if it does
try {
var event = cal.getEventSeriesById(id);
}
catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
if (!event) {
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
var newEvent = cal.createAllDayEvent(title, new Date(startDate), advancedArgs).getId(); This is the row with the error.
row[6] = newEvent; // Update the data array with event ID
}
else {
Utilities.sleep(5000);
event.setTitle(title);
event.setDescription(description);
event.setLocation(location);
// event.setTime(tstart, tstop); // cannot setTime on eventSeries.
// ... but we CAN set recurrence!
var recurrence = CalendarApp.newRecurrence().addDailyRule().times(1);
event.setRecurrence(recurrence, new Date(startDate));
}
debugger;
}
// Record all event IDs to spreadsheet
range.setValues(data);
}
You may refer with this thread: Cannot find function createEvent (or createAllDayEvent) in object Calendar. (Google Spreadsheet App). Make sure that yout startDate variable has the right format.
if you are not sure about the 'date' variable being actually a date
you could use
cal.createAllDayEvent(title, new Date(date), {description:desc,location:loc});
that said, it is quite easy to check with the logger
Logger.log(date)
should return a date value in the form Tue Sep 18 03:00:00 PDT 2012
Additional reference: Google script google sheet to calendar TypeError: Cannot find function createEvent in object Calendar. (line 18, file "Code")
I have a XtraScheduler SchedulerControl configured as the following:
private DevExpress.XtraScheduler.SchedulerControl _SchedulerControl;
public DevExpress.XtraScheduler.SchedulerControl ConvSchedulerControl
{
get
{
if (_SchedulerControl == null)
{
_SchedulerControl = new DevExpress.XtraScheduler.SchedulerControl();
_SchedulerControl.Storage = new SchedulerStorage();
_SchedulerControl.Storage.Appointments.Mappings.Subject = "StandingOrderIDString";
_SchedulerControl.Storage.Appointments.Mappings.Start = "ScheduledDate";
_SchedulerControl.Storage.Appointments.Mappings.RecurrenceInfo = "RecurrenceInfo";
_SchedulerControl.Storage.Appointments.Mappings.Type = "Type";
_SchedulerControl.Storage.Appointments.CustomFieldMappings.Add(new DevExpress.XtraScheduler.AppointmentCustomFieldMapping("Inactive", "Inactive"));
_SchedulerControl.Storage.Appointments.CustomFieldMappings.Add(new DevExpress.XtraScheduler.AppointmentCustomFieldMapping("StandingOrderKEY", "StandingOrderKEY"));
BindingSource bs = new BindingSource();
bs.DataSource = new List<StandingOrder>();
_SchedulerControl.Storage.Appointments.DataSource = bs;
}
return _SchedulerControl;
}
}
and I am attempting to programmatically add an appointment with recurrence information, as in the examples given at http://help.devexpress.com/#WindowsForms/CustomDocument6201 . However, when the method execution reaches its final line (indicated) that adds the created appointment to the storage, it "hangs." No exception is ever thrown; I have left it running for upwards of 15 minutes with no change:
public void SetRecurrence(DateTime startDate, DateTime? endDate)
{
Appointment appointmentObj = ConvSchedulerControl.Storage.CreateAppointment(AppointmentType.Pattern);
if (endDate != null &&
endDate != DateTime.Parse("12/31/2999"))
{
appointmentObj.End = (DateTime)endDate;
}
else
{
appointmentObj.RecurrenceInfo.Range = RecurrenceRange.NoEndDate;
}
appointmentObj.Start = startDate;
appointmentObj.RecurrenceInfo.Type = RecurrenceType.Weekly;
appointmentObj.RecurrenceInfo.WeekDays = WeekDays.Monday;
appointmentObj.AllDay = true;
//Program execution reaches this line, but never proceeds past it.
ConvSchedulerControl.Storage.Appointments.Add(appointmentObj);
}
I would imagine that there's something wrong with the configuration that's preventing the storage from being able to successfully add the appointment, but I've been unable to turn up any other information on the subject. Does anyone know why this method isn't appropriate for adding an appointment to the storage, and how it can be corrected?
You've failed to provide a mapping for the 'End' field. This is a required mapping. Honestly, I only know this from having created a calendar in the designer. When you place a SchedulerControl onto a form/control, one of the things the designer gives you is a "Mappings Wizard". The 'Start' and 'End' fields are marked in the wizard as being required.