diff --git a/composer.json b/composer.json index f24d119..ae34fb8 100644 --- a/composer.json +++ b/composer.json @@ -13,8 +13,9 @@ "psr-4": {"InvoiceNinja\\Sdk\\": "src/"} }, "require": { - "php": "^7.4|^8.0|^8.1", - "guzzlehttp/guzzle": "^7.3" + "php": "^8.1|^8.2", + "guzzlehttp/guzzle": "^7.5", + "nesbot/carbon": "^2.66" }, "require-dev": { "fakerphp/faker": "^1.16", diff --git a/src/Exceptions/ApiException.php b/src/Exceptions/ApiException.php index 0da12db..6ca5f27 100644 --- a/src/Exceptions/ApiException.php +++ b/src/Exceptions/ApiException.php @@ -32,6 +32,7 @@ protected static function parseResponseBody($response) $body = (string) $response->getBody(); $error = ""; $object = @json_decode($body); + $error_array = []; if(property_exists($object, "message")) $error = $object->message; @@ -40,10 +41,10 @@ protected static function parseResponseBody($response) { $properties = array_keys(get_object_vars($object->errors)); - if(is_array($properties)) + if(is_array($properties) && count($properties) >=1) $error_array = $object->errors->{$properties[0]}; - if(is_array($error_array)) + if(is_array($error_array) && count($error_array) >=1) $error = $error_array[0]; } diff --git a/src/Exceptions/ModelValidationException.php b/src/Exceptions/ModelValidationException.php new file mode 100644 index 0000000..081f61b --- /dev/null +++ b/src/Exceptions/ModelValidationException.php @@ -0,0 +1,16 @@ +resetValidationErrors(); + + foreach($this->rules as $key => $rule) + { + + switch($rule) + { + case 'required': + isset($this->{$key}) ?: $this->setValidationErrors(["error" => "{$this->model} - `{$key}` must be set", "code" => 422]); + break; + case 'date': + isset($this->{$key}) ? $this->checkDate($key) : true; + break; + default: + $this->setValidationErrors(["error" => "{$this->model} - Unknown validation rule `{$rule}` for property `{$key}`", "code" => 500]); + + } + + } + + if(count($this->getValidationErrors()) == 0) + return true; + + throw new ModelValidationException($this->getValidationErrors()[0]["error"] ,$this->getValidationErrors()[0]["code"]); + } + + private function resetValidationErrors() + { + $this->validation_errors = []; + + return $this; + } + + private function setValidationErrors($error): self + { + $this->validation_errors[] = $error; + + return $this; + } + + public function getValidationErrors(): array + { + return $this->validation_errors; + } + + public function checkDate(string $date_field): bool + { + + try { + + $parsed_date = \Carbon\Carbon::parse($this->{$date_field}); + $this->{$date_field} = $parsed_date->format('Y-m-d'); + + return true; + } + catch(\Exception $e) { + $this->setValidationErrors([$date_field => "Invalid date format for field {$date_field} - '{$this->{$date_field}}'"]); + return false; + } + } + + + + + +} \ No newline at end of file diff --git a/src/Models/Client.php b/src/Models/Client.php new file mode 100644 index 0000000..d53d70a --- /dev/null +++ b/src/Models/Client.php @@ -0,0 +1,279 @@ + 'required', + ]; + + public function __construct() + { + + } + + public function setContact(ClientContact $contact): self + { + $this->contacts = array_merge($this->contacts, $contact); + + return $this; + } + + public function getContacts(): array + { + return $this->contacts; + } + + public function save() + { + $this->validate(); + } +} diff --git a/src/Models/ClientContact.php b/src/Models/ClientContact.php new file mode 100644 index 0000000..35d46a0 --- /dev/null +++ b/src/Models/ClientContact.php @@ -0,0 +1,59 @@ + 'required', + 'date' => 'date', + 'due_date' => 'date', + 'partial_due_date' => 'date', + ]; + + private array $validation_errors = []; + + public function __construct() + { + + } + + public function setClient(Client $client): self + { + $this->client_id = $client->id; + + return $this; + } + + public function setClientId(string $client_id): self + { + $this->client_id = $client->id; + + return $this; + } + + public function addLine(InvoiceItem $item) + { + $this->line_items = array_merge($this->line_items, $item); + + return $this; + } + + + //////////////////////////////////////// helpers - for abstraction/////////////////////////////////////////// + + + + +} \ No newline at end of file diff --git a/src/Models/InvoiceItem.php b/src/Models/InvoiceItem.php new file mode 100644 index 0000000..a7b4f47 --- /dev/null +++ b/src/Models/InvoiceItem.php @@ -0,0 +1,83 @@ +setUrl($this->url); $bank_integrations = $ninja->bank_integrations->create(['bank_account_name' => $this->faker->firstName]); - + $this->assertTrue(is_array($bank_integrations)); } diff --git a/tests/Invoice/CreateInvoiceTest.php b/tests/Invoice/CreateInvoiceTest.php new file mode 100644 index 0000000..220acb0 --- /dev/null +++ b/tests/Invoice/CreateInvoiceTest.php @@ -0,0 +1,72 @@ +faker = \Faker\Factory::create(); + } + + // $ninja = new InvoiceNinja($this->token); + // $ninja->setUrl($this->url); + + public function testInitInvoice() + { + $invoice = new Invoice(); + $this->assertInstanceOf(Invoice::class, $invoice); + } + + public function testInitItem() + { + $item = new InvoiceItem(); + $this->assertInstanceOf(InvoiceItem::class, $item); + } + + public function testBaseName() + { + $client = new Client; + + $this->assertEquals("InvoiceNinja\Sdk\Models\Client", get_class($client)); + } + + public function testClientValidation() + { + $client = new Client; + $client->name = 'Jim'; + + $client->save(); + + $this->assertInstanceOf(Client::class, $client); + } + + // public function testBuildInvoice() + // { + // $client = new Client; + // $client->name = 'Jim'; + // $client->save(); + + // $invoice = new Invoice; + // $invoice->setClient($client); + // } +} \ No newline at end of file