acumatica
Acumatica 플랫폼 속성 참조
수색…
PXFormula 특성
일반적인 설명
Acumatica의 수식은 다른 개체 필드의 값을 기반으로 계산되는 DAC 필드입니다.
수식을 계산하기 위해 Aсumatiça 프레임 워크는 산술, 논리 및 비교 연산 및 문자열 처리 함수와 같은 다양한 연산 및 함수 집합을 제공하며 내장 된 수식 목록을 참조하십시오. 필드 값 외에도 수식은 Acumatica의 핵심과 애플리케이션 솔루션이 제공하는 다양한 상수를 사용할 수 있습니다. 또한 수식은 현재 레코드뿐만 아니라 다른 소스에서도 계산 값을 얻을 수 있습니다 ( 수식 컨텍스트 및 해당 수식어 참조 ).
수식의 장점은 적시에 자동으로 값을 다시 계산한다는 것입니다.
- 필드 기본값 (새 행 삽입, 수식 필드의
FieldDefaulting이벤트 처리기) - 종속 필드 업데이트시 (각 종속 필드의
FieldUpdated이벤트 처리기) - 데이터베이스 선택시 (언 바운드 필드에만 해당,
RowSelecting이벤트 핸들러) - 필요한 경우 데이터베이스 유지시 (개발자가 명시 적으로 지정해야 함,
RowPersisted이벤트 처리기)
종속 필드를 업데이트 할 때 수식 필드 값을 다시 계산하면 수식 필드의 FieldUpdated 이벤트가 발생합니다. 이렇게하면 종속 수식 체인을 만들 수 있습니다 (수식에서 직접 및 중개 순환 참조 참고).
응용 프로그램 개발자는 자체 응용 프로그램 수식을 작성할 수 있습니다.
사용법의 형태
공식은 세 가지 주요 모드로 사용할 수 있습니다.
- 값을 계산하고 수식 필드에 할당하기 만하면됩니다 ( 기본 사용법 참고 )
- 수식 필드의 기존 값에서 집계 값 계산 및이를 부모 개체의 지정된 필드에 할당 ( 집계 사용 참조)
- 혼합 모드 : 수식 값을 계산하여 수식 필드에 할당하고 집계 값을 계산 한 다음 상위 개체의 필드에 할당합니다 ( 복합 사용 참조).
혼합 모드와 매우 유사한 다른 언 바운드 수식이 있지만 수식의 계산 된 값은 수식 필드에 할당되지 않습니다. 집계 된 값은 즉시 계산되어 상위 개체의 필드에 할당됩니다. 자세한 내용 은 언 바운드 수식의 사용 을 참조하십시오.
PXFormulaAttribute 속성 및 생성자 매개 변수
수식 기능은 PXFormulaAttribute 의해 구현됩니다. PXFormulaAttribute의 생성자에는 다음 시그니처가 있습니다.
public PXFormulaAttribute(Type formulaType)
{
// ...
}
단일 매개 변수 formulaType 은 동일한 데이터 레코드의 다른 필드에서 필드 값을 계산하는 수식의 형식입니다. 이 매개 변수는 다음 조건 중 하나를 충족해야합니다.
- IBqlField 인터페이스를 구현해야합니다.
- BQL 상수 여야합니다.
- IBqlCreator 인터페이스를 구현해야합니다 (기본 제공 일반 수식 목록 참고).
public PXFormulaAttribute(Type formulaType, Type aggregateType)
{
// ...
}
첫 번째 매개 변수 인 formulaType 은 첫 번째 생성자와 같습니다. 두 번째 매개 변수 인 aggregateType 은 하위 데이터 레코드 필드에서 상위 데이터 레코드 필드를 계산하는 집계 수식 유형입니다. SumCalc, CountCalc, MinCalc 및 MaxCalc와 같은 집계 함수를 사용할 수 있습니다. 응용 프로그램 개발자는 자체 집계 수식을 만들 수 있습니다.
집계 수식 유형은 제네릭 형식이어야하며 IBqlAggregateCalculator 인터페이스를 구현해야합니다. 집계 수식 유형의 첫 번째 제네릭 매개 변수는 IBqlField 인터페이스를 구현해야하며 부모 개체의 필드 형식을 가져야합니다.
public virtual bool Persistent { get; set; }
PXFormulaAttribute.Persistent 속성은 변경 내용을 데이터베이스에 저장 한 후 특성에서 수식을 다시 계산할지 여부를 나타냅니다. 수식이 사용하는 필드가 RowPersisting 이벤트에서 업데이트되면 다시 계산해야 할 수 있습니다. 기본적으로이 속성은 false 입니다.
용법
대부분의 경우 수식은 동일한 데이터 레코드의 다른 필드에서 수식 필드 값을 직접 계산하는 데 사용됩니다.
수식 사용의 가장 간단한 예 :
[PXDBDate]
[PXFormula(typeof(FADetails.receiptDate))]
[PXDefault]
[PXUIField(DisplayName = Messages.PlacedInServiceDate)]
public virtual DateTime? DepreciateFromDate { get; set; }
이 예에서는 새 레코드를 삽입하고 ReceiptDate 필드를 업데이트 할 때 ReceiptDate 필드의 값이 DepreciateFromDate 필드에 할당됩니다.
약간 더 복잡한 예 :
[PXCurrency(typeof(APPayment.curyInfoID), typeof(APPayment.unappliedBal))]
[PXUIField(DisplayName = "Unapplied Balance", Visibility = PXUIVisibility.Visible, Enabled = false)]
[PXFormula(typeof(Sub<APPayment.curyDocBal, APPayment.curyApplAmt>))]
public virtual Decimal? CuryUnappliedBal { get; set; }
여기에서 문서의 적용되지 않은 잔액은 문서 잔액과 적용된 금액 간의 차이로 계산됩니다.
기본값이있는 다중 선택의 예 :
[PXUIField(DisplayName = "Class Icon", IsReadOnly = true)]
[PXImage]
[PXFormula(typeof(Switch<
Case<Where<EPActivity.classID, Equal<CRActivityClass.task>>, EPActivity.classIcon.task,
Case<Where<EPActivity.classID, Equal<CRActivityClass.events>>, EPActivity.classIcon.events,
Case<Where<EPActivity.classID, Equal<CRActivityClass.email>,
And<EPActivity.isIncome, NotEqual<True>>>, EPActivity.classIcon.email,
Case<Where<EPActivity.classID, Equal<CRActivityClass.email>,
And<EPActivity.isIncome, Equal<True>>>, EPActivity.classIcon.emailResponse,
Case<Where<EPActivity.classID, Equal<CRActivityClass.history>>, EPActivity.classIcon.history>>>>>,
Selector<Current2<EPActivity.type>, EPActivityType.imageUrl>>))]
public virtual string ClassIcon { get; set; }
분야의 순서
DAC의 필드 순서는 수식 계산을 수정하는 데 중요합니다. 다른 수식을 비롯하여 수식이 계산되는 모든 원본 필드는 수식 필드 앞에 DAC에 정의되어야합니다. 그렇지 않으면 필드가 잘못 계산되거나 런타임 오류가 발생할 수 있습니다.
수식 컨텍스트 및 해당 수식어
기본적으로 수식 계산의 컨텍스트는 수식 선언이 들어있는 클래스의 현재 개체 (레코드)에 의해 제한됩니다. 또한 상수 ( Constant<> 클래스의 자손)를 사용할 수 있습니다.
해당 필드의 필드 만 사용하는 수식 :
public partial class Contract : IBqlTable, IAttributeSupport
{
//...
[PXDecimal(4)]
[PXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
[PXFormula(typeof(Add<Contract.pendingRecurring, Add<Contract.pendingRenewal, Contract.pendingSetup>>))]
[PXUIField(DisplayName = "Total Pending", Enabled=false)]
public virtual decimal? TotalPending { get; set; }
//...
}
그러나 다른 소스에서 수식 계산에 대한 입력 값을 얻을 수 있습니다.
- BLC에있는 캐시의 현재 레코드 (할당 된 경우).
-
PXSelectorAttribute지정된 외부 레코드입니다. -
PXParentAttribute지정된 부모 레코드입니다.
수식은 다음 컨텍스트 수정자를 지원합니다.
Current<TRecord.field> 및 Current2<TRecord.field>
TRecord 캐시의 Current 속성에 저장된 레코드의 필드 값을 가져옵니다.
캐시의 Current 속성 또는 필드 자체 에 null이 포함 된 경우 :
- 현재 <>는 필드 기본값을 강제 설정하고 기본 필드 값을 반환합니다.
- Current2 <>는 null을 리턴합니다.
예:
[PXFormula(typeof(Switch<
Case<Where<
ARAdjust.adjgDocType, Equal<Current<ARPayment.docType>>,
And<ARAdjust.adjgRefNbr, Equal<Current<ARPayment.refNbr>>>>,
ARAdjust.classIcon.outgoing>,
ARAdjust.classIcon.incoming>))]
protected virtual void ARAdjust_ClassIcon_CacheAttached(PXCache sender)
Parent<TParent.field>
현재 DAC에있는 PXParentAttribute에 정의 된대로 부모 데이터 레코드의 필드 값을 가져옵니다.
public class INTran : IBqlTable
{
[PXParent(typeof(Select<
INRegister,
Where<
INRegister.docType, Equal<Current<INTran.docType>>,
And<INRegister.refNbr,Equal<Current<INTran.refNbr>>>>>))]
public virtual String RefNbr { ... }
[PXFormula(typeof(Parent<INRegister.origModule>))]
public virtual String OrigModule { ... }
}
IsTableEmpty<TRecord>
반환 true 지정된 DAC에 해당하는 DB 테이블 레코드, 포함되지 않는 경우 false , 그렇지.
public class APRegister : IBqlTable
{
[PXFormula(typeof(Switch<
Case<Where<
IsTableEmpty<APSetupApproval>, Equal<True>>,
True,
Case<Where<
APRegister.requestApproval, Equal<True>>,
False>>,
True>))]
public virtual bool? DontApprove { get; set; }
}
Selector<KeyField, ForeignOperand>
현재의 DAC의 외래 키 필드 (KeyField)로 정의되고있는 PXSelectorAttribute를 꺼냅니다.
selector에 의해 현재 참조 된 외부 데이터 레코드를 가져옵니다.
ForeignOperand에 정의 된대로 해당 데이터 레코드의 식을 계산하여 반환합니다.
public class APVendorPrice : IBqlTable
{
// Note: inventory attribute is an
// aggregate containing a PXSelectorAttribute
// inside, which is also valid for Selector<>.
// -
[Inventory(DisplayName = "Inventory ID")]
public virtual int? InventoryID
[PXFormula(typeof(Selector<
APVendorPrice.inventoryID,
InventoryItem.purchaseUnit>))]
public virtual string UOM { get; set; }
}
언 바운드 필드에 수식 사용
수식 필드가 PXFieldAttribute 자손 중 하나 (예 : PXIntAttribute 또는 PXStringAttribute )로 표시된 언 바운드 필드이면 RowSelecting 이벤트 중에 해당 계산이 추가로 트리거됩니다.
기본 제공 일반 수식 목록
미정
수식의 직접 및 중재 순환 참조
미정
조건부 수식의 제어 흐름
미정
한 필드에서 여러 수식 사용
미정
PXRestrictor 특성
소개
그러나 중요하고 자주 사용되는 PXSelectorAttribute 특성 (선택기라고도 함)에는 두 가지 주요 단점이 있습니다.
- 선택기 조건을 만족하는 항목이없는 경우 정보 메시지
"<object_name> cannot be found in the system"제공합니다. - 레코드의 다른 필드를 업데이트하지만 선택기에서 참조하는 개체가 이미 변경되어 해당 조건을 더 이상 충족하지 않으면 동일한 오류 메시지가 나타납니다. 법이 소급해서는 안되기 때문에이 행동은 분명히 잘못되었습니다.
PXRestrictorAttribute (제한 PXRestrictorAttribute 도 함)는 이러한 문제를 해결하는 데 사용할 수 있습니다.
세부
PXRestrictorAttribute 가 단독으로 작동하지 않습니다. 항상 PXSelectorAttribute 와 쌍을 PXSelectorAttribute 합니다. 선택자없이리스트 릭터를 사용하면 효과가 없습니다.
제한 기는 동일한 필드에서 선택기를 찾아서 추가 조건과 해당 오류 메시지를 주입합니다. 제한 조건은 부울 AND를 통해 선택기 조건에 추가되며 참조 된 개체가 제한 조건 제약 조건을 위반하는 경우 적절한 오류 메시지가 생성됩니다. 또한 참조 된 객체가 변경되어 더 이상 제한 조건을 충족시키지 않으면 참조 객체의 다른 필드를 변경할 때 오류 메시지가 생성되지 않습니다.
일반적인 사용법 :
[PXDBInt]
[PXSelector(typeof(Search<FAClass.assetID, Where<FAClass.recordType, Equal<FARecordType.classType>>>),
typeof(FAClass.assetCD), typeof(FAClass.assetTypeID), typeof(FAClass.description), typeof(FAClass.usefulLife),
SubstituteKey = typeof(FAClass.assetCD),
DescriptionField = typeof(FAClass.description), CacheGlobal = true)]
[PXRestrictor(typeof(Where<FAClass.active, Equal<True>>), Messages.InactiveFAClass, typeof(FAClass.assetCD))]
[PXUIField(DisplayName = "Asset Class", Visibility = PXUIVisibility.Visible)]
public virtual int? ClassID { get; set; }
하나의 선택자 속성과 함께 여러 제한자가 사용될 수 있습니다. 이 경우 모든 추가 제한 기 조건은 결정되지 않은 순서로 적용됩니다. 조건을 위반하면 해당 오류 메시지가 생성됩니다.
선택기 자체의 Where<> 조건은 모든 제한 자 조건 후에 적용됩니다.
[PXDefault]
// An aggregate attribute containing the selector inside.
// -
[ContractTemplate(Required = true)]
[PXRestrictor(typeof(Where<ContractTemplate.status, Equal<Contract.status.active>>), Messages.TemplateIsNotActivated, typeof(ContractTemplate.contractCD))]
[PXRestrictor(typeof(Where<ContractTemplate.effectiveFrom, LessEqual<Current<AccessInfo.businessDate>>,
Or<ContractTemplate.effectiveFrom, IsNull>>), Messages.TemplateIsNotStarted)]
[PXRestrictor(typeof(Where<ContractTemplate.discontinueAfter, GreaterEqual<Current<AccessInfo.businessDate>>,
Or<ContractTemplate.discontinueAfter, IsNull>>), Messages.TemplateIsExpired)]
public virtual int? TemplateID { get; set; }
옵션
PXRestrictorAttribute의 생성자는 세 개의 매개 변수를 사용합니다.
- 제한 기의 추가 조건. 이 BQL 유형은
IBqlWhere인터페이스를 구현해야합니다. - 적절한 오류 메시지. 메시지에는 컨텍스트를 표시하는 형식 요소 (중괄호)가 포함될 수 있습니다. 메시지는 지역화 가능한 정적 클래스 (예 :
PX.Objects.GL.Messages)에 정의 된 문자열 상수 여야합니다. - 필드 유형의 배열입니다. 이러한 필드는 현재 개체에 속해야하며
IBqlField인터페이스를 구현해야합니다. 필드 값은 오류 메시지 형식으로 사용됩니다.
또한 제한 기 동작을 지정하는 몇 가지 옵션이 있습니다.
상속 된 제한 자 재정의
ReplaceInherited 속성은 현재 제한자가 상속 된 제한을 재정의해야하는지 여부를 나타냅니다. 이 속성을 true로 설정하면 모든 집계 속성 또는 기본 속성에 배치 된 모든 상속 된 제한자가 대체됩니다.
상속 된 제한 기 대체 :
[CustomerActive(Visibility = PXUIVisibility.SelectorVisible, Filterable = true, TabOrder = 2)]
[PXRestrictor(typeof(Where<Customer.status, Equal<CR.BAccount.status.active>,
Or<Customer.status, Equal<CR.BAccount.status.oneTime>,
Or<Customer.status, Equal<CR.BAccount.status.hold>,
Or<Customer.status, Equal<CR.BAccount.status.creditHold>>>>>), Messages.CustomerIsInStatus, typeof(Customer.status),
ReplaceInherited = true)] // Replaced all restrictors from CustomerActiveAttribute
[PXUIField(DisplayName = "Customer")]
[PXDefault()]
public override int? CustomerID { get; set; }
합리적인 대안이있는 경우 응용 프로그램 코드에서 ReplaceInherited 속성을 사용하는 것을 권장하지 않습니다. 이 속성은 주로 사용자 지정에 사용하기위한 것입니다.
전역 캐싱
CacheGlobal 에서와 같은 방법으로 글로벌 사전 기능을 지원 PXSelectorAttribute .
사용을위한 권장 사항
제한 조건 만 사용하십시오.
제한 자와 선택기를 함께 사용하면 후자에 IBqlWhere 절이 IBqlWhere 합니다. 이상적으로 모든 조건은 제한 장치로 옮겨야합니다. 이 접근 방식은보다 사용자 친화적 인 오류 메시지를 제공하고 불필요한 소급 오류를 제거합니다.
이상적인 예 :
[PXDBString(5, IsFixed = true, IsUnicode = false)]
[PXUIField(DisplayName = "Type", Required = true)]
[PXSelector(typeof(EPActivityType.type), DescriptionField = typeof(EPActivityType.description))]
[PXRestrictor(typeof(Where<EPActivityType.active, Equal<True>>), Messages.InactiveActivityType, typeof(EPActivityType.type))]
[PXRestrictor(typeof(Where<EPActivityType.isInternal, Equal<True>>), Messages.ExternalActivityType, typeof(EPActivityType.type))]
public virtual string Type { get; set; }
가능한 소급 오류 :
[PXDBInt]
[PXUIField(DisplayName = "Contract")]
[PXSelector(typeof(Search2<Contract.contractID,
LeftJoin<ContractBillingSchedule, On<Contract.contractID, Equal<ContractBillingSchedule.contractID>>>,
Where<Contract.isTemplate, NotEqual<True>,
And<Contract.baseType, Equal<Contract.ContractBaseType>,
And<Where<Current<CRCase.customerID>, IsNull,
Or2<Where<Contract.customerID, Equal<Current<CRCase.customerID>>,
And<Current<CRCase.locationID>, IsNull>>,
Or2<Where<ContractBillingSchedule.accountID, Equal<Current<CRCase.customerID>>,
And<Current<CRCase.locationID>, IsNull>>,
Or2<Where<Contract.customerID, Equal<Current<CRCase.customerID>>,
And<Contract.locationID, Equal<Current<CRCase.locationID>>>>,
Or<Where<ContractBillingSchedule.accountID, Equal<Current<CRCase.customerID>>,
And<ContractBillingSchedule.locationID, Equal<Current<CRCase.locationID>>>>>>>>>>>>,
OrderBy<Desc<Contract.contractCD>>>),
DescriptionField = typeof(Contract.description),
SubstituteKey = typeof(Contract.contractCD), Filterable = true)]
[PXRestrictor(typeof(Where<Contract.status, Equal<Contract.status.active>>), Messages.ContractIsNotActive)]
[PXRestrictor(typeof(Where<Current<AccessInfo.businessDate>, LessEqual<Contract.graceDate>, Or<Contract.expireDate, IsNull>>), Messages.ContractExpired)]
[PXRestrictor(typeof(Where<Current<AccessInfo.businessDate>, GreaterEqual<Contract.startDate>>), Messages.ContractActivationDateInFuture, typeof(Contract.startDate))]
[PXFormula(typeof(Default<CRCase.customerID>))]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
public virtual int? ContractID { get; set; }