How to create Copy of same appointment again in an new action?
Hello Everyone,
I have created a new action button in appointment screen and need to create a new appointment with all the current appointment information includes tabs also in this new action. I have to perform same like copy/paste functionality from this action and have to save the new appointment. How do we perform Copy/paste through logic or is there any other way to do it with acumatica existing methods in easy way instead of creating and assigning everything to a new objects.
Need some suggestions for best possible way to implement this.
Thanks in advance.
Page 1 / 1
Hi @rajeshvemunoori31 Try this way, when you click on action button then it will create as a new record with same data.
this is sample code. May be it’s useful.
public PXAction<SSPAgreement> revision; PXButton(CommitChanges = true)] PXUIField(DisplayName = "Revision", MapEnableRights = PXCacheRights.Insert, MapViewRights = PXCacheRights.Insert)] public virtual IEnumerable Revision(PXAdapter adapter) { string msg = "Are you sure you want to create a new revision?"; WebDialogResult result = Agreements.Ask(ActionsMessages.Warning, PXMessages.LocalizeFormatNoPrefix(msg), MessageButtons.OKCancel, MessageIcon.Information, true);
// Update the Active field to False to the Revisioning record. SSPAgreement sspAgreement = this.Agreements.Current; sspAgreement.Active = false; Agreements.Cache.Update(sspAgreement); Agreements.Update(sspAgreement); Actions.PressSave();
// Step 2: Insert the newly created DAC into DB. PXDatabase.Insert<SSPAgreement>(new PXDataFieldAssign(typeof(SSPAgreement.agreeNbr).Name, PXDbType.NVarChar, 15, NewRecord.AgreeNbr), new PXDataFieldAssign(typeof(SSPAgreement.revision).Name, PXDbType.Int, NewRecord.Revision), new PXDataFieldAssign(typeof(SSPAgreement.agreeRevision).Name, PXDbType.NVarChar, 30, (NewRecord.AgreeNbr + "-" + NewRecord.Revision)), new PXDataFieldAssign(typeof(SSPAgreement.agreeType).Name, PXDbType.NVarChar, 5, NewRecord.AgreeType), new PXDataFieldAssign(typeof(SSPAgreement.templateCode).Name, PXDbType.NVarChar, 30, NewRecord.TemplateCode), new PXDataFieldAssign(typeof(SSPAgreement.active).Name, PXDbType.Bit, NewRecord.Active), new PXDataFieldAssign(typeof(SSPAgreement.descr).Name, PXDbType.NVarChar, 256, NewRecord.Descr), new PXDataFieldAssign(typeof(SSPAgreement.agreeDate).Name, PXDbType.DateTime, NewRecord.AgreeDate), new PXDataFieldAssign(typeof(SSPAgreement.expDate).Name, PXDbType.DateTime, NewRecord.ExpDate), new PXDataFieldAssign(typeof(SSPAgreement.refNoteid).Name, PXDbType.UniqueIdentifier, 100, NewRecord.RefNoteid), new PXDataFieldAssign(typeof(SSPAgreement.refNbr).Name, PXDbType.NVarChar, 30, NewRecord.RefNbr), new PXDataFieldAssign(typeof(SSPAgreement.createdByID).Name, PXDbType.UniqueIdentifier, 100, UserIDNumbering), new PXDataFieldAssign(typeof(SSPAgreement.createdByScreenID).Name, PXDbType.Char, 8, "SSP20103"), new PXDataFieldAssign(typeof(SSPAgreement.createdDateTime).Name, PXDbType.DateTime, System.DateTime.Now), new PXDataFieldAssign(typeof(SSPAgreement.lastModifiedByID).Name, PXDbType.UniqueIdentifier, 100, UserIDNumbering), new PXDataFieldAssign(typeof(SSPAgreement.lastModifiedByScreenID).Name, PXDbType.Char, 8, "SSP20103"), new PXDataFieldAssign(typeof(SSPAgreement.noteid).Name, PXDbType.UniqueIdentifier, 100, agreementMaint.UID), new PXDataFieldAssign(typeof(SSPAgreement.lastModifiedDateTime).Name, PXDbType.DateTime, System.DateTime.Now));
SSPAgreementMaint graph = PXGraph.CreateInstance<SSPAgreementMaint>(); graph.Agreements.Current = PXSelectOrderBy<SSPAgreement, OrderBy<Desc<SSPAgreement.createdDateTime>>>.Select(graph); if (graph.Agreements.Current != null) throw new PXRedirectRequiredException(graph, "SSP20103");
return adapter.Get(); }
Hello @NageswaraRaoAddanki60 ,
Thank you for the response.
I have tried similar way but it is creating lot of issues in the code.
I have to copy every tab data to create new one. This may miss few columns as well. My actual requirement is to create new appointment in Complete Action. I’m getting another process error here.
public class TestAppointmentEntryExt : PXGraphExtension<AppointmentEntry> { public static bool IsActive() { return true;// PXAccess.FeatureInstalled<FeaturesSet.>(); }
public delegate IEnumerable CompleteAppointmentDelegate(PXAdapter adapter); PPXOverride] public IEnumerable CompleteAppointment(PXAdapter adapter, CompleteAppointmentDelegate baseMethod) { if(Base.AppointmentSelected.Current != null) { FSAppointmentExt rowExt = Base.AppointmentRecords.Current.GetExtension<FSAppointmentExt>(); if(rowExt.UsrCompleted == "GB") { //FSAppointment AppoldOrderRow = new FSAppointment();
I’d say there are two different approaches that have their pros and cons.
Approach 1. Copy object in code.
You can find an example of this approach in CATranEntry.Reverse action.
Here is a generic example:
//use cache.CreateCopy to duplicate the record var record= (RecordType)Cache.CreateCopy(Records.Current); //clear key field values from the record record.RefNbr=null; //Insert the record to the cache Records.Insert(record);
Pros of this approach are
It is efficient in terms of performance
You have full control on all the fields and if you need some additional data manipulation with the object you can easily implement it
Cons:
Some values of the record may be redefaulted when you insert it, so you need to be aware of the defaulting logic for each field.
If what you are trying to copy is a complex record, e.g. consisting of several DACs, you’ll need to copy each of them and also be aware of the relations between the DACs
Approach 2. Use standard UI Copy-paste functionally.
Here is an example:
// use screenID of the screen that you use to copy data using (new PXScreenIDScope("IN202500")) { InventoryItemMaint graph = PXGraph.CreateInstance<InventoryItemMaint>();
graph.Item.Current = Item; PXCopyPasteData<InventoryItemMaint> copyPasteData = new PXCopyPasteData<InventoryItemMaint>(); copyPasteData.CopyFrom(graph);
If there is a complex object that needs to be copied, the copy paste functionality takes care of it.
If the copy paste functionality for the screen is already implemented, you reuse the same logic.
You don’t need to write a lot of code.
Cons:
If there is no standard Copy-Paste buttons in UI, you need to implement and test it first.
It’s not that great from the performance point of view.
You don’t have the same level of flexibility of the process.
Hello @Dmitrii Naumov ,
Thanks for the detailed explanation.
I’m trying to use the 2nd approch in appointment screen but i’m getting errors in my code.
I have used below code.
public delegate IEnumerable CompleteAppointmentDelegate(PXAdapter adapter); PXOverride] public IEnumerable CompleteAppointment(PXAdapter adapter, CompleteAppointmentDelegate baseMethod) { if(Base.AppointmentSelected.Current != null) { FSAppointmentExt rowExt = Base.AppointmentRecords.Current.GetExtension<FSAppointmentExt>(); if (rowExt.UsrCompleted == "Test") { using (new PXScreenIDScope("FS300200")) { AppointmentEntry graph = PXGraph.CreateInstance<AppointmentEntry>();
graph.AppointmentRecords.Current = Base.AppointmentRecords.Current; //graph.AppointmentSelected.Current = Base.AppointmentSelected.Current; //graph.ServiceOrderRelated.Current = Base.ServiceOrderRelated.Current; PXCopyPasteData<AppointmentEntry> copyPasteData = new PXCopyPasteData<AppointmentEntry>(); copyPasteData.CopyFrom(graph); //Used Base as well here
The Document summary contains 3 main views( AppointmentRecords, ServiceOrderRelated,AppointmentSelected). I’m trying to use these views as well in the code but getting different errors.
Am i missing anything here? Please suggest.
Thanks
Hello @Dmitrii Naumov ,
I have tried to implement with the first approach as well, but it is also creating same issue while creating a new appointment.
var record = (FSAppointment)graph.AppointmentRecords.Cache.CreateCopy(Base.AppointmentRecords.Current); record.SrvOrdType = "MRO"; record.RefNbr = null; //record.SORefNbr = Base.AppointmentRecords.Current.SORefNbr; //record.SrvOrdType = Base.AppointmentRecords.Current.SrvOrdType; graph.AppointmentRecords.Cache.Insert(record); //Getting object reference and fields cannot be empty error here
var recordselected = (FSAppointment)graph.AppointmentSelected.Cache.CreateCopy(Base.AppointmentSelected.Current); recordselected.RefNbr = null; graph.AppointmentSelected.Cache.Insert(recordselected);
var recordSrvorder = (FSServiceOrder)graph.ServiceOrderRelated.Cache.CreateCopy(Base.ServiceOrderRelated.Current); recordSrvorder.RefNbr = null; graph.ServiceOrderRelated.Cache.Insert(recordSrvorder); graph.Save.Press();
Thanks
@rajeshvemunoori31 it seems the appointment screen has some tricks that cause the error. Could you create a support case for that?
Hi @rajeshvemunoori31 have you been able to resolve your issue? Thank you!
@rajeshvemunoori31 , please find the code which copies the appointment to a new one (with appointment details, but without creation of a new service order) upon the Complete action
public class VanDykAppointmentEntry_Extension : PXGraphExtension<AppointmentEntry> { #region COmplete Action public virtual void CopyAppointmentBeforeCompletion() { AppointmentEntry graph = PXGraph.CreateInstance<AppointmentEntry>();
public delegate IEnumerable CompleteAppointmentDelegate(PXAdapter adapter); PXOverride] public IEnumerable CompleteAppointment(PXAdapter adapter, CompleteAppointmentDelegate baseMethod) { if (Base.AppointmentSelected.Current != null) { CopyAppointmentBeforeCompletion();
} return baseMethod(adapter);
} #endregion
}
Notice that this code assigns the key fields values (SrvOrdType and Refnbr) to the appointment details created (instead of leaving them blank and relying on PXDbDefault)
This happens because the insert operation into the primary (FSAppointment) cache launched during the workflow action inherits the auto-saving behavior for the existing record. Because the Complete Appointment action auto-persists an existing FSAppointment record, this auto-persisting is applied to all other FSAppointment records we operate on during this action.
This reason might explain why you get the error trying t use the ‘generic copy-paste mechanism’ though I did not investigate it deep
@rajeshvemunoori31
Alternatively, you can use the ‘generic Copy-Paste’ approach (
) , but you need to swap the order of base method and custom methods execution
Base method should be executed first, and after this ‘the auto-save’ behavior won’t be observed for FSAppointment inserted to cache