diff --git a/README.md b/README.md index 4bb36d2..679dd6d 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,37 @@ Retrieve all clients $clients = $ninja->clients->all(); ``` +You can perform complex filtering on the ->all() method. + +Query parameters can be chained together to form complex queries. The current supported values are: + +**per_page**: The number of clients per page you want returned +**page**: The page number +**include**: A comma separated list of relations to include ie. contacts,documents,gateway_tokens +**balance**: A query to return clients with a balance using an operator and value + - ie ?balance=lt:10 Returns clients with a balance less than 10 + - available operators lt, lte, gt, gte, eq +**between_balance**: Returns clients with a balance between two values + - ie ?between_balance=10:20 - Returns clients with a balance between 10 and 20 +**email**: Returns clients with a contacts.email field equal to an email +**id_number**: Search by id_number +**number**: Search by number +**filter**: Search across multiple columns (name, id_number, first_name, last_name, email, custom_value1, custom_value2, custom_value3, custom_value4) +**created_at**: Search by created at (Unix timestamp) +**is_deleted**: Search using is_deleted boolean flag + +For example, + +```php +$clients = $ninja->clients->all([ + 'balance' => 'lt:10', // get all clients with a balance less than 10 + 'per_page' => 10, // return 10 results per page + 'page' => 2, // paginate to page 2 + 'include' => 'documents', // include the documents relationship +]); + +``` + Retrieve a client by its primary key. ```php $client = $ninja->clients->get("CLIENT_HASHED_ID"); @@ -59,7 +90,54 @@ Create an invoice $client = $ninja->invoices->create(['client_id' => CLIENT_HASHED_ID]); ``` -Download an invoice PDF + +When creating an invoice, you can perform actions on the invoice in a single call, for example, say you wish to create an invoice and also apply a payment to the invoice: + +```php + $invoice = $ninja->invoices->create(['client_id'=> 'CLIENT_HASHED_ID'], ['mark_paid' => true]); +``` + +Or if you wish to apply a partial payment + +```php + $invoice = $ninja->invoices->create(['client_id'=> 'CLIENT_HASHED_ID'], ['amount_paid' => 10]); +``` + +Or you may want to automatically send and charge the invoice **note requires a payment method on file** +```php + $invoice = $ninja->invoices->create(['client_id'=> 'CLIENT_HASHED_ID'], ['auto_bill' => true, 'send_email' => true]); +``` + + +### Bulk actions + +You can perform bulk actions against one or many entities. For example if you wish to batch archive a range of invoice you would do + +```php + $bulk = $ninja->invoices->archive(["hash_1","hash_2"]); +``` + +You can access the raw bulk method using the following: + +```php +$bulk = $ninja->invoices->bulk("archive", ["hash_1","hash_2"]); +``` + +If you wanted to download a invoice PDF ```php - $pdf = $invoice->download(); -``` \ No newline at end of file + $pdf = $ninja->invoices->bulk("download", ["hash_1"]); +``` + +The following are a list of available bulk actions for invoices: + ++ mark_sent ++ download ++ restore ++ archive ++ delete ++ mark_paid ++ clone_to_quote ++ clone_to_invoice ++ cancel ++ reverse ++ email \ No newline at end of file diff --git a/composer.json b/composer.json index d46dd2b..60d9bfc 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ "guzzlehttp/guzzle": "^7.3" }, "require-dev": { + "fakerphp/faker": "^1.16", "phpunit/phpunit": "^9.5" }, "autoload-dev": { diff --git a/src/Endpoints/BaseEntity.php b/src/Endpoints/BaseEntity.php new file mode 100644 index 0000000..c2313ee --- /dev/null +++ b/src/Endpoints/BaseEntity.php @@ -0,0 +1,43 @@ + $action, "ids" => $ids]; + + return $this->ninja->send("POST", "{$this->uri}/bulk", $query); + } + + public function archive(array $entity_array) + { + return $this->bulk("archive", $entity_array); + } + + public function delete(array $entity_array) + { + return $this->bulk("delete", $entity_array); + } + + public function restore(array $entity_array) + { + return $this->bulk("restore", $entity_array); + } + +} + diff --git a/src/Endpoints/Clients.php b/src/Endpoints/Clients.php index cf69468..a2e368e 100644 --- a/src/Endpoints/Clients.php +++ b/src/Endpoints/Clients.php @@ -14,11 +14,13 @@ use GuzzleHttp\Exception\GuzzleException; use InvoiceNinja\Sdk\InvoiceNinja; -class Clients +class Clients extends BaseEntity { protected InvoiceNinja $ninja; + protected string $uri = "/api/v1/clients"; + public function __construct(InvoiceNinja $ninja) { $this->ninja = $ninja; @@ -33,28 +35,28 @@ public function all(array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/clients", $query); + return $this->ninja->send("GET", "{$this->uri}", $query); } public function get(string $client_id, array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/clients/{$client_id}", $query); + return $this->ninja->send("GET", "{$this->uri}/{$client_id}", $query); } public function update(string $client_id, array $client) { $query = ['form_params' => $client]; - return $this->ninja->send("PUT", "/api/v1/clients/{$client_id}", $query); + return $this->ninja->send("PUT", "{$this->uri}/{$client_id}", $query); } public function create(array $client, array $includes = []) { $query = ['form_params' => $client, 'query' => $includes]; - return $this->ninja->send("POST", "/api/v1/clients", $query); + return $this->ninja->send("POST", "{$this->uri}", $query); } } diff --git a/src/Endpoints/Invoices.php b/src/Endpoints/Invoices.php index 53fb40d..85dab5f 100644 --- a/src/Endpoints/Invoices.php +++ b/src/Endpoints/Invoices.php @@ -14,11 +14,13 @@ use GuzzleHttp\Exception\GuzzleException; use InvoiceNinja\Sdk\InvoiceNinja; -class Invoices +class Invoices extends BaseEntity { protected InvoiceNinja $ninja; + protected string $uri = "/api/v1/invoices"; + public function __construct(InvoiceNinja $ninja) { $this->ninja = $ninja; @@ -33,28 +35,28 @@ public function all(array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/invoices", $query); + return $this->ninja->send("GET", "{$this->uri}", $query); } public function get(string $invoice_id, array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/invoices/{$invoice_id}", $query); + return $this->ninja->send("GET", "{$this->uri}/{$invoice_id}", $query); } public function update(string $invoice_id, array $invoices) { $query = ['form_params' => $invoices]; - return $this->ninja->send("PUT", "/api/v1/invoices/{$invoice_id}", $query); + return $this->ninja->send("PUT", "{$this->uri}/{$invoice_id}", $query); } public function create(array $invoices, array $includes = []) { $query = ['form_params' => $invoices, 'query' => $includes]; - return $this->ninja->send("POST", "/api/v1/invoices", $query); + return $this->ninja->send("POST", "{$this->uri}", $query); } } diff --git a/src/Endpoints/Payments.php b/src/Endpoints/Payments.php index 36884a0..4bfe1dd 100644 --- a/src/Endpoints/Payments.php +++ b/src/Endpoints/Payments.php @@ -14,11 +14,13 @@ use GuzzleHttp\Exception\GuzzleException; use InvoiceNinja\Sdk\InvoiceNinja; -class Payments +class Payments extends BaseEntity { protected InvoiceNinja $ninja; + protected string $uri = "/api/v1/payments"; + public function __construct(InvoiceNinja $ninja) { $this->ninja = $ninja; @@ -33,28 +35,28 @@ public function all(array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/payments", $query); + return $this->ninja->send("GET", "{$this->uri}", $query); } public function get(string $payment_id, array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/payments/{$payment_id}", $query); + return $this->ninja->send("GET", "{$this->uri}/{$payment_id}", $query); } public function update(string $payment_id, array $payment) { $query = ['form_params' => $payment]; - return $this->ninja->send("PUT", "/api/v1/payments/{$payment_id}", $query); + return $this->ninja->send("PUT", "{$this->uri}/{$payment_id}", $query); } public function create(array $payment, array $includes = []) { $query = ['form_params' => $payment, 'query' => $includes]; - return $this->ninja->send("POST", "/api/v1/payments", $query); + return $this->ninja->send("POST", "{$this->uri}", $query); } } diff --git a/src/Endpoints/Products.php b/src/Endpoints/Products.php index a9b1182..d2d5e70 100644 --- a/src/Endpoints/Products.php +++ b/src/Endpoints/Products.php @@ -14,11 +14,13 @@ use GuzzleHttp\Exception\GuzzleException; use InvoiceNinja\Sdk\InvoiceNinja; -class Products +class Products extends BaseEntity { protected InvoiceNinja $ninja; + protected string $uri = "/api/v1/products"; + public function __construct(InvoiceNinja $ninja) { $this->ninja = $ninja; @@ -33,28 +35,28 @@ public function all(array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/products", $query); + return $this->ninja->send("GET", "{$this->uri}", $query); } public function get(string $product_id, array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/products/{$product_id}", $query); + return $this->ninja->send("GET", "{$this->uri}/{$product_id}", $query); } public function update(string $product_id, array $product) { $query = ['form_params' => $product]; - return $this->ninja->send("PUT", "/api/v1/products/{$product_id}", $query); + return $this->ninja->send("PUT", "{$this->uri}/{$product_id}", $query); } public function create(array $product, array $includes = []) { $query = ['form_params' => $product, 'query' => $includes]; - return $this->ninja->send("POST", "/api/v1/products", $query); + return $this->ninja->send("POST", "{$this->uri}", $query); } } diff --git a/src/Endpoints/Quotes.php b/src/Endpoints/Quotes.php index f19b95d..c83a5fd 100644 --- a/src/Endpoints/Quotes.php +++ b/src/Endpoints/Quotes.php @@ -14,11 +14,13 @@ use GuzzleHttp\Exception\GuzzleException; use InvoiceNinja\Sdk\InvoiceNinja; -class Quotes +class Quotes extends BaseEntity { protected InvoiceNinja $ninja; + protected string $uri = "/api/v1/quotes"; + public function __construct(InvoiceNinja $ninja) { $this->ninja = $ninja; @@ -33,28 +35,28 @@ public function all(array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/quotes", $query); + return $this->ninja->send("GET", "{$this->uri}", $query); } public function get(string $quote_id, array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/quotes/{$quote_id}", $query); + return $this->ninja->send("GET", "{$this->uri}/{$quote_id}", $query); } public function update(string $quote_id, array $quote) { $query = ['form_params' => $quote]; - return $this->ninja->send("PUT", "/api/v1/quotes/{$quote_id}", $query); + return $this->ninja->send("PUT", "{$this->uri}/{$quote_id}", $query); } public function create(array $entity, array $includes = []) { $query = ['form_params' => $entity, 'query' => $includes]; - return $this->ninja->send("POST", "/api/v1/quotes", $query); + return $this->ninja->send("POST", "{$this->uri}", $query); } } diff --git a/src/Endpoints/TaxRates.php b/src/Endpoints/TaxRates.php index 86c33aa..5da4380 100644 --- a/src/Endpoints/TaxRates.php +++ b/src/Endpoints/TaxRates.php @@ -14,11 +14,13 @@ use GuzzleHttp\Exception\GuzzleException; use InvoiceNinja\Sdk\InvoiceNinja; -class TaxRates +class TaxRates extends BaseEntity { protected InvoiceNinja $ninja; + protected string $uri = "/api/v1/tax_rates"; + public function __construct(InvoiceNinja $ninja) { $this->ninja = $ninja; @@ -33,28 +35,28 @@ public function all(array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/tax_rates", $query); + return $this->ninja->send("GET", "{$this->uri}", $query); } public function get(string $tax_rate_id, array $search = []) { $query = ['query' => $search]; - return $this->ninja->send("GET", "/api/v1/tax_rates/{$tax_rate_id}", $query); + return $this->ninja->send("GET", "{$this->uri}/{$tax_rate_id}", $query); } public function update(string $tax_rate_id, array $tax_rate) { $query = ['form_params' => $tax_rate]; - return $this->ninja->send("PUT", "/api/v1/tax_rates/{$tax_rate_id}", $query); + return $this->ninja->send("PUT", "{$this->uri}/{$tax_rate_id}", $query); } public function create(array $tax_rate, array $includes = []) { $query = ['form_params' => $tax_rate, 'query' => $includes]; - return $this->ninja->send("POST", "/api/v1/tax_rates", $query); + return $this->ninja->send("POST", "{$this->uri}", $query); } } diff --git a/tests/BulkActionsTest.php b/tests/BulkActionsTest.php new file mode 100644 index 0000000..dc49f6a --- /dev/null +++ b/tests/BulkActionsTest.php @@ -0,0 +1,54 @@ +token); + $ninja->setUrl($this->url); + + $client = $ninja->clients->create(['name' => 'A name']); + + $this->assertTrue(is_array($client)); + + $this->assertEquals(0, $client['data']['archived_at']); + + $a[] = $client['data']['id']; + + $archived_client = $ninja->clients->bulk("archive", $a); + + $this->assertGreaterThan(0, $archived_client['data'][0]['archived_at']); + + $archived_client = $ninja->clients->bulk("restore", $a); + + $this->assertEquals(0, $client['data']['archived_at']); + + $archived_client = $ninja->clients->bulk("delete", $a); + + $this->assertGreaterThan(0, $archived_client['data'][0]['archived_at']); + $this->assertEquals(1, $archived_client['data'][0]['is_deleted']); + + } + + + + +} \ No newline at end of file diff --git a/tests/ClientsTest.php b/tests/ClientsTest.php index 85590c6..ff398f7 100644 --- a/tests/ClientsTest.php +++ b/tests/ClientsTest.php @@ -21,10 +21,13 @@ class ClientsTest extends TestCase public function testClients() { - $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); + $clients = $ninja->clients->create(['name' => 'Brand spanking new client']); + + $this->assertTrue(is_array($clients)); + $clients = $ninja->clients->all(['balance' => '0:gt']); $this->assertTrue(is_array($clients)); @@ -33,11 +36,18 @@ public function testClients() public function testClientGet() { + + $ninja = new InvoiceNinja($this->token); + $ninja->setUrl($this->url); + + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); + $this->assertTrue(is_array($client)); + $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $clients = $ninja->clients->get('7LDdwRb1YK'); + $clients = $ninja->clients->get($client['data']['id']); $this->assertTrue(is_array($clients)); @@ -50,7 +60,9 @@ public function testClientPut() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $clients = $ninja->clients->update('7LDdwRb1YK', ['name' => 'A new client name updated']); + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); + + $clients = $ninja->clients->update($client['data']['id'], ['name' => 'A new client name updated']); $this->assertTrue(is_array($clients)); diff --git a/tests/InvoicesTest.php b/tests/InvoicesTest.php index 587b177..6d13274 100644 --- a/tests/InvoicesTest.php +++ b/tests/InvoicesTest.php @@ -25,6 +25,10 @@ public function testInvoices() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); + + $invoice = $ninja->invoices->create(['client_id' => $client['data']['id']]); + $invoices = $ninja->invoices->all(); $this->assertTrue(is_array($invoices)); @@ -37,7 +41,11 @@ public function testInvoiceGet() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $invoices = $ninja->invoices->get('4w9aAOdvMR'); + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); + + $invoice = $ninja->invoices->create(['client_id' => $client['data']['id']]); + + $invoices = $ninja->invoices->get($invoice['data']['id']); $this->assertTrue(is_array($invoices)); @@ -50,7 +58,11 @@ public function testInvoicePut() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $invoices = $ninja->invoices->update('4w9aAOdvMR', ['discount' => '10']); + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); + + $invoice = $ninja->invoices->create(['client_id' => $client['data']['id']]); + + $invoices = $ninja->invoices->update($invoice['data']['id'], ['discount' => '10']); $this->assertTrue(is_array($invoices)); diff --git a/tests/PaymentsTest.php b/tests/PaymentsTest.php index 1eeb6ee..f3ffd4f 100644 --- a/tests/PaymentsTest.php +++ b/tests/PaymentsTest.php @@ -37,7 +37,10 @@ public function testInvoiceGet() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $payments = $ninja->payments->get('VolejRejNm'); + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); + $payment = $ninja->payments->create(['client_id' => $client['data']['id'], 'amount' => 10]); + + $payments = $ninja->payments->get($payment['data']['id']); $this->assertTrue(is_array($payments)); @@ -50,7 +53,10 @@ public function testInvoicePut() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $payments = $ninja->payments->update('VolejRejNm', ['transaction_reference' => 'ref']); + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); + $payment = $ninja->payments->create(['client_id' => $client['data']['id'], 'amount' => 10]); + + $payments = $ninja->payments->update($payment['data']['id'], ['transaction_reference' => 'ref']); $this->assertTrue(is_array($payments)); diff --git a/tests/ProductsTest.php b/tests/ProductsTest.php index 2a252e7..9d35c28 100644 --- a/tests/ProductsTest.php +++ b/tests/ProductsTest.php @@ -37,7 +37,9 @@ public function testInvoiceGet() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $products = $ninja->products->get('gl9avmeG1v'); + $product = $ninja->products->create(['product_key' => 'that']); + + $products = $ninja->products->get($product['data']['id']); $this->assertTrue(is_array($products)); @@ -50,7 +52,9 @@ public function testInvoicePut() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $products = $ninja->products->update('gl9avmeG1v', ['product_key' => 'this']); + $product = $ninja->products->create(['product_key' => 'thatx']); + + $products = $ninja->products->update($product['data']['id'], ['product_key' => 'this']); $this->assertTrue(is_array($products)); diff --git a/tests/QuotesTest.php b/tests/QuotesTest.php index 394b2bd..a1cb7fd 100644 --- a/tests/QuotesTest.php +++ b/tests/QuotesTest.php @@ -37,7 +37,10 @@ public function testQuoteGet() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $quotes = $ninja->quotes->get('gl9avmeG1v'); + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); + $quote = $ninja->quotes->create(['client_id' => $client['data']['id']]); + + $quotes = $ninja->quotes->get($quote['data']['id']); $this->assertTrue(is_array($quotes)); @@ -50,7 +53,11 @@ public function testQuotePut() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $quotes = $ninja->quotes->update('gl9avmeG1v', ['discount' => '10']); + + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); + $quote = $ninja->quotes->create(['client_id' => $client['data']['id']]); + + $quotes = $ninja->quotes->update($quote['data']['id'], ['discount' => '10']); $this->assertTrue(is_array($quotes)); @@ -62,8 +69,9 @@ public function testQuotePost() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); + $client = $ninja->clients->create(['name' => 'Brand spanking new client']); - $quotes = $ninja->quotes->create(['client_id' => '7LDdwRb1YK']); + $quotes = $ninja->quotes->create(['client_id' => $client['data']['id']]); $this->assertTrue(is_array($quotes)); diff --git a/tests/TaxRatesTest.php b/tests/TaxRatesTest.php index 3926e24..aa2f715 100644 --- a/tests/TaxRatesTest.php +++ b/tests/TaxRatesTest.php @@ -19,6 +19,13 @@ class TaxRatesTest extends TestCase protected string $token = "company-token-test"; protected string $url = "http://ninja.test:8000"; + public $faker; + + protected function setUp(): void + { + $this->faker = \Faker\Factory::create(); + } + public function testProducts() { @@ -37,7 +44,9 @@ public function testTaxRateGet() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $tax_rates = $ninja->tax_rates->get('Opnel5aKBz'); + $tax_rate = $ninja->tax_rates->create(['rate' => 10, 'name' => $this->faker->word()]); + + $tax_rates = $ninja->tax_rates->get($tax_rate['data']['id']); $this->assertTrue(is_array($tax_rates)); @@ -50,7 +59,9 @@ public function testTaxRatePut() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $tax_rates = $ninja->tax_rates->update('Opnel5aKBz', ['rate' => 10, 'name' => 'GST']); + $tax_rate = $ninja->tax_rates->create(['rate' => 10, 'name' => 'GSTa']); + + $tax_rates = $ninja->tax_rates->update($tax_rate['data']['id'], ['rate' => 10, 'name' => $this->faker->word()]); $this->assertTrue(is_array($tax_rates)); @@ -63,7 +74,7 @@ public function testTaxRatePost() $ninja = new InvoiceNinja($this->token); $ninja->setUrl($this->url); - $tax_rates = $ninja->tax_rates->create(['rate' => 10, 'name' => 'GSTX']); + $tax_rates = $ninja->tax_rates->create(['rate' => 10, 'name' => $this->faker->word()]); $this->assertTrue(is_array($tax_rates));