From 0cf1c9125d645405a377da665ebc02b4ca2d74ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Efe=20Ba=C4=9Fr=C4=B1?= Date: Thu, 28 Sep 2023 23:53:00 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8D=8C=20first=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 21 ++ README.md | 220 +++++++++++++ composer.json | 36 +++ phpunit.xml | 13 + src/BaseClient.php | 102 +++++++ src/ClientInterface.php | 42 +++ src/Contact/Contact.php | 25 ++ src/Country/Country.php | 54 ++++ src/CreditNote/CreditNote.php | 50 +++ src/DownPaymentInvoice/DownPaymentInvoice.php | 53 ++++ src/Event/Event.php | 53 ++++ src/Exceptions/BadMethodCallException.php | 8 + src/Exceptions/CacheException.php | 9 + src/Exceptions/LexOfficeApiException.php | 8 + src/File/File.php | 73 +++++ src/Invoice/Invoice.php | 51 ++++ src/LexOfficeClient.php | 289 ++++++++++++++++++ src/OrderConfirmation/OrderConfirmation.php | 32 ++ src/PaginationClient.php | 65 ++++ src/Payment/Payment.php | 43 +++ src/PaymentCondition/PaymentCondition.php | 54 ++++ src/PostingCategory/PostingCategory.php | 54 ++++ src/Profile/Profile.php | 54 ++++ src/Quotation/Quotation.php | 50 +++ src/RecurringTemplate/RecurringTemplate.php | 31 ++ src/Traits/CacheResponseTrait.php | 118 +++++++ src/Traits/DocumentClientTrait.php | 33 ++ src/Utils.php | 63 ++++ src/Voucher/Voucher.php | 48 +++ src/Voucherlist/Voucherlist.php | 84 +++++ 30 files changed, 1836 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 composer.json create mode 100644 phpunit.xml create mode 100644 src/BaseClient.php create mode 100644 src/ClientInterface.php create mode 100644 src/Contact/Contact.php create mode 100644 src/Country/Country.php create mode 100644 src/CreditNote/CreditNote.php create mode 100644 src/DownPaymentInvoice/DownPaymentInvoice.php create mode 100644 src/Event/Event.php create mode 100644 src/Exceptions/BadMethodCallException.php create mode 100644 src/Exceptions/CacheException.php create mode 100644 src/Exceptions/LexOfficeApiException.php create mode 100644 src/File/File.php create mode 100644 src/Invoice/Invoice.php create mode 100644 src/LexOfficeClient.php create mode 100644 src/OrderConfirmation/OrderConfirmation.php create mode 100644 src/PaginationClient.php create mode 100644 src/Payment/Payment.php create mode 100644 src/PaymentCondition/PaymentCondition.php create mode 100644 src/PostingCategory/PostingCategory.php create mode 100644 src/Profile/Profile.php create mode 100644 src/Quotation/Quotation.php create mode 100644 src/RecurringTemplate/RecurringTemplate.php create mode 100644 src/Traits/CacheResponseTrait.php create mode 100644 src/Traits/DocumentClientTrait.php create mode 100644 src/Utils.php create mode 100644 src/Voucher/Voucher.php create mode 100644 src/Voucherlist/Voucherlist.php diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e2ccb66 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Exbil Bilgisayar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d531694 --- /dev/null +++ b/README.md @@ -0,0 +1,220 @@ +# πŸ’Ύ Lexoffice PHP API + +
+ discord.js +
+ +![visitors](https://visitor-badge.laobi.icu/badge?page_id=exbil.lexoffice-php-api) +![](https://img.shields.io/badge/stable-v.1.0-informational?style=flat&logoColor=white&color=6aa6f8) +![](https://img.shields.io/badge/license-MIT-informational?style=flat&logoColor=white&color=6aa6f8) + +# Getting Started +### Requirements +* [**PHP 7.4+**](https://www.php.net/downloads.php) +* Extensions: [Composer](https://getcomposer.org/), [PHP-JSON](https://www.php.net/manual/en/book.json.php) + +# βš’οΈ Install +```bash +composer require exbil/lexoffice-php-api +``` + +# πŸ“‘ Usage + +Search for the official API Documentation [here](https://developers.lexoffice.io/docs/). +You need an [API Key](https://app.lexoffice.de/addons/public-api) for that. + +### πŸ—ƒοΈ Basic + +```php +$apiKey = getenv('LEX_OFFICE_API_KEY'); // store keys in .env file +$api = new \exbil\LexOffice\LexOfficeClient($apiKey); +``` + +### πŸ—ƒοΈ set cache + +```php +// can be any PSR-6 compatibly cache handler +// in this example we are using symfony/cache +$cacheInterface = new \Symfony\Component\Cache\Adapter\FilesystemAdapter( + 'lexoffice', + 3600, + __DIR__ . '/cache' +); + +$api->setCacheInterface($cacheInterface); +``` + +### πŸ”š Contact Endpoint + +```php + +// get a page +/** @var \exbil\LexOffice\LexOfficeClient $api */ +$client = $api->contact(); + +$client->size = 100; +$client->sortDirection = 'ASC'; +$client->sortProperty = 'name'; + +// get a page +$response = $client->getPage(0); + +//get all +$response = $client->getAll(); + +// other methods +$response = $client->get($entityId); +$response = $client->create($data); +``` + +### πŸ—ΊοΈ Country Endpoint +```php +$response = $api->country()->getAll(); +``` + +### πŸ”š Invoices Endpoint +```php +$response = $api->invoice()->getAll(); +$response = $api->invoice()->get($entityId); +$response = $api->invoice()->create($data); +$response = $api->invoice()->document($entityId); // get document ID +$response = $api->invoice()->document($entityId, true); // get file content +``` + +### πŸ”š Down Payment Invoices Endpoint +```php +$response = $api->downPaymentInvoice()->getAll(); +$response = $api->downPaymentInvoice()->get($entityId); +$response = $api->downPaymentInvoice()->create($data); +$response = $api->downPaymentInvoice()->document($entityId); // get document ID +$response = $api->downPaymentInvoice()->document($entityId, true); // get file content +``` + +### πŸ’΅ Order Confirmation Endpoint +```php +$response = $api->orderConfirmation()->getAll(); +$response = $api->orderConfirmation()->get($entityId); +$response = $api->orderConfirmation()->create($data); +$response = $api->orderConfirmation()->document($entityId); // get document ID +$response = $api->orderConfirmation()->document($entityId, true); // get file content +``` + +### πŸ“ƒ Quotation Endpoint +```php +$response = $api->quotation()->getAll(); +$response = $api->quotation()->get($entityId); +$response = $api->quotation()->create($data); +$response = $api->quotation()->document($entityId); // get document ID +$response = $api->quotation()->document($entityId, true); // get file content +``` + +### πŸ“„ Voucher Endpoint +```php +$response = $api->voucher()->getAll(); +$response = $api->voucher()->get($entityId); +$response = $api->voucher()->create($data); +$response = $api->voucher()->update($entityId, $data); +$response = $api->voucher()->document($entityId); // get document ID +$response = $api->voucher()->document($entityId, true); // get file content +``` + + +### πŸ’΅ Credit Notes Endpoint +```php +$response = $api->creditNote()->getAll(); +$response = $api->creditNote()->get($entityId); +$response = $api->creditNote()->create($data); +$response = $api->creditNote()->document($entityId); // get document ID +$response = $api->creditNote()->document($entityId, true); // get file content +``` + +### πŸ’΅ Payment Endpoint +```php +$response = $api->payment()->get($entityId); +``` + +### πŸ’΅ Payment Conditions Endpoint +```php +$response = $api->paymentCondition()->getAll(); +``` + +### πŸ—‚οΈ Posting Categories Endpoint +```php +$response = $api->postingCategory()->getAll(); +``` + +### πŸ§‘πŸ» Profile Endpoint +```php +$response = $api->profile()->get(); +``` + +### πŸ“œ Recurring Templates Endpoint +```php + +// get single entitiy +$response = $api->recurringTemplate()->get($entityId); + +// use pagination +$client = $api->recurringTemplate(); +$client->size = 100; + + +// get a page +$response = $client->getPage(0); + +//get all +$response = $client->getAll(); +``` + + +### πŸ”š Voucherlist Endpoint +```php +$client = $api->voucherlist(); + +$client->size = 100; +$client->sortDirection = 'DESC'; +$client->sortColumn = 'voucherNumber'; +$client->types = [ + 'salesinvoice', + 'salescreditnote', + 'purchaseinvoice', + 'purchasecreditnote', + 'invoice', + 'downpaymentinvoice', + 'creditnote', + 'orderconfirmation', + 'quotation' +]; +$client->statuses = [ + 'draft', + 'open', + 'paid', + 'paidoff', + 'voided', + //'overdue', overdue can only be fetched alone + 'accepted', + 'rejected' +]; + +// get everything what we can, not recommend: +//$client->setToEverything() + +// get a page +$response = $client->getPage(0); + +//get all +$response = $client->getAll(); +``` + +### πŸ“ File Endpoint +```php +$response = $api->file()->upload($filePath, $voucherType); +$response = $api->file()->get($entityId); +``` + + +### βš’οΈ Get JSON from Response + +```php +$json = $api->*()->getAsJson($response); +``` diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..004995b --- /dev/null +++ b/composer.json @@ -0,0 +1,36 @@ +{ + "name": "exbil/lexoffice-php-api", + "type": "library", + "description": "Simple API Integration for Lex-Office", + "keywords": [ + "lex-office", + "lexoffice", + "rest", + "api" + ], + "license": "MIT", + "require": { + "php": "^7.4 | ^8", + "ext-json": "*", + "ext-curl": "*", + "guzzlehttp/guzzle": "^6.2 | ^7.0", + "psr/cache": "^1.0 | ^2.0 | ^3.0" + }, + "require-dev": { + "fzaninotto/faker": "^1.9.1", + "phpunit/phpunit": "^9.0", + "symfony/cache": "^5.1" + }, + "autoload": { + "psr-4": { + "Exbil\\LexOffice\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Exbil\\LexOffice\\Tests\\": "tests/" + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..3135c50 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,13 @@ + + + + + tests + + + \ No newline at end of file diff --git a/src/BaseClient.php b/src/BaseClient.php new file mode 100644 index 0000000..347e506 --- /dev/null +++ b/src/BaseClient.php @@ -0,0 +1,102 @@ +api = $lexOffice; + } + + /** + * @param array $data + * @return ResponseInterface + * @throws Exceptions\CacheException + * @throws Exceptions\LexOfficeApiException + */ + public function create(array $data) + { + $api = $this->api->newRequest('POST', $this->resource); + + $api->request = $api->request->withBody($this->createStream($data)); + + return $api->getResponse(); + } + + /** + * @param string $id + * @param array $data + * @return void + * @throws Exception + */ + public function update(string $id, array $data) + { + throw new Exceptions\BadMethodCallException('method update is not defined for ' . $this->resource); + } + + /** + * @param string $id + * @return ResponseInterface + * @throws Exceptions\CacheException + * @throws Exceptions\LexOfficeApiException + */ + public function get(string $id) + { + return $this->api->newRequest('GET', $this->resource . '/' . $id) + ->getResponse(); + } + + /** + * @param ResponseInterface $response + * @return object + */ + public function getAsJson(ResponseInterface $response) + { + $body = $response->getBody()->__toString(); + + return Utils::jsonDecode($body); + } + + /** + * @param mixed $content + * @return StreamInterface + */ + protected function createStream($content): StreamInterface + { + return Utils::streamFor( + Utils::jsonEncode($content) + ); + } + + /** + * @param array $content + * @param string|null $boundary + * @return MultipartStream + */ + protected function createMultipartStream(array $content, string $boundary = null): MultipartStream + { + $stream = []; + $boundary = $boundary ?: '--lexoffice'; + + foreach ($content as $key => $value) { + $stream[] = [ + 'name' => $key, + 'contents' => $value + ]; + } + + return new MultipartStream($stream, $boundary); + } +} diff --git a/src/ClientInterface.php b/src/ClientInterface.php new file mode 100644 index 0000000..f38d206 --- /dev/null +++ b/src/ClientInterface.php @@ -0,0 +1,42 @@ +sortDirection . + '&property=' .$this->sortProperty; + } +} diff --git a/src/Country/Country.php b/src/Country/Country.php new file mode 100644 index 0000000..c04bf5c --- /dev/null +++ b/src/Country/Country.php @@ -0,0 +1,54 @@ +resource); + } + + /** + * @param string $id + * @throws BadMethodCallException + */ + public function get(string $id) + { + throw new BadMethodCallException('method get is not defined for ' . $this->resource); + } + + /** + * @param string $id + * @param array $data + * @throws BadMethodCallException + */ + public function update(string $id, array $data) + { + throw new BadMethodCallException('method update is not defined for ' . $this->resource); + } + + /** + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function getAll() + { + return $this->api->newRequest('GET', $this->resource) + ->getResponse(); + } +} diff --git a/src/CreditNote/CreditNote.php b/src/CreditNote/CreditNote.php new file mode 100644 index 0000000..edbb602 --- /dev/null +++ b/src/CreditNote/CreditNote.php @@ -0,0 +1,50 @@ +resource; + + $this->resource .= $finalized ? '?finalize=true' : ''; + $response = parent::create($data); + $this->resource = $oldResource; + + return $response; + } + + /** + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function getAll() + { + $client = new VoucherlistClient($this->api); + + $client->setToEverything(); + $client->types = ['creditnote']; + + return $client->getAll(); + } +} diff --git a/src/DownPaymentInvoice/DownPaymentInvoice.php b/src/DownPaymentInvoice/DownPaymentInvoice.php new file mode 100644 index 0000000..1878544 --- /dev/null +++ b/src/DownPaymentInvoice/DownPaymentInvoice.php @@ -0,0 +1,53 @@ +resource); + } + + + /** + * @param string $id + * @param array $data + * @throws BadMethodCallException + */ + public function update(string $id, array $data) + { + throw new BadMethodCallException('method update is not defined for ' . $this->resource); + } + + /** + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function getAll() + { + $client = new VoucherlistClient($this->api); + + $client->setToEverything(); + $client->types = ['downpaymentinvoice']; + + return $client->getAll(); + } +} diff --git a/src/Event/Event.php b/src/Event/Event.php new file mode 100644 index 0000000..08410f0 --- /dev/null +++ b/src/Event/Event.php @@ -0,0 +1,53 @@ +api->newRequest('GET', 'event-subscriptions') + ->getResponse(); + } + + /** + * @param string $id + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function delete(string $id) + { + return $this->api->newRequest('DELETE', 'event-subscriptions/' . $id) + ->getResponse(); + } +} diff --git a/src/Exceptions/BadMethodCallException.php b/src/Exceptions/BadMethodCallException.php new file mode 100644 index 0000000..a2118a8 --- /dev/null +++ b/src/Exceptions/BadMethodCallException.php @@ -0,0 +1,8 @@ +supportedExtension) . ')/'; + $matchResult = preg_match($regex, $filepath, $matches); + + if (!$matchResult || !$matches[0]) { + throw new LexOfficeApiException('file extension is not supported: ' . basename($filepath) . ' '); + } + + if (!is_file($filepath)) { + throw new LexOfficeApiException('file could not be found to upload: ' . $filepath); + } + + if (filesize($filepath) > self::MAX_FILE_SIZE) { + throw new LexOfficeApiException('file is to big to upload: ' . $filepath . ', max upload size: ' . self::MAX_FILE_SIZE . 'bytes'); + } + + $body = $this->createMultipartStream([ + 'file' => fopen($filepath, 'r'), + 'type' => $type + ]); + + $api = $this->api->newRequest('POST', $this->resource, [ + 'Content-Type' => 'multipart/form-data; boundary=' . $body->getBoundary() + ]); + + $api->request = $api->request->withBody($body); + + return $api->getResponse(); + } + + /** + * @param array $data + * @throws BadMethodCallException + */ + public function create(array $data) + { + throw new BadMethodCallException('method update is not defined for ' . $this->resource); + } + + /** + * @throws BadMethodCallException + */ + public function getAll() + { + throw new BadMethodCallException('method update is not defined for ' . $this->resource); + } +} diff --git a/src/Invoice/Invoice.php b/src/Invoice/Invoice.php new file mode 100644 index 0000000..d46c7f1 --- /dev/null +++ b/src/Invoice/Invoice.php @@ -0,0 +1,51 @@ +resource; + + $this->resource .= $finalized ? '?finalize=true' : ''; + $response = parent::create($data); + $this->resource = $oldResource; + + return $response; + } + + + /** + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function getAll() + { + $client = new VoucherlistClient($this->api); + + $client->setToEverything(); + $client->types = ['invoice']; + + return $client->getAll(); + } +} diff --git a/src/LexOfficeClient.php b/src/LexOfficeClient.php new file mode 100644 index 0000000..d287f7f --- /dev/null +++ b/src/LexOfficeClient.php @@ -0,0 +1,289 @@ +apiKey = $apiKey; + $this->client = $client; + } + + /** + * @param $method + * @param $resource + * @param array $headers + * @return $this + */ + public function newRequest($method, $resource, $headers = []): self + { + $this->setRequest( + new Request($method, $this->createApiUrl($resource), $headers) + ); + + return $this; + } + + /** + * @param RequestInterface $request + * @return $this + */ + public function setRequest(RequestInterface $request) + { + $request = $request + ->withHeader('Authorization', 'Bearer ' . $this->apiKey) + ->withHeader('Accept', 'application/json'); + + + if (!$request->hasHeader('Content-Type') && in_array($request->getMethod(), ['POST', 'PUT'])) { + $request = $request->withHeader('Content-Type', 'application/json'); + } + + $this->request = $request; + + return $this; + } + + /** + * @param string $resource + * @return string + */ + protected function createApiUrl(string $resource): string + { + return $this->apiUrl . '/' . $this->apiVersion . '/' . $resource; + } + + /** + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function getResponse() + { + $cache = null; + if ($this->cacheInterface) { + $response = $cache = $this->getCacheResponse($this->request); + } + + // when no cacheInterface is set or the cache is invalid + if (!isset($response) || !$response) { + try { + $response = $this->client->send($this->request); + } catch (GuzzleException $exception) { + throw new LexOfficeApiException( + $exception->getMessage(), + $exception->getCode(), + $exception + ); + } + } + + // set cache response when cache is invalid + if ($this->cacheInterface && !$cache) { + $this->setCacheResponse($this->request, $response); + } + + return $response; + } + + /** + * @return ContactClient + */ + public function contact() + { + return new ContactClient($this); + } + + /** + * @return CountryClient + */ + public function country() + { + return new CountryClient($this); + } + + /** + * @return EventClient + */ + public function event() + { + return new EventClient($this); + } + + /** + * @return InvoiceClient + */ + public function invoice() + { + return new InvoiceClient($this); + } + + /** + * @return DownPaymentInvoiceClient + */ + public function downPaymentInvoice() + { + return new DownPaymentInvoiceClient($this); + } + + /** + * @return OrderConfirmationClient + */ + public function orderConfirmation() + { + return new OrderConfirmationClient($this); + } + + /** + * @return PaymentClient + */ + public function payment() + { + return new PaymentClient($this); + } + + /** + * @return PaymentConditionClient + */ + public function paymentCondition() + { + return new PaymentConditionClient($this); + } + + /** + * @return CreditNoteClient + */ + public function creditNote() + { + return new CreditNoteClient($this); + } + + /** + * @return QuotationClient + */ + public function quotation() + { + return new QuotationClient($this); + } + + /** + * @return VoucherClient + */ + public function voucher() + { + return new VoucherClient($this); + } + + /** + * @return RecurringTemplateClient + */ + public function recurringTemplate() + { + return new RecurringTemplateClient($this); + } + + /** + * @return VoucherlistClient + */ + public function voucherlist() + { + return new VoucherlistClient($this); + } + + /** + * @return ProfileClient + */ + public function profile() + { + return new ProfileClient($this); + } + + /** + * @return PostingCategoryClient + */ + public function postingCategory() + { + return new PostingCategoryClient($this); + } + + /** + * @return FileClient + */ + public function file() + { + return new FileClient($this); + } +} diff --git a/src/OrderConfirmation/OrderConfirmation.php b/src/OrderConfirmation/OrderConfirmation.php new file mode 100644 index 0000000..eaefd2b --- /dev/null +++ b/src/OrderConfirmation/OrderConfirmation.php @@ -0,0 +1,32 @@ +api); + + $client->setToEverything(); + $client->types = ['orderconfirmation']; + + return $client->getAll(); + } +} diff --git a/src/PaginationClient.php b/src/PaginationClient.php new file mode 100644 index 0000000..59cd33c --- /dev/null +++ b/src/PaginationClient.php @@ -0,0 +1,65 @@ +resource . '?page=' . $page . '&size=' . $this->size; + } + + /** + * @param int $page + * @return ResponseInterface + * @throws Exceptions\CacheException + * @throws Exceptions\LexOfficeApiException + */ + public function getPage(int $page): ResponseInterface + { + $api = $this->api->newRequest( + 'GET', + $this->generateUrl($page) + ); + + return $api->getResponse(); + } + + /** + * @return ResponseInterface + * @throws Exceptions\CacheException + * @throws Exceptions\LexOfficeApiException + */ + public function getAll() + { + $response = $this->getPage(0); + $result = $this->getAsJson($response); + + if ($result->totalPages == 1) { + return $response; + } + + // update content to get all contacts + for ($i = 1; $i < $result->totalPages; $i++) { + $responsePage = $this->getPage($i); + $resultPage = $this->getAsJson($responsePage); + + foreach ($resultPage->content as $entity) { + $result->content = [ + ...$result->content, + $entity + ]; + } + } + + return $response->withBody($this->createStream($result)); + } +} \ No newline at end of file diff --git a/src/Payment/Payment.php b/src/Payment/Payment.php new file mode 100644 index 0000000..1e79a30 --- /dev/null +++ b/src/Payment/Payment.php @@ -0,0 +1,43 @@ +resource); + } + + /** + * @param string $id + * @param array $data + * @throws BadMethodCallException + */ + public function update(string $id, array $data) + { + throw new BadMethodCallException('method update is not defined for ' . $this->resource); + } + + /** + * @throws BadMethodCallException + */ + public function getAll() + { + throw new BadMethodCallException('method getAll is not defined for ' . $this->resource); + } +} diff --git a/src/PaymentCondition/PaymentCondition.php b/src/PaymentCondition/PaymentCondition.php new file mode 100644 index 0000000..7b33800 --- /dev/null +++ b/src/PaymentCondition/PaymentCondition.php @@ -0,0 +1,54 @@ +resource); + } + + /** + * @param string $id + * @throws BadMethodCallException + */ + public function get(string $id) + { + throw new BadMethodCallException('method get is not defined for ' . $this->resource); + } + + /** + * @param string $id + * @param array $data + * @throws BadMethodCallException + */ + public function update(string $id, array $data) + { + throw new BadMethodCallException('method update is not defined for ' . $this->resource); + } + + /** + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function getAll() + { + return $this->api->newRequest('GET', $this->resource) + ->getResponse(); + } +} diff --git a/src/PostingCategory/PostingCategory.php b/src/PostingCategory/PostingCategory.php new file mode 100644 index 0000000..9e952fa --- /dev/null +++ b/src/PostingCategory/PostingCategory.php @@ -0,0 +1,54 @@ +resource); + } + + /** + * @param array $data + * @throws BadMethodCallException + */ + public function create(array $data) + { + throw new BadMethodCallException('method create is not defined for ' . $this->resource); + } + + /** + * @param string $id + * @param array $data + * @throws BadMethodCallException + */ + public function update(string $id, array $data) + { + throw new BadMethodCallException('method update is not defined for ' . $this->resource); + } + + /** + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function getAll() + { + return $this->api->newRequest('GET', $this->resource) + ->getResponse(); + } +} diff --git a/src/Profile/Profile.php b/src/Profile/Profile.php new file mode 100644 index 0000000..7cee132 --- /dev/null +++ b/src/Profile/Profile.php @@ -0,0 +1,54 @@ +api->newRequest('GET', $this->resource) + ->getResponse(); + } + /** + * @throws BadMethodCallException + */ + public function getAll() + { + throw new BadMethodCallException('method getAll is not defined for ' . $this->resource); + } + + /** + * @param array $data + * @throws BadMethodCallException + */ + public function create(array $data) + { + throw new BadMethodCallException('method create is not defined for ' . $this->resource); + } + + + /** + * @param string $id + * @param array $data + * @throws BadMethodCallException + */ + public function update(string $id, array $data) + { + throw new BadMethodCallException('method update is not defined for ' . $this->resource); + } +} diff --git a/src/Quotation/Quotation.php b/src/Quotation/Quotation.php new file mode 100644 index 0000000..92a9932 --- /dev/null +++ b/src/Quotation/Quotation.php @@ -0,0 +1,50 @@ +resource; + + $this->resource .= $finalized ? '?finalize=true' : ''; + $response = parent::create($data); + $this->resource = $oldResource; + + return $response; + } + + /** + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function getAll() + { + $client = new VoucherlistClient($this->api); + + $client->setToEverything(); + $client->types = ['quotation']; + + return $client->getAll(); + } +} diff --git a/src/RecurringTemplate/RecurringTemplate.php b/src/RecurringTemplate/RecurringTemplate.php new file mode 100644 index 0000000..a7c0ac5 --- /dev/null +++ b/src/RecurringTemplate/RecurringTemplate.php @@ -0,0 +1,31 @@ +resource); + } + + /** + * @param string $id + * @param array $data + * @throws BadMethodCallException + */ + public function update(string $id, array $data) + { + throw new BadMethodCallException('method update is not defined for ' . $this->resource); + } +} diff --git a/src/Traits/CacheResponseTrait.php b/src/Traits/CacheResponseTrait.php new file mode 100644 index 0000000..2a2a5ae --- /dev/null +++ b/src/Traits/CacheResponseTrait.php @@ -0,0 +1,118 @@ +cacheInterface = $cache; + + return $this; + } + + /** + * @param RequestInterface $request + * @return string + */ + protected function getCacheName(RequestInterface $request): string + { + return 'lex-office-' . str_replace('/', '-', $request->getUri()->getPath()) . $request->getUri()->getQuery(); + } + + + /** + * @param RequestInterface $request + * @return Response|null + * @throws CacheException + */ + public function getCacheResponse(RequestInterface $request): ?Response + { + $cacheName = $this->getCacheName($request); + + try { + if ($request->getMethod() == 'GET') { + $cache = $this->cacheInterface->getItem($cacheName); + + if ($cache && $cache->isHit()) { + $cache = Utils::jsonDecode($cache->get()); + + return new Response( + $cache->status, + (array)$cache->headers, + Utils::streamFor($cache->body), + $cache->version, + $cache->reason + ); + } + } + } catch (InvalidArgumentException $exception) { + throw new CacheException( + 'could not load cache response from request' . $request->getUri()->getPath(), + $exception->getCode(), + $exception + ); + } + + return null; + } + + /** + * @param RequestInterface $request + * @param ResponseInterface $response + * @return $this + * @throws CacheException + */ + public function setCacheResponse(RequestInterface $request, ResponseInterface $response): self + { + if ($request->getMethod() != 'GET') { + return $this; + } + + if (!$this->cacheInterface) { + throw new CacheException('response could not be cached, cacheInterface is not defined'); + } + + try { + $cacheName = $this->getCacheName($request); + + $cache = new stdClass(); + $cache->status = $response->getStatusCode(); + $cache->headers = $response->getHeaders(); + $cache->body = $response->getBody()->__toString(); + $cache->version = $response->getProtocolVersion(); + $cache->reason = $response->getReasonPhrase(); + + $item = $this->cacheInterface->getItem($cacheName); + $item->set(Utils::jsonEncode($cache)); + + $this->cacheInterface->save($item); + } catch (InvalidArgumentException $exception) { + throw new CacheException( + 'response could not set cache for request ' . $request->getUri()->getPath(), + $exception->getCode(), + $exception + ); + } + + return $this; + } +} \ No newline at end of file diff --git a/src/Traits/DocumentClientTrait.php b/src/Traits/DocumentClientTrait.php new file mode 100644 index 0000000..cd39eab --- /dev/null +++ b/src/Traits/DocumentClientTrait.php @@ -0,0 +1,33 @@ +api->newRequest('GET', $this->resource . '/' . $id . '/document') + ->getResponse(); + + if ($asContent === false) { + return $response; + } + + $content = $this->getAsJson($response); + $fileClient = new FileClient($this->api); + + return $fileClient->get($content->documentFileId); + } +} \ No newline at end of file diff --git a/src/Utils.php b/src/Utils.php new file mode 100644 index 0000000..86d5f17 --- /dev/null +++ b/src/Utils.php @@ -0,0 +1,63 @@ +api->newRequest('PUT', $this->resource . '/' . $id); + + $api->request = $api->request->withBody($this->createStream($data)); + + return $api->getResponse(); + } + + /** + * @return ResponseInterface + * @throws CacheException + * @throws LexOfficeApiException + */ + public function getAll() + { + $client = new VoucherlistClient($this->api); + + /** + * @link https://developers.lexoffice.io/docs/#vouchers-endpoint-purpose + */ + $client->statuses = ['open', 'paid', 'paidoff', 'voided', 'transferred', 'sepadebit']; + $client->types = ['salesinvoice', 'salescreditnote', 'purchaseinvoice', 'purchasecreditnote']; + + return $client->getAll(); + } +} diff --git a/src/Voucherlist/Voucherlist.php b/src/Voucherlist/Voucherlist.php new file mode 100644 index 0000000..a210836 --- /dev/null +++ b/src/Voucherlist/Voucherlist.php @@ -0,0 +1,84 @@ +types = [ + 'salesinvoice', + 'salescreditnote', + 'purchaseinvoice', + 'purchasecreditnote', + 'invoice', + 'downpaymentinvoice', + 'creditnote', + 'orderconfirmation', + 'quotation' + ]; + + $this->statuses = [ + 'draft', + 'open', + 'paid', + 'paidoff', + 'voided', + //'overdue', + 'accepted', + 'rejected' + ]; + } + + /** + * @param int $page + * @return string + */ + public function generateUrl(int $page): string + { + return parent::generateUrl($page) . + '&sort=' . $this->sortColumn . ',' . $this->sortDirection . + '&voucherType=' . implode(',', $this->types) . + '&voucherStatus=' . implode(',', $this->statuses); + } + + /** + * @param array $data + * @throws BadMethodCallException + */ + public function create(array $data) + { + throw new BadMethodCallException('method create is not supported for ' . $this->resource); + } + + /** + * @param string $id + * @param array $data + * @throws BadMethodCallException + */ + public function update(string $id, array $data) + { + throw new BadMethodCallException('method update is not supported for ' . $this->resource); + } + + /** + * @param string $id + * @throws BadMethodCallException + */ + public function get(string $id) + { + throw new BadMethodCallException('method get is not supported for ' . $this->resource); + } +}