Skip to content

chore: invoice updated#237

Merged
hmbanan666 merged 1 commit intomainfrom
invoice-update
Oct 21, 2025
Merged

chore: invoice updated#237
hmbanan666 merged 1 commit intomainfrom
invoice-update

Conversation

@hmbanan666
Copy link
Copy Markdown
Collaborator

@hmbanan666 hmbanan666 commented Oct 21, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added three new invoice types: lump sum fees, marketing fees, and Rospatent fees.
    • Invoice cards now display creation timestamps with date formatting.
  • Improvements

    • Invoices now appear in reverse-chronological order (newest first).
    • Updated status badge color styling for better visual consistency.
    • Invoice descriptions display only when present.
    • Enhanced partner balance calculation for replenishment invoices.

@hmbanan666 hmbanan666 self-assigned this Oct 21, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 21, 2025

Walkthrough

The changes expand supported invoice types from three to six values, add timestamps and descriptions to invoice displays, centralize invoice type options through a helper function, update form components to use the centralized helper, and refine balance calculation logic for replenishment invoices.

Changes

Cohort / File(s) Summary
Type definitions and helper functions
packages/database/src/types/entities.ts, apps/web-app/shared/utils/helpers.ts
Expanded InvoiceType union to include lump_sum_fee, marketing_fee, and rospatent_fee alongside existing replenishment, royalties, and other. Added getInvoiceTypeForSelect() helper to return invoice type options as static array for form selects.
Invoice UI display component
apps/web-app/app/components/InvoiceCard.vue
Added invoice creation timestamp display formatted with date-fns in Russian locale; conditionally render invoice description when present; updated icon styling for banknote-arrow-up; mapped new invoice types to Russian labels; extended status-label mapping with default fallback.
Invoice form components
apps/web-app/app/components/form/CreateInvoice.vue, apps/web-app/app/components/form/UpdateInvoice.vue
Replaced hard-coded type option arrays with dynamic calls to getInvoiceTypeForSelect() helper to provide form select options.
Invoice page component
apps/web-app/app/pages/partner/[id]/invoice.vue
Added computed invoices property that sorts partner invoices by createdAt in descending order using toSorted; replaced activeInvoices data source with invoices for rendering.
Invoice service logic
apps/web-app/server/services/invoice.ts
Modified balance calculation: replenishment invoices now only add to balance when paid status; all non-replenishment invoice types subtract from balance via single default path instead of separate branches.

Sequence Diagram

sequenceDiagram
    participant Component as Invoice Component
    participant Helper as getInvoiceTypeForSelect()
    participant Service as Invoice Service
    participant DB as Database

    Component->>Helper: Request invoice type options
    Helper-->>Component: Return array of type-label mappings
    Component->>Component: Render form select with options
    
    Note over Service: Balance Calculation Flow
    Service->>DB: Fetch partner invoices
    DB-->>Service: Return invoices
    
    loop For each invoice
        alt Replenishment type
            alt Status is paid
                Service->>Service: Add to balance
            else Not paid
                Service->>Service: Skip (no change)
            end
        else Other types
            Service->>Service: Subtract from balance
        end
    end
    
    Service-->>Component: Return calculated balance
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The changes span six files with mixed complexity: UI updates to InvoiceCard with new display logic and extended type mappings require careful review; service logic changes to balance calculation affect financial calculations; form refactoring to use centralized helper is straightforward. Type expansion is simple but affects multiple components. The heterogeneous nature of changes across display, form, service, and type layers warrants moderate review effort.

Possibly related PRs

Poem

🐰 Six types now dance where three once stood,
With timestamps bright and labels good,
Balance calculated, forms set free,
The invoice system's harmony! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The pull request title "chore: invoice updated" is vague and generic, using the non-descriptive term "updated" that fails to communicate the actual scope and nature of the changes. While the title is technically related to the changeset (the changes do involve invoices), it provides no meaningful information about what was specifically updated. A teammate scanning the commit history would not understand whether this is a minor bug fix, a refactoring effort, or a feature addition that includes new invoice types, UI modifications, business logic changes, and public API updates. The title should be more specific and descriptive. Consider revising it to reflect the main objective, such as "refactor: add new invoice types and update balance calculation logic" or "feat: support additional invoice types (lump_sum_fee, marketing_fee, rospatent_fee)" to clearly communicate the primary changes to reviewers and future developers reviewing the history.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 invoice-update

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.

@sonarqubecloud
Copy link
Copy Markdown

@hmbanan666 hmbanan666 merged commit 7a9c357 into main Oct 21, 2025
7 of 8 checks passed
@hmbanan666 hmbanan666 deleted the invoice-update branch October 21, 2025 10:51
Copy link
Copy Markdown

@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: 3

🧹 Nitpick comments (5)
apps/web-app/shared/utils/helpers.ts (1)

4-13: Type the helper return to InvoiceType, and consider reusing a shared const array

Add an explicit return type so TS enforces only valid InvoiceType values. Also consider exporting a const array and returning it to avoid reallocating on each call.

Apply this minimal typing change:

-export function getInvoiceTypeForSelect() {
+export function getInvoiceTypeForSelect(): { label: string; value: InvoiceType }[] {

And (outside this hunk), import the type and optionally cache the options:

// add near the top
import type { InvoiceType } from '@roll-stack/database'

// optional: cache
export const INVOICE_TYPE_OPTIONS: ReadonlyArray<{ label: string; value: InvoiceType }> = [
  { label: 'Оплата роялти', value: 'royalties' },
  { label: 'Паушальный взнос', value: 'lump_sum_fee' },
  { label: 'Маркетинговый сбор', value: 'marketing_fee' },
  { label: 'Роспатент', value: 'rospatent_fee' },
  { label: 'Пополнение', value: 'replenishment' },
  { label: 'Другое', value: 'other' },
] as const

export function getInvoiceTypeForSelect(): ReadonlyArray<{ label: string; value: InvoiceType }> {
  return INVOICE_TYPE_OPTIONS
}
apps/web-app/app/components/form/CreateInvoice.vue (1)

34-34: Avoid recreating options on every render

Hoist the items to a const so the array isn’t rebuilt each render; reduces churn in USelect.

Template:

-        :items="getInvoiceTypeForSelect()"
+        :items="invoiceTypeItems"

Script (outside this hunk):

const invoiceTypeItems = getInvoiceTypeForSelect()
apps/web-app/app/components/form/UpdateInvoice.vue (1)

51-51: Hoist select options to avoid per-render allocations

Mirror CreateInvoice.vue: compute once.

Template:

-        :items="getInvoiceTypeForSelect()"
+        :items="invoiceTypeItems"

Script (outside this hunk):

const invoiceTypeItems = getInvoiceTypeForSelect()
apps/web-app/app/components/InvoiceCard.vue (2)

68-77: Deduplicate type label mapping; derive from a single source

Type labels here can drift from getInvoiceTypeForSelect(). Centralize via a shared label map/helper and reuse in both places.

Example (in helpers.ts):

export const invoiceTypeLabelMap: Record<Invoice['type'], string> = {
  replenishment: 'Пополнение',
  royalties: 'Роялти',
  lump_sum_fee: 'Паушальный взнос',
  marketing_fee: 'Маркетинговый сбор',
  rospatent_fee: 'Роспатент',
  other: 'Другое',
}
export const getInvoiceTypeLabel = (t: Invoice['type']) => invoiceTypeLabelMap[t] ?? 'Другое'

Then here:

function getInfoByType(type: Invoice['type']) {
  return getInvoiceTypeLabel(type)
}

17-19: Guard formatting if createdAt can be null/invalid

If any legacy invoices lack createdAt, render a fallback to avoid Invalid Date.

<div class="text-sm/4 text-muted">
  {{ invoice.createdAt ? `Создан ${format(new Date(invoice.createdAt), 'd MMMM в HH:mm', { locale: ru })}` : 'Дата неизвестна' }}
</div>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f80cf5b and d8cfd0d.

📒 Files selected for processing (7)
  • apps/web-app/app/components/InvoiceCard.vue (7 hunks)
  • apps/web-app/app/components/form/CreateInvoice.vue (2 hunks)
  • apps/web-app/app/components/form/UpdateInvoice.vue (2 hunks)
  • apps/web-app/app/pages/partner/[id]/invoice.vue (2 hunks)
  • apps/web-app/server/services/invoice.ts (1 hunks)
  • apps/web-app/shared/utils/helpers.ts (1 hunks)
  • packages/database/src/types/entities.ts (1 hunks)
⏰ 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: build
🔇 Additional comments (1)
apps/web-app/server/services/invoice.ts (1)

8-13: Confirm business rule: subtract all non‑replenishment invoices regardless of status

Current logic:

  • Replenishment: add only when status === 'paid'.
  • All others: always subtract.

Is it intended that unpaid expense invoices reduce balance immediately (i.e., balance reflects liabilities), while unpaid replenishments don’t increase it? If yes, consider a brief comment and a unit test to lock this in. If not, gate the subtraction on status.

If subtraction should apply only when unpaid:

-  // All other invoices
-  balance -= invoice.total
+  // All other invoices (count only unpaid as liability)
+  if (invoice.status === 'unpaid') {
+    balance -= invoice.total
+  }

Also applies to: 16-17

Comment on lines +55 to 57
import { format } from 'date-fns'
import { ru } from 'date-fns/locale/ru'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix date‑fns locale import to avoid runtime error

date-fns/locale/ru exports default, not a named ru. Use default import.

-import { format } from 'date-fns'
-import { ru } from 'date-fns/locale/ru'
+import { format } from 'date-fns'
+import ru from 'date-fns/locale/ru'
📝 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
import { format } from 'date-fns'
import { ru } from 'date-fns/locale/ru'
import { format } from 'date-fns'
import ru from 'date-fns/locale/ru'
🤖 Prompt for AI Agents
In apps/web-app/app/components/InvoiceCard.vue around lines 55 to 57, the
date-fns locale is imported as a named export (`{ ru }`) but date-fns/locale/ru
provides a default export; change the import to use the default (`import ru from
'date-fns/locale/ru'`) and update any references that expect a named `ru` to use
the default `ru` variable so the locale is passed correctly to format functions
to avoid the runtime error.


<InvoiceCard
v-for="invoice in activeInvoices"
v-for="invoice in invoices"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix potential crash and compatibility: optional chain + avoid toSorted

  • If partner is undefined, partner.value?.invoices.toSorted(...) calls toSorted on undefined → runtime error.
  • Array.prototype.toSorted is ES2023; SSR/runtime may not support it.

Use a safe fallback and compatible sort:

-const invoices = computed(() => partner.value?.invoices.toSorted((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()))
+const invoices = computed(() =>
+  (partner.value?.invoices ?? [])
+    .slice() // clone to avoid mutating store
+    .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()),
+)

Also applies to: 31-31

🤖 Prompt for AI Agents
In apps/web-app/app/pages/partner/[id]/invoice.vue around lines 7 and 31, the
current expressions call partner.value?.invoices.toSorted(...) which can throw
if partner or invoices is undefined and also uses the ES2023
Array.prototype.toSorted API which may not be available at SSR/runtime; change
both occurrences to safely fall back to an empty array and use a compatible sort
such as [...(partner.value?.invoices ?? [])].sort((a,b) => /* comparator */) or
(partner.value?.invoices ?? []).slice().sort((a,b) => /* comparator */) so you
never call methods on undefined and avoid toSorted. Ensure the comparator
replicates the original sort logic.

Comment on lines +100 to 106
export type InvoiceType = 'replenishment'
| 'royalties' // Роялти
| 'lump_sum_fee' // Паушальный взнос
| 'marketing_fee' // Маркетинговый сбор
| 'rospatent_fee' // Роспатент
| 'other'
export type InvoiceStatus = 'paid' | 'unpaid'
Copy link
Copy Markdown

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

Ensure validators/DB constraints accept the new InvoiceType values

With new literals added, please verify:

  • DB enum/check constraints (if any) and migrations include these values.
  • API/Zod/DTO validators and UI filters handle them.

Run to find hard‑coded checks that may need updates:


🏁 Script executed:

#!/bin/bash
# Find InvoiceType usages and literal comparisons
rg -nP -C2 "\bInvoiceType\b|invoice\.type\s*[!=]==?\s*['\"][a-z_]+['\"]|['\"](lump_sum_fee|marketing_fee|rospatent_fee)['\"]"

Length of output: 3466


🏁 Script executed:

#!/bin/bash
# Find DB migrations, enum definitions, and validators
echo "=== DB Migrations and Enum Definitions ==="
fd -t f -e sql -e ts -e js -path "*migration*" . 2>/dev/null | head -20

echo -e "\n=== Zod Validators and Schema Definitions ==="
rg -l "ZodType|z\.enum|z\.literal|validator|schema" --type=ts --type=js packages/ apps/ 2>/dev/null | grep -E "(validator|schema|zod)" | head -20

echo -e "\n=== Enum definitions in database package ==="
rg -nP "enum.*Invoice|InvoiceType.*=" packages/database/ --type=ts

echo -e "\n=== Check constraints in table definitions ==="
rg -nP -A2 -B2 "type.*varchar.*InvoiceType|\.check\(" packages/database/src/tables.ts

Length of output: 314


🏁 Script executed:

#!/bin/bash
# Find DB migrations, enum definitions, and validators
echo "=== DB Migrations and SQL Definitions ==="
find . -type f \( -name "*migration*" -o -name "*schema*" \) 2>/dev/null | head -20

echo -e "\n=== Zod Validators in packages ==="
rg -l "z\.enum|z\.literal|validator" --type=ts --type=js 2>/dev/null | grep -v node_modules | head -20

echo -e "\n=== Enum or const for InvoiceType ==="
rg -nP "(enum|const).*Invoice" --type=ts 2>/dev/null

echo -e "\n=== DB Table definition with check constraints ==="
rg -nP -A5 "invoices.*table|type.*varchar.*Invoice" packages/database/src/ --type=ts 2>/dev/null | head -30

Length of output: 3065


🏁 Script executed:

#!/bin/bash
# View the Zod schema definitions for invoices
echo "=== Zod Schema for createPartnerInvoiceSchema ==="
sed -n '55,75p' apps/web-app/shared/services/partner.ts

echo -e "\n=== Zod Schema for updatePartnerInvoiceSchema ==="
sed -n '64,80p' apps/web-app/shared/services/partner.ts

echo -e "\n=== Search for migrations in database package ==="
find packages/database -type f \( -name "*.sql" -o -name "*.ts" -o -name "*.js" \) 2>/dev/null | grep -i migrat

echo -e "\n=== Check for enum() or check constraints in tables.ts ==="
rg -nP "enum\(|\.check\(|values\(" packages/database/src/tables.ts

echo -e "\n=== Full context around invoice table definition ==="
sed -n '790,800p' packages/database/src/tables.ts

Length of output: 2324


🏁 Script executed:

#!/bin/bash
# Check if type() function has enum validation or if used with enum values
echo "=== Definition of type() helper function ==="
rg -nP "export.*const type|function type" apps/web-app/shared/ --type=ts | head -5

echo -e "\n=== Check partner.ts imports ==="
head -20 apps/web-app/shared/services/partner.ts

echo -e "\n=== Search for any InvoiceType validation in routes ==="
rg -nP "InvoiceType|invoiceType" apps/web-app/server/api/ --type=ts

echo -e "\n=== Check for database schema constraints in SQL or migrations ==="
find packages/database -type f -name "*.sql" 2>/dev/null

Length of output: 1317


🏁 Script executed:

#!/bin/bash
# Verify arktype supports literal constraints for enums
echo "=== Full createPartnerInvoiceSchema definition ==="
rg -nP -A15 "export const createPartnerInvoiceSchema" apps/web-app/shared/services/partner.ts

echo -e "\n=== Search for arktype examples with literals in codebase ==="
rg -nP "type\(['\"](.*\s*\|\s*.*)['\"]" apps/web-app/shared/services/ --type=ts | head -10

echo -e "\n=== Check if any schema uses enum patterns ==="
rg -nP "'\w+'\s*\|" apps/web-app/shared/services/partner.ts | head -10

Length of output: 2415


Update Arktype validators to enforce new InvoiceType values

The invoice schemas in apps/web-app/shared/services/partner.ts use generic string validation and will not enforce the new InvoiceType literals. The codebase already demonstrates the correct pattern in task.ts (line 3) with literal unions.

Required fixes:

  • Line 59: Change type: type('string') to type: type('replenishment' | 'royalties' | 'lump_sum_fee' | 'marketing_fee' | 'rospatent_fee' | 'other')
  • Line 60: Change status: type('string') to status: type('paid' | 'unpaid')
  • Line 68: Change type: type('string | undefined') to type: type('replenishment' | 'royalties' | 'lump_sum_fee' | 'marketing_fee' | 'rospatent_fee' | 'other' | undefined)
  • Line 69: Change status: type('string | undefined') to status: type('paid' | 'unpaid' | undefined)

Additionally, no database-level check constraints were found. Consider adding Drizzle check constraints to the invoices table definition as a secondary validation layer.

🤖 Prompt for AI Agents
packages/database/src/types/entities.ts lines 100-106: The Arktype validators in
apps/web-app/shared/services/partner.ts currently use generic 'string' types
which won't enforce the InvoiceType/InvoiceStatus literal unions; update the
validator calls as follows: change type('string') to type('replenishment' |
'royalties' | 'lump_sum_fee' | 'marketing_fee' | 'rospatent_fee' | 'other') and
type('string') for status to type('paid' | 'unpaid'); for optional fields change
type('string | undefined') to type('replenishment' | 'royalties' |
'lump_sum_fee' | 'marketing_fee' | 'rospatent_fee' | 'other' | undefined) and
type('string | undefined') for status to type('paid' | 'unpaid' | undefined);
also consider adding Drizzle check constraints on the invoices table to enforce
these enums at the DB level as a secondary validation layer.

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