From 573f51d8286d9c946618e84b7424a0516dcf3d75 Mon Sep 17 00:00:00 2001 From: Vadym Hrechukha Date: Wed, 4 Feb 2026 12:16:49 +0200 Subject: [PATCH 1/8] HP-2883: Implement Business Central bills import service --- src/bill/Bill.php | 22 ++++++++++++++++- src/bill/BillInterface.php | 4 ++++ src/bill/BillSource.php | 29 ++++++++++++++++++++++ src/bill/BillTxn.php | 49 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/bill/BillSource.php create mode 100644 src/bill/BillTxn.php diff --git a/src/bill/Bill.php b/src/bill/Bill.php index 81782680..c78dc8e0 100755 --- a/src/bill/Bill.php +++ b/src/bill/Bill.php @@ -67,6 +67,12 @@ class Bill implements BillInterface /** @var UsageInterval */ protected $usageInterval; + /** @var BillSource|null */ + protected $source; + + /** @var BillTxn|null */ + protected $txn; + public function __construct( $id, TypeInterface $type, @@ -77,7 +83,9 @@ public function __construct( TargetInterface $target = null, PlanInterface $plan = null, array $charges = [], - BillState $state = null + BillState $state = null, + BillSource $source = null, + BillTxn $txn = null, ) { $this->id = $id; $this->type = $type; @@ -89,6 +97,8 @@ public function __construct( $this->plan = $plan; $this->charges = $charges; $this->state = $state; + $this->source = $source; + $this->txn = $txn; } /** @@ -242,6 +252,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; diff --git a/src/bill/BillInterface.php b/src/bill/BillInterface.php index 13bb58d5..869197a5 100644 --- a/src/bill/BillInterface.php +++ b/src/bill/BillInterface.php @@ -55,4 +55,8 @@ public function getCharges(); public function getUsageInterval(): UsageInterval; public function setUsageInterval(UsageInterval $usageInterval): void; + + public function getSource(): ?BillSource; + + public function getTxn(): ?BillTxn; } diff --git a/src/bill/BillSource.php b/src/bill/BillSource.php new file mode 100644 index 00000000..898fc18a --- /dev/null +++ b/src/bill/BillSource.php @@ -0,0 +1,29 @@ +id = $id; + $this->name = $name; + } + + public function getId() + { + return $this->id; + } + + public function getName(): ?string + { + return $this->name; + } +} diff --git a/src/bill/BillTxn.php b/src/bill/BillTxn.php new file mode 100644 index 00000000..1b2de795 --- /dev/null +++ b/src/bill/BillTxn.php @@ -0,0 +1,49 @@ +value = $txn; + } + + public function getValue() + { + return $this->value; + } + + public static function fromString(string $txn): self + { + return new self($txn); + } +} From 38f51ddf1b9458a5fc2574fe2aa8633945fb3096 Mon Sep 17 00:00:00 2001 From: Vadym Hrechukha Date: Wed, 25 Feb 2026 10:23:08 +0200 Subject: [PATCH 2/8] HP-2883: added support reversesId to Bill --- src/bill/Bill.php | 19 +++++++++++++++++++ src/bill/BillInterface.php | 2 ++ src/bill/BillReversesId.php | 26 ++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 src/bill/BillReversesId.php diff --git a/src/bill/Bill.php b/src/bill/Bill.php index c78dc8e0..dca11c2c 100755 --- a/src/bill/Bill.php +++ b/src/bill/Bill.php @@ -73,6 +73,9 @@ class Bill implements BillInterface /** @var BillTxn|null */ protected $txn; + /** @var BillReversesId|null */ + protected $reversesId; + public function __construct( $id, TypeInterface $type, @@ -86,6 +89,7 @@ public function __construct( BillState $state = null, BillSource $source = null, BillTxn $txn = null, + BillReversesId $reversesId = null, ) { $this->id = $id; $this->type = $type; @@ -99,6 +103,7 @@ public function __construct( $this->state = $state; $this->source = $source; $this->txn = $txn; + $this->reversesId = $reversesId; } /** @@ -276,4 +281,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; + } } diff --git a/src/bill/BillInterface.php b/src/bill/BillInterface.php index 869197a5..84274b21 100644 --- a/src/bill/BillInterface.php +++ b/src/bill/BillInterface.php @@ -59,4 +59,6 @@ public function setUsageInterval(UsageInterval $usageInterval): void; public function getSource(): ?BillSource; public function getTxn(): ?BillTxn; + + public function getReversesId(): ?BillReversesId; } diff --git a/src/bill/BillReversesId.php b/src/bill/BillReversesId.php new file mode 100644 index 00000000..ba9a9a97 --- /dev/null +++ b/src/bill/BillReversesId.php @@ -0,0 +1,26 @@ +id = $id; + } + + public function getId(): int + { + return $this->id; + } + + public static function fromInt(int $id): self + { + return new self($id); + } +} From 38ed9c9700357614fda404f72acf37415e538f4a Mon Sep 17 00:00:00 2001 From: Vadym Hrechukha Date: Mon, 23 Mar 2026 15:40:00 +0200 Subject: [PATCH 3/8] HQD-21: fixing "Implicitly marking parameters as nullable is deprecated, the explicit nullable type must be used instead" deprecation warning in Bill --- src/bill/Bill.php | 12 ++++++------ src/bill/BillRequisite.php | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bill/Bill.php b/src/bill/Bill.php index dca11c2c..f4050d25 100755 --- a/src/bill/Bill.php +++ b/src/bill/Bill.php @@ -83,13 +83,13 @@ public function __construct( Money $sum, QuantityInterface $quantity, CustomerInterface $customer, - TargetInterface $target = null, - PlanInterface $plan = null, + ?TargetInterface $target = null, + ?PlanInterface $plan = null, array $charges = [], - BillState $state = null, - BillSource $source = null, - BillTxn $txn = null, - BillReversesId $reversesId = null, + ?BillState $state = null, + ?BillSource $source = null, + ?BillTxn $txn = null, + ?BillReversesId $reversesId = null, ) { $this->id = $id; $this->type = $type; diff --git a/src/bill/BillRequisite.php b/src/bill/BillRequisite.php index 0d6db484..4a15082a 100644 --- a/src/bill/BillRequisite.php +++ b/src/bill/BillRequisite.php @@ -9,7 +9,7 @@ class BillRequisite protected ?string $name = null; - public function __construct($id = null, string $name = null) + public function __construct($id = null, ?string $name = null) { $this->id = $id; $this->name = $name; From e8a00329f351b8f3870f9f3c78f1010dcf61f23d Mon Sep 17 00:00:00 2001 From: Vadym Hrechukha Date: Mon, 23 Mar 2026 15:46:20 +0200 Subject: [PATCH 4/8] HQD-21: fixing "Implicitly marking parameters as nullable is deprecated, the explicit nullable type must be used instead" deprecation warning in batch of classes --- src/action/AbstractAction.php | 6 +++--- src/charge/Charge.php | 2 +- src/customer/Customer.php | 2 +- src/plan/Plan.php | 4 ++-- src/price/AbstractPrice.php | 2 +- src/product/price/PriceTypeDefinitionCollection.php | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/action/AbstractAction.php b/src/action/AbstractAction.php index a28cddc8..1483cc89 100755 --- a/src/action/AbstractAction.php +++ b/src/action/AbstractAction.php @@ -68,9 +68,9 @@ public function __construct( QuantityInterface $quantity, CustomerInterface $customer, DateTimeImmutable $time, - SaleInterface $sale = null, - ActionState $state = null, - ActionInterface $parent = null, + ?SaleInterface $sale = null, + ?ActionState $state = null, + ?ActionInterface $parent = null, float $fractionOfMonth = 0.0 ) { $this->id = $id; diff --git a/src/charge/Charge.php b/src/charge/Charge.php index 34e43f10..408909f7 100755 --- a/src/charge/Charge.php +++ b/src/charge/Charge.php @@ -72,7 +72,7 @@ public function __construct( ?PriceInterface $price, QuantityInterface $usage, Money $sum, - BillInterface $bill = null + ?BillInterface $bill = null ) { $this->id = $id; $this->type = $type; diff --git a/src/customer/Customer.php b/src/customer/Customer.php index 4b02c668..51658920 100755 --- a/src/customer/Customer.php +++ b/src/customer/Customer.php @@ -37,7 +37,7 @@ class Customer implements CustomerInterface */ protected $sellers = []; - public function __construct($id, $login, CustomerInterface $seller = null) + public function __construct($id, $login, ?CustomerInterface $seller = null) { $this->id = $id; $this->login = $login; diff --git a/src/plan/Plan.php b/src/plan/Plan.php index 6f79dabf..f1fdc874 100755 --- a/src/plan/Plan.php +++ b/src/plan/Plan.php @@ -57,9 +57,9 @@ class Plan implements PlanInterface public function __construct( $id, $name, - CustomerInterface $seller = null, + ?CustomerInterface $seller = null, $prices = [], - TypeInterface $type = null, + ?TypeInterface $type = null, $parent_id = null ) { $this->id = $id; diff --git a/src/price/AbstractPrice.php b/src/price/AbstractPrice.php index 938a77d1..c577e4c1 100755 --- a/src/price/AbstractPrice.php +++ b/src/price/AbstractPrice.php @@ -56,7 +56,7 @@ public function __construct( $id, TypeInterface $type, TargetInterface $target, - PlanInterface $plan = null + ?PlanInterface $plan = null ) { $this->id = $id; $this->type = $type; diff --git a/src/product/price/PriceTypeDefinitionCollection.php b/src/product/price/PriceTypeDefinitionCollection.php index b0a45693..dd5d72f7 100644 --- a/src/product/price/PriceTypeDefinitionCollection.php +++ b/src/product/price/PriceTypeDefinitionCollection.php @@ -31,7 +31,7 @@ public function __construct( */ private readonly TariffTypeDefinitionInterface $parent, private readonly PriceTypeDefinitionFactoryInterface $factory, - PriceTypeDefinitionCollectionInterface $collectionInstance = null, + ?PriceTypeDefinitionCollectionInterface $collectionInstance = null, ) { $this->storage = new PriceTypeStorage(); $this->collectionInstance = $collectionInstance ?? $this; From e833bf262563e9821facfd02ae6948081884f743 Mon Sep 17 00:00:00 2001 From: Vadym Hrechukha Date: Mon, 23 Mar 2026 15:50:10 +0200 Subject: [PATCH 5/8] HQD-21: fixing "Implicitly marking parameters as nullable is deprecated, the explicit nullable type must be used instead" deprecation warning in SinglePrice --- src/price/SinglePrice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/price/SinglePrice.php b/src/price/SinglePrice.php index 99c1ba33..0be6e0fa 100644 --- a/src/price/SinglePrice.php +++ b/src/price/SinglePrice.php @@ -36,7 +36,7 @@ public function __construct( $id, TypeInterface $type, TargetInterface $target, - PlanInterface $plan = null, + ?PlanInterface $plan = null, QuantityInterface $prepaid, Money $price ) { From a4ac7823d27ec22665d777df485a7085d7468422 Mon Sep 17 00:00:00 2001 From: Vadym Hrechukha Date: Mon, 23 Mar 2026 15:55:00 +0200 Subject: [PATCH 6/8] HQD-21: fixing "Implicitly marking parameters as nullable is deprecated, the explicit nullable type must be used instead" deprecation warning in BillSource --- src/bill/BillSource.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bill/BillSource.php b/src/bill/BillSource.php index 898fc18a..08366f2c 100644 --- a/src/bill/BillSource.php +++ b/src/bill/BillSource.php @@ -11,7 +11,7 @@ class BillSource protected ?string $name = null; - public function __construct($id = null, string $name = null) + public function __construct($id = null, ?string $name = null) { $this->id = $id; $this->name = $name; From b979df277e39f6a71ff3f2d425c28a7e87c05130 Mon Sep 17 00:00:00 2001 From: Vadym Hrechukha Date: Mon, 23 Mar 2026 17:00:21 +0200 Subject: [PATCH 7/8] HQD-21: fixing "Optional parameter $plan declared before required parameter $price is implicitly treated as a required parameter" deprecation warning in SinglePrice --- src/charge/modifiers/Installment.php | 2 +- src/price/PriceFactory.php | 2 +- src/price/SinglePrice.php | 4 ++-- tests/behat/bootstrap/FeatureContext.php | 2 +- tests/unit/action/ActionTest.php | 2 +- tests/unit/charge/modifiers/InstallmentTest.php | 2 +- tests/unit/charge/modifiers/OnceTest.php | 2 +- tests/unit/price/SinglePriceTest.php | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/charge/modifiers/Installment.php b/src/charge/modifiers/Installment.php index dcfe6a10..8cfe5d5d 100644 --- a/src/charge/modifiers/Installment.php +++ b/src/charge/modifiers/Installment.php @@ -39,7 +39,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() diff --git a/src/price/PriceFactory.php b/src/price/PriceFactory.php index 02e794d8..3e94d6b7 100644 --- a/src/price/PriceFactory.php +++ b/src/price/PriceFactory.php @@ -89,7 +89,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 diff --git a/src/price/SinglePrice.php b/src/price/SinglePrice.php index 0be6e0fa..6af3052b 100644 --- a/src/price/SinglePrice.php +++ b/src/price/SinglePrice.php @@ -36,9 +36,9 @@ public function __construct( $id, TypeInterface $type, TargetInterface $target, - ?PlanInterface $plan = null, QuantityInterface $prepaid, - Money $price + Money $price, + ?PlanInterface $plan = null, ) { parent::__construct($id, $type, $target, $plan); $this->prepaid = $prepaid; diff --git a/tests/behat/bootstrap/FeatureContext.php b/tests/behat/bootstrap/FeatureContext.php index 9e17a508..fc51ea92 100644 --- a/tests/behat/bootstrap/FeatureContext.php +++ b/tests/behat/bootstrap/FeatureContext.php @@ -100,7 +100,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 = []; diff --git a/tests/unit/action/ActionTest.php b/tests/unit/action/ActionTest.php index e0ad2f9d..da5baaf2 100644 --- a/tests/unit/action/ActionTest.php +++ b/tests/unit/action/ActionTest.php @@ -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(); diff --git a/tests/unit/charge/modifiers/InstallmentTest.php b/tests/unit/charge/modifiers/InstallmentTest.php index 51d19f22..d5e89ada 100644 --- a/tests/unit/charge/modifiers/InstallmentTest.php +++ b/tests/unit/charge/modifiers/InstallmentTest.php @@ -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) diff --git a/tests/unit/charge/modifiers/OnceTest.php b/tests/unit/charge/modifiers/OnceTest.php index a1c64a5c..95f00362 100644 --- a/tests/unit/charge/modifiers/OnceTest.php +++ b/tests/unit/charge/modifiers/OnceTest.php @@ -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')] diff --git a/tests/unit/price/SinglePriceTest.php b/tests/unit/price/SinglePriceTest.php index 92829f97..483698b9 100644 --- a/tests/unit/price/SinglePriceTest.php +++ b/tests/unit/price/SinglePriceTest.php @@ -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 From a15b6e8013a3dbe28f95db3d60682f4b177a86ab Mon Sep 17 00:00:00 2001 From: merovingian Date: Wed, 13 May 2026 16:06:45 +0300 Subject: [PATCH 8/8] HQD-129: thightly refectored BillReversesId --- src/bill/BillReversesId.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/bill/BillReversesId.php b/src/bill/BillReversesId.php index ba9a9a97..fccf7754 100644 --- a/src/bill/BillReversesId.php +++ b/src/bill/BillReversesId.php @@ -4,19 +4,15 @@ namespace hiqdev\php\billing\bill; -class BillReversesId +readonly class BillReversesId { - /** @var int|null */ - protected $id; - - public function __construct($id = null) + public function __construct(private ?int $value = null) { - $this->id = $id; } - public function getId(): int + public function getId(): ?int { - return $this->id; + return $this->value; } public static function fromInt(int $id): self