Skip to content

Commit

Permalink
Consolidate Customer & Data Source (#37)
Browse files Browse the repository at this point in the history
* Consolidating Customer & DataSource

* moving methods from Enrichment/Customer
* moving Customers out of Customer (was unintentionally  nested)
* added fields for multiple DS and external_ids
* DataSource was missing system field

* Fixing specs & fixtures (moved)
  • Loading branch information
pkopac authored Mar 6, 2017
1 parent f18673f commit ca4cfa6
Show file tree
Hide file tree
Showing 20 changed files with 247 additions and 150 deletions.
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# chartmogul-ruby Change Log

## Version 1.0.2 - 6 March 2017
- Consolidated Customer, Enrichment/Customer now deprecated

## Version 1.0.1 - 21 February 2017
- Fixed all() in Customer, now returns Customers with paging

Expand Down
112 changes: 101 additions & 11 deletions lib/chartmogul/customer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,22 @@ class Customer < APIResource
set_resource_path '/v1/customers'

readonly_attr :uuid
readonly_attr :id

readonly_attr :status
readonly_attr :customer_since, type: :time
readonly_attr :address
readonly_attr :mrr
readonly_attr :arr
readonly_attr :billing_system_url
readonly_attr :chartmogul_url
readonly_attr :billing_system_type
readonly_attr :currency
readonly_attr :currency_sign
readonly_attr :data_source_uuids
readonly_attr :external_ids

writeable_attr :attributes
writeable_attr :external_id
writeable_attr :name
writeable_attr :email
Expand All @@ -18,12 +33,18 @@ class Customer < APIResource
writeable_attr :free_trial_started_at, type: :time

include API::Actions::Create
include API::Actions::Update
include API::Actions::Custom
include API::Actions::Destroy

def self.all(options = {})
Customers.all(options)
end

def self.retrieve(uuid)
custom!(:get, "/v1/customers/#{uuid}")
end

def self.search(email)
Customers.search(email)
end
Expand All @@ -44,22 +65,91 @@ def invoices=(invoices_array)
@invoices = ChartMogul::CustomerInvoices.new(customer_uuid: uuid, invoices: invoices_array)
end

# Enrichment
def tags
@attributes[:tags]
end

def custom_attributes
@attributes[:custom]
end

def add_tags!(*tags)
self.tags = custom_without_assign!(:post,
"/v1/customers/#{uuid}/attributes/tags",
tags: tags)[:tags]
end

def remove_tags!(*tags)
self.tags = custom_without_assign!(:delete,
"/v1/customers/#{uuid}/attributes/tags",
tags: tags)[:tags]
end

def add_custom_attributes!(*custom_attrs)
self.custom_attributes = custom_without_assign!(:post,
"/v1/customers/#{uuid}/attributes/custom",
custom: custom_attrs)[:custom]
end

def update_custom_attributes!(custom_attrs = {})
self.custom_attributes = custom_without_assign!(:put,
"/v1/customers/#{uuid}/attributes/custom",
custom: custom_attrs)[:custom]
end

def remove_custom_attributes!(*custom_attrs)
self.custom_attributes = custom_without_assign!(:delete,
"/v1/customers/#{uuid}/attributes/custom",
custom: custom_attrs)[:custom]
end

def merge_into!(other_customer)
options = {
from: { customer_uuid: uuid },
into: { customer_uuid: other_customer.uuid }
}
custom!(:post, '/v1/customers/merges', options)
true
end

private

class Customers < APIResource
set_resource_name 'Customers'
set_resource_path '/v1/customers'
def tags=(tags)
@attributes[:tags] = tags
end

include Concerns::Entries
include API::Actions::Custom
include Concerns::Pageable
include Concerns::Pageable2
def custom_attributes=(custom_attributes = {})
@attributes[:custom] = typecast_custom_attributes(custom_attributes)
end

set_entry_class Customer
def set_attributes(attributes_attributes)
@attributes = attributes_attributes
@attributes[:custom] = typecast_custom_attributes(attributes_attributes[:custom])
end

def self.search(email)
path = ChartMogul::ResourcePath.new('/v1/customers/search')
custom!(:get, path.apply_with_get_params(email: email))
def typecast_custom_attributes(custom_attributes)
return {} unless custom_attributes
custom_attributes.each_with_object({}) do |(key, value), hash|
hash[key] = value.instance_of?(String) ? (Time.parse(value) rescue value) : value
end
end
end

class Customers < APIResource
set_resource_name 'Customers'
set_resource_path '/v1/customers'

include Concerns::Entries
include API::Actions::Custom
include Concerns::Pageable
include Concerns::Pageable2

set_entry_class Customer

def self.search(email)
path = ChartMogul::ResourcePath.new('/v1/customers/search')
custom!(:get, path.apply_with_get_params(email: email))
end
end
end
1 change: 1 addition & 0 deletions lib/chartmogul/data_source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class DataSource < APIResource

readonly_attr :uuid
readonly_attr :status
readonly_attr :system
readonly_attr :created_at, type: :time

writeable_attr :name
Expand Down
13 changes: 11 additions & 2 deletions lib/chartmogul/enrichment/customer.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
module ChartMogul
module Enrichment
class Customer < APIResource

# <b>DEPRECATED:</b> Please use <tt>ChartMogul/Customer</tt> instead.
class DeprecatedCustomer < APIResource

set_resource_name 'Customer'
set_resource_path '/v1/customers'

Expand Down Expand Up @@ -113,6 +116,12 @@ def typecast_custom_attributes(custom_attributes)
end
end

def self.const_missing(const_name)
super unless const_name == :Customer
warn "DEPRECATION WARNING: the class ChartMogul::Enrichment::Customer is deprecated. Use ChartMogul::Customer instead."
DeprecatedCustomer
end

class Customers < APIResource
set_resource_name 'Customers'
set_resource_path '/v1/customers'
Expand All @@ -121,7 +130,7 @@ class Customers < APIResource
include API::Actions::Custom
include Concerns::Pageable

set_entry_class Customer
set_entry_class DeprecatedCustomer

def self.search(email)
path = ChartMogul::ResourcePath.new('/v1/customers/search')
Expand Down
2 changes: 1 addition & 1 deletion lib/chartmogul/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module ChartMogul
VERSION = "1.0.1"
VERSION = "1.0.2"
end
131 changes: 130 additions & 1 deletion spec/chartmogul/customer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
describe 'API Interactions', vcr: true do
let(:lead_created_at) { Time.utc(2016,10,1,23,55) }
let(:free_trial_started_at) { Time.utc(2016,10,12,11,12) }

it 'correctly interracts with the API', uses_api: true do
ds = ChartMogul::DataSource.create!(name: 'Customer Test Data Source')

Expand Down Expand Up @@ -159,5 +159,134 @@
it 'correctly handles a 422 response', uses_api: true do
expect { ChartMogul::Customer.create! }.to raise_error(ChartMogul::ResourceInvalidError)
end
it 'returns all customers through list all endpoint', uses_api: true do
customers = described_class.all(per_page: 10)
expect(customers).to be_any
end

it 'returns right customers through search endpoint', uses_api: true do
customers = described_class.search('adam@smith.com')
expect(customers.first.email).to eq('adam@smith.com')
expect(customers.has_more).to eq(false)
expect(customers.per_page).to eq(200)
expect(customers.page).to eq(1)
end

it 'raises 404 if no customers found', uses_api: true do
expect{described_class.search('no@email.com')}.to raise_error(ChartMogul::NotFoundError)
end

it 'returns customer through retrieve endpoint', uses_api: true do
customer = described_class.retrieve('cus_07393ece-aab1-4255-8bcd-0ef11e24b047')
expect(customer).to be
end

it 'adds required tags', uses_api: true do
customer = described_class.retrieve('cus_07393ece-aab1-4255-8bcd-0ef11e24b047')
customer.add_tags!('example', 'another-tag')
expect(customer.tags).to match_array(['example', 'another-tag'])
end

it 'removes tags', uses_api: true do
customer = described_class.retrieve('cus_07393ece-aab1-4255-8bcd-0ef11e24b047')
customer.remove_tags!('example')
expect(customer.tags).to match_array(['another-tag'])
end

it 'adds custom attributes', uses_api: true do
customer = described_class.retrieve('cus_07393ece-aab1-4255-8bcd-0ef11e24b047')
customer.add_custom_attributes!(
{ type: "String", key: "string_key", value: "String Value" },
{ type: "Integer", key: "integer_key", value: 1234 },
{ type: "Timestamp", key: "timestamp_key", value: Time.utc(2016,01,31) },
{ type: "Boolean", key: "boolean_key", value: true }
)
expect(customer.custom_attributes).to eq(
string_key: "String Value",
integer_key: 1234,
timestamp_key: Time.utc(2016,01,31),
boolean_key: true
)
end

it 'updates custom attributes', uses_api: true do
customer = described_class.retrieve('cus_07393ece-aab1-4255-8bcd-0ef11e24b047')
customer.update_custom_attributes!(
string_key: "Another String Value",
integer_key: 5678,
timestamp_key: Time.utc(2016,02,1),
boolean_key: false
)
expect(customer.custom_attributes).to eq(
string_key: "Another String Value",
integer_key: 5678,
timestamp_key: Time.utc(2016,02,1),
boolean_key: false
)
end

it 'removes custom attributes', uses_api: true do
customer = described_class.retrieve('cus_07393ece-aab1-4255-8bcd-0ef11e24b047')
customer.remove_custom_attributes!(:string_key, :integer_key, :timestamp_key, :boolean_key)
expect(customer.custom_attributes).to eq({})
end

it 'merges customers', uses_api: true do
from_uuid = 'cus_35da5436-a730-11e6-a5a0-d32f2a781b50'
into_uuid = 'cus_fc5451ee-a72f-11e6-9019-3b1a0ecf3c73'

from_customer = described_class.retrieve(from_uuid)
into_customer = described_class.retrieve(into_uuid)

expect(from_customer.merge_into!(into_customer)).to eq(true)

expect do
described_class.retrieve(from_uuid)
end.to raise_error ChartMogul::NotFoundError

merged_customer = described_class.retrieve(into_uuid)
expect(merged_customer.attributes[:tags]).to eq ['merged-customer']
end

it 'updates customer', uses_api: true do
customer_uuid = 'cus_782b0716-a728-11e6-8eab-a7d0e8cd5c1e'
customer = described_class.retrieve(customer_uuid)

customer.name = 'Currywurst'
customer.email = 'curry@wurst.com'
customer.company = 'Curry 36'
customer.country = 'DE'
customer.state = 'NY'
customer.city = 'Berlin'
customer.lead_created_at = Time.utc(2016,1,1,14,30)
customer.free_trial_started_at = Time.utc(2016,2,2,22,40)
customer.attributes[:tags] = [:wurst]
customer.attributes[:custom][:meinung] = [:lecker]

customer.update!

updated_customer = described_class.retrieve(customer_uuid)
expect(updated_customer.name).to eq 'Currywurst'
expect(updated_customer.email).to eq 'curry@wurst.com'
expect(updated_customer.address).to eq({ country: 'Germany', state: 'New York', city: 'Berlin', address_zip: nil})
expect(updated_customer.attributes[:tags]).to eq ['wurst']
expect(updated_customer.attributes[:custom][:meinung]).to eq ['lecker']
end

it 'raises 422 for update with invalid data', uses_api: true do
customer_uuid = 'cus_782b0716-a728-11e6-8eab-a7d0e8cd5c1e'
customer = described_class.retrieve(customer_uuid)

customer.email = 'schnitzel.com'
expect do
customer.update!
end.to raise_error(ChartMogul::ResourceInvalidError, 'The Customer could not be created or updated.')
end

it 'raises 401 if invalid credentials', uses_api: true do
expect do
described_class.all(per_page: 10)
end.to raise_error(ChartMogul::UnauthorizedError, 'No valid API key provided')
end
end
end
Loading

0 comments on commit ca4cfa6

Please sign in to comment.