diff --git a/examples/sales-invoices/create-sales-invoice.php b/examples/sales-invoices/create-sales-invoice.php new file mode 100644 index 000000000..69f93a84a --- /dev/null +++ b/examples/sales-invoices/create-sales-invoice.php @@ -0,0 +1,51 @@ +salesInvoices->create([ + 'currency' => 'EUR', + 'status' => SalesInvoiceStatus::DRAFT, + 'vatScheme' => 'standard', + 'vatMode' => 'inclusive', + 'paymentTerm' => PaymentTerm::DAYS_30, + 'recipientIdentifier' => 'XXXXX', + 'recipient' => [ + 'type' => 'consumer', + 'email' => 'darth@vader.deathstar', + 'streetAndNumber' => 'Sample Street 12b', + 'postalCode' => '2000 AA', + 'city' => 'Amsterdam', + 'country' => 'NL', + 'locale' => 'nl_NL', + ], + 'lines' => [ + [ + 'description' => 'Monthly subscription fee', + 'quantity' => 1, + 'vatRate' => '21', + 'unitPrice' => [ + 'currency' => 'EUR', + 'value' => '10.00', // Corrected the format from '10,00' to '10.00' to match typical API expectations + ], + ], + ], + ]); + + echo "

New sales invoice created with ID: " . htmlspecialchars($salesInvoice->id) . "

"; +} catch (\Mollie\Api\Exceptions\ApiException $e) { + echo "API call failed: " . htmlspecialchars($e->getMessage()); +} diff --git a/examples/sales-invoices/delete-sales-invoice.php b/examples/sales-invoices/delete-sales-invoice.php new file mode 100644 index 000000000..3b154b802 --- /dev/null +++ b/examples/sales-invoices/delete-sales-invoice.php @@ -0,0 +1,25 @@ +salesInvoices->delete($invoiceId); + + echo "

Sales invoice deleted with ID: " . htmlspecialchars($invoiceId) . "

"; +} catch (\Mollie\Api\Exceptions\ApiException $e) { + echo "API call failed: " . htmlspecialchars($e->getMessage()); +} diff --git a/examples/sales-invoices/list-sales-invoices.php b/examples/sales-invoices/list-sales-invoices.php new file mode 100644 index 000000000..49d6d3611 --- /dev/null +++ b/examples/sales-invoices/list-sales-invoices.php @@ -0,0 +1,28 @@ +'; + $salesInvoices = $mollie->salesInvoices->page(); + foreach ($salesInvoices as $invoice) { + echo '
  • Invoice ' . htmlspecialchars($invoice->id) . ': (' . htmlspecialchars($invoice->issuedAt) . ')'; + echo '
    Status: ' . htmlspecialchars($invoice->status) . ''; + echo '
    Total Amount: ' . htmlspecialchars($invoice->amount->currency) . ' ' . htmlspecialchars($invoice->amount->value) . ''; + echo '
  • '; + } + echo ''; +} catch (\Mollie\Api\Exceptions\ApiException $e) { + echo "API call failed: " . htmlspecialchars($e->getMessage()); +} diff --git a/examples/sales-invoices/update-sales-invoice.php b/examples/sales-invoices/update-sales-invoice.php new file mode 100644 index 000000000..08c6e671b --- /dev/null +++ b/examples/sales-invoices/update-sales-invoice.php @@ -0,0 +1,40 @@ +salesInvoices->update($invoiceId, [ + 'status' => \Mollie\Api\Types\SalesInvoiceStatus::PAID, + 'recipientIdentifier' => 'XXXXX', + 'lines' => [ + [ + 'id' => 'line_001', + 'description' => 'Updated subscription fee', + 'quantity' => 2, + 'vatRate' => '21', + 'unitPrice' => [ + 'currency' => 'EUR', + 'value' => '15.00', + ], + ], + ], + ]); + + echo "

    Sales invoice updated with ID: " . htmlspecialchars($updatedInvoice->id) . "

    "; +} catch (\Mollie\Api\Exceptions\ApiException $e) { + echo "API call failed: " . htmlspecialchars($e->getMessage()); +} diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index a8db7218f..17bb3a20d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -220,6 +220,26 @@ parameters: count: 1 path: examples/profiles/update-profile.php + - + message: "#^Variable \\$mollie might not be defined\\.$#" + count: 1 + path: examples/sales-invoices/create-sales-invoice.php + + - + message: "#^Variable \\$mollie might not be defined\\.$#" + count: 1 + path: examples/sales-invoices/delete-sales-invoice.php + + - + message: "#^Variable \\$mollie might not be defined\\.$#" + count: 1 + path: examples/sales-invoices/list-sales-invoices.php + + - + message: "#^Variable \\$mollie might not be defined\\.$#" + count: 1 + path: examples/sales-invoices/update-sales-invoice.php + - message: "#^Variable \\$mollie might not be defined\\.$#" count: 1 diff --git a/src/Endpoints/SalesInvoiceEndpoint.php b/src/Endpoints/SalesInvoiceEndpoint.php new file mode 100644 index 000000000..e0379d32d --- /dev/null +++ b/src/Endpoints/SalesInvoiceEndpoint.php @@ -0,0 +1,122 @@ +client); + } + + /** + * Get the collection object that is used by this API endpoint. Every API endpoint uses one type of collection object. + * + * @param int $count + * @param \stdClass $_links + * + * @return SalesInvoiceCollection + */ + protected function getResourceCollectionObject($count, $_links): SalesInvoiceCollection + { + return new SalesInvoiceCollection($this->client, $count, $_links); + } + + /** + * Creates a payment in Mollie. + * + * @param array $data An array containing details on the payment. + * + * @return SalesInvoice + * @throws ApiException + */ + public function create(array $data = []): SalesInvoice + { + return $this->rest_create($data, []); + } + + /** + * Update the given Payment. + * + * Will throw a ApiException if the payment id is invalid or the resource cannot be found. + * + * @param string $salesInvoiceId + * + * @param array $data + * @return SalesInvoice + * @throws ApiException + */ + public function update($salesInvoiceId, array $data = []): SalesInvoice + { + if (empty($salesInvoiceId) || strpos($salesInvoiceId, self::RESOURCE_ID_PREFIX) !== 0) { + throw new ApiException("Invalid sales invoice ID: '{$salesInvoiceId}'. A sales invoice ID should start with '" . self::RESOURCE_ID_PREFIX . "'."); + } + + return parent::rest_update($salesInvoiceId, $data); + } + + /** + * @param string $salesInvoiceId + * @param array $parameters + * @return SalesInvoice + * @throws ApiException + */ + public function get($salesInvoiceId, array $parameters = []): SalesInvoice + { + if (empty($salesInvoiceId) || strpos($salesInvoiceId, self::RESOURCE_ID_PREFIX) !== 0) { + throw new ApiException("Invalid sales invoice ID: '{$salesInvoiceId}'. A sales invoice ID should start with '" . self::RESOURCE_ID_PREFIX . "'."); + } + + return parent::rest_read($salesInvoiceId, $parameters); + } + + /** + * @param string $salesInvoiceId + * + * @param array $data + * @throws ApiException + */ + public function delete($salesInvoiceId, array $data = []): void + { + $this->rest_delete($salesInvoiceId, $data); + } + + /** + * @param string $from The first payment ID you want to include in your list. + * @param int $limit + * + * @return SalesInvoiceCollection + * @throws ApiException + */ + public function page($from = null, $limit = null) + { + return $this->rest_list($from, $limit, []); + } + + /** + * @param string $from The first resource ID you want to include in your list. + * @param int $limit + * @param bool $iterateBackwards Set to true for reverse order iteration (default is false). + * + * @return LazyCollection + */ + public function iterator(?string $from = null, ?int $limit = null, bool $iterateBackwards = false): LazyCollection + { + return $this->rest_iterator($from, $limit, [], $iterateBackwards); + } +} diff --git a/src/MollieApiClient.php b/src/MollieApiClient.php index 6ae63f254..04b02d745 100644 --- a/src/MollieApiClient.php +++ b/src/MollieApiClient.php @@ -32,6 +32,7 @@ use Mollie\Api\Endpoints\ProfileEndpoint; use Mollie\Api\Endpoints\ProfileMethodEndpoint; use Mollie\Api\Endpoints\RefundEndpoint; +use Mollie\Api\Endpoints\SalesInvoiceEndpoint; use Mollie\Api\Endpoints\SessionEndpoint; use Mollie\Api\Endpoints\SettlementCaptureEndpoint; use Mollie\Api\Endpoints\SettlementChargebackEndpoint; @@ -122,6 +123,13 @@ class MollieApiClient */ public $customerPayments; + /** + * RESTful Sales Invoice resource. + * + * @var SalesInvoiceEndpoint + */ + public $salesInvoices; + /** * RESTful Settlement resource. * @@ -444,6 +452,7 @@ public function initializeEndpoints() $this->profileMethods = new ProfileMethodEndpoint($this); $this->profiles = new ProfileEndpoint($this); $this->refunds = new RefundEndpoint($this); + $this->salesInvoices = new SalesInvoiceEndpoint($this); $this->settlementCaptures = new SettlementCaptureEndpoint($this); $this->settlementChargebacks = new SettlementChargebackEndpoint($this); $this->settlementPayments = new SettlementPaymentEndpoint($this); diff --git a/src/Resources/SalesInvoice.php b/src/Resources/SalesInvoice.php new file mode 100644 index 000000000..432d0cded --- /dev/null +++ b/src/Resources/SalesInvoice.php @@ -0,0 +1,167 @@ +status === SalesInvoiceStatus::DRAFT; + } + + /** + * Returns whether the sales invoice is issued. + * + * @return bool + */ + public function isIssued() + { + return $this->status === SalesInvoiceStatus::ISSUED; + } + + /** + * Returns whether the sales invoice is paid. + * + * @return bool + */ + public function isPaid() + { + return $this->status === SalesInvoiceStatus::PAID; + } +} diff --git a/src/Resources/SalesInvoiceCollection.php b/src/Resources/SalesInvoiceCollection.php new file mode 100644 index 000000000..6a76b9953 --- /dev/null +++ b/src/Resources/SalesInvoiceCollection.php @@ -0,0 +1,22 @@ +client); + } +} diff --git a/src/Types/PaymentTerm.php b/src/Types/PaymentTerm.php new file mode 100644 index 000000000..7691a2e0b --- /dev/null +++ b/src/Types/PaymentTerm.php @@ -0,0 +1,20 @@ +