Skip to content

Conversation

@nandkishorr
Copy link
Contributor

@nandkishorr nandkishorr commented Nov 7, 2025

Proposed Changes

  • Added validation for amount and factor in sync_charge_item_costs helper function

Merge Checklist

  • Tests added/fixed
  • Update docs in /docs
  • Linting Complete
  • Any other necessary step

Only PR's with test cases included and passing lint and test pipelines will be reviewed

@ohcnetwork/care-backend-maintainers @ohcnetwork/care-backend-admins

Summary by CodeRabbit

  • Bug Fixes
    • Strengthened validation for discounts and charge item costs: negative amounts and discounts exceeding the net price are rejected with clear errors.
    • Enforced discount factor range (1–100).
    • Validation now runs before applying discounts to prevent invalid entries affecting total cost calculations.
    • Prevents downstream issues and ensures accurate final totals.

✏️ Tip: You can customize this high-level summary in your review settings.

@nandkishorr nandkishorr requested a review from a team as a code owner November 7, 2025 12:00
@nandkishorr nandkishorr self-assigned this Nov 7, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 7, 2025

📝 Walkthrough

Walkthrough

Single-file change adding validation inside the discount handling loop of sync_charge_item_costs.py: checks that discount amounts are not negative or greater than current net price, and that discount factors are between 1 and 100; raises ValidationError on violations before computing/applying the discount.

Changes

Cohort / File(s) Summary
Discount validation in charge item cost sync
care/emr/resources/charge_item/sync_charge_item_costs.py
Introduced validation checks inside the discount-processing loop: if component.amount is negative or greater than the current net_price, a ValidationError is raised; if component.factor is provided and not within 1–100, a ValidationError is raised. After validation, discount amount is determined (using existing calculate_amount logic when needed), total_price is reduced, and the discount component is recorded. No public signatures changed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Pay attention to the discount loop where validations were added.
  • Check boundary cases for factor values 1 and 100 and for amount equal to net_price.
  • Verify ValidationError messages/context match calling code expectations (so nothing breaks quietly).

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description includes proposed changes and merge checklist, but is missing the 'Associated Issue' section and lacks detail about what validation was added. Consider adding the 'Associated Issue' section referencing PR #3350, and expand 'Proposed Changes' to specify the validation rules (e.g., discount amount cannot be negative, must not exceed net price, factor must be 1-100).
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Added validation for sync charge item costs' directly matches the main change: validation checks for discount amount and factor in the sync_charge_item_costs function.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch nandkishorr/fix/chargeitem_validation

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 754e508 and 815d873.

📒 Files selected for processing (1)
  • care/emr/resources/charge_item/sync_charge_item_costs.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursorrules)

**/*.py: Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance).
Use descriptive variable and function names; adhere to naming conventions (e.g., lowercase with underscores for functions and variables).

Files:

  • care/emr/resources/charge_item/sync_charge_item_costs.py
🪛 Ruff (0.14.5)
care/emr/resources/charge_item/sync_charge_item_costs.py

43-43: Avoid specifying long messages outside the exception class

(TRY003)


45-47: Avoid specifying long messages outside the exception class

(TRY003)


49-49: Unused noqa directive (non-enabled: PLR2004)

Remove unused noqa directive

(RUF100)


51-51: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test / Test

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 (2)
care/emr/resources/charge_item/sync_charge_item_costs.py (2)

11-14: Consider defining error messages as constants.

The static analysis tool suggests avoiding inline exception messages. While not critical, defining these messages as module-level constants or custom exception classes would improve maintainability and consistency, especially if these messages need to be referenced elsewhere.

Example refactor:

# At module level
ERROR_AMOUNT_NEGATIVE = "Amount cannot be negative"
ERROR_AMOUNT_EXCEEDS_BASE = "Amount cannot be more than base amount"
ERROR_FACTOR_OUT_OF_RANGE = "Factor must be between 1 and 100"

def calculate_amount(component, quantity, base):
    if component.amount:
        if component.amount < 0:
            raise ValidationError(ERROR_AMOUNT_NEGATIVE)
        if component.amount > base:
            raise ValidationError(ERROR_AMOUNT_EXCEEDS_BASE)
        # ... rest of the logic

Also applies to: 18-20


26-59: Consider adding validation for quantity and base amount.

While the new validations for surcharge/discount/tax components are helpful, there's no validation for quantity (line 31) or the base component.amount (line 37). Negative or zero quantities could lead to unexpected behavior in the calculations.

Would you like me to suggest validation logic for these parameters as well?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fefde08 and 754e508.

📒 Files selected for processing (1)
  • care/emr/resources/charge_item/sync_charge_item_costs.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursorrules)

**/*.py: Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance).
Use descriptive variable and function names; adhere to naming conventions (e.g., lowercase with underscores for functions and variables).

Files:

  • care/emr/resources/charge_item/sync_charge_item_costs.py
🪛 Ruff (0.14.3)
care/emr/resources/charge_item/sync_charge_item_costs.py

12-12: Avoid specifying long messages outside the exception class

(TRY003)


14-14: Avoid specifying long messages outside the exception class

(TRY003)


20-20: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test / Test

Comment on lines 11 to 14
if component.amount < 0:
raise ValidationError("Amount cannot be negative")
if component.amount > base:
raise ValidationError("Amount cannot be more than base amount")
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

🧩 Analysis chain

Verify the amount validation logic.

The validation at line 13 compares component.amount (unit amount, before multiplication) against base (which is the total base amount after quantity multiplication from line 39). This means you're comparing a unit price to a total price, which seems inconsistent.

For example, if base unit = 100, quantity = 10 (so base = 1000), and component.amount = 150, the validation would fail even though the intent might be to ensure the computed total component amount (150 × 10 = 1500) doesn't exceed some threshold. Please clarify whether you intended to compare unit amounts or validate the final computed amount instead.

Run the following to check how this validation behaves with actual test cases:


🏁 Script executed:

#!/bin/bash
# Description: Search for test cases or usage examples of calculate_amount to understand expected behavior

rg -n -C5 'calculate_amount|sync_charge_item_costs' --type=py -g '!care/emr/resources/charge_item/sync_charge_item_costs.py'

Length of output: 5548



---

🏁 Script executed:

```shell
#!/bin/bash
# Get full file to understand the context of base and component.amount values

cat care/emr/resources/charge_item/sync_charge_item_costs.py

Length of output: 2719



---

🏁 Script executed:

```shell
#!/bin/bash
# Check the test file for any test cases that exercise calculate_amount logic

rg -n -A 20 'test_sync_charge_item_costs_called' care/emr/tests/test_charge_item_api.py

Length of output: 783


Fix the unit vs. total comparison in amount validation at lines 11–14.

The validation compares component.amount (a unit amount, not yet multiplied by quantity at line 15) against base (which is already the total amount after multiplication at line 39). When calculate_amount is called for surcharge/discount/tax components (lines 43, 48, 52), this means you're comparing apples to oranges.

For example: if the base unit is 100 with quantity 10 (total base = 1,000) and a surcharge unit is 500, the validation passes (500 ≤ 1,000), but the computed surcharge becomes 500 × 10 = 5,000, which far exceeds the base. Either validate the final computed amount (unit × quantity) or adjust the comparison logic to be unit-to-unit.

🧰 Tools
🪛 Ruff (0.14.3)

12-12: Avoid specifying long messages outside the exception class

(TRY003)


14-14: Avoid specifying long messages outside the exception class

(TRY003)

🤖 Prompt for AI Agents
In care/emr/resources/charge_item/sync_charge_item_costs.py around lines 11–14,
the validation incorrectly compares component.amount (a per-unit value) to base
(a total already multiplied by quantity). Fix by validating the same units:
either compute the component total (component.amount * quantity) and compare
that to base, or compute the base per-unit (base / quantity) and compare
component.amount to that per-unit base; update the error messages accordingly
and ensure quantity is available/used in the check.

@codecov
Copy link

codecov bot commented Nov 7, 2025

Codecov Report

❌ Patch coverage is 0% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.85%. Comparing base (e0b163e) to head (815d873).

Files with missing lines Patch % Lines
...mr/resources/charge_item/sync_charge_item_costs.py 0.00% 6 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3350      +/-   ##
===========================================
- Coverage    73.88%   73.85%   -0.03%     
===========================================
  Files          435      435              
  Lines        19760    19766       +6     
  Branches      2143     2146       +3     
===========================================
  Hits         14599    14599              
- Misses        4715     4721       +6     
  Partials       446      446              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

if component.factor:
component.amount = base * component.factor / 100
max_factor = 100
if component.factor < 1 or component.factor > max_factor:
Copy link
Member

Choose a reason for hiding this comment

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

Factor can be any number, surcharges can be more than 100% and surcharges can be negative as well, remove this validation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants