Fees allow actions performed on service transactions to attract a charge so payment is required before the action may be performed.

Associating one or more fees to a service transaction is the standard mechanism for managing (charging) fees for a service transaction. When and how fees are required for payment is ultimately up to the configured application, although it is usually included in the workflow configuration which typically results in payment being required for any unpaid fees associated to a service transaction when it is submitted.

Fees can be associated to a service transaction using Verne’s fee derivation process. In fact that is usually all that’s required to support any fee functionality. It’s worth noting however that there’s nothing stopping fees being added and/or updated via custom rules, either in addition to the standard fee derivation (perhaps via one of the associated rule scopes) or just via one or more of Verne’s other standard rule scopes.

Fee derivation

Out-of-the-box Verne derives/calculates fees on every update. This allows fees to be displayed as soon as a service transaction is started, as well as having the fees updated (added or removed) based on the domain data relating to the service transaction (e.g. data entered in the form) if appropriate.

Fees are derived using the DeriveFees command or the deriveFees convenience method on the service transaction.

Fee Instructions

Which fees are applicable to a service transaction when derived are determined by processing an application’s configured fee instructions. Fees are associated to a service transaction for any fee instruction that "matches" the service transaction in its current state. A single fee instruction could relate to service transactions for a specific service, or relate to any service that meets the criteria defined within the instruction.

See fee instructions configuration for specific details relating to configuring fee instructions.

Fee instructions determine which fees (fee codes) get associated to a service transaction. The fee amount relating to those fee codes are configured via fees and a fee can be referenced by a number of fee instructions.

Fees

See fees configuration for details of what fee amount to charge (as opposed to which fees to charge).

Additional rule scopes

The first-level fee instruction fee scope options for defining rules around when a fee should apply and the rule element for defining custom rules all relate to whether a service transaction fee relating to the fee instruction fee is added or not.

There are two additional rule scopes relating to fees that are run after the fees are derived using the fee instructions. For efficiency, these rule scopes are only called if there has been a change in the fees associated to the service transaction.

fees-changed scope

If the fees associated to the service transaction change, the fees-changed rule scope is called before the new fees are set on the service transaction. This allows decisions to be made or the fees altered before being updated. Rules of this scope can be from the application down to the service.

The following rule variables are available to use in this rule scope:

Variable nameTypeDescription
appCtxApplicationContextThe application context when the rule is called
serviceTransactionServiceTransactionThe service transaction the fees are about to be updated on (note: the old fees are still associated with the service transaction at this point)
hashStringA unique fingerprint relating to the details of the new fees
newFeesListThe new fees that are about to be set on the service transaction so they can be changed before they are set
changedbooleanWhether the fees are changing (always true since this rule scope isn’t called if false)

fees-changed-complete scope

If the fees associated to the service transaction change, the fees-changed-complete rule scope is called after the new fees have been set on the service transaction. This allows decisions to be made or the fees altered after being updated. Rules of this scope can be from the application down to the view tree nodes.

The following rule variables are available to use in this rule scope:

Variable nameDescription
appCtxThe application context when the rule is called
serviceTransactionThe service transaction the fees have just been updated on (note: the new fees have already been set on the service transaction at this point)

Fee examples

Given the following fee configuration:

<fees>
  <fee code="newSolarSystemFee">
    <amount amount="10000000"/>
  </fee>
  <fee code="newPlanetFee">
    <amount amount="50000000"/>
  </fee>
  <fee code="newEarthFee">
    <amount amount="100000000"/>
  </fee>
  <fee code="changedPlanetFee">
    <amount amount="5000000"/>
  </fee>
  <fee code="objectRenameFee">
    <amount amount="100000"/>
  </fee>
  <fee code="extinctionEventFee">
    <amount amount="33000000"/>
  </fee>
  <fee code="planetDestroyedFee">
    <amount amount="66000000"/>
  </fee>
  <fee code="newNonPlanetFee">
    <amount amount="700000"/>
  </fee>
</fees>

The following fee instruction configuration:

<feeInstructions>
  <!-- Simple case: a single flat fee for a single service (only once per service transaction as allowMultiple is not set to true) -->
  <feeInstruction name="newSolarSystemFee" feeCode="newSolarSystemFee" textKey="fee.newSolarSystemFee">
    <feeScope service="createSolarSystem"/>
  </feeInstruction>
  <!-- Fee per new Planet added -->
  <feeInstruction name="newPlanetFee" feeCode="newPlanetFee" textKey="fee.newPlanetFee" allowMultiple="true">
    <feeScope domain="Planet" domainAction="added"/>
  </feeInstruction>
  <!-- Fee for a new Planet added called 'Earth' (but only allowed once per service transaction as allowMultiple is not set to true) -->
  <feeInstruction name="newEarthFee" feeCode="newEarthFee" textKey="fee.newEarthFee">
    <feeScope domain="Planet" domainAction="added" attribute="Name" attributeValue="Earth"/>
  </feeInstruction>
  <!-- Fee per Planet changed other than its population -->
  <feeInstruction name="changedPlanetFee" feeCode="changedPlanetFee" textKey="fee.changedPlanetFee" allowMultiple="true">
    <feeScope domain="Planet" domainAction="modified">
      <rule type="groovy">return domainChange?.node?.isChanged({ e -> e.key != 'Population' })</rule> <!-- Any attribute changed other than Population -->
    </feeScope>
  </feeInstruction>
  <!-- Fee per domain (i.e. solar system, planet, comet or asteroid) who's name attribute is changed (excludes new domains - modified only) -->
  <feeInstruction name="objectRenameFee" feeCode="objectRenameFee" textKey="fee.objectRenameFee" allowMultiple="true">
    <feeScope service="updateSolarSystem" domainAction="modified" attribute="Name" attributeAction="modified"/>
  </feeInstruction>
  <!-- Fee if a planet has it's population attribute removed/set to null (but only allowed once per service transaction as allowMultiple is not set to true) -->
  <feeInstruction name="extinctionEventFee" feeCode="extinctionEventFee" textKey="fee.extinctionEventFee">
    <feeScope domain="Planet" attribute="Population" attributeAction="removed"/>
  </feeInstruction>
  <!-- Fee if a planet is removed (but only allowed once per service transaction allowMultiple is not set to true) -->
  <feeInstruction name="planetDestroyedFee" feeCode="planetDestroyedFee" textKey="fee.planetDestroyedFee">
    <feeScope domain="Planet" domainAction="removed"/>
  </feeInstruction>
  <!-- Fee per new Asteroid or Comet domain is added (but only up to a maximum of 2) -->
  <feeInstruction name="newNonPlanetFee" feeCode="newNonPlanetFee" textKey="fee.newNonPlanetFee" allowMultiple="true" max="2">
    <feeScope domain="Asteroid,Comet" domainAction="added"/>
  </feeInstruction>
</feeInstructions>

And the following services and form configuration:

<businessServices>
  <businessService code="createSolarSystem" formItem="solarSystemDetails" mode="Create"/>
  <businessService code="updateSolarSystem" formItem="solarSystemDetails" mode="Change"/>
</businessServices>
<serviceFormItems>
  <record shortCode="solarSystemDetails" domain="SolarSystem">
    <attribute attribute="Name"/>
    <repeater shortCode="planets">
      <record domain="Planet">
        <attribute attribute="Name"/>
        <attribute attribute="Diameter"/>
        <attribute attribute="Population"/>
      </record>
    </repeater>
    <repeater shortCode="asteroids">
      <record domain="Asteroid">
        <attribute attribute="Name"/>
        <attribute attribute="Diameter"/>
        <attribute attribute="Velocity"/>
        <attribute attribute="Risk"/>
      </record>
    </repeater>
    <repeater shortCode="comets">
      <record domain="Comet">
        <attribute attribute="Name"/>
        <attribute attribute="Diameter"/>
        <attribute attribute="Velocity"/>
      </record>
    </repeater>
  </record>
</serviceFormItems>

The following actions would attract the mentioned fees (note: this assumes that fees are derived on each update):

StepActionFee change(s)Full list of current fee codesNotes
1Start createSolarSystem service+newSolarSystemFeenewSolarSystemFee
2Add a planet+newPlanetFeenewSolarSystemFee, newPlanetFee
3Set the planet name to GaianewSolarSystemFee, newPlanetFee
4Update the planet name to Earth+newEarthFeenewSolarSystemFee, newPlanetFee, newEarthFee
5Set Earth’s populationnewSolarSystemFee, newPlanetFee, newEarthFee
6Set the planet name to New Earth-newEarthFeenewSolarSystemFee, newPlanetFee
7Set the planet name to Earth again+newEarthFeenewSolarSystemFee, newPlanetFee, newEarthFee
8Add a second planet+newPlanetFeenewSolarSystemFee, newPlanetFee, newEarthFee, newPlanetFee
9Set the 2nd planet name to MarsnewSolarSystemFee, newPlanetFee, newEarthFee, newPlanetFee
10Add a comet+nonPlanetFeenewSolarSystemFee, newPlanetFee, newEarthFee, newPlanetFee, newNonPlanetFee
11Set the comet detailsnewSolarSystemFee, newPlanetFee, newEarthFee, newPlanetFee, newNonPlanetFee
12Apply/activate the servicenewSolarSystemFee, newPlanetFee, newEarthFee, newPlanetFee, newNonPlanetFee
13Start updateSolarSystem for the newly created solar system
14Clear the Earth’s population attribute+extinctionEventFeeextinctionEventFeePopulation excluded from changedPlanetFee
15Set the Earth’s diameter attribute+changedPlanetFeeextinctionEventFee, changedPlanetFee
15Remove the Mars planet+planetDestroyedFeeextinctionEventFee, changedPlanetFee, planetDestroyedFee
16Set the Earth planet name to New Earth+objectRenameFeeextinctionEventFee, changedPlanetFee, planetDestroyedFee, objectRenameFee
17Set the Halley’s Comet comet name to Comet Halley+objectRenameFeeextinctionEventFee, changedPlanetFee, planetDestroyedFee, objectRenameFee, objectRenameFee
18Add another planet and set its name to Earth+newEarthFeeextinctionEventFee, changedPlanetFee, planetDestroyedFee, objectRenameFee, objectRenameFee, newEarthFee
19Add another planet and set its name to EarthextinctionEventFee, changedPlanetFee, planetDestroyedFee, objectRenameFee, objectRenameFee, newEarthFeeMultiple newEarthFee fees not allowed
20Add another comet and set its name to Comet2+newNonPlanetFeeextinctionEventFee, changedPlanetFee, planetDestroyedFee, objectRenameFee, objectRenameFee, newEarthFee, newNonPlanetFee
21Add an asteroid and set its name to Asteroid1+newNonPlanetFeeextinctionEventFee, changedPlanetFee, planetDestroyedFee, objectRenameFee, objectRenameFee, newEarthFee, newNonPlanetFee, newNonPlanetFee
22Add another comet and set its name to Comet3extinctionEventFee, changedPlanetFee, planetDestroyedFee, objectRenameFee, objectRenameFee, newEarthFee, newNonPlanetFee, newNonPlanetFeeMax of 2 newNonPlanetFee fees
23Set the Solar System name to Outer Space+objectRenameFeeextinctionEventFee, changedPlanetFee, planetDestroyedFee, objectRenameFee, objectRenameFee, newEarthFee, newNonPlanetFee, newNonPlanetFee, objectRenameFee

Implementation

Service transaction methods

The following methods are available on the service transaction relating to fees:

MethodArgumentsReturnsComments
getFees(List<ServiceTransactionFee>) The list of service transaction fees currently associated to the service transaction
deriveFeesCalls the DeriveFees command setting itself as the service transaction property

Service transaction fee

Fees relating to a service transaction are stored as a list of service transaction fee objects, available via the service transaction getFees method.

Object names

NameFull nameComments
ServiceTransactionFeecom.fostermoore.catalyst.ng.blade.model.ServiceTransactionFeeThe interface for a service transaction fee
ServiceTransactionFeeImplcom.fostermoore.catalyst.ng.blade.model.impl.ServiceTransactionFeeImplThe implementation of ServiceTransactionFee

Methods

MethodArgumentsReturns
getCode(String) A fee code identifying the fee
getType(String) The fee type e.g. fee or penalty
getTextKey(String) The text key to derive the fee name/description
getAmount(String) Cost amount of the fee. A string by design to allow for easy transport
getStatus(String) The status of the fee e.g. unpaid, paid
getStatusUpdateDate(String) The date the status of the fee was last updated
isDerived(boolean) Whether this fee was derived or not. This defaults to false but is set to true for the fees derived using fee instructions configuration. Fees with a derived value of false are not removed when fees are re-derived so leave as/set to false for service transaction fees added manually so they not be impacted by the standard fee derivation
getAssociatedCode(String) The fee code of an associated fee e.g. in the case where this fees is penalty fee for another code
getCurrencyCode(String) The code for currency this fee is charged in

Fee instruction

A simple object that mimics a fee instruction configuration item (but is not required to) used when deriving fees.

Object names

NameFull nameComments
FeeInstructioncom.fostermoore.catalyst.ng.blade.model.fees.FeeInstruction

Methods

MethodArgumentsReturnsComments
getName(String) The name of the fee instruction
getFeeCode(String) The fee code used if the fee instruction results in a fee being associated to a service transaction
getTextKey(String) The text key for the textual description of the fee
isAllowMultiple(boolean) Whether this fee can be charged multiple times for the same service transaction
getMax(Integer) An upper limit on the number of times this fee can be charged against a service transaction
getType(String) The type of fee
getAssociatedFeeCode(String) An associated fee code
getAssociatedFeeInstruction(String) An associated fee instruction name
isEnabled(boolean) Whether the fee instruction should be considered
getScopes(FeeScope) The fee scopes belonging to this fee instruction

Fee scope

A simple object that mimics a fee scope configuration item (but is not required to) used when deriving fees.

Object names

NameFull nameComments
FeeScopecom.fostermoore.catalyst.ng.blade.model.fees.FeeScope
FeeScope.Actioncom.fostermoore.catalyst.ng.blade.model.fees.FeeScope.ActionEnum for the available match actions, i.e. added, modified, removed
FeeScope.AttributeMatchcom.fostermoore.catalyst.ng.blade.model.fees.FeeScope.AttributeMatchEnum for the available attribute match options i.e. match, any, blank

Methods

MethodArgumentsReturnsComments
getName(String) A convenience name for the fee scope which provides no other function
getServices(Set) Set of service codes of which the service transaction’s must be one of to relate to this fee scope
getForms(Set) Set of form codes of which the service transaction’s must be one of to relate to this fee scope
getDomains(Set) Set of domain CSS selectors targeting domains this fee scope can relate to
getDomainActionoptional; stringThe action a record of type domain must undertake in order for the fee to apply. Supported values are:
added – the domain is added in this version
modified – the domain existed in the previous version and any attribute within the domain has changed in this version
removed – the domain existed on the previous version but is removed in this version
getAttributes(Set) Set of attribute CSS selectors targeting attributes this fee scope can relate to
getAttributeAction(FilingScope.Action) The action attributes must be undertaking for this fee scope to apply
getAttributeMatch(FilingScope.AttributeMatch) The method to use to match the getAttributeValue
getAttributeValue(String) The value attributes must match against using the getAttributeMatch method if the getAttributeAction is FilingScope.Action.added or FilingScope.Action.modified for this fee scope to apply
isServiceTree(boolean) Whether the domain or attribute specified to be matched against is part of the service tree rather than the domain tree
isEnabled(boolean) Whether this fee scope should be considered
getRules(List<Rule>) The rules relating to this fee scope
getInstructionFeeInstruction the fee instruction this fee scope belongs to

Fee result

A fee result represents a single fee result relating to those derived by the DerivedFees command.

Object names

NameFull nameComments
FeeResultcom.fostermoore.catalyst.ng.blade.model.fees.FeeResult

Methods

MethodArgumentsReturns
getChange(DomainNodeChange) The domain change used to relating to this fee result
getScope(FilingScope) The filing scope (which in turn points to a FilingInstruction) relating to this fee result

Fee helper

A general helper class for fee functionality support.

Object names

NameFull nameComments
FeeHelpercom.fostermoore.catalyst.ng.blade.impl.FeeHlper

Methods

MethodArgumentsReturns
getFeeAmountString feeCode(String) The fee amount relating to the given fee code within the current application
getFeeAmountString appCode, String feeCode(String) The fee amount relating to the given fee code within the specified application code
getFeeCurrencyCodeString feeCode(String) The fee code relating to the given fee code within the current application
getFeeCurrencyCodeString appCode, String feeCode(String) The fee code relating to the given fee code within the specified application code

Derive fees

The DeriveFees command is responsible for adding/removing fees to a service transaction’s list of fees. It calculates the fees that apply to a service transaction in its current state (i.e. properties and data) using the fee instructions and adds a ServiceTransactionFee for each fee that is applicable, and removes those that are no longer applicable.

Object names

NameFull nameComments
DeriveFeescom.fostermoore.catalyst.ng.blade.command.transaction.DeriveFees

Methods

The following methods are available for the DeriveFees command object:

MethodArgumentsReturnsComments
setServiceTransaction(ServiceTransaction) The service transaction to derive the fees forThis DeriveFees object
execute(boolean) Whether the fee derivation resulted in a change in the service transaction fees associated to the service transactionExecutes the derive fees logic

Outline

Below is some pseudo code to outline how the DeriveFees command calculates the fees that apply to a service transaction.

  1. Exits if there are no fee instructions to process
  2. Builds the service transaction view tree if it isn’t already present (so rules called later can operate on the view tree if applicable)
  3. Calls the DerivedFees command using the following parameters:
    • instructions: all fee instructions configuration for the current application
    • serviceTransaction: the current service transaction
    • domainTreeChanges: domain tree changes based on this version and the previous version of the service transaction
    • serviceTreeChanges: service tree changes based on this version and the previous version of the service transaction
  4. Converts each of the FeeResult results from the DerivedFees command into a ServiceTransactionFee, calculating the amounts using FeeHelper and FeeResult details
  5. Merges the latest list of derived fees with the fees already associated with the service transaction into a new list of fees. This involves the following:
    1. Loops over existing fees first (so order and status is preserved) and adds any to the new list of fees that:
      • Have the same fee code and amount as a fee in the latest list of derived fees (removes from the latest derived fees if so so it won’t be considered further)
      • Is not a derived fee (this allows you to add fees via custom code that will not be affected by the fee derivation process)
    2. Adds all fees remaining in the latest list of derived fees to the new list of fees
  6. Compares the footprint hashes of the existing fees with the new list of fees to see if they’ve changed. If they have then:
    1. Call the fees-changed rule scope
    2. Set the service transaction fees using the new list of fees
    3. Call the fees-changed-complete rule scope

Derived fees

The DerivedFees command is responsible for calculating which fee instruction scopes apply based on a service transaction and it’s domain and service data and their changes using the fee instructions.

Object names

NameFull nameComments
DerivedFeescom.fostermoore.catalyst.ng.blade.model.fees.DerivedFeesGenerates the fee results on instantiation

Constructor

The following methods are required when constructing a DerivedFees command object (note: the fee results are generated on instantiation):

TypeDescription
ServiceTransactionThe service transaction to derive/calculate the fee results for
ListThe fee instructions to consider for determining the fee results that apply
DomainTreeChangesThe domain tree data changes to use for determining the fee results that apply
DomainTreeChangesThe service tree data changes to use for determining the fee results that apply

Methods

The following methods are available for the DerivedFees command object:

MethodArgumentsReturnsComments
getResults(List) The list of fee results highlighting which fee instruction scopes apply to the given service transaction and the domain and service tree data and their changes
getFeeCodes(Set) The set of fee instruction codes relating to the fee results (note: as this returns a distinct set of fee instruction codes so may be a smaller set than the full fee results list if the same fee instruction exists more than once)

Outline

Below are the steps outlining how the DerivedFees command determines the fee results for the given fee instructions, service transaction and domain and service tree changes.

  1. Gathers the following lists of fee scopes from the fee instructions that satisfy the given criteria in addition to the overarching criteria of only keeping fee scopes that either don’t have a service and/or form value or have a value that matches the value from the service transaction:
    • addedScopes: either no domainAction value or added
    • modifiedScopes: either no domainAction value or modified
    • removedScopes: either no domainAction value or removed
  2. Processes the three lists fee scopes against each of the domain tree data changes, adding a FeeResult if the scope matches for the given domain tree domain change. A match involves:
    1. Comparing the fee scopes to the domain change to ensure it matches based on the fee scope configuration values
    2. Applying any fee scope rules to see if the fee scope is applicable for the given domain change i.e. returns a result of true
  3. Further processes the three lists fee scopes against the service tree data changes, adding a FeeResult if the scope matches for the given service tree domain change. A match involves:
    1. Comparing the fee scopes to the domain change to ensure it matches based on the fee scope configuration values
    2. Applying any fee scope rules to see if the fee scope is applicable for the given domain change i.e. returns a result of true
  4. Further filters the fee results by applying the fee instruction allowMultiple and max attribute values if specified to ensure fee results relating to the same fee instructions are not included more than they are supposed to
0
0

Jump to Section