Skip to content

Commit

Permalink
feat(sc-57427): Support Opportunities API (#154)
Browse files Browse the repository at this point in the history
* feat(sc-57427): Support Opportunities API

* feat(sc-57427): Support Opportunities API : added tests for created_at and updated_at
  • Loading branch information
kamilpavlicko authored Mar 25, 2024
1 parent 776589b commit 79d9ca9
Show file tree
Hide file tree
Showing 13 changed files with 574 additions and 20 deletions.
1 change: 1 addition & 0 deletions lib/chartmogul.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
require 'chartmogul/plan_groups/plans'
require 'chartmogul/account'
require 'chartmogul/subscription_event'
require 'chartmogul/opportunity'

require 'chartmogul/metrics/arpa'
require 'chartmogul/metrics/arr'
Expand Down
14 changes: 12 additions & 2 deletions lib/chartmogul/customer.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# frozen_string_literal: true

module ChartMogul
# rubocop:disable Metrics/ClassLength
class Customer < APIResource
set_resource_name 'Customer'
set_resource_path '/v1/customers'
set_immutable_keys([:attributes, :custom])
set_immutable_keys(%i[attributes custom])

readonly_attr :uuid
readonly_attr :id
Expand Down Expand Up @@ -93,6 +94,14 @@ def create_note(options = {})
Note.create!(options.merge(customer_uuid: uuid))
end

def opportunities(options = {})
Opportnities.all(options.merge(customer_uuid: uuid))
end

def create_opportunity(options = {})
Opportunity.create!(options.merge(customer_uuid: uuid))
end

# Enrichment
def tags
@attributes[:tags]
Expand Down Expand Up @@ -160,7 +169,7 @@ def set_attributes(attributes_attributes)
class Customers < APIResource
set_resource_name 'Customers'
set_resource_path '/v1/customers'
set_immutable_keys([:attributes, :custom])
set_immutable_keys(%i[attributes custom])

include Concerns::Entries
include API::Actions::Custom
Expand All @@ -175,4 +184,5 @@ def self.search(email, options = {})
custom!(:get, path.apply_with_get_params(options.merge(email: email)))
end
end
# rubocop:enable Metrics/ClassLength
end
46 changes: 46 additions & 0 deletions lib/chartmogul/opportunity.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

require 'forwardable'

module ChartMogul
class Opportunity < APIResource
set_resource_name 'Opportunity'
set_resource_path '/v1/opportunities'
set_immutable_keys([:custom])

readonly_attr :uuid
readonly_attr :created_at
readonly_attr :updated_at

writeable_attr :customer_uuid
writeable_attr :owner
writeable_attr :pipeline
writeable_attr :pipeline_stage
writeable_attr :estimated_close_date
writeable_attr :currency
writeable_attr :amount_in_cents
writeable_attr :type
writeable_attr :forecast_category
writeable_attr :win_likelihood
writeable_attr :custom

include API::Actions::Create
include API::Actions::Destroy
include API::Actions::Retrieve
include API::Actions::Update

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

class Opportnities < APIResource
set_resource_name 'Opportunities'
set_resource_path '/v1/opportunities'

include Concerns::Entries
include Concerns::PageableWithCursor

set_entry_class Opportunity
end
end
70 changes: 52 additions & 18 deletions spec/chartmogul/customer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,19 @@
end
let(:customer_uuid) { 'cus_23e01538-2c7e-11ee-b2ce-fb986e96e21b' }
let(:data_source_uuid) { 'ds_03cfd2c4-2c7e-11ee-ab23-cb0f008cff46' }
let(:customer_note_uuid) { 'note_23e5e234-94e7-11ee-b12d-33351b909dc1'}
let(:customer_note_uuid) { 'note_23e5e234-94e7-11ee-b12d-33351b909dc1' }
let(:customer_note_attrs) do
{
uuid: 'cus_58f81bdc-94e6-11ee-ba3e-63f79c1ac982',
data_source_uuid: 'ds_a628a2ae-7451-11eb-a2cf-ab1ab88dd733'
}
end
let(:opportunity_attrs) do
{
uuid: 'cus_4e49211a-df7b-11ee-8949-df3c4571686f',
data_source_uuid: 'ds_7ed73928-dd2a-11ee-a144-bf5bc12d16ea'
}
end

describe '#initialize' do
subject { described_class.new(attrs) }
Expand Down Expand Up @@ -159,12 +165,12 @@
customer_uuid = 'cus_a4680a9c-76a4-11ee-83ab-d3b9aabc7f00'

updated_customer = described_class.update!(customer_uuid, {
email: 'customer_test@example.com',
company: 'Curry 42',
attributes: { custom: { Toggle: true } },
name: 'Test Customer',
website_url: 'https://example.co'
})
email: 'customer_test@example.com',
company: 'Curry 42',
attributes: { custom: { Toggle: true } },
name: 'Test Customer',
website_url: 'https://example.co'
})

expect(updated_customer).to have_attributes(
email: 'customer_test@example.com',
Expand Down Expand Up @@ -378,24 +384,23 @@

it 'creates a note belonging to the customer correctly' do
new_note = described_class.new_from_json({
uuid: customer_note_attrs[:uuid],
data_source_uuid: customer_note_attrs[:data_source_uuid],
}).create_note(
text: 'This is a call',
type: 'call',
author_email: 'soeun+staff@chartmogul.com',
)
uuid: customer_note_attrs[:uuid],
data_source_uuid: customer_note_attrs[:data_source_uuid],
}).create_note(
text: 'This is a call',
type: 'call',
author_email: 'soeun+staff@chartmogul.com',
)
expect(new_note.text).to eq('This is a call')
expect(new_note.type).to eq('call')
expect(new_note.author).to eq('Soeun Lee[staff-user-2] (soeun+staff@chartmogul.com)')

end

it 'lists the notes belonging to the customer correctly' do
notes = described_class.new_from_json({
uuid: customer_note_attrs[:uuid],
data_source_uuid: customer_note_attrs[:data_source_uuid],
}).notes
uuid: customer_note_attrs[:uuid],
data_source_uuid: customer_note_attrs[:data_source_uuid],
}).notes
expect(notes.entries.size).to eq(1)
expect(notes.has_more).to eq(false)
expect(notes.cursor).not_to be_nil
Expand All @@ -414,5 +419,34 @@
expect(subs.has_more).to eq(false)
expect(subs.cursor).not_to be_nil
end

it 'creates a opportunity belonging to the customer correctly' do
attrs = { owner: 'kamil+pavlicko@chartmogul.com',
pipeline: 'New Business',
pipeline_stage: 'Discovery',
estimated_close_date: '2024-03-30',
currency: 'USD',
amount_in_cents: 200_000,
type: 'one-time',
forecast_category: 'best_case',
win_likelihood: 30,
custom: [{ key: 'from_campaign', value: true }] }

new_opportunity = described_class.new_from_json({
uuid: opportunity_attrs[:uuid],
data_source_uuid: opportunity_attrs[:data_source_uuid]
}).create_opportunity(attrs)
expect(new_opportunity).to have_attributes(**attrs.merge(custom: { :from_campaign => true }))
end

it 'lists the opportunities belonging to the customer correctly' do
opportunities = described_class.new_from_json({
uuid: opportunity_attrs[:uuid],
data_source_uuid: opportunity_attrs[:data_source_uuid]
}).opportunities
expect(opportunities.entries.size).to eq(1)
expect(opportunities.has_more).to eq(false)
expect(opportunities.cursor).not_to be_nil
end
end
end
130 changes: 130 additions & 0 deletions spec/chartmogul/opportunity_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# frozen_string_literal: true

require 'spec_helper'

describe ChartMogul::Opportunity do
let(:attrs) do
{
uuid: uuid,
customer_uuid: customer_uuid,
owner: 'kamil+pavlicko@chartmogul.com',
pipeline: 'New Business',
pipeline_stage: 'Discovery',
estimated_close_date: '2024-03-30',
currency: 'USD',
amount_in_cents: 100_000,
type: 'one-time',
forecast_category: 'best_case',
win_likelihood: 30,
custom: [{ key: 'from_campaign', value: true }]
}
end

let(:uuid) { '3726cd86-e0f0-11ee-8d22-93b1d57bf35d' }
let(:customer_uuid) { 'cus_8bae29d0-df51-11ee-88c8-97dc7855258a' }
let(:updated_attributes) { { estimated_close_date: '2024-04-30' } }
let(:cursor) { 'MjAyNC0wMy0xMVQwNjozODo0Ny44Nzk2NDYwMDBaJjAzZDdkNWJjLWRmNzItMTFlZS1iMTBkLThiNzg5ZDc1N2MyYQ==' }

describe '#initialize' do
subject { described_class.new(attrs) }

it 'sets the read-only properties correctly' do
expect(subject).to have_attributes({ uuid: nil, created_at: nil, updated_at: nil})
end

it 'sets the writeable properties correctly' do
expect(subject).to have_attributes(attrs.reject { |k, _| [:uuid, :created_at, :updated_at].include?(k) })
end
end

describe '.new_from_json' do
subject { described_class.new_from_json(attrs) }

it 'sets all properties correctly' do
expect(subject).to have_attributes(attrs)
end
end

describe 'API Actions', uses_api: true, vcr: true do
it 'retrieves all opportunities correctly' do
opportunities = described_class.all(customer_uuid: customer_uuid)

expect(opportunities.first).to have_attributes(
uuid: uuid,
customer_uuid: customer_uuid,
)
expect(opportunities.cursor).to eq(cursor)
expect(opportunities.has_more).to eq(false)
end

it 'retrieves a opportunity correctly' do
opportunity = described_class.retrieve(uuid)

expect(opportunity).to have_attributes(
uuid: uuid,
customer_uuid: customer_uuid,
)
end

it 'creates a opportunity correctly' do
attributes = attrs.reject { |key, _| key == :uuid }
opportunity = described_class.create!(**attributes)
expect(opportunity).to have_attributes(**attributes.merge(custom: { from_campaign: true }))
end

it 'updates the opportunity correctly with the class method' do
updated_opportunity = described_class.update!(
uuid, **updated_attributes
)

expect(updated_opportunity).to have_attributes(
uuid: uuid,
customer_uuid: customer_uuid,
**updated_attributes
)
end

it 'destroys the opportunity correctly' do
target_opportunity_uuid = '52115b0c-e54b-11ee-b769-a7d79ddfc0fb'
deleted_opportunity = described_class.destroy!(uuid: target_opportunity_uuid)
expect(deleted_opportunity).to eq(true)
end

context 'with old pagination' do
let(:get_resources) { described_class.all(per_page: 1, page: 3) }

it_behaves_like 'raises deprecated param error'
end

context 'with pagination' do
let(:first_cursor) do
'MjAyNC0wMy0xMVQwNzo0NTo0MS4xMzM4NjEwMDBaJjViZWUwYTQyLWRmN2ItMTFlZS05NTA2LWNiMjM4ZTliMTIxOA=='
end
let(:next_cursor) do
'MjAyNC0wMy0xMVQwNjozODo0Ny44Nzk2NDYwMDBaJjAzZDdkNWJjLWRmNzItMTFlZS1iMTBkLThiNzg5ZDc1N2MyYQ=='
end

it 'paginates correctly' do
opportunities = ChartMogul::Opportunity.all(per_page: 1)
expect(opportunities).to have_attributes(
cursor: first_cursor,
has_more: true,
size: 1
)
expect(opportunities.first).to have_attributes(
uuid: '5bee0a42-df7b-11ee-9506-cb238e9b1218'
)

next_opportunities = opportunities.next(per_page: 1, customer_uuid: customer_uuid)
expect(next_opportunities).to have_attributes(
cursor: next_cursor,
has_more: false,
size: 1
)
expect(next_opportunities.first).to have_attributes(
uuid: '03d7d5bc-df72-11ee-b10d-8b789d757c2a'
)
end
end
end
end

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 79d9ca9

Please sign in to comment.