Skip to content

Comments

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

Open
VadymHrechukha wants to merge 2 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 2 commits intohiqdev:masterfrom
VadymHrechukha:HP-2883_implement_business_central_bills_import_service

Conversation

@VadymHrechukha
Copy link
Collaborator

@VadymHrechukha VadymHrechukha commented Feb 4, 2026

Summary by CodeRabbit

  • New Features
    • Billing records can now include and retrieve source information for better bill origin tracking.
    • Added support for external payment transaction identifiers to enhance reconciliation and transaction management.
    • Added support for linking reversal references to bills and corresponding accessors for these new fields.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

Adds three new value objects (BillSource, BillTxn, BillReversesId) and extends Bill and BillInterface to store and expose optional source, txn, and reversesId fields, including constructor wiring and accessors (plus a setter for reversesId).

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 BillSource $source = null, BillTxn $txn = null, BillReversesId $reversesId = null; added getters getSource(): ?BillSource, getTxn(): ?BillTxn, getReversesId(): ?BillReversesId and setter setReversesId($reversesId): void; interface extended with the three getter declarations.
New value objects
src/bill/BillSource.php, src/bill/BillTxn.php, src/bill/BillReversesId.php
Added BillSource (id, name, getters), BillTxn (value holder, fromString() factory), and BillReversesId (id holder, fromInt() factory) as simple immutable/value-object classes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • SilverFire

Poem

🐰
I nibble code and plant a seed,
New fields hop in with gentle speed,
Source and txn and reverse id too,
They hop together—fresh and new! 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title references a Business Central bills import service feature (HP-2883), but the changeset only adds properties and accessors to the Bill class and introduces new value objects (BillSource, BillTxn, BillReversesId). No import service implementation is present in the changes. Update the title to reflect the actual changes, such as 'HP-2883: Add Bill properties and value objects for Business Central integration' or similar, accurately describing the data model enhancements being introduced.
Docstring Coverage ⚠️ Warning Docstring coverage is 4.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
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
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
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.

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