Я хочу реализовать ЦАП для использования на странице обработки, где данные не будут сохранены в базе данных.
Вариант использования этого вопроса - загрузка данных из внешнего веб-сервиса вподготовка к созданию платежных записей AR.Мы бы хотели, чтобы пользователь зашел на выделенную страницу обработки, а затем смог бы использовать существующую платформу обработки страниц, чтобы выполнить генерацию платежа.
Нам нужна страница обработки, чтобы обратиться к веб-службеи запрашивать любые необработанные платежи, затем загружать данные в экземпляры DAC для отображения конечному пользователю, прежде чем платежи будут выбраны для обработки.Мы не видим причин для сохранения этих данных в базе данных, поэтому я пытался заставить их работать, используя только непостоянные атрибуты в ЦАП.Единственный способ приблизиться к этому - это объявить хотя бы одно поле с помощью атрибута [PXDB {type}].Если я пытаюсь заставить их всех использовать непостоянные данные, я получаю сообщение об ошибке «Неверный синтаксис рядом с ключевым словом« FROM. »»
Я также ищу способ загрузить сетку обработки, когда графикпервый экземпляр.Я могу загрузить данные с помощью кнопки, но результат должен загружаться всякий раз, когда обновляется график обработки.Я, вероятно, создам для этого отдельный билет, чтобы этот фокус был сфокусирован на непостоянном ЦАП.
Я дал искреннюю попытку просмотреть документацию по любым подсказкам, как это сделать, но я этого не сделалвидел что-нибудь еще в этом конкретном случае использования.Я предполагаю, что мне нужно использовать атрибут уровня класса, чтобы установить это, но не удалось найти то, что нужно использовать.
[Serializable]
//[PXNonInstantiatedExtension] this looked close
//to what we are looking for but experimenting
//with it did not yield desired results.
public class CtpPayment : IBqlTable
{
#region Selected
public abstract class selected : IBqlField{ }
[PXBool]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
#endregion
public abstract class id : IBqlField { }
//todo: find out what size we need 50 is just a guess.
//[PXDBString(50, IsKey = true)] //We are able to get this to work only if
//we have at least one persisting field.
//we can live with this but would prefer to
//have the whole class as non-persistent
[PXString(50)] //having only non-persisting attributes will result in a
//Incorrect syntax near the keyword 'FROM'. error.
[PXUIField(DisplayName = "Click To Pay Id")]
public virtual string Id { get; set; }
public abstract class description : IBqlField {}
[PXString(200)]
[PXUIField(DisplayName = "Payment Description")]
public virtual string Description { get; set; }
public abstract class amount : IBqlField { }
[PXDecimal(2)]
[PXUIField(DisplayName = "Payment Amount")]
public virtual decimal? Amount { get; set; }
public abstract class customerId : IBqlField { }
[PXInt]
[PXUIField(DisplayName = "Customer ID")]
//todo: decorate this with the needed attributes to display friendly key instead of int.
public virtual int? CustomerID { get; set; }
}
//the graph is defined as follows.
//todo: follow up and determine the most appropriate name for this graph.
public class CtpPaymentProcess : PXGraph<CtpPaymentProcess>
{
public PXAction<CtpPayment> checkForC2PPayments;
public PXSetup<CtpSetup> setup;
public PXProcessing<CtpPayment> Payments;
private CtpAcumatica _ctpAcumatica;
public CtpAcumatica CtpAcumatica
{
get
{
if (_ctpAcumatica == null)
{
var graph = PXGraph.CreateInstance<PXGraph>();
_ctpAcumatica = new CtpAcumatica(setup.Current.CtpUrl,
setup.Current.CtpApiKey,
"NoLongerNeeded", //todo: refactor this out.
"NoLongerNeeded", //todo: refactor this out.
graph);
}
return _ctpAcumatica;
}
}
public CtpPaymentProcess()
{
Payments.SetProcessCaption("Process Payments");
Payments.SetProcessAllCaption("Process All Payments");
Payments.SetProcessDelegate<CtpPaymentProcess>(
delegate(CtpPaymentProcess graph, CtpPayment payment)
{
graph.Clear();
graph.ProcessPayment(payment, true);
}
);
this.Initialized += InitializePayments;
}
private void InitializePayments(PXGraph sender)
{
//this looked like a candidate to auto populate the
//graph with pending payments on initializing the graph.
//this unfortunately does not get the desired end result.
//it works fine via the button.
CreateNonPersistedPaymentRecords();
}
private void ProcessPayment(CtpPayment payment, bool massProcess)
{
PXTrace.WriteInformation($"Processing {payment}");
//todo: process Payment
}
/// <summary>
/// This is a temporary method with the purpose of exploring retrieval of payments and rendering
/// Payment and application records. this method will not exist in production code and will
/// be replaced with a dedicated PXProcessing page.
/// </summary>
[PXButton]
[PXUIField(DisplayName = "Check for Click-to-Pay Payments")]
protected void CheckForC2PPayments()
{
//todo: we need to find a way to do this
// without the user needing to hit
// this button.
CreateNonPersistedPaymentRecords();
}
public QueryPaymentsResponseViewModel payments { get; internal set; }
private void CreateNonPersistedPaymentRecords()
{
payments = this.CtpAcumatica.CheckForAllNewPayments(100);
PXTrace.WriteInformation("Processing " + (payments.Payments.Count) + " payments");
if (payments.Payments != null)
{
// Loop processing each payment returned from the gateway, storing the
// information into non persisted cache.
foreach (var payment in payments.Payments)
{
if (!payment.IsMarkedRetrieved)
{
createPaymentProcessRecord(payment);
}
}
}
}
private void createPaymentProcessRecord(PaymentViewModel payment)
{
CtpPayment ctpPayment = new CtpPayment
{
Id = payment.Id,
Description = $"CustID{payment.CustomerId} ApsTransID:{payment.ApsTransactionId} Currency{payment.Currency} {payment.AccountName} {payment.PaymentType} {payment.Date}",
CustomerID = int.Parse(payment.CustomerId),
Amount = payment.Amount
};
var r = Payments.Cache.Insert(ctpPayment) ?? Payments.Cache.Update(ctpPayment);
}
}