POST | /sales/contract/sold | Sell a package to an existing user | Sell a package to an existing user. The PaymentMethods property is an array of objects describing how you want ClubReady to take payment while selling the PackageId/InstallmentPlanId. If omitted (or null), the preferred on-file profile will be used.* When using Query String values (or this web site), this value must be encoded with JSV [(JSON-like Separated Values)](https://docs.servicestack.net/jsv-format). * Basic steps to convert JSON to JSV: 1) Remove properties that are null 2) Remove white space including line feeds 3) Remove quotes. |
---|
import 'package:servicestack/servicestack.dart';
// @DataContract
class PaymentMethodDto implements IConvertible
{
// @DataMember
String? AcctToken;
// @DataMember
String? ProfileToken;
// @DataMember
String? PaymentProfileId;
// @DataMember
double? PaymentAmount;
// @DataMember
bool? UsePreferred;
// @DataMember
bool? DoNotUpdatePaymentTypePreference;
PaymentMethodDto({this.AcctToken,this.ProfileToken,this.PaymentProfileId,this.PaymentAmount,this.UsePreferred,this.DoNotUpdatePaymentTypePreference});
PaymentMethodDto.fromJson(Map<String, dynamic> json) { fromMap(json); }
fromMap(Map<String, dynamic> json) {
AcctToken = json['AcctToken'];
ProfileToken = json['ProfileToken'];
PaymentProfileId = json['PaymentProfileId'];
PaymentAmount = JsonConverters.toDouble(json['PaymentAmount']);
UsePreferred = json['UsePreferred'];
DoNotUpdatePaymentTypePreference = json['DoNotUpdatePaymentTypePreference'];
return this;
}
Map<String, dynamic> toJson() => {
'AcctToken': AcctToken,
'ProfileToken': ProfileToken,
'PaymentProfileId': PaymentProfileId,
'PaymentAmount': PaymentAmount,
'UsePreferred': UsePreferred,
'DoNotUpdatePaymentTypePreference': DoNotUpdatePaymentTypePreference
};
getTypeName() => "PaymentMethodDto";
TypeContext? context = _ctx;
}
enum RestrictedResourceType
{
Store,
Chain,
User,
Undefined,
}
// @ApiResponse(Description="", ResponseType=typeof(ContractSoldResponse), StatusCode=200)
class ContractSoldEndpoint implements IContractSoldEndpoint, IRestrictedApiRequest, IConvertible
{
/**
* IP address of the end user
*/
// @ApiMember(Description="IP address of the end user", Name="X-Forwarded-For", ParameterType="header")
String? XForwardedFor;
/**
* Api Authentication Key
*/
// @ApiMember(Description="Api Authentication Key", IsRequired=true, ParameterType="query")
String? ApiKey;
/**
* Member Id of the user buying the Package
*/
// @ApiMember(Description="Member Id of the user buying the Package", IsRequired=true, ParameterType="query")
int? MemberId;
/**
* Id for the chain of the Api Key
*/
// @ApiMember(Description="Id for the chain of the Api Key")
int? ChainId;
/**
* Id of the store for the user
*/
// @ApiMember(Description="Id of the store for the user", IsRequired=true)
int? StoreId;
/**
* Package Id number of the package being purchased
*/
// @ApiMember(Description="Package Id number of the package being purchased", IsRequired=true)
int? PackageId;
/**
* Installment Plan Id being purchased. If empty, the default package will be selected.
*/
// @ApiMember(Description="Installment Plan Id being purchased. If empty, the default package will be selected.")
int? InstallmentId;
/**
* Date contract takes affect
*/
// @ApiMember(Description="Date contract takes affect")
DateTime? StartDate;
/**
* Amount being paid down, including tax
*/
// @ApiMember(Description="Amount being paid down, including tax", IsRequired=true)
double? PaymentAmount;
/**
* Promo code to apply a discount.
*/
// @ApiMember(Description="Promo code to apply a discount.")
String? PromoCode;
/**
* Staff Id of salesperson who sold the agreement.
*/
// @ApiMember(Description="Staff Id of salesperson who sold the agreement.")
int? StaffId;
/**
* An array of PaymentMethod objects to be used for this purchase. A null array (or omitted property) will use thePreferred method for the total amount.Each object of the array may contain properties:| Property | Description || --- | --- || PaymentAmount | The maximum amount to be attempted for this PaymentMethod. When null or omitted, the remaining PaymentAmount will be attempted. || **Use only one of the following three** | **UsePreferred** or **AcctToken** or **ProfileToken [DoNotUpdatePaymentTypePreference]** || UsePreferred | Set to `true` to use the Preferred method, otherwise omit the value or set to `null` or `false` || AcctToken | The AcctToken to attempt payment || ProfileToken | When provided, a PaymentMethod will be created (this will prevent the requirement to call `/sales/paymentprofile/import`) || DoNotUpdatePaymentTypePreference | [Optional] When creating a PaymentMethod (ProfileToken), it is set as the preferred method. To not create as preferred, set `DoNotUpdatePaymentTypePreference` to `true`. (for more information, see `/sales/paymentprofile/import`) || | |Only one of `UsePreferred`, `AcctToken`, `ProfileToken` or is needed. `DoNotUpdatePaymentTypePreference` is optionaland only valid with `ProfileToken`.* Scenario #1: Sell $3 contract using an existing PaymentMethod (i.e. AcctToken) for $1 and the Preferred method for $2.JSON:```json{ ... "PaymentAmount": 3.00, "PaymentMethods": [ { "PaymentAmount": "1.00", "AcctToken": "eyJ..." }, { "PaymentAmount": "2.00", "UsePreferred": true } ]}```JSV:```...,PaymentAmount:3.00,PaymentMethods:[{PaymentAmount:1.00,AcctToken:eyJ...NdQ},{PaymentAmount:2.00,UsePreferred:true}]```* Scenario #2: Sell $3 contract using a new PaymentMethod (i.e. ProfileToken) for $1 and the Preferred method for the remaining.Note, the sum of the PaymentMethod's PaymentAmount ($4) is greater than the agreement amount ($3). PaymentAmount is the maximum amount.This allows the first PaymentMethod to decline or partially approve (common with gift cards). Therefore, if the first PaymentMethod approvesfor $0.75, the second will be attempted for $2.25.JSON:```json{ ... "PaymentAmount": 3.00, "PaymentMethods": [ { "PaymentAmount": "1.00", "ProfileToken": "eyJ..." }, { "PaymentAmount": "3.00", "UsePreferred": true } ]}```JSV:```jsv...,PaymentAmount:3.00,PaymentMethods:[{PaymentAmount:1.00,ProfileToken:eyj...NdQ},{PaymentAmount:3.00,UsePreferred:true}]```Notes: * AcctTokens should not be parsed or persisted in the client application. They are currently jsonbased, but can be updated without notice.* ProfileToken is used to create a PaymentMethod in the ClubReady system. For more information, see `/sales/paymentprofile/import`.* If `PaymentMethods` is missing or `null`, the Preferred method will be used.* If a `PaymentMethods` `PaymentAmount` is not specified, the remaining amount will be attempted.* If a PaymentMethod is partially approved (common for gift cards), the PaymentMethod with anunspecified PaymentAmount will be charged the remaining amount, including the unapproved amount not.* When testing with this website, the PaymentMethods textbox needs JSV and only the square brackets and contents(e.g. `[{PaymentAmount:1.00,UsePreferred:true}]`).
*/
// @ApiMember(Description="An array of PaymentMethod objects to be used for this purchase. A null array (or omitted property) will use the\r\nPreferred method for the total amount.\r\n\r\nEach object of the array may contain properties:\r\n\r\n| Property | Description |\r\n| --- | --- |\r\n| PaymentAmount | The maximum amount to be attempted for this PaymentMethod. When null or omitted, the remaining PaymentAmount will be attempted. |\r\n| **Use only one of the following three** | **UsePreferred** or **AcctToken** or **ProfileToken [DoNotUpdatePaymentTypePreference]** |\r\n| UsePreferred | Set to `true` to use the Preferred method, otherwise omit the value or set to `null` or `false` |\r\n| AcctToken | The AcctToken to attempt payment |\r\n| ProfileToken | When provided, a PaymentMethod will be created (this will prevent the requirement to call `/sales/paymentprofile/import`) |\r\n| DoNotUpdatePaymentTypePreference | [Optional] When creating a PaymentMethod (ProfileToken), it is set as the preferred method. To not create as preferred, set `DoNotUpdatePaymentTypePreference` to `true`. (for more information, see `/sales/paymentprofile/import`) |\r\n| | |\r\n\r\nOnly one of `UsePreferred`, `AcctToken`, `ProfileToken` or is needed. `DoNotUpdatePaymentTypePreference` is optional\r\nand only valid with `ProfileToken`.\r\n\r\n* Scenario #1: Sell $3 contract using an existing PaymentMethod (i.e. AcctToken) for $1 and the Preferred method for $2.\r\n\r\nJSON:\r\n```json\r\n{\r\n ...\r\n \"PaymentAmount\": 3.00,\r\n \"PaymentMethods\": [\r\n {\r\n \"PaymentAmount\": \"1.00\",\r\n \"AcctToken\": \"eyJ...\"\r\n },\r\n {\r\n \"PaymentAmount\": \"2.00\",\r\n \"UsePreferred\": true\r\n }\r\n ]\r\n}\r\n```\r\nJSV:\r\n```\r\n...,PaymentAmount:3.00,PaymentMethods:[{PaymentAmount:1.00,AcctToken:eyJ...NdQ},{PaymentAmount:2.00,UsePreferred:true}]\r\n```\r\n\r\n* Scenario #2: Sell $3 contract using a new PaymentMethod (i.e. ProfileToken) for $1 and the Preferred method for the remaining.\r\nNote, the sum of the PaymentMethod's PaymentAmount ($4) is greater than the agreement amount ($3). PaymentAmount is the maximum amount.\r\nThis allows the first PaymentMethod to decline or partially approve (common with gift cards). Therefore, if the first PaymentMethod approves\r\nfor $0.75, the second will be attempted for $2.25.\r\n\r\nJSON:\r\n```json\r\n{ \r\n ...\r\n \"PaymentAmount\": 3.00,\r\n \"PaymentMethods\": [\r\n {\r\n \"PaymentAmount\": \"1.00\",\r\n \"ProfileToken\": \"eyJ...\"\r\n },\r\n {\r\n \"PaymentAmount\": \"3.00\",\r\n \"UsePreferred\": true\r\n }\r\n ]\r\n}\r\n```\r\nJSV:\r\n```jsv\r\n...,PaymentAmount:3.00,PaymentMethods:[{PaymentAmount:1.00,ProfileToken:eyj...NdQ},{PaymentAmount:3.00,UsePreferred:true}]\r\n```\r\n\r\nNotes: \r\n\r\n* AcctTokens should not be parsed or persisted in the client application. They are currently json\r\nbased, but can be updated without notice.\r\n\r\n* ProfileToken is used to create a PaymentMethod in the ClubReady system. For more information, \r\nsee `/sales/paymentprofile/import`.\r\n\r\n* If `PaymentMethods` is missing or `null`, the Preferred method will be used.\r\n\r\n* If a `PaymentMethods` `PaymentAmount` is not specified, the remaining amount will be attempted.\r\n\r\n* If a PaymentMethod is partially approved (common for gift cards), the PaymentMethod with an\r\nunspecified PaymentAmount will be charged the remaining amount, including the unapproved amount not.\r\n\r\n* When testing with this website, the PaymentMethods textbox needs JSV and only the square brackets and contents\r\n(e.g. `[{PaymentAmount:1.00,UsePreferred:true}]`).")
List<PaymentMethodDto>? PaymentMethods;
int? RestrictedId;
RestrictedResourceType? RestrictedResourceType;
ContractSoldEndpoint({this.XForwardedFor,this.ApiKey,this.MemberId,this.ChainId,this.StoreId,this.PackageId,this.InstallmentId,this.StartDate,this.PaymentAmount,this.PromoCode,this.StaffId,this.PaymentMethods,this.RestrictedId,this.RestrictedResourceType});
ContractSoldEndpoint.fromJson(Map<String, dynamic> json) { fromMap(json); }
fromMap(Map<String, dynamic> json) {
XForwardedFor = json['XForwardedFor'];
ApiKey = json['ApiKey'];
MemberId = json['MemberId'];
ChainId = json['ChainId'];
StoreId = json['StoreId'];
PackageId = json['PackageId'];
InstallmentId = json['InstallmentId'];
StartDate = JsonConverters.fromJson(json['StartDate'],'DateTime',context!);
PaymentAmount = JsonConverters.toDouble(json['PaymentAmount']);
PromoCode = json['PromoCode'];
StaffId = json['StaffId'];
PaymentMethods = JsonConverters.fromJson(json['PaymentMethods'],'List<PaymentMethodDto>',context!);
RestrictedId = json['RestrictedId'];
RestrictedResourceType = JsonConverters.fromJson(json['RestrictedResourceType'],'RestrictedResourceType',context!);
return this;
}
Map<String, dynamic> toJson() => {
'XForwardedFor': XForwardedFor,
'ApiKey': ApiKey,
'MemberId': MemberId,
'ChainId': ChainId,
'StoreId': StoreId,
'PackageId': PackageId,
'InstallmentId': InstallmentId,
'StartDate': JsonConverters.toJson(StartDate,'DateTime',context!),
'PaymentAmount': PaymentAmount,
'PromoCode': PromoCode,
'StaffId': StaffId,
'PaymentMethods': JsonConverters.toJson(PaymentMethods,'List<PaymentMethodDto>',context!),
'RestrictedId': RestrictedId,
'RestrictedResourceType': JsonConverters.toJson(RestrictedResourceType,'RestrictedResourceType',context!)
};
getTypeName() => "ContractSoldEndpoint";
TypeContext? context = _ctx;
}
enum ResponseStatus
{
stsUnknown,
stsSuccess,
stsDecline,
stsError,
HardDeclineAccount,
HardDeclineExpiry,
PartialApproval,
PendingSuccess,
}
class PendingPaymentResponse implements IConvertible
{
String? ResponseTransactionId;
String? ResponseTxnId;
ResponseStatus? ResponseStatus;
double? ResponseAmount;
String? ResponseText;
String? Last4;
String? AcctClass;
String? AcctType;
String? AcctToken;
PendingPaymentResponse({this.ResponseTransactionId,this.ResponseTxnId,this.ResponseStatus,this.ResponseAmount,this.ResponseText,this.Last4,this.AcctClass,this.AcctType,this.AcctToken});
PendingPaymentResponse.fromJson(Map<String, dynamic> json) { fromMap(json); }
fromMap(Map<String, dynamic> json) {
ResponseTransactionId = json['ResponseTransactionId'];
ResponseTxnId = json['ResponseTxnId'];
ResponseStatus = JsonConverters.fromJson(json['ResponseStatus'],'ResponseStatus',context!);
ResponseAmount = JsonConverters.toDouble(json['ResponseAmount']);
ResponseText = json['ResponseText'];
Last4 = json['Last4'];
AcctClass = json['AcctClass'];
AcctType = json['AcctType'];
AcctToken = json['AcctToken'];
return this;
}
Map<String, dynamic> toJson() => {
'ResponseTransactionId': ResponseTransactionId,
'ResponseTxnId': ResponseTxnId,
'ResponseStatus': JsonConverters.toJson(ResponseStatus,'ResponseStatus',context!),
'ResponseAmount': ResponseAmount,
'ResponseText': ResponseText,
'Last4': Last4,
'AcctClass': AcctClass,
'AcctType': AcctType,
'AcctToken': AcctToken
};
getTypeName() => "PendingPaymentResponse";
TypeContext? context = _ctx;
}
class ContractSoldResponse implements IConvertible
{
String? ContractSaleID;
String? description;
bool? Success;
IReadOnlyList<PendingPaymentResponse>? PaymentResponses;
ContractSoldResponse({this.ContractSaleID,this.description,this.Success,this.PaymentResponses});
ContractSoldResponse.fromJson(Map<String, dynamic> json) { fromMap(json); }
fromMap(Map<String, dynamic> json) {
ContractSaleID = json['ContractSaleID'];
description = json['description'];
Success = json['Success'];
PaymentResponses = JsonConverters.fromJson(json['PaymentResponses'],'IReadOnlyList<PendingPaymentResponse>',context!);
return this;
}
Map<String, dynamic> toJson() => {
'ContractSaleID': ContractSaleID,
'description': description,
'Success': Success,
'PaymentResponses': JsonConverters.toJson(PaymentResponses,'IReadOnlyList<PendingPaymentResponse>',context!)
};
getTypeName() => "ContractSoldResponse";
TypeContext? context = _ctx;
}
TypeContext _ctx = TypeContext(library: 'www.clubready.com', types: <String, TypeInfo> {
'PaymentMethodDto': TypeInfo(TypeOf.Class, create:() => PaymentMethodDto()),
'RestrictedResourceType': TypeInfo(TypeOf.Enum, enumValues:RestrictedResourceType.values),
'ContractSoldEndpoint': TypeInfo(TypeOf.Class, create:() => ContractSoldEndpoint()),
'List<PaymentMethodDto>': TypeInfo(TypeOf.Class, create:() => <PaymentMethodDto>[]),
'PendingPaymentResponse': TypeInfo(TypeOf.Class, create:() => PendingPaymentResponse()),
'ContractSoldResponse': TypeInfo(TypeOf.Class, create:() => ContractSoldResponse()),
'IReadOnlyList<PendingPaymentResponse>': TypeInfo(TypeOf.Class, create:() => IReadOnlyList<PendingPaymentResponse>()),
});
Dart ContractSoldEndpoint DTOs
To override the Content-type in your clients, use the HTTP Accept Header, append the .jsv suffix or ?format=jsv
The following are sample HTTP requests and responses. The placeholders shown need to be replaced with actual values.
POST /sales/contract/sold HTTP/1.1
Host: www.clubready.com
Accept: text/jsv
Content-Type: text/jsv
Content-Length: length
{
XForwardedFor: String,
ApiKey: String,
MemberId: 0,
ChainId: 0,
StoreId: 0,
PackageId: 0,
InstallmentId: 0,
StartDate: 0001-01-01,
PaymentAmount: 0,
PromoCode: String,
StaffId: 0,
PaymentMethods:
[
{
AcctToken: String,
ProfileToken: String,
PaymentProfileId: String,
PaymentAmount: 0,
UsePreferred: False,
DoNotUpdatePaymentTypePreference: False
}
],
RestrictedId: 0,
RestrictedResourceType: Chain
}
HTTP/1.1 200 OK Content-Type: text/jsv Content-Length: length { ContractSaleID: String, description: String, Success: False }