From 0802d5cac23f6d3f79dfa722f4d57d3bdbc601dc Mon Sep 17 00:00:00 2001 From: Mathias Palmqvist Date: Mon, 30 Jun 2025 11:24:20 +0200 Subject: [PATCH] Customers can now be created --- src/Resources/Customer.php | 8 +++++ src/Validation/CustomerValidator.php | 38 +++++++++++++++++++++ tests/CustomerTest.php | 43 ++++++++++++++++++++++++ tests/CustomerValidatorTest.php | 27 +++++++++++++++ tests/Responses/Customer/create.201.json | 24 +++++++++++++ 5 files changed, 140 insertions(+) create mode 100644 src/Validation/CustomerValidator.php create mode 100644 tests/CustomerValidatorTest.php create mode 100644 tests/Responses/Customer/create.201.json diff --git a/src/Resources/Customer.php b/src/Resources/Customer.php index 9827828..f207fa0 100644 --- a/src/Resources/Customer.php +++ b/src/Resources/Customer.php @@ -3,6 +3,7 @@ namespace Mattitja\BokioApiLaravel\Resources; use Mattitja\BokioApiLaravel\BokioClient; +use Mattitja\BokioApiLaravel\Validation\CustomerValidator; class Customer { @@ -32,4 +33,11 @@ class Customer { return $this->client->get('customers/'.$customerId); } + + public function create(array $data): object + { + $validated = CustomerValidator::validate($data); + + return $this->client->post('customers', $validated); + } } diff --git a/src/Validation/CustomerValidator.php b/src/Validation/CustomerValidator.php new file mode 100644 index 0000000..7269d73 --- /dev/null +++ b/src/Validation/CustomerValidator.php @@ -0,0 +1,38 @@ + 'required|string', + 'type' => 'required|string', + 'vatNumber' => 'nullable|string', + 'orgNumber' => 'nullable|string', + 'paymentTerms' => 'nullable|string', + 'language' => 'nullable|string|in:sv,en', + 'contactsDetails' => 'nullable|array', + 'contactsDetails.*.name' => 'required_with:contactsDetails|string', + 'contactsDetails.*.email' => 'nullable|email', + 'contactsDetails.*.phone' => 'nullable|string', + 'contactsDetails.*.isDefault' => 'boolean', + 'address' => 'required|array', + 'address.line1' => 'required|string', + 'address.line2' => 'nullable|string', + 'address.city' => 'required|string', + 'address.postalCode' => 'required|string', + 'address.country' => 'required|string|size:2', + ]); + + if ($validator->fails()) { + throw new ValidationException($validator); + } + + return $validator->validated(); + } +} diff --git a/tests/CustomerTest.php b/tests/CustomerTest.php index 8118bb9..fda1f6c 100644 --- a/tests/CustomerTest.php +++ b/tests/CustomerTest.php @@ -3,6 +3,8 @@ use Illuminate\Support\Facades\Http; use Mattitja\BokioApiLaravel\BokioClient; use Mattitja\BokioApiLaravel\Resources\Customer; +use Mattitja\BokioApiLaravel\Validation\CustomerValidator; +use Illuminate\Validation\ValidationException; function loadFixture(string $path): array { @@ -21,6 +23,10 @@ beforeEach(function () { return Http::response(loadFixture('Customer/all.200.json'), 200); } + if ($request->method() === 'POST' && str_contains($request->url(), '/customers')) { + return Http::response(loadFixture('Customer/create.201.json'), 201); + } + // fallback return Http::response([], 404); }); @@ -42,3 +48,40 @@ it('can fetch a single customer from Bokio', function () { expect($response->id)->toBe($customerId); expect($response->name)->toBe('customer 1'); }); + +it('can create a customer via Bokio API', function () { + $data = [ + 'name' => 'Testbolaget AB', + 'type' => 'company', + 'vatNumber' => 'SE1234567890', + 'orgNumber' => '556677-8899', + 'paymentTerms' => '30', + 'language' => 'sv', + 'contactsDetails' => [ + [ + 'name' => 'John Doe', + 'email' => 'john@example.com', + 'phone' => '0123456789', + 'isDefault' => true, + ] + ], + 'address' => [ + 'line1' => 'Testgatan 1', + 'line2' => null, + 'city' => 'Göteborg', + 'postalCode' => '12345', + 'country' => 'SE', + ], + ]; + + $response = (new Customer($this->client))->create($data); + + expect($response->id)->toBe('generated-id'); + expect($response->name)->toBe('Testbolaget AB'); + + Http::assertSent(function ($request) use ($data) { + return $request->method() === 'POST' && + str_contains($request->url(), '/customers') && + $request['name'] === $data['name']; + }); +}); diff --git a/tests/CustomerValidatorTest.php b/tests/CustomerValidatorTest.php new file mode 100644 index 0000000..1ed1f41 --- /dev/null +++ b/tests/CustomerValidatorTest.php @@ -0,0 +1,27 @@ + 'Test AB', + 'type' => 'company', + 'address' => [ + 'line1' => 'Gata 1', + 'city' => 'Ort', + 'postalCode' => '12345', + 'country' => 'SE', + ], + ]; + + $validated = CustomerValidator::validate($data); + + expect($validated['name'])->toBe('Test AB'); +}); + +it('throws exception when required fields are missing', function () { + $this->expectException(ValidationException::class); + + CustomerValidator::validate([]); +}); diff --git a/tests/Responses/Customer/create.201.json b/tests/Responses/Customer/create.201.json new file mode 100644 index 0000000..20718e9 --- /dev/null +++ b/tests/Responses/Customer/create.201.json @@ -0,0 +1,24 @@ +{ + "id": "generated-id", + "name": "Testbolaget AB", + "type": "company", + "vatNumber": "SE1234567890", + "orgNumber": "556677-8899", + "paymentTerms": "30", + "language": "sv", + "contactsDetails": [ + { + "name": "John Doe", + "email": "john@example.com", + "phone": "0123456789", + "isDefault": true + } + ], + "address": { + "line1": "Testgatan 1", + "line2": null, + "city": "Göteborg", + "postalCode": "12345", + "country": "SE" + } +}