diff --git a/CHANGES.md b/CHANGES.md index f6c480f..7de666a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,24 @@ # Connect SDK Changes History +## v17.3 + +* HTTP timeout request to Connect platform should be not less than 300 seconds. +* Accept Usage File is sending wrong parameter in post request. +* Usage processor filter "product__id" is not filtering by product id. +* All fields accept null to avoid parsing errors. + +## v17.2 + +* external_id is sometimes returned as an integer by Connect API, which breaks Python SDK parsing. + +## v17.1 + +* Add custom loggers to the automation classes, that automatically add relevant info of the request being processed. Legacy global logger still working in order to have a context-independent logger. +* Get product templates and configuration params. +* Put each model in its own Python file, to reduce the chance of having circular references on imports. +* Tier requests are not filtering by product id by default. +* Fulfillment assignee not receiving the right type. + ## v17.0 * Fixed bugs when listing and working with usage files. diff --git a/connect/models/asset.py b/connect/models/asset.py index f347584..06ea5c1 100644 --- a/connect/models/asset.py +++ b/connect/models/asset.py @@ -9,6 +9,7 @@ from .configuration import Configuration from .connection import Connection from .contract import Contract +from .events import Events from .item import Item from .marketplace import Marketplace from .param import Param @@ -57,6 +58,9 @@ class Asset(BaseModel): - suspended: Asset becomes suspended once 'suspend' request type is fulfilled. """ + events = None # type: Events + """ (:py:class:`.Events`) Events occurred on this asset. """ + external_id = None # type: str """ (str) Identification for asset object on eCommerce. """ diff --git a/connect/models/schemas.py b/connect/models/schemas.py index d96c8f2..8411e00 100644 --- a/connect/models/schemas.py +++ b/connect/models/schemas.py @@ -10,6 +10,11 @@ class BaseSchema(Schema): id = fields.Str() + # Set allow_none to True in all fields + def on_bind_field(self, field_name, field_obj): + super(BaseSchema, self).on_bind_field(field_name, field_obj) + field_obj.allow_none = True + @post_load def make_object(self, data): from connect.models import BaseModel @@ -17,9 +22,9 @@ def make_object(self, data): class ActivationSchema(BaseSchema): - link = fields.Str(allow_none=True) + link = fields.Str() message = fields.Str() - date = fields.DateTime(allow_none=True) + date = fields.DateTime() @post_load def make_object(self, data): @@ -28,7 +33,7 @@ def make_object(self, data): class AgreementStatsSchema(BaseSchema): - contracts = fields.Int(allow_none=True) + contracts = fields.Int() versions = fields.Int() @post_load @@ -47,10 +52,10 @@ def make_object(self, data): class PhoneNumberSchema(BaseSchema): - country_code = fields.Str(allow_none=True) - area_code = fields.Str(allow_none=True) - phone_number = fields.Str(allow_none=True) - extension = fields.Str(allow_none=True) + country_code = fields.Str() + area_code = fields.Str() + phone_number = fields.Str() + extension = fields.Str() @post_load def make_object(self, data): @@ -60,8 +65,8 @@ def make_object(self, data): class ContactSchema(BaseSchema): email = fields.Str() - first_name = fields.Str(allow_none=True) - last_name = fields.Str(allow_none=True) + first_name = fields.Str() + last_name = fields.Str() phone_number = fields.Nested(PhoneNumberSchema) @post_load @@ -72,12 +77,12 @@ def make_object(self, data): class ContactInfoSchema(BaseSchema): address_line1 = fields.Str() - address_line2 = fields.Str(allow_none=True) + address_line2 = fields.Str() city = fields.Str() contact = fields.Nested(ContactSchema) country = fields.Str() postal_code = fields.Str() - state = fields.Str(allow_none=True) + state = fields.Str() @post_load def make_object(self, data): @@ -130,7 +135,7 @@ def make_object(self, data): class UserSchema(BaseSchema): name = fields.Str() - email = fields.Str(allow_none=True) + email = fields.Str() @post_load def make_object(self, data): @@ -139,8 +144,8 @@ def make_object(self, data): class EventSchema(BaseSchema): - at = fields.DateTime(allow_none=True) - by = fields.Nested(UserSchema, allow_none=True) + at = fields.DateTime() + by = fields.Nested(UserSchema) @post_load def make_object(self, data): @@ -189,7 +194,7 @@ def make_object(self, data): class HubSchema(BaseSchema): name = fields.Str() company = fields.Nested(CompanySchema) - description = fields.Str(allow_none=True) + description = fields.Str() instance = fields.Nested(HubInstanceSchema) events = fields.Nested(EventsSchema) stats = fields.Nested(HubStatsSchema) @@ -282,19 +287,19 @@ class ParamSchema(BaseSchema): name = fields.Str() description = fields.Str() type = fields.Str() - value = fields.Str(allow_none=True) - value_error = fields.Str(allow_none=True) - value_choice = fields.Str(many=True, allow_none=True) + value = fields.Str() + value_error = fields.Str() + value_choice = fields.Str(many=True) # Undocumented fields (they appear in PHP SDK) - title = fields.Str(allow_none=True) - scope = fields.Str(allow_none=True) - constraints = fields.Nested(ConstraintsSchema, allow_none=True) - value_choices = fields.Nested(ValueChoiceSchema, many=True, allow_none=True) - phase = fields.Str(allow_none=True) - events = fields.Nested(EventsSchema, allow_none=True) - marketplace = fields.Nested(MarketplaceSchema, allow_none=True) - countries = fields.Nested(CountrySchema, many=True, allow_none=True) + title = fields.Str() + scope = fields.Str() + constraints = fields.Nested(ConstraintsSchema) + value_choices = fields.Nested(ValueChoiceSchema, many=True) + phase = fields.Str() + events = fields.Nested(EventsSchema) + marketplace = fields.Nested(MarketplaceSchema) + countries = fields.Nested(CountrySchema, many=True) @post_load def make_object(self, data): @@ -305,15 +310,15 @@ def make_object(self, data): class ItemSchema(BaseSchema): mpn = fields.Str() quantity = QuantityField() - old_quantity = QuantityField(allow_none=True) - renewal = fields.Nested(RenewalSchema, allow_none=True) - params = fields.Nested(ParamSchema, many=True, allow_none=True) - display_name = fields.Str(allow_none=True) - global_id = fields.Str(allow_none=True) - item_type = fields.Str(allow_none=True) - period = fields.Str(allow_none=True) - type = fields.Str(allow_none=True) - name = fields.Str(allow_none=True) + old_quantity = QuantityField() + renewal = fields.Nested(RenewalSchema) + params = fields.Nested(ParamSchema, many=True) + display_name = fields.Str() + global_id = fields.Str() + item_type = fields.Str() + period = fields.Str() + type = fields.Str() + name = fields.Str() @post_load def make_object(self, data): @@ -328,17 +333,17 @@ class AgreementSchema(BaseSchema): created = fields.DateTime() updated = fields.DateTime() owner = fields.Nested(CompanySchema) - stats = fields.Nested(AgreementStatsSchema, allow_none=True) - author = fields.Nested(UserSchema, allow_none=True) + stats = fields.Nested(AgreementStatsSchema) + author = fields.Nested(UserSchema) version = fields.Int() active = fields.Bool() link = fields.Str() version_created = fields.DateTime() version_contracts = fields.Int() agreements = fields.Nested('AgreementSchema', many=True) - parent = fields.Nested('AgreementSchema', only=('id', 'name'), allow_none=True) - marketplace = fields.Nested(MarketplaceSchema, only=('id', 'name'), allow_none=True) - name = fields.Str(allow_none=True) + parent = fields.Nested('AgreementSchema', only=('id', 'name')) + marketplace = fields.Nested(MarketplaceSchema, only=('id', 'name')) + name = fields.Str() @post_load def make_object(self, data): @@ -352,15 +357,15 @@ class ContractSchema(BaseSchema): type = fields.Str() status = fields.Str() agreement = fields.Nested(AgreementSchema, only=('id', 'name')) - marketplace = fields.Nested(MarketplaceSchema, only=('id', 'name'), allow_none=True) - owner = fields.Nested(CompanySchema, only=('id', 'name'), allow_none=True) + marketplace = fields.Nested(MarketplaceSchema, only=('id', 'name')) + owner = fields.Nested(CompanySchema, only=('id', 'name')) creator = fields.Nested(UserSchema, only=('id', 'name')) created = fields.DateTime() updated = fields.DateTime() - enrolled = fields.DateTime(allow_none=True) + enrolled = fields.DateTime() version_created = fields.DateTime() activation = fields.Nested(ActivationSchema) - signee = fields.Nested(UserSchema, only=('id', 'name'), allow_none=True) + signee = fields.Nested(UserSchema, only=('id', 'name')) @post_load def make_object(self, data): @@ -401,9 +406,9 @@ def make_object(self, data): class ProductCategorySchema(BaseSchema): name = fields.Str() - parent = fields.Nested('ProductCategorySchema', allow_none=True) - children = fields.Nested('ProductCategorySchema', many=True, allow_none=True) - family = fields.Nested(ProductFamilySchema, allow_none=True) + parent = fields.Nested('ProductCategorySchema') + children = fields.Nested('ProductCategorySchema', many=True) + family = fields.Nested(ProductFamilySchema) @post_load def make_object(self, data): @@ -433,12 +438,12 @@ def make_object(self, data): class ProductConfigurationParameterSchema(BaseSchema): - value = fields.Str(allow_none=True) + value = fields.Str() parameter = fields.Nested(ParamSchema) - marketplace = fields.Nested(MarketplaceSchema, allow_none=True) - item = fields.Nested(ItemSchema, allow_none=True) + marketplace = fields.Nested(MarketplaceSchema) + item = fields.Nested(ItemSchema) events = fields.Nested(EventsSchema) - constraints = fields.Nested(ConstraintsSchema, allow_none=True) + constraints = fields.Nested(ConstraintsSchema) @post_load def make_object(self, data): @@ -452,13 +457,13 @@ class ProductSchema(BaseSchema): short_description = fields.Str() detailed_description = fields.Str() version = fields.Int() - published_at = fields.DateTime(allow_none=True) + published_at = fields.DateTime() configurations = fields.Nested(ProductConfigurationSchema) customer_ui_settings = fields.Nested(CustomerUiSettingsSchema) - category = fields.Nested(ProductCategorySchema, allow_none=True) - owner = fields.Nested(CompanySchema, allow_none=True) - latest = fields.Bool(allow_none=True) - stats = fields.Nested(ProductStatsSchema, allow_none=True) + category = fields.Nested(ProductCategorySchema) + owner = fields.Nested(CompanySchema) + latest = fields.Bool() + stats = fields.Nested(ProductStatsSchema) @post_load def make_object(self, data): @@ -468,8 +473,8 @@ def make_object(self, data): class ServerErrorResponseSchema(Schema): error_code = fields.Str() - params = fields.Dict(allow_none=True) - errors = fields.List(fields.Str()) + params = fields.Dict() + errors = fields.Str(many=True) @post_load def make_object(self, data): @@ -511,8 +516,8 @@ def make_object(self, data): class TierAccountsSchema(Schema): customer = fields.Nested(TierAccountSchema) - tier1 = fields.Nested(TierAccountSchema, allow_none=True) - tier2 = fields.Nested(TierAccountSchema, allow_none=True) + tier1 = fields.Nested(TierAccountSchema) + tier2 = fields.Nested(TierAccountSchema) @post_load def make_object(self, data): @@ -536,18 +541,19 @@ def make_object(self, data): class AssetSchema(BaseSchema): status = fields.Str() external_id = ExternalIdField() - external_uid = fields.Str(allow_none=True) - external_name = fields.Str(allow_none=True) + events = fields.Nested(EventsSchema) + external_uid = fields.Str() + external_name = fields.Str() product = fields.Nested(ProductSchema, only=('id', 'name')) connection = fields.Nested( - ConnectionSchema, only=('id', 'type', 'provider', 'vendor'), + ConnectionSchema, only=('id', 'type', 'provider', 'vendor') ) - contract = fields.Nested(ContractSchema, allow_none=True) - marketplace = fields.Nested(MarketplaceSchema, allow_none=True) + contract = fields.Nested(ContractSchema) + marketplace = fields.Nested(MarketplaceSchema) params = fields.Nested(ParamSchema, many=True) tiers = fields.Nested(TierAccountsSchema) items = fields.Nested(ItemSchema, many=True) - configuration = fields.Nested(ConfigurationSchema, allow_none=True) + configuration = fields.Nested(ConfigurationSchema) @post_load def make_object(self, data): @@ -576,7 +582,7 @@ class FulfillmentSchema(BaseSchema): asset = fields.Nested(AssetSchema) contract = fields.Nested(ContractSchema, only=('id', 'name')) marketplace = fields.Nested(MarketplaceSchema, only=('id', 'name')) - assignee = AssigneeField(allow_none=True) + assignee = AssigneeField() @post_load def make_object(self, data): @@ -591,13 +597,13 @@ class TierConfigSchema(BaseSchema): tier_level = fields.Int() params = fields.Nested(ParamSchema, many=True) connection = fields.Nested(ConnectionSchema) - open_request = fields.Nested(BaseSchema, allow_none=True) + open_request = fields.Nested(BaseSchema) template = fields.Nested(TemplateSchema) contract = fields.Nested(ContractSchema) marketplace = fields.Nested(MarketplaceSchema) - configuration = fields.Nested(ConfigurationSchema, allow_none=True) - events = fields.Nested(EventsSchema, allow_none=True) - status = fields.Str(allow_none=True) + configuration = fields.Nested(ConfigurationSchema) + events = fields.Nested(EventsSchema) + status = fields.Str() @post_load def make_object(self, data): @@ -615,15 +621,15 @@ class TierConfigRequestSchema(BaseSchema): tier_level = fields.Int() params = fields.Nested(ParamSchema, many=True) environment = fields.Str() - assignee = fields.Nested(UserSchema, allow_none=True) - template = fields.Nested(TemplateSchema, allow_none=True) - reason = fields.Str(allow_none=True) - activation = fields.Nested(ActivationSchema, allow_none=True) - notes = fields.Str(allow_none=True) - events = fields.Nested(EventsSchema, allow_none=True) - tiers = fields.Nested(TierAccountsSchema, allow_none=True) - marketplace = fields.Nested(MarketplaceSchema, allow_none=True) - contract = fields.Nested(ContractSchema, allow_none=True) + assignee = fields.Nested(UserSchema) + template = fields.Nested(TemplateSchema) + reason = fields.Str() + activation = fields.Nested(ActivationSchema) + notes = fields.Str() + events = fields.Nested(EventsSchema) + tiers = fields.Nested(TierAccountsSchema) + marketplace = fields.Nested(MarketplaceSchema) + contract = fields.Nested(ContractSchema) @post_load def make_object(self, data): diff --git a/examples/fulfillment.py b/examples/fulfillment.py index 48856cd..35ede92 100644 --- a/examples/fulfillment.py +++ b/examples/fulfillment.py @@ -41,8 +41,7 @@ def process_request(self, request): if request.type == 'purchase': for item in request.asset.items: if item.quantity > 100000: - raise FailRequest( - message='Is Not possible to purchase product') + raise FailRequest('Is not possible to purchase product in such quantities') for param in request.asset.params: if param.name == 'email' and not param.value: @@ -50,17 +49,25 @@ def process_request(self, request): 'please provide one' raise InquireRequest(params=[param]) - # Approve by ActivationTile - return ActivationTileResponse('\n # Welcome to Fallball!\n\nYes, you decided ' - 'to have an account in our amazing service!') - # Or - # return TemplateResource().render(pk='TEMPLATE_ID', request_id=request.id) + # Find a param by its id + param = request.asset.get_param_by_id('purchase_id') + if param: + param.value = '...' # We can assign the id given by the external service here + self.update_parameters(request.id, [param]) # Update param on the platform + else: + raise FailRequest('The asset is expected to have a "purchase_id" param.') # Approve by Template - # return ActivationTemplateResponse('TL-497-535-242') + return ActivationTemplateResponse('TL-497-535-242') # Or # return TemplateResource().get(pk='TEMPLATE_ID') + # Approve by ActivationTile + # return ActivationTileResponse('\n # Welcome to Fallball!\n\nYes, you decided ' + # 'to have an account in our amazing service!') + # Or + # return TemplateResource().render(pk='TEMPLATE_ID', request_id=request.id) + elif request.type == 'change': # Fail raise FailRequest()