diff --git a/README.md b/README.md index 097ddcc..ad54c95 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,13 @@ chartmogul.DataSource.destroy(config, uuid='ds_5915ee5a-babd-406b-b8ce-d207133fb chartmogul.Customer.create(config, data={}) chartmogul.Customer.all(config, cursor='cursor==', per_page=20) chartmogul.Customer.retrieve(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb') +chartmogul.Customer.retrieve(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', + with_overrides=True, attributes_with_history='company,custom.channel') +# with_overrides and attributes_with_history only work on retrieve; list and search endpoints ignore them +# attributes_with_history is a comma-separated string of case-sensitive names; +# custom attributes take the custom. prefix; unknown names return a 422 +# Overrides and history live at the top level of the customer (customer.overrides, +# customer.historical_values); customer.attributes.overrides is never populated chartmogul.Customer.search(config, email='email@email.com') chartmogul.Customer.merge(config, data={ 'from': {'customer_uuid': 'cus_5915ee5a-babd-406b-b8ce-d207133fb4cb'}, @@ -150,6 +157,20 @@ chartmogul.Customer.modify(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4c "country": "US", "state": "CA", }) +chartmogul.Customer.modify(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={ + "company": "Pinata Technologies", + "overrides": { + "company": True, + "address": True, + "attributes": {"custom": {"channel": True}} + } +}) +# An overrides flag set to True protects the value written by the request from +# later updates; False removes an existing override and restores the field's +# most recent value from edit history. API writes to an overridden field are +# reverted unless the request carries a flag for that field. All write calls accept an overrides entry in data: +# Customer and Contact create/modify, Customer.createContact, and +# CustomAttributes add/update/remove (including add by email). chartmogul.Customer.destroy(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb') chartmogul.Customer.subscriptions(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb') chartmogul.Customer.connectSubscriptions(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={ @@ -196,11 +217,18 @@ chartmogul.Customer.createTask(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133 chartmogul.Contact.create(config, data={}) chartmogul.Contact.all(config, cursor='aabbcc', per_page=20, customer_uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', data_source_uuid='ds_fef05d54-47b4-431b-aed2-eb6b9e545430', email='test@example.com', customer_external_id='cus_0001', external_id='con_0001') chartmogul.Contact.retrieve(config, uuid='con_5915ee5a-babd-406b-b8ce-d207133fb4cb') +chartmogul.Contact.retrieve(config, uuid='con_5915ee5a-babd-406b-b8ce-d207133fb4cb', + with_overrides=True, attributes_with_history='title,email') +# with_overrides and attributes_with_history only work on retrieve; list endpoints ignore them chartmogul.Contact.merge(config, into_uuid='con_5915ee5a-babd-406b-b8ce-d207133fb4cb', from_uuid='con_2123290f-09c8-4628-a205-db5596bd58f7') chartmogul.Contact.modify(config, uuid='con_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={ "email": "test@example.com", "last_seen": "2025-04-01T12:00:00Z" }) +chartmogul.Contact.modify(config, uuid='con_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={ + "title": "CTO", + "overrides": {"title": True} +}) chartmogul.Contact.destroy(config, uuid='con_5915ee5a-babd-406b-b8ce-d207133fb4cb') chartmogul.Contact.tasks(config, uuid='con_5915ee5a-babd-406b-b8ce-d207133fb4cb', cursor='aabbcc', per_page=20) chartmogul.Contact.createTask(config, uuid='con_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={}) @@ -290,10 +318,14 @@ Date filters take ISO 8601 strings. `Task.patch` returns `None` when the API rep #### [Customer Attributes](https://dev.chartmogul.com/reference/customers/attributes/) -Note that the returned attributes of type date are not parsed and stay in string. +Note that the returned attributes of type date are not parsed and stay in string. The same applies inside `historical_values` entries: `update_performed_at` stays an ISO 8601 string. ```python chartmogul.Attributes.retrieve(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb') +chartmogul.Attributes.retrieve(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', + with_overrides=True, attributes_with_history='custom.channel') +# attributes_with_history accepts custom attributes only on this endpoint; +# standard field names like 'company' return a 422 ``` #### [Tags](https://dev.chartmogul.com/reference/customers/tags/) @@ -325,6 +357,15 @@ chartmogul.CustomAttributes.add(config, data={ {'type': 'Integer', 'key': 'age', 'value': 8} ] }) +chartmogul.CustomAttributes.add(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={ + 'custom': [ + {'type': 'String', 'key': 'channel', 'value': 'Facebook'} + ], + 'overrides': {'custom': {'channel': True}} +}) +# Note the overrides shape here is {'custom': {...}} — on Customer create/modify +# and in Customer.retrieve responses the same flags nest under 'attributes': +# {'attributes': {'custom': {...}}} chartmogul.CustomAttributes.update(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={ 'custom': { 'age': 20, @@ -334,6 +375,12 @@ chartmogul.CustomAttributes.update(config, uuid='cus_5915ee5a-babd-406b-b8ce-d20 chartmogul.CustomAttributes.remove(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={ 'custom': ['CAC'] }) +chartmogul.CustomAttributes.remove(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={ + 'custom': ['CAC'], + 'overrides': {'custom': {'CAC': False}} +}) +# remove keeps overridden attributes unless the request carries a False flag +# for them; the response message names the ones kept. ``` #### [Plans](https://dev.chartmogul.com/reference/plans/) diff --git a/chartmogul/api/attributes.py b/chartmogul/api/attributes.py index 3824d8c..a561be7 100644 --- a/chartmogul/api/attributes.py +++ b/chartmogul/api/attributes.py @@ -8,12 +8,17 @@ class Attributes(Resource): """ _path = "/customers{/uuid}/attributes" + _bool_query_params = ["with_overrides"] class _Schema(Schema): tags = fields.List(fields.String()) stripe = fields.Dict() clearbit = fields.Dict() custom = fields.Dict() + # load_default=None ensures these attributes are always present; the API + # omits the keys unless with_overrides / attributes_with_history is passed + overrides = fields.Dict(load_default=None) + historical_values = fields.Dict(load_default=None) @post_load def make(self, data, **kwargs): diff --git a/chartmogul/api/contact.py b/chartmogul/api/contact.py index 7853a20..d293f16 100644 --- a/chartmogul/api/contact.py +++ b/chartmogul/api/contact.py @@ -12,6 +12,7 @@ class Contact(Resource): _path = "/contacts{/uuid}" _root_key = "entries" + _bool_query_params = ["with_overrides"] _many = namedtuple("Contacts", [_root_key, "has_more", "cursor"]) class _Schema(Schema): @@ -33,6 +34,11 @@ class _Schema(Schema): external_id = fields.String(allow_none=True, load_default=None) last_seen = fields.DateTime(allow_none=True) custom = fields.Dict(allow_none=True) + # load_default=None ensures these attributes are always present; on + # retrieve the API omits the keys unless with_overrides / + # attributes_with_history is passed + overrides = fields.Dict(load_default=None) + historical_values = fields.Dict(load_default=None) @post_load def make(self, data, **kwargs): diff --git a/chartmogul/api/custom_attrs.py b/chartmogul/api/custom_attrs.py index d5b4cc2..a6bf684 100644 --- a/chartmogul/api/custom_attrs.py +++ b/chartmogul/api/custom_attrs.py @@ -12,7 +12,12 @@ class CustomAttributes(Resource): _path = "/customers{/uuid}/attributes/custom" class _Schema(Schema): - custom = fields.Dict() + # load_default=None ensures these attributes are always present; the API + # omits custom when a DELETE removes the last custom attribute, and + # returns message only on DELETE responses + custom = fields.Dict(load_default=None) + overrides = fields.Dict(load_default=None) + message = fields.String(load_default=None) @post_load def make(self, data, **kwargs): diff --git a/chartmogul/api/customer.py b/chartmogul/api/customer.py index f4bff27..7facb95 100644 --- a/chartmogul/api/customer.py +++ b/chartmogul/api/customer.py @@ -36,6 +36,7 @@ class Customer(Resource): _path = "/customers{/uuid}" _root_key = "entries" + _bool_query_params = ["with_overrides"] _many = namedtuple("Customers", [_root_key, "has_more", "cursor"], defaults=[None, None]) class _Schema(Schema): @@ -71,6 +72,11 @@ class _Schema(Schema): currency_sign = fields.String(data_key="currency-sign") address = fields.Nested(Address._Schema, allow_none=True, unknown=EXCLUDE) website_url = fields.String(allow_none=True) + # load_default=None ensures these attributes are always present; on + # retrieve the API omits the keys unless with_overrides / + # attributes_with_history is passed + overrides = fields.Dict(load_default=None) + historical_values = fields.Dict(load_default=None) @post_load def make(self, data, **kwargs): diff --git a/test/api/test_attributes.py b/test/api/test_attributes.py new file mode 100644 index 0000000..610bc48 --- /dev/null +++ b/test/api/test_attributes.py @@ -0,0 +1,72 @@ +import unittest +from chartmogul import Attributes, Config +import requests_mock + +attributesResponse = { + "tags": ["engage", "unit loss"], + "stripe": {"uid": 7, "coupon": True}, + "custom": {"CAC": 213, "salesRep": "Gabi"}, + "overrides": {"custom": {"salesRep": True}}, + "historical_values": { + "custom": { + "salesRep": [ + { + "value": "Gabi", + "update_performed_at": "2026-01-01T16:58:58Z", + "update_performed_by": "API", + "initial": False, + } + ] + } + }, +} + + +class AttributesTestCase(unittest.TestCase): + @requests_mock.mock() + def test_retrieve(self, mock_requests): + plainResponse = {key: attributesResponse[key] for key in ("tags", "stripe", "custom")} + mock_requests.register_uri( + "GET", + "https://api.chartmogul.com/v1/customers/CUSTOMER_UUID/attributes", + status_code=200, + json=plainResponse, + ) + + config = Config("token") + result = Attributes.retrieve(config, uuid="CUSTOMER_UUID").get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.qs, {}) + self.assertTrue(isinstance(result, Attributes)) + self.assertEqual(result.custom, attributesResponse["custom"]) + self.assertIsNone(result.overrides) + self.assertIsNone(result.historical_values) + + # case_sensitive asserts that the SDK preserves attribute name casing in the query + @requests_mock.Mocker(case_sensitive=True) + def test_retrieve_with_overrides_and_history(self, mock_requests): + mock_requests.register_uri( + "GET", + "https://api.chartmogul.com/v1/customers/CUSTOMER_UUID/attributes", + status_code=200, + json=attributesResponse, + ) + + config = Config("token") + result = Attributes.retrieve( + config, + uuid="CUSTOMER_UUID", + with_overrides=True, + attributes_with_history="custom.salesRep", + ).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual( + mock_requests.last_request.qs, + {"with_overrides": ["true"], "attributes_with_history": ["custom.salesRep"]}, + ) + self.assertTrue(isinstance(result, Attributes)) + self.assertEqual(result.custom, attributesResponse["custom"]) + self.assertEqual(result.overrides, attributesResponse["overrides"]) + self.assertEqual(result.historical_values, attributesResponse["historical_values"]) diff --git a/test/api/test_contact.py b/test/api/test_contact.py index 74fd2f6..929662f 100644 --- a/test/api/test_contact.py +++ b/test/api/test_contact.py @@ -314,6 +314,8 @@ def test_retrieve(self, mock_requests): self.assertTrue(isinstance(expected, Contact)) self.assertEqual(expected.email, "test@example.com") self.assertTrue(isinstance(expected.last_seen, datetime)) + self.assertIsNone(expected.overrides) + self.assertIsNone(expected.historical_values) @requests_mock.mock() def test_tasks(self, mock_requests): @@ -474,3 +476,77 @@ def test_destroy(self, mock_requests): self.assertEqual(mock_requests.call_count, 1, "expected call") self.assertEqual(mock_requests.last_request.qs, {}) self.assertTrue(expected, {}) + + @requests_mock.mock() + def test_retrieve_with_overrides_and_history(self, mock_requests): + overrides = {"title": True} + historical_values = { + "title": [ + { + "value": "CEO", + "update_performed_at": "2026-01-01T16:58:58Z", + "update_performed_by": "API", + "initial": False, + } + ] + } + mock_requests.register_uri( + "GET", + "https://api.chartmogul.com/v1/contacts/con_00000000-0000-0000-0000-000000000000", + status_code=200, + json={**contact, "overrides": overrides, "historical_values": historical_values}, + ) + + config = Config("token") + result = Contact.retrieve( + config, + uuid="con_00000000-0000-0000-0000-000000000000", + with_overrides=True, + attributes_with_history="title", + ).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual( + mock_requests.last_request.qs, + {"with_overrides": ["true"], "attributes_with_history": ["title"]}, + ) + self.assertEqual(result.overrides, overrides) + self.assertEqual(result.historical_values, historical_values) + + @requests_mock.mock() + def test_modify_with_overrides(self, mock_requests): + overrides = {"title": True} + mock_requests.register_uri( + "PATCH", + "https://api.chartmogul.com/v1/contacts/con_00000000-0000-0000-0000-000000000000", + status_code=200, + json={**contact, "overrides": overrides}, + ) + + jsonRequest = {"title": "CTO", "overrides": overrides} + config = Config("token") + result = Contact.modify( + config, uuid="con_00000000-0000-0000-0000-000000000000", data=jsonRequest + ).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.json(), jsonRequest) + self.assertEqual(result.overrides, overrides) + + @requests_mock.mock() + def test_create_with_overrides(self, mock_requests): + overrides = {"title": True} + mock_requests.register_uri( + "POST", + "https://api.chartmogul.com/v1/contacts", + status_code=201, + json={**contact, "overrides": overrides}, + ) + + jsonRequest = {**createContact, "overrides": overrides} + config = Config("token") + result = Contact.create(config, data=jsonRequest).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.json(), jsonRequest) + self.assertEqual(result.overrides, overrides) diff --git a/test/api/test_custom_attrs.py b/test/api/test_custom_attrs.py index 7b0fa7f..25db21a 100644 --- a/test/api/test_custom_attrs.py +++ b/test/api/test_custom_attrs.py @@ -56,6 +56,7 @@ "clearbit": {"name": "Acme"}, "custom": {"channel": "Facebook"}, }, + "overrides": {"attributes": {"custom": {"channel": True}}}, }, { "id": 13456, @@ -71,6 +72,7 @@ "clearbit": {"name": "Umbrella Corp."}, "custom": {"channel": "Facebook"}, }, + "overrides": {}, }, ] } @@ -87,7 +89,7 @@ def test_add(self, mock_requests): "POST", "https://api.chartmogul.com/v1/customers/CUSTOMER_UUID/attributes/custom", status_code=200, - json=simpleJSONResult, + json={**simpleJSONResult, "overrides": {}}, ) expected = CustomAttributes(**simpleJSONResult) @@ -104,21 +106,109 @@ def test_add(self, mock_requests): self.assertEqual(result.custom["convertedAt"], expected.custom["convertedAt"]) self.assertEqual(result.custom["pro"], expected.custom["pro"]) self.assertEqual(result.custom["salesRep"], expected.custom["salesRep"]) + self.assertEqual(result.overrides, {}) + self.assertIsNone(result.message) @requests_mock.mock() def test_add_to_email(self, mock_requests): mock_requests.register_uri( "POST", - "https://api.chartmogul.com/v1/customers/CUSTOMER_UUID/attributes/custom", + "https://api.chartmogul.com/v1/customers/attributes/custom", status_code=200, json=jsonResponse2, ) config = Config("token") - result = CustomAttributes.add(config, uuid="CUSTOMER_UUID", data=jsonRequest2).get() + result = CustomAttributes.add_by_email(config, data=jsonRequest2).get() self.assertEqual(mock_requests.call_count, 1, "expected call") self.assertEqual(mock_requests.last_request.qs, {}) self.assertEqual(mock_requests.last_request.json(), jsonRequest2) - # No comparison, because unicode strings, dates, serialization order etc. - # vary on different Python versions. + self.assertEqual(result.entries[0].overrides, {"attributes": {"custom": {"channel": True}}}) + self.assertEqual(result.entries[1].overrides, {}) + + @requests_mock.mock() + def test_add_with_overrides(self, mock_requests): + overrides = {"custom": {"channel": True}} + mock_requests.register_uri( + "POST", + "https://api.chartmogul.com/v1/customers/CUSTOMER_UUID/attributes/custom", + status_code=200, + json={"custom": {"channel": "Facebook"}, "overrides": overrides}, + ) + + jsonRequest = { + "custom": [{"type": "String", "key": "channel", "value": "Facebook"}], + "overrides": overrides, + } + config = Config("token") + result = CustomAttributes.add(config, uuid="CUSTOMER_UUID", data=jsonRequest).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.json(), jsonRequest) + self.assertEqual(result.custom, {"channel": "Facebook"}) + self.assertEqual(result.overrides, overrides) + + @requests_mock.mock() + def test_update_with_overrides(self, mock_requests): + overrides = {"custom": {"channel": True}} + mock_requests.register_uri( + "PUT", + "https://api.chartmogul.com/v1/customers/CUSTOMER_UUID/attributes/custom", + status_code=200, + json={"custom": {"channel": "Twitter"}, "overrides": overrides}, + ) + + jsonRequest = {"custom": {"channel": "Twitter"}, "overrides": overrides} + config = Config("token") + result = CustomAttributes.update(config, uuid="CUSTOMER_UUID", data=jsonRequest).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.json(), jsonRequest) + self.assertEqual(result.custom, {"channel": "Twitter"}) + self.assertEqual(result.overrides, overrides) + + @requests_mock.mock() + def test_remove_with_overrides_and_message(self, mock_requests): + mock_requests.register_uri( + "DELETE", + "https://api.chartmogul.com/v1/customers/CUSTOMER_UUID/attributes/custom", + status_code=202, + json={ + "custom": {"channel": "Facebook"}, + "overrides": {}, + "message": "Custom attributes deleted from customer", + }, + ) + + jsonRequest = {"custom": ["age"], "overrides": {"custom": {"age": False}}} + config = Config("token") + result = CustomAttributes.remove(config, uuid="CUSTOMER_UUID", data=jsonRequest).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.json(), jsonRequest) + self.assertEqual(result.custom, {"channel": "Facebook"}) + self.assertEqual(result.overrides, {}) + self.assertEqual(result.message, "Custom attributes deleted from customer") + + @requests_mock.mock() + def test_remove_last_attribute_omits_custom(self, mock_requests): + mock_requests.register_uri( + "DELETE", + "https://api.chartmogul.com/v1/customers/CUSTOMER_UUID/attributes/custom", + status_code=202, + json={ + "overrides": {}, + "message": "Custom attributes deleted from customer", + }, + ) + + config = Config("token") + result = CustomAttributes.remove( + config, uuid="CUSTOMER_UUID", data={"custom": ["age"]} + ).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertIsNone(result.custom) + self.assertEqual(result.overrides, {}) + self.assertEqual(result.message, "Custom attributes deleted from customer") diff --git a/test/api/test_customer.py b/test/api/test_customer.py index 7cf6f2e..6536920 100644 --- a/test/api/test_customer.py +++ b/test/api/test_customer.py @@ -521,15 +521,35 @@ def test_create(self, mock_requests): mock_requests.register_uri( "POST", "https://api.chartmogul.com/v1/customers", + status_code=201, + json={**entry, "overrides": {}}, + ) + + config = Config("token") + result = Customer.create(config, data=createCustomer).get() + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.qs, {}) + self.assertEqual(mock_requests.last_request.json(), sentCreateExpected) + self.assertEqual(result.overrides, {}) + self.assertIsNone(result.historical_values) + + @requests_mock.mock() + def test_retrieve(self, mock_requests): + mock_requests.register_uri( + "GET", + "https://api.chartmogul.com/v1/customers/cus_5915ee5a-babd-406b-b8ce-d207133fb4cb", status_code=200, json=entry, ) config = Config("token") - Customer.create(config, data=createCustomer).get() + result = Customer.retrieve(config, uuid="cus_5915ee5a-babd-406b-b8ce-d207133fb4cb").get() + self.assertEqual(mock_requests.call_count, 1, "expected call") self.assertEqual(mock_requests.last_request.qs, {}) - self.assertEqual(mock_requests.last_request.json(), sentCreateExpected) + self.assertTrue(isinstance(result, Customer)) + self.assertIsNone(result.overrides) + self.assertIsNone(result.historical_values) @requests_mock.mock() def test_search(self, mock_requests): @@ -928,3 +948,109 @@ def test_createTask(self, mock_requests): self.assertEqual(mock_requests.last_request.qs, {}) self.assertEqual(mock_requests.last_request.json(), createTask) self.assertTrue(isinstance(expected, Task)) + + # case_sensitive asserts that the SDK preserves attribute name casing in the query + @requests_mock.Mocker(case_sensitive=True) + def test_retrieve_with_overrides_and_history(self, mock_requests): + overrides = {"company": True, "attributes": {"custom": {"salesRep": True}}} + historical_values = { + "company": [ + { + "value": "Example Company", + "update_performed_at": "2026-01-01T16:58:58Z", + "update_performed_by": "API", + "initial": False, + } + ], + "attributes": { + "custom": { + "salesRep": [ + { + "value": "Gabi", + "update_performed_at": None, + "update_performed_by": None, + "initial": True, + } + ] + } + }, + } + mock_requests.register_uri( + "GET", + "https://api.chartmogul.com/v1/customers/cus_00000000-0000-0000-0000-000000000000", + status_code=200, + json={**entry, "overrides": overrides, "historical_values": historical_values}, + ) + + config = Config("token") + result = Customer.retrieve( + config, + uuid="cus_00000000-0000-0000-0000-000000000000", + with_overrides=True, + attributes_with_history="company,custom.salesRep", + ).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual( + mock_requests.last_request.qs, + {"with_overrides": ["true"], "attributes_with_history": ["company,custom.salesRep"]}, + ) + self.assertEqual(result.overrides, overrides) + self.assertEqual(result.historical_values, historical_values) + + @requests_mock.mock() + def test_create_with_overrides(self, mock_requests): + overrides = {"company": True, "attributes": {"custom": {"channel": True}}} + mock_requests.register_uri( + "POST", + "https://api.chartmogul.com/v1/customers", + status_code=201, + json={**entry, "overrides": overrides}, + ) + + config = Config("token") + result = Customer.create(config, data={**createCustomer, "overrides": overrides}).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.json()["overrides"], overrides) + self.assertEqual(result.overrides, overrides) + + @requests_mock.mock() + def test_modify_with_overrides(self, mock_requests): + overrides = {"company": True, "attributes": {"custom": {"channel": True}}} + mock_requests.register_uri( + "PATCH", + "https://api.chartmogul.com/v1/customers/cus_5915ee5a-babd-406b-b8ce-d207133fb4cb", + status_code=200, + json={**entry, "overrides": overrides}, + ) + + jsonRequest = {"company": "Pinata Technologies", "overrides": overrides} + config = Config("token") + result = Customer.modify( + config, uuid="cus_5915ee5a-babd-406b-b8ce-d207133fb4cb", data=jsonRequest + ).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.json(), jsonRequest) + self.assertEqual(result.overrides, overrides) + + @requests_mock.mock() + def test_createContact_with_overrides(self, mock_requests): + overrides = {"title": True} + mock_requests.register_uri( + "POST", + "https://api.chartmogul.com/v1/customers/cus_00000000-0000-0000-0000-000000000000/contacts", + status_code=201, + json={**contact, "overrides": overrides}, + ) + + jsonRequest = {**createContact, "overrides": overrides} + config = Config("token") + result = Customer.createContact( + config, uuid="cus_00000000-0000-0000-0000-000000000000", data=jsonRequest + ).get() + + self.assertEqual(mock_requests.call_count, 1, "expected call") + self.assertEqual(mock_requests.last_request.json(), jsonRequest) + self.assertEqual(result.overrides, overrides)