diff --git a/Tests/Feature/Order/IndexOrdersTest.php b/Tests/Feature/Order/IndexOrdersTest.php index c474337..55ac51a 100644 --- a/Tests/Feature/Order/IndexOrdersTest.php +++ b/Tests/Feature/Order/IndexOrdersTest.php @@ -35,8 +35,8 @@ public function index_orders(): void } /** - * @dataProvider orderFilterDataProvider * @test + * @dataProvider orderFilterDataProvider */ public function index_orders_with_filter(string $method, mixed $value, string $queryKey, string $queryValue): void { diff --git a/Tests/Feature/Order/Mock/OrderShowMockClient.php b/Tests/Feature/Order/Mock/OrderShowMockClient.php index 238ef61..844514d 100644 --- a/Tests/Feature/Order/Mock/OrderShowMockClient.php +++ b/Tests/Feature/Order/Mock/OrderShowMockClient.php @@ -237,4 +237,25 @@ public function taxes(): self return $this; } + + public function customFields(): self + { + $this->items(); + + $this->responseBody['data']['items'][0]['custom_fields'] = [ + 'id' => 1, + 'input' => 'Bart', + 'label' => 'Wie is jouw contactpersoon?', + ]; + + $this->responseBody['data']['custom_fields'] = [ + [ + 'id' => 1, + 'input' => 'Bart', + 'label' => 'Wie is jouw contactpersoon?', + ], + ]; + + return $this; + } } diff --git a/Tests/Feature/Order/ShowOrderTest.php b/Tests/Feature/Order/ShowOrderTest.php index e3a793b..ea9819b 100644 --- a/Tests/Feature/Order/ShowOrderTest.php +++ b/Tests/Feature/Order/ShowOrderTest.php @@ -75,13 +75,14 @@ public function show_none_loaded_relationships(string $relation): void public static function relationsProvider(): array { return [ - 'billing' => ['billing'], - 'comments' => ['comments'], - 'totalDiscounts' => ['totalDiscounts'], - 'items' => ['items'], - 'payment' => ['payment'], - 'tags' => ['tags'], - 'taxes' => ['taxes'], + 'billing' => ['billing'], + 'comments' => ['comments'], + 'customFields' => ['customFields'], + 'totalDiscounts' => ['totalDiscounts'], + 'items' => ['items'], + 'payment' => ['payment'], + 'tags' => ['tags'], + 'taxes' => ['taxes'], ]; } @@ -135,6 +136,7 @@ public function show_order_billing_basic(): void static::assertSame(TaxExempt::NONE, $contact->taxExempt()); $address = $billing->address(); + static::assertNull($address->city()); static::assertNull($address->country()); static::assertNull($address->street()); @@ -183,11 +185,13 @@ public function show_order_unknown_tax_exempt(): void 'website' => null, 'vat_id_number' => null, ], ]); + $service = new OrderService($client); $order = $service->find(1); $contact = $order->billing()->contact(); + static::assertEquals(TaxExempt::UNKNOWN, $contact->taxExempt()); } @@ -200,6 +204,7 @@ public function show_order_comments(): void $order = $service->find(1); $comment = $order->comments()[0]; + static::assertSame('2019-01-16 12:00:00', $comment->createdAt()->format('Y-m-d H:i:s')); static::assertSame(1, $comment->id()); static::assertSame('2019-01-17 12:10:00', $comment->updatedAt()->format('Y-m-d H:i:s')); @@ -294,12 +299,34 @@ public function show_order_taxes(): void static::assertSame(21., $order->taxes()[0]->rate()->percentage()); $tax = $order->items()[0]->tax(); + static::assertSame(10., $tax->amount()); static::assertSame(CountryCode::NL, $tax->rate()->country()); static::assertSame(57, $tax->rate()->id()); static::assertSame(21., $tax->rate()->percentage()); } + // /** @test */ + // public function show_order_custom_fields(): void + // { + // $client = (new OrderShowMockClient())->customFields(); + // $service = new OrderService($client); + + // $order = $service->find(1); + + // static::assertSame(10., $order->customFields()[0]->amount()); + // static::assertSame(CountryCode::NL, $order->taxes()[0]->rate()->country()); + // static::assertSame(57, $order->taxes()[0]->rate()->id()); + // static::assertSame(21., $order->taxes()[0]->rate()->percentage()); + + // $tax = $order->items()[0]->tax(); + + // static::assertSame(10., $tax->amount()); + // static::assertSame(CountryCode::NL, $tax->rate()->country()); + // static::assertSame(57, $tax->rate()->id()); + // static::assertSame(21., $tax->rate()->percentage()); + // } + /** @test */ public function show_order_discount(): void { @@ -318,6 +345,7 @@ public function show_order_with_empty_source(): void $client = (new OrderShowMockClient([ 'source' => null, ])); + $service = new OrderService($client); $order = $service->find(1); diff --git a/Tests/Feature/Order/StoreOrderTest.php b/Tests/Feature/Order/StoreOrderTest.php index 8694b55..c5e6f7d 100644 --- a/Tests/Feature/Order/StoreOrderTest.php +++ b/Tests/Feature/Order/StoreOrderTest.php @@ -130,7 +130,7 @@ public function convert_item_to_body(): void /** * @test - * @dataProvider convert_order_fields_data_provider + * @dataProvider convertOrderFieldsDataProvider */ public function convert_order_fields(string $method, string $bodyField, $value): void { @@ -141,7 +141,7 @@ public function convert_order_fields(string $method, string $bodyField, $value): static::assertEquals($value, $body[$bodyField]); } - public static function convert_order_fields_data_provider(): array + public static function convertOrderFieldsDataProvider(): array { return [ 'isHidden' => [ diff --git a/src/Director/BodyTo/BodyToCustomField.php b/src/Director/BodyTo/BodyToCustomField.php new file mode 100644 index 0000000..7e23382 --- /dev/null +++ b/src/Director/BodyTo/BodyToCustomField.php @@ -0,0 +1,18 @@ +setId($data['id']) + ->setInput($data['input']) + ->setLabel($data['label']); + } +} diff --git a/src/Director/BodyTo/BodyToItems.php b/src/Director/BodyTo/BodyToItems.php index 0a3a370..920c830 100644 --- a/src/Director/BodyTo/BodyToItems.php +++ b/src/Director/BodyTo/BodyToItems.php @@ -16,15 +16,18 @@ class BodyToItems public static function build(array $data): array { $result = []; + foreach ($data as $itemData) { - $item = (new ItemInternal()) + $item = (new ItemInternal()); + + $item ->setId($itemData['id']) + ->setType($itemData['type'] ? ItemType::from($itemData['type']) : ItemType::STANDARD) ->setProductId($itemData['product_id']) ->setLabel($itemData['label']) ->setQuantity($itemData['quantity']) ->setAmount((float) $itemData['amount']) - ->setAmountWithTax((float) $itemData['amount_with_tax']) - ->setType($itemData['type'] ? ItemType::from($itemData['type']) : ItemType::STANDARD); + ->setAmountWithTax((float) $itemData['amount_with_tax']); if (isset($itemData['discounts'])) { $item->setDiscounts(BodyToDiscounts::buildMany($itemData['discounts'])); @@ -34,6 +37,10 @@ public static function build(array $data): array $item->setTax(BodyToTax::build($itemData['tax'])); } + if (isset($itemData['custom_fields'])) { + $item->setCustomFields(BodyToCustomField::build($itemData['custom_fields'])); + } + $result[] = $item; } diff --git a/src/Director/BodyTo/BodyToOrder.php b/src/Director/BodyTo/BodyToOrder.php index 6fde6f7..c0364fe 100644 --- a/src/Director/BodyTo/BodyToOrder.php +++ b/src/Director/BodyTo/BodyToOrder.php @@ -17,24 +17,27 @@ class BodyToOrder { /** * @throws DecodeResponseException - * @throws Exception */ public static function build(array $data): Order { - $order = (new OrderInternal(false)) + $order = new OrderInternal( + allowEmptyRelations: false + ); + + $order ->setCreatedAt(self::date($data, 'created_at')) ->setDeletedAt($data['deleted_at'] ? self::date($data, 'deleted_at') : null) ->setFirst($data['is_first']) - ->setHidden($data['is_hidden']) ->setId($data['id']) ->setInvoiceNumber($data['invoice_number']) ->setInvoiceStatus(InvoiceStatus::from($data['invoice_status'])) - ->setMode(Mode::from($data['mode'])) ->setReference($data['reference']) ->setSource(Source::tryFrom($data['source'] ?? '') ?? Source::UNKNOWN) + ->setUpdatedAt(self::date($data, 'updated_at')) + ->setHidden($data['is_hidden']) + ->setMode(Mode::from($data['mode'])) ->setAmount((float) $data['amount']) - ->setAmountWithTax((float) $data['amount_with_tax']) - ->setUpdatedAt(self::date($data, 'updated_at')); + ->setAmountWithTax((float) $data['amount_with_tax']); if (isset($data['billing'])) { $order->setBilling(BodyToOrderBilling::build($data['billing'])); diff --git a/src/Entity/CustomField.php b/src/Entity/CustomField.php new file mode 100644 index 0000000..50dcf99 --- /dev/null +++ b/src/Entity/CustomField.php @@ -0,0 +1,49 @@ +id; + } + + public function setId(int $id): self + { + $this->id = $id; + + return $this; + } + + public function input(): string + { + return $this->input; + } + + public function setInput(string $input): self + { + $this->input = $input; + + return $this; + } + + public function label(): string + { + return $this->label; + } + + public function setLabel(string $label): self + { + $this->label = $label; + + return $this; + } +} diff --git a/src/Entity/Item.php b/src/Entity/Item.php index 7a91859..0450a22 100644 --- a/src/Entity/Item.php +++ b/src/Entity/Item.php @@ -5,6 +5,7 @@ namespace PlugAndPay\Sdk\Entity; use PlugAndPay\Sdk\Enum\ItemType; +use PlugAndPay\Sdk\Exception\RelationNotLoadedException; use PlugAndPay\Sdk\Traits\ValidatesFieldMethods; class Item @@ -13,15 +14,22 @@ class Item protected float $amount; protected float $amountWithTax; + /** @var Discount[] */ protected array $discounts; + protected int $id; protected string $label; + protected int $productId; protected int $quantity; + protected Tax $tax; protected ItemType $type; + /** @var CustomField[] */ + protected array $customFields; + public function id(): int { return $this->id; @@ -115,4 +123,16 @@ public function type(): ItemType { return $this->type; } + + /** + * @throws RelationNotLoadedException + */ + public function customFields(): array + { + if (!isset($this->customFields)) { + throw new RelationNotLoadedException('customFields'); + } + + return $this->customFields; + } } diff --git a/src/Entity/ItemInternal.php b/src/Entity/ItemInternal.php index c965ed4..835e1f5 100644 --- a/src/Entity/ItemInternal.php +++ b/src/Entity/ItemInternal.php @@ -40,4 +40,14 @@ public function setType(ItemType $type): self return $this; } + + /** + * @internal + */ + public function setCustomFields(CustomField $customFields): self + { + $this->customFields = $customFields; + + return $this; + } } diff --git a/src/Entity/Order.php b/src/Entity/Order.php index b74442a..13c17ab 100644 --- a/src/Entity/Order.php +++ b/src/Entity/Order.php @@ -15,31 +15,47 @@ class Order { use HasDynamicFields; + protected int $id; + protected bool $allowEmptyRelations; + protected float $amount; protected float $amountWithTax; + protected OrderBilling $billing; + /** @var Comment[] */ protected array $comments; + protected DateTimeImmutable $createdAt; - protected ?DateTimeImmutable $deletedAt; + protected DateTimeImmutable | null $deletedAt; + /** @var Discount[] */ protected array $totalDiscounts; + protected bool $first; protected bool $hidden; - protected int $id; - protected ?string $invoiceNumber; + + protected string | null $invoiceNumber; + protected InvoiceStatus $invoiceStatus; + /** @var Item[] */ protected array $items; + protected Mode $mode; + protected Payment $payment; protected string $reference; + protected Source $source; + /** @var string[] */ protected array $tags; + /** @var Tax[] */ protected array $taxes; + protected DateTimeImmutable $updatedAt; public function __construct(bool $allowEmptyRelations = true) @@ -123,7 +139,7 @@ public function createdAt(): DateTimeImmutable return $this->createdAt; } - public function deletedAt(): ?DateTimeImmutable + public function deletedAt(): DateTimeImmutable | null { return $this->deletedAt; } @@ -140,14 +156,11 @@ public function totalDiscounts(): array return $this->totalDiscounts; } - public function invoiceNumber(): ?string + public function setTotalDiscounts(array $totalDiscounts): self { - return $this->invoiceNumber; - } + $this->totalDiscounts = $totalDiscounts; - public function invoiceStatus(): InvoiceStatus - { - return $this->invoiceStatus; + return $this; } public function isFirst(): bool @@ -167,6 +180,16 @@ public function setHidden(bool $hidden): self return $this; } + public function invoiceNumber(): string | null + { + return $this->invoiceNumber; + } + + public function invoiceStatus(): InvoiceStatus + { + return $this->invoiceStatus; + } + /** * @throws RelationNotLoadedException */ @@ -262,6 +285,13 @@ public function taxes(): array return $this->taxes; } + public function setTaxes(array $taxes): self + { + $this->taxes = $taxes; + + return $this; + } + public function updatedAt(): DateTimeImmutable { return $this->updatedAt; diff --git a/src/Entity/OrderInternal.php b/src/Entity/OrderInternal.php index cda969b..3e42716 100644 --- a/src/Entity/OrderInternal.php +++ b/src/Entity/OrderInternal.php @@ -26,7 +26,7 @@ public function setCreatedAt(DateTimeImmutable $createdAt): self /** * @internal */ - public function setDeletedAt(?DateTimeImmutable $deletedAt): self + public function setDeletedAt(DateTimeImmutable | null $deletedAt): self { $this->deletedAt = $deletedAt; @@ -56,7 +56,7 @@ public function setId(int $id): self /** * @internal */ - public function setInvoiceNumber(?string $invoiceNumber): self + public function setInvoiceNumber(string | null $invoiceNumber): self { $this->invoiceNumber = $invoiceNumber; @@ -93,26 +93,6 @@ public function setSource(Source $source): self return $this; } - /** - * @internal - */ - public function setTaxes(array $taxes): self - { - $this->taxes = $taxes; - - return $this; - } - - /** - * @internal - */ - public function setTotalDiscounts(array $totalDiscounts): self - { - $this->totalDiscounts = $totalDiscounts; - - return $this; - } - /** * @internal */ diff --git a/src/Enum/OrderIncludes.php b/src/Enum/OrderIncludes.php index d9aac26..0381b45 100644 --- a/src/Enum/OrderIncludes.php +++ b/src/Enum/OrderIncludes.php @@ -4,11 +4,12 @@ enum OrderIncludes: string { - case BILLING = 'billing'; - case COMMENTS = 'comments'; - case DISCOUNTS = 'discounts'; - case ITEMS = 'items'; - case PAYMENT = 'payment'; - case TAGS = 'tags'; - case TAXES = 'taxes'; + case BILLING = 'billing'; + case COMMENTS = 'comments'; + case CUSTOM_FIELDS = 'custom_fields'; + case DISCOUNTS = 'discounts'; + case ITEMS = 'items'; + case PAYMENT = 'payment'; + case TAGS = 'tags'; + case TAXES = 'taxes'; } diff --git a/src/Service/OrderService.php b/src/Service/OrderService.php index f089286..fbb5b92 100644 --- a/src/Service/OrderService.php +++ b/src/Service/OrderService.php @@ -5,7 +5,6 @@ namespace PlugAndPay\Sdk\Service; use PlugAndPay\Sdk\Contract\ClientInterface; -use PlugAndPay\Sdk\Contract\ClientPatchInterface; use PlugAndPay\Sdk\Director\BodyTo\BodyToOrder; use PlugAndPay\Sdk\Director\ToBody\OrderToBody; use PlugAndPay\Sdk\Entity\Order; @@ -17,7 +16,8 @@ class OrderService { - private ClientPatchInterface $client; + private ClientInterface $client; + /** @var string[] */ private array $includes = [];