Skip to content

Conversation

@sr-rolando
Copy link

@sr-rolando sr-rolando commented Jan 3, 2026

Add 'Purchase Price per Month' to an item's details.

What type of PR is this?

  • feature

What this PR does / why we need it:

  • Add field 'Purchase Price per Month' to an item.
  • Value is calculated based on purchase price and age of item.
  • If item has no age (i.e. no purchase time), the purchase price per month equals the purchase price.

Which issue(s) this PR fixes:

None. (Can surely create one if so required.)

Special notes for your reviewer:

  • Value of the field 'purchase price per month' is calculated in the backend (i.e. backend/iternal/data/repo/repo_items.go).

Testing

  • Interactively checked the item details view.

Summary by CodeRabbit

  • New Features

    • Added "Purchase Price per Month" metric to item details (displayed as currency).
  • API

    • Item output now includes a purchasePricePerMonth field in the public data contract.
  • Localization

    • English locale updated with a label for "Purchase Price per Month".

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 3, 2026

Walkthrough

Backend now includes a calculated PurchasePricePerMonth on item responses; frontend types, locale, and the item details view were updated to accept and render this new monthly purchase-price field.

Changes

Cohort / File(s) Summary
Backend: item mapping
backend/internal/data/repo/repo_items.go
Added exported field PurchasePricePerMonth float64 to ItemOut, introduced countMonths(start, end time.Time) int, and populate PurchasePricePerMonth in mapItemOut (fallback to PurchasePrice when months ≤ 0 or purchase time missing).
Frontend: API types
frontend/lib/api/types/data-contracts.ts
Added purchasePricePerMonth: number to the ItemOut interface to match backend responses.
Frontend: i18n
frontend/locales/en.json
Added items.edit_details.purchase_price_per_month: "Purchase Price per Month".
Frontend: item page
frontend/pages/item/[id]/index.vue
Added a detail entry rendering purchasePricePerMonth as a currency field in the item purchase details array.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • tankerkiller125
  • tonyaellie

Security Recommendations

  • Guard against division-by-zero or non-positive month counts when computing monthly price; ensure backend defaults to PurchasePrice or zero when months ≤ 0.
  • Validate incoming PurchaseTime values (future dates) and sanitize before computing months.
  • Ensure monetary values are serialized with appropriate precision/rounding to avoid client-side surprises.
  • Add unit tests covering edge cases: missing purchase time, same-day purchases, future purchase timestamps, and very large durations.

Poem

A monthly figure joins the stream,
From repo to the UI's beam,
Labeled, typed, and neatly shown,
A new small field to call our own,
Numbers lined up, steady and clean. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the main change: adding a 'Purchase Price per Month' field to item details.
Description check ✅ Passed The PR description includes all required sections: PR type (feature), what it does with rationale, issue references, and testing notes. Structure is complete and informative.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 677c025 and 40f67aa.

📒 Files selected for processing (1)
  • backend/internal/data/repo/repo_items.go
🧰 Additional context used
📓 Path-based instructions (1)
backend/**/*.go

📄 CodeRabbit inference engine (.github/instructions/code.instructions.md)

Backend Go code must pass golangci-lint validation with no errors (6-minute timeout in CI)

Files:

  • backend/internal/data/repo/repo_items.go
🧠 Learnings (1)
📚 Learning: 2025-12-29T16:29:27.462Z
Learnt from: CR
Repo: sysadminsmedia/homebox PR: 0
File: .github/instructions/backend-internal-data.instructions.md:0-0
Timestamp: 2025-12-29T16:29:27.462Z
Learning: Use the Repository pattern for data access in `repo/` implementations with structured repository struct, input types (e.g., `ItemCreate`), output types (e.g., `ItemOut`), query types (e.g., `ItemQuery`), and mapper functions (e.g., `mapToItemOut`)

Applied to files:

  • backend/internal/data/repo/repo_items.go
🧬 Code graph analysis (1)
backend/internal/data/repo/repo_items.go (1)
backend/internal/data/types/date.go (2)
  • Date (19-19)
  • DateFromTime (27-30)
⏰ 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). (15)
  • GitHub Check: build (linux/amd64, ubuntu-latest)
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 3/4
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 2/4
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 1/4
  • GitHub Check: Frontend Tests / Integration Tests
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 16
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 17
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 4/4
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 15
  • GitHub Check: build (linux/arm64, ubuntu-24.04-arm)
  • GitHub Check: build (linux/arm64, ubuntu-24.04-arm)
  • GitHub Check: build (linux/amd64, ubuntu-latest)
  • GitHub Check: Backend Server Tests / Go
  • GitHub Check: build (linux/arm64, ubuntu-24.04-arm)
  • GitHub Check: build (linux/amd64, ubuntu-latest)
🔇 Additional comments (4)
backend/internal/data/repo/repo_items.go (4)

173-175: LGTM: New field properly integrated into ItemOut struct.

The PurchasePricePerMonth field is correctly typed as float64 (consistent with PurchasePrice) and appropriately placed within the Purchase section of the struct.


269-287: Excellent edge case handling in countMonths!

The function now properly addresses all concerns from previous reviews:

Negative time ranges: Lines 272-274 guard against start.After(end) by returning 0
Non-negative guarantee: Lines 283-285 provide a safety net ensuring totalMonths >= 0
Partial month adjustment: Lines 279-281 correctly handle cases where the end day precedes the start day within a month

The logic for calculating complete months is correct and robust.


306-314: Division by zero issue resolved!

The critical issue flagged in previous reviews has been properly fixed. Line 310 now guards against division by zero by checking months <= 0 before performing the division on line 313.

The fallback behavior (setting pppm = item.PurchasePrice for items with no age or age < 1 month) is semantically appropriate and prevents runtime errors.


331-333: Field assignment looks good.

The calculated PurchasePricePerMonth value is properly assigned to the ItemOut struct alongside the existing purchase-related fields, maintaining consistency with the established pattern.


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

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10ce256 and e1030ab.

⛔ Files ignored due to path filters (1)
  • backend/internal/data/ent/item.go is excluded by !backend/internal/data/ent/**
📒 Files selected for processing (4)
  • backend/internal/data/repo/repo_items.go
  • frontend/lib/api/types/data-contracts.ts
  • frontend/locales/en.json
  • frontend/pages/item/[id]/index.vue
🧰 Additional context used
📓 Path-based instructions (10)
frontend/**/*.{ts,tsx,vue,js,jsx}

📄 CodeRabbit inference engine (.github/instructions/code.instructions.md)

Frontend TypeScript/Vue code must pass ESLint with a maximum of 1 warning in CI (pnpm run lint:ci)

Files:

  • frontend/pages/item/[id]/index.vue
  • frontend/lib/api/types/data-contracts.ts
frontend/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (.github/instructions/code.instructions.md)

Frontend code must pass TypeScript type checking with task ui:check before PR submission

Files:

  • frontend/pages/item/[id]/index.vue
  • frontend/lib/api/types/data-contracts.ts
frontend/pages/**/*.vue

📄 CodeRabbit inference engine (.github/instructions/code.instructions.md)

Page components must use file-based routing conventions in frontend/pages/ directory

Pages in pages/ automatically become routes via file-based routing. Use square brackets for dynamic segments (e.g., [id].vue for :id route parameter)

Files:

  • frontend/pages/item/[id]/index.vue
frontend/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (.github/instructions/code.instructions.md)

Use Tailwind CSS utility classes for styling in Vue components instead of custom CSS

Files:

  • frontend/pages/item/[id]/index.vue
  • frontend/lib/api/types/data-contracts.ts
frontend/{components,pages,layouts}/**/*.vue

📄 CodeRabbit inference engine (.github/instructions/frontend.instructions.md)

frontend/{components,pages,layouts}/**/*.vue: Use <script setup lang="ts"> for all Vue component files with TypeScript
Use Tailwind CSS for styling Vue components

Files:

  • frontend/pages/item/[id]/index.vue
frontend/{components,pages,composables}/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/instructions/frontend.instructions.md)

frontend/{components,pages,composables}/**/*.{vue,ts}: Use useUserApi() composable for all API calls - provides typed, authenticated API client access
Use TypeScript types from lib/api/types/data-contracts.ts for API request/response objects (e.g., ItemCreate, ItemOut)

Files:

  • frontend/pages/item/[id]/index.vue
frontend/{components,pages}/**/*.vue

📄 CodeRabbit inference engine (.github/instructions/frontend.instructions.md)

frontend/{components,pages}/**/*.vue: Use Shadcn-vue UI components from components/ui/ for common UI elements
Use Pinia stores from stores/ for global state management (auth, preferences, etc.)

Files:

  • frontend/pages/item/[id]/index.vue
**/*.{ts,vue}

⚙️ CodeRabbit configuration file

**/*.{ts,vue}: Check for hardcoded strings in UI components that should be translatable.
Look for:

  • String literals in Vue components (e.g. Click me)
  • Alert messages, error messages, and user-facing text
  • Placeholder text and labels

Files:

  • frontend/pages/item/[id]/index.vue
  • frontend/lib/api/types/data-contracts.ts
frontend/lib/api/types/**/*.ts

📄 CodeRabbit inference engine (.github/instructions/code.instructions.md)

Never manually edit generated TypeScript API types in frontend/lib/api/types/; these are auto-generated from the backend and should be regenerated using task generate

Never edit generated types in lib/api/types/ - they are auto-generated from backend Swagger docs. Run task generate after backend API changes to regenerate

Files:

  • frontend/lib/api/types/data-contracts.ts
backend/**/*.go

📄 CodeRabbit inference engine (.github/instructions/code.instructions.md)

Backend Go code must pass golangci-lint validation with no errors (6-minute timeout in CI)

Files:

  • backend/internal/data/repo/repo_items.go
🧠 Learnings (2)
📚 Learning: 2025-12-29T16:30:10.230Z
Learnt from: CR
Repo: sysadminsmedia/homebox PR: 0
File: .github/instructions/frontend.instructions.md:0-0
Timestamp: 2025-12-29T16:30:10.230Z
Learning: Applies to frontend/{components,pages,composables}/**/*.{vue,ts} : Use TypeScript types from `lib/api/types/data-contracts.ts` for API request/response objects (e.g., `ItemCreate`, `ItemOut`)

Applied to files:

  • frontend/lib/api/types/data-contracts.ts
📚 Learning: 2025-12-29T16:29:27.462Z
Learnt from: CR
Repo: sysadminsmedia/homebox PR: 0
File: .github/instructions/backend-internal-data.instructions.md:0-0
Timestamp: 2025-12-29T16:29:27.462Z
Learning: Use the Repository pattern for data access in `repo/` implementations with structured repository struct, input types (e.g., `ItemCreate`), output types (e.g., `ItemOut`), query types (e.g., `ItemQuery`), and mapper functions (e.g., `mapToItemOut`)

Applied to files:

  • backend/internal/data/repo/repo_items.go
🧬 Code graph analysis (1)
backend/internal/data/repo/repo_items.go (1)
backend/internal/data/types/date.go (1)
  • Date (19-19)
⏰ 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). (15)
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 4/4
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 17
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 1/4
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 15
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 3/4
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 16
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 2/4
  • GitHub Check: Backend Server Tests / Go
  • GitHub Check: Frontend Tests / Integration Tests
  • GitHub Check: build (linux/arm64, ubuntu-24.04-arm)
  • GitHub Check: build (linux/amd64, ubuntu-latest)
  • GitHub Check: build (linux/amd64, ubuntu-latest)
  • GitHub Check: build (linux/arm64, ubuntu-24.04-arm)
  • GitHub Check: build (linux/arm64, ubuntu-24.04-arm)
  • GitHub Check: build (linux/amd64, ubuntu-latest)
🔇 Additional comments (5)
frontend/locales/en.json (1)

460-460: LGTM! Translation key properly placed.

The new translation key follows naming conventions and is logically positioned adjacent to the existing purchase_price entry.

frontend/pages/item/[id]/index.vue (1)

384-388: Implementation looks correct.

The new purchasePricePerMonth detail entry follows the same pattern as existing currency fields and properly integrates with the translation system and empty-value filtering.

Note: If purchasePricePerMonth is legitimately 0 (e.g., for an item purchased at no cost), it will be filtered out when preferences.showEmpty is false due to the filterZeroValues call at line 398. This behavior is consistent with other numeric fields but may hide valid zero values.

backend/internal/data/repo/repo_items.go (2)

173-175: LGTM! ItemOut struct properly extended.

The new PurchasePricePerMonth field is correctly typed as float64 and properly placed within the Purchase section with the appropriate JSON tag.


324-324: Assignment correct, but depends on fixing the calculation.

The assignment of pppm to PurchasePricePerMonth is correct. However, this depends on fixing the division by zero issue in the calculation logic at lines 298-305.

frontend/lib/api/types/data-contracts.ts (1)

654-654: This file was auto-generated; confirm regeneration occurred via task generate.

The purchasePricePerMonth: number field is correctly added to the response type as a read-only, calculated field (derived as purchasePrice / monthsSincePurchase). It appears only in the ItemOut response contract and is not present in ItemCreate/ItemUpdate input contracts, which is the correct structure. The file header confirms auto-generation via swagger-typescript-api, and the field aligns properly with the backend implementation where it's calculated at query time, not persisted. Ensure task generate was run after backend schema modifications to regenerate this contract.

@tankerkiller125
Copy link
Contributor

What is this trying to solve?? Sorry but I'm a bit confused on what exact situation this is trying to solve in the real world? Is it deprecating assets? Some weird subscription based hardware? I'm just not entirely sure what this solution is trying to solve.

@sr-rolando
Copy link
Author

What is this trying to solve?? Sorry but I'm a bit confused on what exact situation this is trying to solve in the real world? Is it deprecating assets? Some weird subscription based hardware? I'm just not entirely sure what this solution is trying to solve.

Valid question. The intention is indeed similar to deprecating assets. It's simply serving the curiosity on how much an item actually costs per month, especially when viewed over time.

A clear value add would be in calculating on TOC, i.e. including any maintenance & costs of supply parts.

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.

2 participants