Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions packages/core/src/Models/OrderLine.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use Lunar\Base\Traits\HasMacros;
use Lunar\Base\Traits\LogsActivity;
use Lunar\Database\Factories\OrderLineFactory;
use Lunar\DataTypes\ShippingOption;
use Lunar\Models\TaxClass;

/**
* @property int $id
Expand Down Expand Up @@ -81,6 +83,23 @@ public function order(): BelongsTo
return $this->belongsTo(Order::modelClass());
}

public function getPurchasableAttribute(): mixed
{
if ($this->purchasable_type === ShippingOption::class) {
return new ShippingOption(
name: (string) $this->description,
description: (string) $this->description,
identifier: (string) $this->identifier,
price: $this->unit_price,
taxClass: TaxClass::getDefault(),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made it use default as taxClass property is not nullable and there is no tax_class_id stored on order_lines (as every detail is captured on $orderLine->tax_breakdown).

Copy link
Copy Markdown
Contributor Author

@bpotmalnik bpotmalnik May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about DX and how to inform dev about that this taxClass might be not accurate representation of what is in tax_breakdown, but I did not find right place for comment.

I think also rather than returning ShippingOption, it could return ShippingLineSnapshot that could be more accurate object (as it is already not real model class stored in db.

option: $this->option,
meta: $this->meta ? (array) $this->meta : null,
);
}

return $this->getRelationValue('purchasable');
}

public function purchasable(): MorphTo
{
return $this->morphTo();
Expand Down
32 changes: 32 additions & 0 deletions tests/core/Unit/Models/OrderLineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,35 @@
->and($orderLine->unit_price->unitDecimal)
->toEqual(6.5);
});

test('can access purchasable on a shipping order line', function () {
$order = Order::factory()->create();

Currency::factory()->create([
'default' => true,
]);

TaxClass::factory()->create([
'default' => true,
]);

$orderLine = OrderLine::factory()->create([
'order_id' => $order->id,
'quantity' => 1,
'type' => 'shipping',
'description' => 'Basic Delivery',
'identifier' => 'BASDEL',
'option' => 'standard',
'purchasable_type' => ShippingOption::class,
'purchasable_id' => 1,
'unit_price' => 500,
'unit_quantity' => 1,
]);

$purchasable = $orderLine->purchasable;

expect($purchasable)->toBeInstanceOf(ShippingOption::class)
->and($purchasable->getIdentifier())->toBe('BASDEL')
->and($purchasable->getName())->toBe('Basic Delivery')
->and($purchasable->getOption())->toBe('standard');
});