ClubReady Api

<back to all web services

SellContractRequest

The following routes are available for this service:
POST/sales/contract/soldSell 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.
import datetime
import decimal
from marshmallow.fields import *
from servicestack import *
from typing import *
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, LetterCase, Undefined, config
from enum import Enum, IntEnum


@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class ApiDtoBase:
    api_key: Optional[str] = None
    store_id: Optional[int] = None
    chain_id: Optional[int] = None


class PaymentMethodType(IntEnum):
    UNINITIALIZED = 0
    PAYMENT_PROFILE_ID = 1
    PREFERRED_ON_FILE = 2
    ACCT_TOKEN = 3
    ERROR = -1


@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class PaymentMethodDto:
    acct_token: Optional[str] = None
    profile_token: Optional[str] = None
    payment_profile_id: Optional[str] = None
    payment_amount: Optional[Decimal] = None
    payment_method_type: Optional[PaymentMethodType] = None
    do_not_update_payment_type_preference: Optional[bool] = None


@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class SellContractRequestDto(ApiDtoBase):
    member_id: int = 0
    package_id: int = 0
    installment_id: Optional[int] = None
    start_date: Optional[datetime.datetime] = None
    payment_amount: Optional[Decimal] = None
    promo_code: Optional[str] = None
    payment_methods: Optional[List[PaymentMethodDto]] = None
    staff_id: Optional[int] = None


class RestrictedResourceType(str, Enum):
    STORE = 'Store'
    CHAIN = 'Chain'
    USER = 'User'
    UNDEFINED = 'Undefined'


# @ApiResponse(Description="", ResponseType=typeof(SellContractResultDto), StatusCode=200)
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class SellContractRequest(SellContractRequestDto, IRestrictedApiRequest):
    # @ApiMember(Description="Api Authentication Key", IsRequired=true, ParameterType="query")
    api_key: Optional[str] = None
    """
    Api Authentication Key
    """


    # @ApiMember(Description="Member Id of the user buying the Package", IsRequired=true, ParameterType="query")
    member_id: int = 0
    """
    Member Id of the user buying the Package
    """


    # @ApiMember(Description="Id for the chain of the Api Key")
    chain_id: Optional[int] = None
    """
    Id for the chain of the Api Key
    """


    # @ApiMember(Description="Id of the store for the user", IsRequired=true)
    store_id: Optional[int] = None
    """
    Id of the store for the user
    """


    # @ApiMember(Description="Package Id number of the package being purchased", IsRequired=true)
    package_id: int = 0
    """
    Package Id number of the package being purchased
    """


    # @ApiMember(Description="Installment Plan Id being purchased. If empty, the default package will be selected.")
    installment_id: Optional[int] = None
    """
    Installment Plan Id being purchased. If empty, the default package will be selected.
    """


    # @ApiMember(Description="Amount being paid down, including tax", IsRequired=true)
    payment_amount: Optional[Decimal] = None
    """
    Amount being paid down, including tax
    """


    # @ApiMember(Description="Promo code to apply a discount.")
    promo_code: Optional[str] = None
    """
    Promo code to apply a discount.
    """


    # @ApiMember(Description="Staff Id of salesperson who sold the agreement.")
    staff_id: Optional[int] = None
    """
    Staff Id of salesperson who sold the agreement.
    """


    # @ApiMember(Description="\r\nAn array of Payment Methods to be used for this purchase. Any entry with PreferredOnFile is assumed if omitted or null.  \r\n\r\nEach object of the array may contain properties:\r\n\r\n| Property | Description |\r\n| --- | --- |\r\n| PaymentMethodType | Usually \"AcctToken\" (Default or omitted/null) or \"PreferredOnFile\" |\r\n| PaymentAmount | The amount to be attempted for this Payment Method. When omitted (or null), the Request's PaymentAmount will be attempted |\r\n| AcctToken | The AcctToken to attempt payment (when using PaymentMethodType:AcctToken) |\r\n| ProfileToken | When provided (with AcctToken), a Payment Profile will be created (this will prevent the requirement to call `/sales/paymentprofile/import` (when using PaymentMethodType:AcctToken) |\r\n| DoNotUpdatePaymentTypePreference | When using ProfileToken, do not set the PaymentTypePreference (for more information, see `/sales/paymentprofile/import` (when using PaymentMethodType:AcctToken) |\r\n| | |\r\n\r\n* Scenario #1: Use the on file profile only. PaymentMethods can be omitted/null, or :  \r\n\r\nJSON:\r\n```json\r\n{\r\n    PaymentMethods: [\r\n        {\r\n            \"PaymentMethodType\":\"PreferredOnFile\",\r\n            \"PaymentAmount\":\"1.00\"\r\n        }\r\n    ]\r\n}\r\n```\r\nJSV:\r\n```jsv\r\n[{PaymentMethodType:PreferredOnFile,PaymentAmount:1.00}]\r\n```\r\n\r\n\r\n* Scenario #2: Use a Gift Card with PreferredOnFile to cover the amount not approved by the Gift Card.  \r\n\r\nJSON:\r\n```json\r\n{\r\n    PaymentMethods: [\r\n        {\r\n            \"PaymentMethodType\":\"AcctToken\",\r\n            \"PaymentAmount\":\"1.00\",\r\n            \"AcctToken\":\"eyJ...GiftCard AcctToken...\",\r\n            \"ProfileToken\":\"eyJ...Gift Card ProfileToken...\"\r\n        },\r\n        {\r\n            \"PaymentMethodType\":\"PreferredOnFile\",\r\n            \"PaymentAmount\":\"1.00\"\r\n        }\r\n    ]\r\n}\r\n```\r\nJSV:\r\n```jsv\r\n[{PaymentMethodType:AcctToken,PaymentAmount:1.00,AcctToken:eyj...,ProfileToken:eyJ...},{PaymentMethodType:PreferredOnFile,PaymentAmount:1.00}]\r\n```  \r\n\r\nNotes:  \r\n\r\n* The example shows PaymentAmount of 1.00 for both \"AcctToken\" and \"PreferredOnFile\". This is for the example\r\nwith a total of $1.00. The firstPaymentMethod (the Gift Card) will be attempted for $1.00. If it partially approves\r\nfor less than 1.00 (example: $0.80), the second payment method (PreferredOnFile) will be attempted for the lesser of\r\nit's PaymentAmount and the remaining amount (example: $0.20).\r\n\r\n* If ProfileToken has already been used (e.g. used with `/sales/paymentprofile/import`), it does not need to be included,\r\nbut AcctToken is required. ProfileToken is only needed once to 'activate' the AcctToken.\r\n\r\n* When using Query String (or this web site), this value must be encoded with JSV [(JSON-like Separated Values)](https://docs.servicestack.net/jsv-format).\r\nBasic steps to convert JSON to JSV: 1) Remove properties that are null, 2) Remove white space including line feeds, 3) Remove quotes.\r\n")
    payment_methods: Optional[List[PaymentMethodDto]] = None
    """
    An array of Payment Methods to be used for this purchase. Any entry with PreferredOnFile is assumed if omitted or null.  Each object of the array may contain properties:| Property | Description || --- | --- || PaymentMethodType | Usually "AcctToken" (Default or omitted/null) or "PreferredOnFile" || PaymentAmount | The amount to be attempted for this Payment Method. When omitted (or null), the Request's PaymentAmount will be attempted || AcctToken | The AcctToken to attempt payment (when using PaymentMethodType:AcctToken) || ProfileToken | When provided (with AcctToken), a Payment Profile will be created (this will prevent the requirement to call `/sales/paymentprofile/import` (when using PaymentMethodType:AcctToken) || DoNotUpdatePaymentTypePreference | When using ProfileToken, do not set the PaymentTypePreference (for more information, see `/sales/paymentprofile/import` (when using PaymentMethodType:AcctToken) || | |* Scenario #1: Use the on file profile only. PaymentMethods can be omitted/null, or :  JSON:```json{    PaymentMethods: [        {            "PaymentMethodType":"PreferredOnFile",            "PaymentAmount":"1.00"        }    ]}```JSV:```jsv[{PaymentMethodType:PreferredOnFile,PaymentAmount:1.00}]```* Scenario #2: Use a Gift Card with PreferredOnFile to cover the amount not approved by the Gift Card.  JSON:```json{    PaymentMethods: [        {            "PaymentMethodType":"AcctToken",            "PaymentAmount":"1.00",            "AcctToken":"eyJ...GiftCard AcctToken...",            "ProfileToken":"eyJ...Gift Card ProfileToken..."        },        {            "PaymentMethodType":"PreferredOnFile",            "PaymentAmount":"1.00"        }    ]}```JSV:```jsv[{PaymentMethodType:AcctToken,PaymentAmount:1.00,AcctToken:eyj...,ProfileToken:eyJ...},{PaymentMethodType:PreferredOnFile,PaymentAmount:1.00}]```  Notes:  * The example shows PaymentAmount of 1.00 for both "AcctToken" and "PreferredOnFile". This is for the examplewith a total of $1.00. The firstPaymentMethod (the Gift Card) will be attempted for $1.00. If it partially approvesfor less than 1.00 (example: $0.80), the second payment method (PreferredOnFile) will be attempted for the lesser ofit's PaymentAmount and the remaining amount (example: $0.20).* If ProfileToken has already been used (e.g. used with `/sales/paymentprofile/import`), it does not need to be included,but AcctToken is required. ProfileToken is only needed once to 'activate' the AcctToken.* When using Query String (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.
    """


    restricted_id: Optional[int] = None
    restricted_resource_type: Optional[RestrictedResourceType] = None


class ResponseStatus(IntEnum):
    STS_UNKNOWN = 0
    STS_SUCCESS = 1
    STS_DECLINE = 2
    STS_ERROR = 3
    HARD_DECLINE_ACCOUNT = 4
    HARD_DECLINE_EXPIRY = 5
    PARTIAL_APPROVAL = 11


@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class PendingPaymentResponse:
    response_transaction_id: Optional[str] = None
    response_txn_id: Optional[str] = None
    response_status: Optional[ResponseStatus] = None
    response_amount: Decimal = decimal.Decimal(0)
    response_text: Optional[str] = None
    last4: Optional[str] = None
    acct_class: Optional[str] = None
    acct_type: Optional[str] = None
    acct_token: Optional[str] = None


@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class SellContractResultDto:
    contract_sale_i_d: Optional[str] = None
    description: Optional[str] = None
    success: bool = False
    payment_responses: Optional[IReadOnlyList[PendingPaymentResponse]] = None

Python SellContractRequest DTOs

To override the Content-type in your clients, use the HTTP Accept Header, append the .jsv suffix or ?format=jsv

HTTP + 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

{
	ApiKey: String,
	MemberId: 0,
	ChainId: 0,
	StoreId: 0,
	PackageId: 0,
	InstallmentId: 0,
	PaymentAmount: 0,
	PromoCode: String,
	StaffId: 0,
	PaymentMethods: 
	[
		{
			AcctToken: String,
			ProfileToken: String,
			PaymentProfileId: String,
			PaymentAmount: 0,
			PaymentMethodType: Uninitialized,
			DoNotUpdatePaymentTypePreference: False
		}
	],
	RestrictedId: 0,
	RestrictedResourceType: Chain,
	StartDate: 0001-01-01
}
HTTP/1.1 200 OK
Content-Type: text/jsv
Content-Length: length

{
	ContractSaleID: String,
	description: String,
	Success: False
}