Skip to content

HP-2883: Implement Business Central bills import service#114

Open
VadymHrechukha wants to merge 7 commits intohiqdev:masterfrom
VadymHrechukha:HP-2883_implement_business_central_bills_import_service
Open

HP-2883: Implement Business Central bills import service#114
VadymHrechukha wants to merge 7 commits intohiqdev:masterfrom
VadymHrechukha:HP-2883_implement_business_central_bills_import_service

Conversation

@VadymHrechukha
Copy link
Copy Markdown
Collaborator

@VadymHrechukha VadymHrechukha commented Feb 4, 2026

Summary by CodeRabbit

  • New Features
    • Bills can store and expose source info, external transaction identifiers, and reversal IDs (with getters/setter).
    • Added lightweight value objects for source, transaction ID, and reversal ID.
  • Bug Fixes / Chores
    • Clarified nullable constructor parameter types across various entities for consistent optional-value handling.
    • Adjusted price/plan parameter ordering to a nullable-last convention.
  • Tests
    • Updated tests to match the revised price/constructor argument order.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 4, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ba47dfad-4c35-432a-958f-cca9dc428092

📥 Commits

Reviewing files that changed from the base of the PR and between e8a0032 and b979df2.

📒 Files selected for processing (9)
  • src/bill/BillSource.php
  • src/charge/modifiers/Installment.php
  • src/price/PriceFactory.php
  • src/price/SinglePrice.php
  • tests/behat/bootstrap/FeatureContext.php
  • tests/unit/action/ActionTest.php
  • tests/unit/charge/modifiers/InstallmentTest.php
  • tests/unit/charge/modifiers/OnceTest.php
  • tests/unit/price/SinglePriceTest.php
✅ Files skipped from review due to trivial changes (1)
  • src/bill/BillSource.php

📝 Walkthrough

Walkthrough

Added three new bill value objects (BillSource, BillTxn, BillReversesId), extended Bill and BillInterface to store/expose optional source/txn/reversesId, added setter/getter for reversesId, and made multiple constructor parameters explicitly nullable; adjusted SinglePrice parameter order and updated related usages/tests.

Changes

Cohort / File(s) Summary
Bill core updates
src/bill/Bill.php, src/bill/BillInterface.php
Added nullable properties $source, $txn, $reversesId; updated Bill::__construct to accept ?TargetInterface $target = null, ?PlanInterface $plan = null, ?BillSource $source = null, ?BillTxn $txn = null, ?BillReversesId $reversesId = null; added getSource(), getTxn(), getReversesId() and setReversesId(); interface extended with the three getters.
New value objects
src/bill/BillSource.php, src/bill/BillTxn.php, src/bill/BillReversesId.php
Introduced BillSource (id, name, getters), BillTxn (txn value holder, fromString()), and BillReversesId (id holder, fromInt()); simple immutable/value-object classes.
Nullable constructor/type hint updates
src/action/AbstractAction.php, src/charge/Charge.php, src/customer/Customer.php, src/plan/Plan.php, src/price/AbstractPrice.php, src/product/price/PriceTypeDefinitionCollection.php
Made several constructor parameters explicitly nullable (e.g., ?SaleInterface, ?BillInterface, ?CustomerInterface, ?PlanInterface, ?TypeInterface, ?PriceTypeDefinitionCollectionInterface) to match allowed null defaults.
SinglePrice signature & usages
src/price/SinglePrice.php, src/price/PriceFactory.php, src/charge/modifiers/Installment.php
Reordered SinglePrice::__construct to move optional PlanInterface to the last parameter (...?PlanInterface $plan = null); updated factory and Installment to pass parameters in the new order.
Tests and callsite updates
tests/.../*, tests/unit/.../ActionTest.php, tests/unit/charge/modifiers/*, tests/unit/price/SinglePriceTest.php, tests/behat/bootstrap/FeatureContext.php
Updated test setup and step definitions to match SinglePrice constructor changes (removed previously passed null argument, adjusted argument order).
Minor signature tweak
src/bill/BillRequisite.php
Made BillRequisite::__construct $name parameter nullable (?string $name = null).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • SilverFire

Poem

🐰
I nibble code and plant a seed,
New fields hop in with gentle speed.
Source, txn, reverse id in tow,
Small carrots help the ledgers grow. 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'HP-2883: Implement Business Central bills import service' references implementing a bills import feature, which aligns with the addition of new bill-related properties and classes, but the changeset significantly extends beyond just the import service implementation to include constructor parameter type refinements across multiple unrelated classes. Clarify whether the title should emphasize the Business Central import feature specifically or broaden to reflect the broader constructor type safety improvements throughout the codebase.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/bill/Bill.php (1)

260-268: Asymmetric mutation API: setter only for reversesId, not for source and txn

setReversesId() allows post-construction mutation of $reversesId, but $source and $txn have no equivalent setters. If mutable post-construction state is intentional only for the reversal use-case, a short inline comment explaining this would prevent confusion for future maintainers. Otherwise, consider making the API consistent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bill/Bill.php` around lines 260 - 268, The class exposes mutation for
$reversesId via setReversesId but has getters getSource() and getTxn() without
corresponding setters, creating an asymmetric API; either add setters
setSource(BillSource $source): void and setTxn(BillTxn $txn): void (or nullable
variants) to mirror setReversesId, or if immutability for source/txn is
intentional, add a concise inline comment near the properties and the
getSource()/getTxn() methods explaining that only reversesId is mutable
post-construction and why (referencing $reversesId, setReversesId, $source,
getSource, $txn, getTxn).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/bill/Bill.php`:
- Around line 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.

In `@src/bill/BillReversesId.php`:
- Around line 9-19: The getId(): int return type is incompatible with the
protected $id (int|null) and the public __construct($id = null); either make the
return nullable by changing getId(): ?int to reflect the property, or prevent
null construction by making __construct private and add a static factory like
fromInt(int $id): self that sets $this->id; locate the class BillReversesId, the
$id property, the __construct and getId methods and apply one of these two fixes
consistently so types no longer conflict.

---

Nitpick comments:
In `@src/bill/Bill.php`:
- Around line 260-268: The class exposes mutation for $reversesId via
setReversesId but has getters getSource() and getTxn() without corresponding
setters, creating an asymmetric API; either add setters setSource(BillSource
$source): void and setTxn(BillTxn $txn): void (or nullable variants) to mirror
setReversesId, or if immutability for source/txn is intentional, add a concise
inline comment near the properties and the getSource()/getTxn() methods
explaining that only reversesId is mutable post-construction and why
(referencing $reversesId, setReversesId, $source, getSource, $txn, getTxn).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 573f51d and 38f51dd.

📒 Files selected for processing (3)
  • src/bill/Bill.php
  • src/bill/BillInterface.php
  • src/bill/BillReversesId.php

Comment on lines +290 to +297
/**
* @param BillReversesId|null $reversesId
* @return void
*/
public function setReversesId($reversesId): void
{
$this->reversesId = $reversesId;
}
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.

Comment on lines +9 to +19
/** @var int|null */
protected $id;

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

public function getId(): int
{
return $this->id;
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.

⚠️ Potential issue | 🔴 Critical

getId(): int will throw TypeError when $id is null

The property is documented as int|null and the constructor defaults $id to null, so any instance created via new BillReversesId() or new BillReversesId(null) will throw a TypeError when getId() is called under declare(strict_types=1). The docblock and return type are contradictory.

Either make the return type nullable to match the property, or restrict the constructor so a null instance cannot be created:

🐛 Option A — fix the return type to match the nullable property
-    public function getId(): int
+    public function getId(): ?int
     {
         return $this->id;
     }
🐛 Option B — restrict construction to the typed factory only
-    public function __construct($id = null)
+    private function __construct(int $id)
     {
         $this->id = $id;
     }

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

With a private constructor, callers are forced through fromInt(int $id) and a null state becomes impossible.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/** @var int|null */
protected $id;
public function __construct($id = null)
{
$this->id = $id;
}
public function getId(): int
{
return $this->id;
/** `@var` int|null */
protected $id;
public function __construct($id = null)
{
$this->id = $id;
}
public function getId(): ?int
{
return $this->id;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bill/BillReversesId.php` around lines 9 - 19, The getId(): int return
type is incompatible with the protected $id (int|null) and the public
__construct($id = null); either make the return nullable by changing getId():
?int to reflect the property, or prevent null construction by making __construct
private and add a static factory like fromInt(int $id): self that sets
$this->id; locate the class BillReversesId, the $id property, the __construct
and getId methods and apply one of these two fixes consistently so types no
longer conflict.

…ed, the explicit nullable type must be used instead" deprecation warning in Bill
…ed, the explicit nullable type must be used instead" deprecation warning in batch of classes
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/plan/Plan.php (1)

63-63: Consider adding explicit type hint for $parent_id parameter.

The $parent_id parameter lacks a type hint, but the property on line 35 is declared as ?int. For consistency with the other nullable parameters being updated in this PR, consider adding the type hint:

♻️ Suggested improvement
-        $parent_id = null
+        ?int $parent_id = null
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plan/Plan.php` at line 63, The $parent_id parameter in the Plan class
signature is missing a type hint while the corresponding property is declared as
?int; update the method/constructor declaration that currently has "$parent_id =
null" to explicitly type it as "?int $parent_id = null" (in the Plan class where
$parent_id is declared) so it matches the property type and other nullable
parameters in this PR; ensure any callers remain compatible with the new
nullable int hint.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/plan/Plan.php`:
- Line 63: The $parent_id parameter in the Plan class signature is missing a
type hint while the corresponding property is declared as ?int; update the
method/constructor declaration that currently has "$parent_id = null" to
explicitly type it as "?int $parent_id = null" (in the Plan class where
$parent_id is declared) so it matches the property type and other nullable
parameters in this PR; ensure any callers remain compatible with the new
nullable int hint.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 30e87f7b-ed9d-424f-ae55-a3b51ee48fda

📥 Commits

Reviewing files that changed from the base of the PR and between 38ed9c9 and e8a0032.

📒 Files selected for processing (6)
  • src/action/AbstractAction.php
  • src/charge/Charge.php
  • src/customer/Customer.php
  • src/plan/Plan.php
  • src/price/AbstractPrice.php
  • src/product/price/PriceTypeDefinitionCollection.php
✅ Files skipped from review due to trivial changes (3)
  • src/price/AbstractPrice.php
  • src/action/AbstractAction.php
  • src/product/price/PriceTypeDefinitionCollection.php

…ed, the explicit nullable type must be used instead" deprecation warning in SinglePrice
…ed, the explicit nullable type must be used instead" deprecation warning in BillSource
…ameter $price is implicitly treated as a required parameter" deprecation warning in SinglePrice
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant