You can charge authenticated Turnkey users for an action and let them top up their account through a purchase window; this page is for developers using the standard authentication package and MDriven Turnkey.
When you use the standard authentication package, an end user is represented by a SysUser object. Add two external late-bound methods to SysUser to:
- deduct an amount when the user consumes a paid resource; and
- open a purchase UI where the user can add funds to the account.
The Portal identifies the user as a SysConsumer and maintains that consumer's account balance and transaction history. Amounts are represented as MCoins/Euros in the returned account data. See Documentation:MCoins for the account concept.
Before you begin
You need:
- A model that includes the standard authentication package, so that it has
SysUser. - A Turnkey site connected to the Portal. The payment flow cannot be validated by a local Turnkey Core instance that is not recognized by the Portal.
- Portal settings sent to the Turnkey site. The Portal writes these settings to
TurnkeySettings.xmlwhen you useSendSettingsin the Portal. - The
PortalConsumercomponent installed inEXT_Componentsif you want to present the purchase UI.
You can start from the consumer-payment model example and merge it into an existing model. The video walkthrough demonstrates using the Open and Merge command to add the example, which adds the consumer-related classes and SysUser functionality. See model examples.
Add payment methods to SysUser
In MDriven Designer, add the following methods to the SysUser class.
| Method | Purpose | Required setting |
|---|---|---|
Consume(amount:Double; message:String; tag:String):String
|
Attempts to deduct amount for a user action and returns account and transaction information as JSON.
|
Set tagged value Eco.ExternalLateBound to Existence.
|
GetPurchaseUrl(amount:Double; amountreadonly:Boolean; product:String; tag:String):String
|
Returns the URL used by the purchase UI to let the user top up the account. | Set IsQuery=true. Set tagged value Eco.ExternalLateBound to Existence.
|
The tagged value marks each method as externally implemented. Turnkey handles the call rather than requiring an OCL method body.
Configure the Portal connection
When Consume is called, Turnkey posts to the Portal's Consume REST-allowed ViewModel. The Portal uses the site identity in TurnkeySettings.xml to find the corresponding TurnkeySite object.
The settings file includes these values:
<PortalGuid>a guid from the TurnkeySite object in portal</PortalGuid>
<SharedSecret>a password shared between your site and portal</SharedSecret>
PortalGuid is the GUID of the Portal's TurnkeySite object. SharedSecret is the password you define on the Portal login tab.
Turnkey signs a UTC timestamp with the shared secret for each consume request. The Portal verifies the signature and timestamp, which confirms that the request came from your Turnkey system and helps prevent replay of an old recorded request.
Do not expose the shared secret in a ViewModel, browser code, or user-visible text.
Charge a user for an action
Call Consume when the current user performs the paid action. For example, the following OCL charges 1.23 for a magic strawberry and records an optional tag that you can use to identify the transaction later:
self.ConsumeRes:=SysSingleton.oclSingleton.CurrentUser
.Consume(1.23,'You bought a magic strawberry','optional tag for you')
Use a message that explains what the user bought. Use a tag consistently when you need to correlate a transaction with a product, feature, or local record.
The method returns JSON with the current account standing, the attempted transaction, its status, and the current transaction plus up to five earlier transactions. A response has this shape:
{
"Guid":"guid of the SysConsumer in portal",
"ChangeTime":"2020-05-17T19:31:02.69",
"MCoinAccount_CurrentStanding":-2.46,
"LastTransactionTriedAmount":1.23,
"LastTransactionTriedMessage":"You bought a magic strawberry",
"LastTransactionTriedStatus":"Success",
"MCoinTransactions":[
{
"Guid":"a58753b9-2fe2-4fff-87ce-15294086fd9a",
"MCoinAmount":-1.23,
"Description":"Test20:06:40",
"ExitStanding":-2.46
}
]
}
Check LastTransactionTriedStatus before granting access to the paid resource. The account standing can be negative, as shown in the example, so do not infer success from the balance alone.
You may use Tajson Merge to maintain a local replica of the Portal account information. This is optional; the consume call already returns the data needed to evaluate the attempted transaction.
Add the account top-up UI
Use the PortalConsumer Angular extension component to open the Portal purchase UI from a ViewModel.
- Install the
PortalConsumercomponent inEXT_Components. - In the ViewModel that presents the purchase action, add a
PurchaseUrlViewModel column. Its expression callsGetPurchaseUrlfor the current user. - Add a string ViewModel column named
PayButtonText. The PortalConsumer component uses its value as the Buy button text. - Add an action ViewModel column named
ReturnFromPurchaseAction. This action runs after the user closes the purchase window. - Add a ViewModel column for the component and set its Angular extension component value to
PortalConsumer.
A typical ViewModel setup is:
| ViewModel column | Type or configuration | Example purpose |
|---|---|---|
PurchaseUrl
|
String expression that calls SysSingleton.oclSingleton.CurrentUser.GetPurchaseUrl(amount; amountreadonly; product; tag)
|
Supplies the URL for a purchase of a selected product or amount. |
PayButtonText
|
String | Shows text such as Buy on the component button.
|
ReturnFromPurchaseAction
|
Action | Checks the account after the purchase window closes. |
PortalConsumer
|
[Angular_Ext_Component=PortalConsumer] self->asset
|
Renders the purchase component. |
For a fixed-price product, pass the product amount and set amountreadonly so the purchase UI presents that amount as read-only. For a user-selected top-up amount, provide the amount according to your ViewModel design.
After the window closes, refresh the account state by calling Consume with amount 0. For example:
vNewVar:=SysSingleton.oclSingleton.CurrentUser.Consume(0,'check')
This call lets your ViewModel inspect the returned transaction status and account information after the purchase flow.
Troubleshooting
| Symptom | Check |
|---|---|
| The payment system reports that the application is unavailable or not recognized. | Verify that the Turnkey site is connected to the Portal and that Portal settings have been sent. A local instance without the Portal site identity cannot complete the flow. |
| A payment request cannot be authenticated by the Portal. | Verify that PortalGuid and SharedSecret in TurnkeySettings.xml match the Portal site configuration.
|
| The purchase button is present but does not use the expected URL. | Verify that GetPurchaseUrl has IsQuery=true, is marked Eco.ExternalLateBound = Existence, and that the PurchaseUrl ViewModel column calls it for the current user.
|
| Your UI does not reflect a completed or failed purchase after the window closes. | Add ReturnFromPurchaseAction and refresh the state, for example with Consume(0,'check').
|
For general REST integration patterns, see Documentation:Rest API. This payment integration is configured through the supplied late-bound methods; you do not need to implement the Portal REST call yourself.
