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; }