diff --git a/README.md b/README.md index d1c6825..971cbf3 100644 --- a/README.md +++ b/README.md @@ -337,6 +337,33 @@ $new_customer_note = $customer->createNote([ ]); ``` +**List Opportunities from a customer** + +```php +$customer = ChartMogul\Customer::retrieve($uuid); +$opportunities = $customer->opportunities([ + 'cursor' => 'aabbccdd...' +]); +``` + +**Create an Opportunity from a customer** + +```php +$customer = ChartMogul\Customer::retrieve($uuid); +$new_opportunity = $customer->createOpportunity([ + 'owner' => 'owner@example.com', + 'pipeline' => 'Sales', + 'pipeline_stage' => 'Qualified', + 'estimated_close_date' => '2022-03-30', + 'currency' => 'USD', + 'amount_in_cents' => 10000, + 'type' => 'one-time', + 'forecast_category' => 'Best Case', + 'win_likelihood' => 80, + 'custom' => [{key: 'custom_key', value: 'custom_value'}] +]); +``` + ### Customer Notes **List Customer Notes** @@ -424,6 +451,55 @@ $updated_contact = ChartMogul\Contact::update([ $merged_contact = ChartMogul\Contact::merge($into_contact_uuid, $from_contact_uuid); ``` +### Opportunities + +**List Opportunities** + +```php +$opportunities = ChartMogul\Opportunity::all([ + 'cursor' => 'aabbccdd...' +]) +``` + +**Create an Opportunity** + +```php +$opportunity = ChartMogul\Opportunity::create([ + 'customer_uuid' => $uuid, + 'owner' => 'test1@example.org', + 'pipeline' => 'New business 1', + 'pipeline_stage' => 'Discovery', + 'estimated_close_date' => '2023-12-22', + 'currency' => 'USD', + 'amount_in_cents' => 100, + 'type' => 'recurring', + 'forecast_category' => 'pipeline', + 'win_likelihood' => 3, + 'custom' => [{ 'key': 'from_campaign', 'value': true }] +]) +``` + +**Get an Opportunity** + +```php +$opportunity = ChartMogul\Opportunity::retrieve($opportunity_uuid) +``` + +**Update an Opportunity** + +```php +$updated_opportunity = ChartMogul\Opportunity::update($opportunity_uuid, [ + 'estimated_close_date' => '2024-12-22', +]); +``` + +**Delete an Opportunity** + +```php +$opportunity = ChartMogul\Opportunity::retrieve($opportunity_uuid) +$opportunity->destroy(); +``` + ### Plans **Import a Plan** diff --git a/src/Customer.php b/src/Customer.php index 8dd4086..066e710 100644 --- a/src/Customer.php +++ b/src/Customer.php @@ -384,4 +384,33 @@ public function createNote(array $data = []) return new CustomerNote($result, $client); } + + /** + * Find all opportunities for a customer + * + * @param array $options + * @return CollectionWithCursor + */ + public function opportunities(array $options = []) + { + $client = $this->getClient(); + $result = $client->send("/v1/opportunities", "GET", [$options, "customer_uuid" => $this->uuid]); + + return Opportunity::fromArray($result, $client); + } + + /** + * Creates an opportunity from the customer. + * + * @param array $data + * @return Opportunity + */ + public function createOpportunity(array $data = []) + { + $client = $this->getClient(); + $data["customer_uuid"] = $this->uuid; + $result = $client->send("/v1/opportunities", "POST", $data); + + return new Opportunity($result, $client); + } } diff --git a/src/Opportunity.php b/src/Opportunity.php new file mode 100644 index 0000000..f8ec4c6 --- /dev/null +++ b/src/Opportunity.php @@ -0,0 +1,63 @@ +assertTrue($result instanceof CustomerNote); $this->assertEquals("note_00000000-0000-0000-0000-000000000000", $result->uuid); } + + public function testListOpportunities() + { + $stream = Psr7\stream_for(CustomerTest::LIST_OPPORTUNITIES_JSON); + list($cmClient, $mockClient) = $this->getMockClient(0, [200], $stream); + + $customer_uuid = "cus_00000000-0000-0000-0000-000000000000"; + + $result = (new Customer(["uuid" => $customer_uuid], $cmClient))->opportunities(); + $request = $mockClient->getRequests()[0]; + + $this->assertEquals("GET", $request->getMethod()); + $uri = $request->getUri(); + $this->assertEquals("/v1/opportunities", $uri->getPath()); + + $this->assertTrue($result[0] instanceof Opportunity); + $this->assertEquals("cursor==", $result->cursor); + $this->assertEquals(true, $result->has_more); + } + + public function testCreateOpportunity() + { + $stream = Psr7\stream_for(CustomerTest::OPPORTUNITY_JSON); + list($cmClient, $mockClient) = $this->getMockClient(0, [200], $stream); + + $customer_uuid = "cus_00000000-0000-0000-0000-000000000000"; + + $result = (new Customer(["uuid" => $customer_uuid], $cmClient))->createOpportunity( + [ + "owner" => "test1@example.org", + "pipeline" => "New business 1", + "pipeline_stage" => "Discovery", + "estimated_close_date" => "2023-12-22", + "currency" => "USD", + "amount_in_cents" => 100, + "type" => "recurring", + "forecast_category" => "pipeline", + "win_likelihood" => 3, + "custom" => [ + [ "key" => "from_campaign", "value" => true ], + ] + ] + ); + $request = $mockClient->getRequests()[0]; + + $this->assertEquals("POST", $request->getMethod()); + $uri = $request->getUri(); + $this->assertEquals("/v1/opportunities", $uri->getPath()); + $requestBody = (string) $request->getBody(); + $this->assertEquals('{"owner":"test1@example.org","pipeline":"New business 1","pipeline_stage":"Discovery","estimated_close_date":"2023-12-22","currency":"USD","amount_in_cents":100,"type":"recurring","forecast_category":"pipeline","win_likelihood":3,"custom":[{"key":"from_campaign","value":true}],"customer_uuid":"cus_00000000-0000-0000-0000-000000000000"}', $requestBody); + $this->assertTrue($result instanceof Opportunity); + $this->assertEquals("00000000-0000-0000-0000-000000000000", $result->uuid); + $this->assertEquals("cus_00000000-0000-0000-0000-000000000000", $result->customer_uuid); + $this->assertEquals("test1@example.org", $result->owner); + $this->assertEquals("New business 1", $result->pipeline); + $this->assertEquals("Discovery", $result->pipeline_stage); + $this->assertEquals("2023-12-22", $result->estimated_close_date); + $this->assertEquals("USD", $result->currency); + $this->assertEquals(100, $result->amount_in_cents); + $this->assertEquals("recurring", $result->type); + $this->assertEquals("pipeline", $result->forecast_category); + $this->assertEquals(3, $result->win_likelihood); + $this->assertEquals(["from_campaign" => true], $result->custom); + $this->assertEquals("2024-03-13T07:33:28.356Z", $result->created_at); + $this->assertEquals("2024-03-13T07:33:28.356Z", $result->updated_at); + } } diff --git a/tests/Unit/OpportunityTest.php b/tests/Unit/OpportunityTest.php new file mode 100644 index 0000000..145e468 --- /dev/null +++ b/tests/Unit/OpportunityTest.php @@ -0,0 +1,208 @@ +getMockClient(0, [200], $stream); + + $customer_uuid = "cus_00000000-0000-0000-0000-000000000000"; + + $result = Opportunity::all(["customer_uuid" => $customer_uuid], $cmClient); + $request = $mockClient->getRequests()[0]; + + $this->assertEquals("GET", $request->getMethod()); + $uri = $request->getUri(); + $this->assertEquals("/v1/opportunities", $uri->getPath()); + + $this->assertTrue($result[0] instanceof Opportunity); + $this->assertEquals("cursor==", $result->cursor); + $this->assertEquals(true, $result->has_more); + } + + public function testCreateOpportunity() + { + $stream = Psr7\stream_for(OpportunityTest::OPPORTUNITY_JSON); + list($cmClient, $mockClient) = $this->getMockClient(0, [200], $stream); + + $customer_uuid = "cus_00000000-0000-0000-0000-000000000000"; + + $result = Opportunity::create( + [ + "customer_uuid" => $customer_uuid, + "owner" => "test1@example.org", + "pipeline" => "New business 1", + "pipeline_stage" => "Discovery", + "estimated_close_date" => "2023-12-22", + "currency" => "USD", + "amount_in_cents" => 100, + "type" => "recurring", + "forecast_category" => "pipeline", + "win_likelihood" => 3, + "custom" => [ + [ "key" => "from_campaign", "value" => true ], + ] + ] + , $cmClient + ); + $request = $mockClient->getRequests()[0]; + + $this->assertEquals("POST", $request->getMethod()); + $uri = $request->getUri(); + $this->assertEquals("/v1/opportunities", $uri->getPath()); + + $this->assertTrue($result instanceof Opportunity); + $this->assertEquals("00000000-0000-0000-0000-000000000000", $result->uuid); + $this->assertEquals("cus_00000000-0000-0000-0000-000000000000", $result->customer_uuid); + $this->assertEquals("test1@example.org", $result->owner); + $this->assertEquals("New business 1", $result->pipeline); + $this->assertEquals("Discovery", $result->pipeline_stage); + $this->assertEquals("2023-12-22", $result->estimated_close_date); + $this->assertEquals("USD", $result->currency); + $this->assertEquals(100, $result->amount_in_cents); + $this->assertEquals("recurring", $result->type); + $this->assertEquals("pipeline", $result->forecast_category); + $this->assertEquals(3, $result->win_likelihood); + $this->assertEquals(["from_campaign" => True], $result->custom); + $this->assertEquals("2024-03-13T07:33:28.356Z", $result->created_at); + $this->assertEquals("2024-03-13T07:33:28.356Z", $result->updated_at); + } + + public function testRetrieveOpportunity() + { + $stream = Psr7\stream_for(OpportunityTest::OPPORTUNITY_JSON); + list($cmClient, $mockClient) = $this->getMockClient(0, [200], $stream); + + $uuid = "00000000-0000-0000-0000-000000000000"; + + $result = Opportunity::retrieve($uuid, $cmClient); + $request = $mockClient->getRequests()[0]; + + $this->assertEquals("GET", $request->getMethod()); + $uri = $request->getUri(); + $this->assertEquals("/v1/opportunities/".$uuid, $uri->getPath()); + + $this->assertTrue($result instanceof Opportunity); + $this->assertEquals("00000000-0000-0000-0000-000000000000", $result->uuid); + $this->assertEquals("cus_00000000-0000-0000-0000-000000000000", $result->customer_uuid); + $this->assertEquals("test1@example.org", $result->owner); + $this->assertEquals("New business 1", $result->pipeline); + $this->assertEquals("Discovery", $result->pipeline_stage); + $this->assertEquals("2023-12-22", $result->estimated_close_date); + $this->assertEquals("USD", $result->currency); + $this->assertEquals(100, $result->amount_in_cents); + $this->assertEquals("recurring", $result->type); + $this->assertEquals("pipeline", $result->forecast_category); + $this->assertEquals(3, $result->win_likelihood); + $this->assertEquals(["from_campaign" => True], $result->custom); + $this->assertEquals("2024-03-13T07:33:28.356Z", $result->created_at); + $this->assertEquals("2024-03-13T07:33:28.356Z", $result->updated_at); + } + + public function testUpdateOpportunity() + { + $stream = Psr7\stream_for(OpportunityTest::UPDATED_OPPORTUNITY_JSON); + list($cmClient, $mockClient) = $this->getMockClient(0, [200], $stream); + + $uuid = "00000000-0000-0000-0000-000000000000"; + + $result = Opportunity::update( + [ + "uuid" => $uuid, + ], [ + "estimated_close_date" => "2024-12-22", + ], $cmClient + ); + $request = $mockClient->getRequests()[0]; + + $this->assertEquals("PATCH", $request->getMethod()); + $uri = $request->getUri(); + $this->assertEquals("/v1/opportunities/".$uuid, $uri->getPath()); + + $this->assertTrue($result instanceof Opportunity); + $this->assertEquals("2024-12-22", $result->estimated_close_date); + } + + public function testDeleteOpportunity() + { + $stream = Psr7\stream_for("{}"); + list($cmClient, $mockClient) = $this->getMockClient(0, [204], $stream); + + $uuid = "00000000-0000-0000-0000-000000000000"; + + $result = (new Opportunity(["uuid" => $uuid], $cmClient))->destroy(); + $request = $mockClient->getRequests()[0]; + + $this->assertEquals("DELETE", $request->getMethod()); + $uri = $request->getUri(); + $this->assertEquals("/v1/opportunities/".$uuid, $uri->getPath()); + + $this->assertEquals("{}", $result); + } +}