Skip to content
Merged
41 changes: 40 additions & 1 deletion src/bill/Bill.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ class Bill implements BillInterface
/** @var UsageInterval */
protected $usageInterval;

/** @var BillSource|null */
protected $source;

/** @var BillTxn|null */
protected $txn;

/** @var BillReversesId|null */
protected $reversesId;

/**
* @param int|string $id
*/
Expand All @@ -77,7 +86,10 @@ public function __construct(
?TargetInterface $target = null,
?PlanInterface $plan = null,
array $charges = [],
?BillState $state = null
?BillState $state = null,
?BillSource $source = null,
?BillTxn $txn = null,
?BillReversesId $reversesId = null,
) {
$this->type = $type;
$this->time = $time;
Expand All @@ -88,6 +100,9 @@ public function __construct(
$this->plan = $plan;
$this->charges = $charges;
$this->state = $state;
$this->source = $source;
$this->txn = $txn;
$this->reversesId = $reversesId;
}

/**
Expand Down Expand Up @@ -241,6 +256,16 @@ public function getComment()
return $this->comment;
}

public function getSource(): ?BillSource
{
return $this->source;
}

public function getTxn(): ?BillTxn
{
return $this->txn;
}

public function setComment(string $comment)
{
$this->comment = $comment;
Expand All @@ -255,4 +280,18 @@ public function setUsageInterval(UsageInterval $usageInterval): void
{
$this->usageInterval = $usageInterval;
}

public function getReversesId(): ?BillReversesId
{
return $this->reversesId;
}

/**
* @param BillReversesId|null $reversesId
* @return void
*/
public function setReversesId($reversesId): void
{
$this->reversesId = $reversesId;
}
Comment on lines +289 to +296
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

setReversesId parameter is untyped — add ?BillReversesId hint

The @param BillReversesId|null docblock documents the intended type, but the actual parameter declaration is untyped. This is inconsistent with the constructor signature (line 92: BillReversesId $reversesId = null) and silently accepts any value at runtime.

♻️ Proposed fix
-    public function setReversesId($reversesId): void
+    public function setReversesId(?BillReversesId $reversesId): void
     {
         $this->reversesId = $reversesId;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bill/Bill.php` around lines 290 - 297, The setter setReversesId is
missing the nullable type hint documented in the docblock; change its signature
to accept ?BillReversesId (i.e. public function setReversesId(?BillReversesId
$reversesId): void) so it matches the constructor's BillReversesId $reversesId =
null intent and prevents arbitrary values, and ensure any necessary import/use
for BillReversesId is present and the docblock stays consistent.

}
6 changes: 6 additions & 0 deletions src/bill/BillInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,10 @@ public function getCharges();
public function getUsageInterval(): UsageInterval;

public function setUsageInterval(UsageInterval $usageInterval): void;

public function getSource(): ?BillSource;

public function getTxn(): ?BillTxn;

public function getReversesId(): ?BillReversesId;
}
22 changes: 22 additions & 0 deletions src/bill/BillReversesId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace hiqdev\php\billing\bill;

readonly class BillReversesId
{
public function __construct(private ?int $value = null)
{
}

public function getId(): ?int
{
return $this->value;
}

public static function fromInt(int $id): self
{
return new self($id);
}
}
29 changes: 29 additions & 0 deletions src/bill/BillSource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace hiqdev\php\billing\bill;

class BillSource
{
/** @var int|string|null */
protected $id;

protected ?string $name = null;

public function __construct($id = null, ?string $name = null)
{
$this->id = $id;
$this->name = $name;
}

public function getId()
{
return $this->id;
}

public function getName(): ?string
{
return $this->name;
}
}
49 changes: 49 additions & 0 deletions src/bill/BillTxn.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace hiqdev\php\billing\bill;

/**
* BillTxn
*
* Represents an immutable external payment transaction identifier.
*
* A TransactionId uniquely identifies a financial transaction
* as defined by an external payment or accounting system
* (e.g. Business Central, merchant gateways, banks).
*
* This value:
* - Is created by an external system, never generated internally
* - Is stable across retries, webhooks, and re-imports
* - Is used for idempotency and reconciliation
* - Has meaning outside of the database and application boundaries
*
* Uniqueness is guaranteed only within the scope of a source system
* (see Source / external system).
*
* Typical examples:
* - UUIDs
* - Gateway transaction references
* - Accounting document numbers
*/
class BillTxn
{
/** @var int|string|null */
protected $value;

public function __construct($txn = null)
{
$this->value = $txn;
}

public function getValue()
{
return $this->value;
}

public static function fromString(string $txn): self
{
return new self($txn);
}
}
2 changes: 1 addition & 1 deletion src/charge/modifiers/Installment.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function buildPrice(Money $sum)
$target = $this->getTarget();
$prepaid = Quantity::create('items', 0);

return new SinglePrice(null, $type, $target, null, $prepaid, $sum);
return new SinglePrice(null, $type, $target, $prepaid, $sum);
}

public function getType()
Expand Down
2 changes: 1 addition & 1 deletion src/price/PriceFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function createRatePrice(PriceCreationDto $dto)

public function createSinglePrice(PriceCreationDto $dto)
{
return new SinglePrice($dto->id, $dto->type, $dto->target, $dto->plan, $dto->prepaid, $dto->price);
return new SinglePrice($dto->id, $dto->type, $dto->target, $dto->prepaid, $dto->price, $dto->plan);
}

public function createProgressivePrice(PriceCreationDto $dto): ProgressivePrice
Expand Down
4 changes: 2 additions & 2 deletions src/price/SinglePrice.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public function __construct(
$id,
TypeInterface $type,
TargetInterface $target,
?PlanInterface $plan = null,
?QuantityInterface $prepaid = null,
?Money $price = null
?Money $price = null,
?PlanInterface $plan = null,
) {
parent::__construct($id, $type, $target, $plan);
$this->prepaid = $prepaid;
Expand Down
2 changes: 1 addition & 1 deletion tests/behat/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public function priceIs($target, $type, $sum, $currency, $unit, $quantity = 0)
$target = new Target(Target::ANY, $target);
$quantity = Quantity::create($unit, $quantity);
$sum = $this->moneyParser->parse($sum, new Currency($currency));
$this->setPrice(new SinglePrice(null, $type, $target, null, $quantity, $sum));
$this->setPrice(new SinglePrice(null, $type, $target, $quantity, $sum));
}

protected array $progressivePrice = [];
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/action/ActionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ protected function setUp(): void
$this->target = new Target(2, 'server');
$this->prepaid = Quantity::gigabyte(1);
$this->money = Money::USD(10000);
$this->price = new SinglePrice(5, $this->type, $this->target, null, $this->prepaid, $this->money);
$this->price = new SinglePrice(5, $this->type, $this->target, $this->prepaid, $this->money);
$this->customer = new Customer(2, 'client');
$this->time = new DateTimeImmutable('now');
$this->generalizer = new Generalizer();
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/charge/modifiers/InstallmentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected function setUp(): void
{
parent::setUp();
$this->type = Type::anyId('monthly,installment');
$this->price = new SinglePrice(5, $this->type, $this->target, null, $this->prepaid, $this->money);
$this->price = new SinglePrice(5, $this->type, $this->target, $this->prepaid, $this->money);
}

protected function buildInstallment($term)
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/charge/modifiers/OnceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ private function createType(string $name): TypeInterface

private function createPrice(TypeInterface $type): PriceInterface
{
return new SinglePrice(5, $type, $this->target, null, $this->prepaid, $this->money);
return new SinglePrice(5, $type, $this->target, $this->prepaid, $this->money);
}

#[\PHPUnit\Framework\Attributes\DataProvider('periodCreationProvider')]
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/price/SinglePriceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected function setUp(): void
$this->type = new Type(null, 'server_traf');
$this->quantity = Quantity::gigabyte(10);
$this->money = Money::USD(15);
$this->price = new SinglePrice(null, $this->type, $this->target, null, $this->quantity, $this->money);
$this->price = new SinglePrice(null, $this->type, $this->target, $this->quantity, $this->money);
}

protected function tearDown(): void
Expand Down
Loading