feat: defer usage invoices below 5 EUR with carry-over#3525
feat: defer usage invoices below 5 EUR with carry-over#3525
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds invoice and carry-over billing features: backend fields ( Changes
Sequence Diagram(s)sequenceDiagram
participant Admin as Admin User
participant UI as Admin UI
participant Comp as Invoices/CarryOvers Components
participant API as Billing API Client
participant Backend as Billing Backend
Admin->>UI: Navigate to Administration → Invoices
UI->>Comp: Render invoices & carry-overs sections
Comp->>API: GET /v2/administration/billing/invoices (page/org) or /carry-overs
API->>Backend: Request data
Backend-->>API: Return JSON models (includes carryOverTotal, org metadata)
API-->>Comp: Deliver data
Comp->>Admin: Display lists
Admin->>Comp: Click "Download PDF"
Comp->>API: GET /v2/administration/billing/invoices/{id}/pdf
API->>Backend: Retrieve PDF
Backend-->>API: PDF blob
API-->>Comp: PDF response
Comp->>UI: useInvoicePdfDownload creates blob URL and triggers browser download
Admin->>Comp: Click "Usage details"
Comp->>API: GET /v2/administration/billing/invoices/{id}/usage
API->>Backend: Fetch UsageData (with carryOverTotal)
Backend-->>API: UsageData
API-->>Comp: Return UsageData
Comp->>Admin: Show UsageTable (includes CarryOverRow & TotalRow hint)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
webapp/src/ee/billing/common/usage/ProportionalUsageItemRow.tsx (1)
9-15:⚠️ Potential issue | 🟠 MajorType-safe invoice downloads by requiring both IDs together.
The optional
organizationIdprop causes silent feature loss.AdminInvoiceUsage.tsx(lines 55–59) passesinvoiceIdbut omitsorganizationId, and the runtime guard on lines 23–25 silently disables the download action. This compiles cleanly despite being incomplete.Model these props as a union type so invoice-backed rows require both IDs together—making the error obvious at compile time instead of discovering it at runtime:
💡 Tighten the prop contract
-export const ProportionalUsageItemRow = (props: { - item: components['schemas']['AverageProportionalUsageItemModel']; - invoiceId?: number; - invoiceNumber?: string; - type: ProportionalUsageType; - organizationId?: number; -}) => { +type ProportionalUsageItemRowProps = + | { + item: components['schemas']['AverageProportionalUsageItemModel']; + invoiceId: number; + invoiceNumber?: string; + type: ProportionalUsageType; + organizationId: number; + } + | { + item: components['schemas']['AverageProportionalUsageItemModel']; + invoiceId?: undefined; + invoiceNumber?: undefined; + type: ProportionalUsageType; + organizationId?: undefined; + }; + +export const ProportionalUsageItemRow = ( + props: ProportionalUsageItemRowProps +) => {Fix
AdminInvoiceUsage.tsxby passingorganizationIdtoUsageTable, or exclude the download feature for admin invoices if the organization context is unavailable.Also applies to: 23–30
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/common/usage/ProportionalUsageItemRow.tsx` around lines 9 - 15, The component ProportionalUsageItemRow currently accepts invoiceId? and organizationId? independently which allows passing invoiceId without organizationId and causes the download guard to silently disable the feature; change the props to a discriminated union so that either both invoiceId and organizationId are present (required together) or neither is present (e.g. { invoiceId: number; invoiceNumber?: string; organizationId: number; type: ProportionalUsageType; item: ... } | { invoiceId?: undefined; invoiceNumber?: string; organizationId?: undefined; type: ProportionalUsageType; item: ... }), update the ProportionalUsageItemRow signature accordingly, and then fix callers (e.g. AdminInvoiceUsage -> UsageTable) to pass organizationId when they pass invoiceId or intentionally omit invoice-related props if organization context is unavailable so the compiler surfaces the missing organizationId instead of failing at runtime.
🧹 Nitpick comments (6)
webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx (2)
79-112: Adddata-cyattribute for E2E testing.The organization filter Autocomplete should have a
data-cyattribute to enable E2E test selectors.Proposed fix
<Autocomplete<OrgItem> options={orgItems} getOptionLabel={(o) => o.name} isOptionEqualToValue={(a, b) => a.id === b.id} loading={orgsLoadable.isFetching} value={selectedOrg} onChange={(_, value) => { setSelectedOrg(value); setInvoicePage(0); }} onInputChange={(_, value) => setSearch(value)} sx={{ width: 280 }} + data-cy="admin-invoices-org-filter" renderInput={(params) => (As per coding guidelines: "STRICTLY use
data-cyattributes for E2E selectors".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx` around lines 79 - 112, Add the missing data-cy attribute to the organization filter Autocomplete's input so E2E tests can target it: update the Autocomplete renderInput/TextField block (in the component using Autocomplete<OrgItem> and renderInput) to include a data-cy prop (e.g., data-cy="administration-invoices-filter-org") on the TextField (or its input props) so the selector is present while preserving existing params and InputProps, value/onChange handlers, and loading behavior.
114-175: Adddata-cyattribute to the list component.The invoice list should have a
data-cyattribute for E2E testing purposes.Proposed fix
<PaginatedHateoasList onPageChange={(p) => setInvoicePage(p)} listComponent={Paper} listComponentProps={{ variant: 'outlined', sx: { display: 'grid', gridTemplateColumns: 'auto auto 1fr auto auto auto', alignItems: 'center', }, + 'data-cy': 'admin-invoices-list', }}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx` around lines 114 - 175, The PaginatedHateoasList rendering the invoices is missing a data-cy attribute for E2E tests; add a data-cy (e.g. data-cy="invoices-list") to the list component props by updating the PaginatedHateoasList call where listComponent={Paper} — put the attribute inside listComponentProps (the same object with variant/sx) so the rendered Paper element includes the data-cy for testing.webapp/src/ee/billing/administration/invoices/CarryOversSection.tsx (1)
161-170: Adddata-cyattributes for E2E testing.The Tabs component should have
data-cyattributes for E2E test selectors.Proposed fix
- <Tabs value={tab} onChange={(_, value) => setTab(value)} sx={{ mb: 2 }}> + <Tabs value={tab} onChange={(_, value) => setTab(value)} sx={{ mb: 2 }} data-cy="carry-overs-tabs"> <Tab value="active" label={t('administration_carry_overs_tab_active', 'Active')} + data-cy="carry-overs-tab-active" /> <Tab value="history" label={t('administration_carry_overs_tab_history', 'History')} + data-cy="carry-overs-tab-history" /> </Tabs>As per coding guidelines: "STRICTLY use
data-cyattributes for E2E selectors".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/CarryOversSection.tsx` around lines 161 - 170, Add data-cy attributes to the Tabs and each Tab for E2E selectors: update the Tabs component (where value={tab} onChange={(_, value) => setTab(value)}) to include a data-cy like data-cy="carry-overs-tabs" and add data-cy attributes to the two Tab components (e.g., data-cy="carry-overs-tab-active" and data-cy="carry-overs-tab-history") so tests can reliably target them; keep the existing props (value, label, sx) and only add the data-cy attributes to Tabs and Tab.webapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsx (2)
34-36: Redundant type assertion on blob.
res.blob()already returnsPromise<Blob>, so theas unknown as Blobcast is unnecessary.Proposed fix
async onSuccess(response) { const res = response as unknown as Response; const data = await res.blob(); - const url = URL.createObjectURL(data as unknown as Blob); + const url = URL.createObjectURL(data);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsx` around lines 34 - 36, The blob cast is redundant: res.blob() returns a Promise<Blob>, so remove the unnecessary "as unknown as Blob" and pass the returned blob directly to URL.createObjectURL; ensure the earlier cast of response to Response (const res = response as unknown as Response) remains appropriate or replace with a direct Response typing for the response variable so that data is used as a Blob when calling URL.createObjectURL(data).
56-65: Adddata-cyattribute for E2E testing.The download button should have a
data-cyattribute to enable reliable E2E test selectors.Proposed fix
<LoadingButton disabled={!invoice.pdfReady} loading={pdfMutation.isLoading} onClick={onDownload} size="small" + data-cy="admin-invoice-download-button" > PDF </LoadingButton>As per coding guidelines: "STRICTLY use
data-cyattributes for E2E selectors".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsx` around lines 56 - 65, The LoadingButton rendered in AdminDownloadButton lacks the required E2E selector; add a data-cy attribute to the LoadingButton (the component using props: disabled={!invoice.pdfReady}, loading={pdfMutation.isLoading}, onClick={onDownload})—e.g. data-cy="admin-invoice-download-pdf"—so tests can reliably target the PDF download button.webapp/src/ee/billing/common/usage/TotalRow.tsx (1)
21-26: Optional simplification: Redundant truthy check.The condition
usageOnlyTotal &&is redundant when followed byusageOnlyTotal > 0, since the latter already handlesundefined,null, and0cases by returningfalse. However, this is a common defensive pattern for explicitness.♻️ Optional simplification
const showHint = Boolean( minUsageInvoiceAmount && - usageOnlyTotal && usageOnlyTotal > 0 && usageOnlyTotal < minUsageInvoiceAmount );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/common/usage/TotalRow.tsx` around lines 21 - 26, Simplify the showHint boolean expression in the TotalRow component by removing the redundant "usageOnlyTotal &&" check; keep the Boolean(...) wrapper and the remaining conditions "minUsageInvoiceAmount && usageOnlyTotal > 0 && usageOnlyTotal < minUsageInvoiceAmount" so the logic is unchanged but less verbose and still handles undefined/null correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@backend/data/src/main/kotlin/io/tolgee/dtos/response/PublicBillingConfigurationDTO.kt`:
- Around line 5-7: PublicBillingConfigurationDTO adds minUsageInvoiceAmount but
no provider populates it; update the provider(s) to supply this value or remove
the field. Concretely, either (A) remove minUsageInvoiceAmount from
PublicBillingConfigurationDTO if unused, or (B) modify
BasePublicBillingConfProvider and all concrete providers that return
PublicBillingConfigurationDTO (look for the constructor call in
BasePublicBillingConfProvider and other providers) to pass the actual billing
minimum invoice amount (e.g., read from your billing configuration/service and
call PublicBillingConfigurationDTO(enabled, minUsageInvoiceAmount)) so the DTO
is not always null.
In `@webapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsx`:
- Around line 55-59: The UsageTable is rendered without the optional
organizationId prop so ProportionalUsageItemRow instances receive no
organizationId and CSV download buttons remain disabled; update the UsageTable
invocation in AdminInvoiceUsage to pass organizationId={invoice.organizationId}
so the prop flows into ProportionalUsageItemRow and enables CSV downloads.
- Around line 40-51: The IconButton opening the usage dialog (the element using
setOpen(true) and labelled via t('billing_invoices_show_usage_button')) needs a
data-cy attribute for E2E selection and all translation calls must include
default values; add a data-cy (e.g. billing-invoice-show-usage-button) to the
IconButton and update the t() usages around the IconButton (aria-label and
Tooltip title) and the DialogTitle call (t('invoice_usage_dialog_title')) to
supply sensible defaultValue strings so meaningful text appears before
translations load.
In
`@webapp/src/ee/billing/administration/invoices/AdministrationInvoicesView.tsx`:
- Around line 23-28: The navigation entry in AdministrationInvoicesView uses
t('administration_organizations') without a defaultValue; update the call to
include a defaultValue (e.g., defaultValue: 'Organizations') so the navigation
label renders before translations load—locate the navigation prop in
AdministrationInvoicesView.tsx and add the defaultValue option to the t(...)
invocation (or to the T component if used) for the
'administration_organizations' key.
In `@webapp/src/ee/billing/administration/invoices/CarryOversSection.tsx`:
- Around line 76-89: Replace the hardcoded "Settled by" string in
CarryOversSection's JSX (inside the conditional that checks showSettledBy and
item.resolvedByInvoiceNumber) with a call to the project's translation function
(e.g., t('...') or i18n.t('...')); import/use the same translation hook used
elsewhere in this component (or module) and pick an appropriate key (for example
'billing.settledBy' or 'invoices.settledBy') so the Box displaying the label
becomes translated while keeping the surrounding layout and Link logic intact.
- Around line 91-97: The AmountItem label strings in CarryOversSection are
hardcoded; update the four labels ("Credits", "Seats", "Translations", "Keys")
to use the i18n translation helper used in this component (e.g., the t function
or <Trans>) so they are localized; locate the CarryOversSection component and
replace the literal label props passed to AmountItem with translated keys (e.g.,
t('billing.credits'), t('billing.seats'), t('billing.translations'),
t('billing.keys')) ensuring the appropriate translation keys are added to the
locale files.
- Around line 67-72: The Chip labels are hardcoded ("Cloud" / "Self-hosted EE");
replace them with the translation helper (use the T component or t() function)
and provide defaultValue strings per guidelines. Update the label prop in the
Chip rendering (the conditional using isCloud) to call t('Cloud', {
defaultValue: 'Cloud' }) and t('Self-hosted EE', { defaultValue: 'Self-hosted
EE' }) or wrap with <T defaultValue="..."> accordingly so both branches use
i18n.
In `@webapp/src/eeSetup/eeModule.ee.tsx`:
- Around line 141-143: The Administration invoices route is currently only
protected by PrivateRoute (authentication) and needs an admin permission guard;
update the route handling for LINKS.ADMINISTRATION_BILLING_INVOICES.template so
only admin/supporter users can access AdministrationInvoicesView. Either wrap
that <PrivateRoute> with an admin-check component (e.g., AdminGuard) or replace
PrivateRoute with an AdminRoute that calls useIsAdminOrSupporter() and redirects
non-admins to a safe page; ensure the check happens in RootRouter around the
route for AdministrationInvoicesView so direct URL access is blocked.
---
Outside diff comments:
In `@webapp/src/ee/billing/common/usage/ProportionalUsageItemRow.tsx`:
- Around line 9-15: The component ProportionalUsageItemRow currently accepts
invoiceId? and organizationId? independently which allows passing invoiceId
without organizationId and causes the download guard to silently disable the
feature; change the props to a discriminated union so that either both invoiceId
and organizationId are present (required together) or neither is present (e.g. {
invoiceId: number; invoiceNumber?: string; organizationId: number; type:
ProportionalUsageType; item: ... } | { invoiceId?: undefined; invoiceNumber?:
string; organizationId?: undefined; type: ProportionalUsageType; item: ... }),
update the ProportionalUsageItemRow signature accordingly, and then fix callers
(e.g. AdminInvoiceUsage -> UsageTable) to pass organizationId when they pass
invoiceId or intentionally omit invoice-related props if organization context is
unavailable so the compiler surfaces the missing organizationId instead of
failing at runtime.
---
Nitpick comments:
In `@webapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsx`:
- Around line 34-36: The blob cast is redundant: res.blob() returns a
Promise<Blob>, so remove the unnecessary "as unknown as Blob" and pass the
returned blob directly to URL.createObjectURL; ensure the earlier cast of
response to Response (const res = response as unknown as Response) remains
appropriate or replace with a direct Response typing for the response variable
so that data is used as a Blob when calling URL.createObjectURL(data).
- Around line 56-65: The LoadingButton rendered in AdminDownloadButton lacks the
required E2E selector; add a data-cy attribute to the LoadingButton (the
component using props: disabled={!invoice.pdfReady},
loading={pdfMutation.isLoading}, onClick={onDownload})—e.g.
data-cy="admin-invoice-download-pdf"—so tests can reliably target the PDF
download button.
In `@webapp/src/ee/billing/administration/invoices/CarryOversSection.tsx`:
- Around line 161-170: Add data-cy attributes to the Tabs and each Tab for E2E
selectors: update the Tabs component (where value={tab} onChange={(_, value) =>
setTab(value)}) to include a data-cy like data-cy="carry-overs-tabs" and add
data-cy attributes to the two Tab components (e.g.,
data-cy="carry-overs-tab-active" and data-cy="carry-overs-tab-history") so tests
can reliably target them; keep the existing props (value, label, sx) and only
add the data-cy attributes to Tabs and Tab.
In `@webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx`:
- Around line 79-112: Add the missing data-cy attribute to the organization
filter Autocomplete's input so E2E tests can target it: update the Autocomplete
renderInput/TextField block (in the component using Autocomplete<OrgItem> and
renderInput) to include a data-cy prop (e.g.,
data-cy="administration-invoices-filter-org") on the TextField (or its input
props) so the selector is present while preserving existing params and
InputProps, value/onChange handlers, and loading behavior.
- Around line 114-175: The PaginatedHateoasList rendering the invoices is
missing a data-cy attribute for E2E tests; add a data-cy (e.g.
data-cy="invoices-list") to the list component props by updating the
PaginatedHateoasList call where listComponent={Paper} — put the attribute inside
listComponentProps (the same object with variant/sx) so the rendered Paper
element includes the data-cy for testing.
In `@webapp/src/ee/billing/common/usage/TotalRow.tsx`:
- Around line 21-26: Simplify the showHint boolean expression in the TotalRow
component by removing the redundant "usageOnlyTotal &&" check; keep the
Boolean(...) wrapper and the remaining conditions "minUsageInvoiceAmount &&
usageOnlyTotal > 0 && usageOnlyTotal < minUsageInvoiceAmount" so the logic is
unchanged but less verbose and still handles undefined/null correctly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2a1abfb5-1fb7-4a98-929b-5a2ad9ef9646
📒 Files selected for processing (19)
backend/api/src/main/kotlin/io/tolgee/hateoas/ee/uasge/proportional/UsageModel.ktbackend/data/src/main/kotlin/io/tolgee/dtos/response/PublicBillingConfigurationDTO.ktee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/UsageModelAssembler.ktee/backend/app/src/main/kotlin/io/tolgee/ee/data/UsageData.ktwebapp/src/constants/links.tsxwebapp/src/ee/billing/Invoices/InvoiceUsage.tsxwebapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsxwebapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsxwebapp/src/ee/billing/administration/invoices/AdministrationInvoicesView.tsxwebapp/src/ee/billing/administration/invoices/CarryOversSection.tsxwebapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsxwebapp/src/ee/billing/common/usage/CarryOverRow.tsxwebapp/src/ee/billing/common/usage/ExpectedUsageDialogButton.tsxwebapp/src/ee/billing/common/usage/ProportionalUsageItemRow.tsxwebapp/src/ee/billing/common/usage/TotalRow.tsxwebapp/src/ee/billing/common/usage/UsageTable.tsxwebapp/src/eeSetup/eeModule.ee.tsxwebapp/src/service/apiSchema.generated.tswebapp/src/service/billingApiSchema.generated.ts
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
webapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsx (1)
40-51:⚠️ Potential issue | 🟡 MinorThis trigger still needs
data-cyanddefaultValues.The new dialog opener is the stable E2E target here, and the three
t()calls in this block still render without fallbacks.As per coding guidelines: "Always provide `defaultValue` when using the `T` component or `t()` function to ensure the UI displays meaningful text before translations are uploaded to Tolgee" and "STRICTLY use `data-cy` attributes for E2E selectors, never rely on text content; use typed helpers `gcy()` or `cy.gcy()`".💡 Possible fix
<IconButton size="small" onClick={() => setOpen(true)} - aria-label={t('billing_invoices_show_usage_button')} + aria-label={t('billing_invoices_show_usage_button', 'Show usage')} + data-cy="admin-invoice-usage-button" > - <Tooltip title={t('billing_invoices_show_usage_button')}> + <Tooltip title={t('billing_invoices_show_usage_button', 'Show usage')}> <PieChart01 /> </Tooltip> </IconButton> </Box> <Dialog open={open} onClose={() => setOpen(false)} maxWidth="md"> - <DialogTitle>{t('invoice_usage_dialog_title')}</DialogTitle> + <DialogTitle>{t('invoice_usage_dialog_title', 'Usage details')}</DialogTitle>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsx` around lines 40 - 51, The dialog opener lacks a stable E2E selector and the t() calls are missing defaultValue fallbacks: add a data-cy attribute to the trigger element (the IconButton that calls setOpen(true) and/or its Tooltip/PieChart01 wrapper) so tests can use gcy()/cy.gcy(), and supply defaultValue arguments to each t(...) call in this block (the IconButton aria-label, Tooltip title, and DialogTitle text) so they render sensible text when translations are absent; update the IconButton/Tooltip/DialogTitle uses accordingly.
🧹 Nitpick comments (6)
webapp/src/ee/billing/Invoices/PdfDownloadButton.tsx (1)
18-25: Missingdata-cyattribute for E2E testing.The
LoadingButtonshould have adata-cyattribute to support E2E selectors per the coding guidelines.Proposed fix
<LoadingButton + data-cy="invoice-pdf-download-button" disabled={!invoice.pdfReady} loading={isLoading} onClick={onDownload} size="small" > PDF </LoadingButton>As per coding guidelines: "STRICTLY use
data-cyattributes for E2E selectors, never rely on text content".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/Invoices/PdfDownloadButton.tsx` around lines 18 - 25, Add a data-cy attribute to the LoadingButton in the PdfDownloadButton component so E2E tests can target it instead of text; update the JSX for the LoadingButton (the element rendered in PdfDownloadButton) to include a stable data-cy value (for example "invoice-download-pdf" or "invoice-download-pdf-{invoice.id}" if an id-based selector is preferred) while keeping existing props (disabled, loading, onClick, size) unchanged.webapp/src/ee/billing/Invoices/useInvoicePdfDownload.ts (1)
13-24: Unnecessarya.remove()call and overly nested try/finally.The anchor element is never appended to the DOM, so
a.remove()is a no-op. The nested try/finally blocks can be simplified.Suggested simplification
const onSuccess = async (response: unknown) => { const res = response as Response; const data = await res.blob(); const url = URL.createObjectURL(data); - try { - const a = document.createElement('a'); - try { - a.href = url; - a.download = `${config.appName.toLowerCase()}-${invoice.number}.pdf`; - a.click(); - } finally { - a.remove(); - } - } finally { - setTimeout(() => URL.revokeObjectURL(url), 7000); - } + const a = document.createElement('a'); + a.href = url; + a.download = `${config.appName.toLowerCase()}-${invoice.number}.pdf`; + a.click(); + setTimeout(() => URL.revokeObjectURL(url), 7000); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/Invoices/useInvoicePdfDownload.ts` around lines 13 - 24, The nested try/finally and the call to a.remove() in useInvoicePdfDownload are unnecessary because the created anchor element is never appended to the DOM; remove the inner try/finally and the a.remove() call, and simplify to create the anchor (const a = document.createElement('a')), set a.href = url and a.download = `${config.appName.toLowerCase()}-${invoice.number}.pdf`, call a.click(), and wrap only the URL.revokeObjectURL(url) in a single finally block (or setTimeout in finally as before) so the object URL is revoked without redundant cleanup code.webapp/src/ee/billing/administration/invoices/CarryOverList.tsx (1)
5-5: Use a Tolgee alias for this import.Please keep new
webappimports on the alias-based scheme instead of./CarryOverRow.As per coding guidelines: "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/CarryOverList.tsx` at line 5, The import of CarryOverRow uses a relative path; replace it with the Tolgee component alias import so the component follows the project's alias-based scheme (e.g. import CarryOverRow from 'tg.component/CarryOverRow') — update the import statement that references CarryOverRow accordingly and ensure the alias path resolves in the project config.webapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsx (1)
15-16: Use the Tolgee alias-based import scheme here.These new
../../imports add another relative hop insidewebapp. Please switch them to the matching project alias instead.As per coding guidelines: "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsx` around lines 15 - 16, Replace the relative imports of TotalTable and UsageTable in AdminInvoiceUsage.tsx with the Tolgee alias paths; update the two lines importing TotalTable and UsageTable from '../../common/usage/TotalTable' and '../../common/usage/UsageTable' to use the tg.component alias (e.g. import { TotalTable } from 'tg.component/common/usage/TotalTable' and import { UsageTable } from 'tg.component/common/usage/UsageTable') so the file follows the Tolgee custom TypeScript path aliases.webapp/src/ee/billing/common/usage/UsageTable.tsx (1)
11-11: Use the Tolgee alias form for the newCarryOverRowimport.Since this import block is already being touched, please avoid extending the relative-import pattern here.
As per coding guidelines: "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/common/usage/UsageTable.tsx` at line 11, The import for CarryOverRow in UsageTable.tsx uses a relative path; replace it with the Tolgee alias form (use the tg.views alias for component imports) so the file imports CarryOverRow via the Tolgee path alias instead of a relative import and update the import statement that references CarryOverRow accordingly.webapp/src/ee/billing/administration/invoices/CarryOverRow.tsx (1)
8-8: Please use a Tolgee path alias for this new import.Keep
webappimports on the alias-based scheme instead of adding another relative path here.As per coding guidelines: "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/CarryOverRow.tsx` at line 8, The import of AmountItem in CarryOverRow.tsx uses a relative path; change it to the Tolgee alias-based import required by the project (use the appropriate alias such as tg.component or another matching tg.* alias for the component) so that AmountItem is imported via the Tolgee path alias instead of a relative path; update the import statement referencing AmountItem accordingly in CarryOverRow.tsx.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@webapp/src/ee/billing/administration/invoices/CarryOverList.tsx`:
- Around line 27-44: The component CarryOverList currently returns an empty
Paper when items.length === 0 and loadable.isLoading is true; change the render
logic so that when loadable.isLoading you return an explicit loading state
(e.g., a Skeleton or CircularProgress wrapped in the same Paper or a Typography
"Loading..." placeholder) instead of falling through to the empty Paper,
otherwise keep the existing emptyMessage path; update the conditional around
items, loadable.isLoading, and the return that renders CarryOverRow to ensure
CarryOverRow mapping only happens when not loading.
In `@webapp/src/ee/billing/administration/invoices/CarryOverRow.tsx`:
- Around line 50-67: The new translation calls in CarryOverRow.tsx (the Chip
label keys 'admin_organization_subscriptions_cloud' and
'admin_organization_subscriptions_self_hosted', and the status label key
'administration_carry_overs_settled_by' inside the showSettledBy block) need
defaultValue fallbacks; update each t(...) invocation to include a defaultValue
string (e.g., "Cloud", "Self-hosted", "Settled by") so the Chip and the status
label render meaningful text before translations are available.
---
Duplicate comments:
In `@webapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsx`:
- Around line 40-51: The dialog opener lacks a stable E2E selector and the t()
calls are missing defaultValue fallbacks: add a data-cy attribute to the trigger
element (the IconButton that calls setOpen(true) and/or its Tooltip/PieChart01
wrapper) so tests can use gcy()/cy.gcy(), and supply defaultValue arguments to
each t(...) call in this block (the IconButton aria-label, Tooltip title, and
DialogTitle text) so they render sensible text when translations are absent;
update the IconButton/Tooltip/DialogTitle uses accordingly.
---
Nitpick comments:
In `@webapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsx`:
- Around line 15-16: Replace the relative imports of TotalTable and UsageTable
in AdminInvoiceUsage.tsx with the Tolgee alias paths; update the two lines
importing TotalTable and UsageTable from '../../common/usage/TotalTable' and
'../../common/usage/UsageTable' to use the tg.component alias (e.g. import {
TotalTable } from 'tg.component/common/usage/TotalTable' and import { UsageTable
} from 'tg.component/common/usage/UsageTable') so the file follows the Tolgee
custom TypeScript path aliases.
In `@webapp/src/ee/billing/administration/invoices/CarryOverList.tsx`:
- Line 5: The import of CarryOverRow uses a relative path; replace it with the
Tolgee component alias import so the component follows the project's alias-based
scheme (e.g. import CarryOverRow from 'tg.component/CarryOverRow') — update the
import statement that references CarryOverRow accordingly and ensure the alias
path resolves in the project config.
In `@webapp/src/ee/billing/administration/invoices/CarryOverRow.tsx`:
- Line 8: The import of AmountItem in CarryOverRow.tsx uses a relative path;
change it to the Tolgee alias-based import required by the project (use the
appropriate alias such as tg.component or another matching tg.* alias for the
component) so that AmountItem is imported via the Tolgee path alias instead of a
relative path; update the import statement referencing AmountItem accordingly in
CarryOverRow.tsx.
In `@webapp/src/ee/billing/common/usage/UsageTable.tsx`:
- Line 11: The import for CarryOverRow in UsageTable.tsx uses a relative path;
replace it with the Tolgee alias form (use the tg.views alias for component
imports) so the file imports CarryOverRow via the Tolgee path alias instead of a
relative import and update the import statement that references CarryOverRow
accordingly.
In `@webapp/src/ee/billing/Invoices/PdfDownloadButton.tsx`:
- Around line 18-25: Add a data-cy attribute to the LoadingButton in the
PdfDownloadButton component so E2E tests can target it instead of text; update
the JSX for the LoadingButton (the element rendered in PdfDownloadButton) to
include a stable data-cy value (for example "invoice-download-pdf" or
"invoice-download-pdf-{invoice.id}" if an id-based selector is preferred) while
keeping existing props (disabled, loading, onClick, size) unchanged.
In `@webapp/src/ee/billing/Invoices/useInvoicePdfDownload.ts`:
- Around line 13-24: The nested try/finally and the call to a.remove() in
useInvoicePdfDownload are unnecessary because the created anchor element is
never appended to the DOM; remove the inner try/finally and the a.remove() call,
and simplify to create the anchor (const a = document.createElement('a')), set
a.href = url and a.download =
`${config.appName.toLowerCase()}-${invoice.number}.pdf`, call a.click(), and
wrap only the URL.revokeObjectURL(url) in a single finally block (or setTimeout
in finally as before) so the object URL is revoked without redundant cleanup
code.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 64178c58-9422-4224-a2f6-eb3a05b52eb4
📒 Files selected for processing (13)
webapp/src/ee/billing/Invoices/DownloadButton.tsxwebapp/src/ee/billing/Invoices/PdfDownloadButton.tsxwebapp/src/ee/billing/Invoices/useInvoicePdfDownload.tswebapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsxwebapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsxwebapp/src/ee/billing/administration/invoices/AdministrationInvoicesView.tsxwebapp/src/ee/billing/administration/invoices/AmountItem.tsxwebapp/src/ee/billing/administration/invoices/CarryOverList.tsxwebapp/src/ee/billing/administration/invoices/CarryOverRow.tsxwebapp/src/ee/billing/administration/invoices/CarryOversSection.tsxwebapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsxwebapp/src/ee/billing/common/usage/TotalRow.tsxwebapp/src/ee/billing/common/usage/UsageTable.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- webapp/src/ee/billing/administration/invoices/CarryOversSection.tsx
- webapp/src/ee/billing/administration/invoices/AdministrationInvoicesView.tsx
- webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx
- webapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsx
fc9db3a to
e5e8924
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (3)
webapp/src/ee/billing/administration/invoices/CarryOverRow.tsx (1)
8-8: Use a Tolgee path alias instead of a relative import.Please replace the relative
./AmountItemimport with the appropriatetg.*alias import path for consistency with the webapp import convention.As per coding guidelines: "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/CarryOverRow.tsx` at line 8, The import in CarryOverRow.tsx currently uses a relative path for AmountItem; update the import to use the Tolgee path alias for components (replace "./AmountItem" with the tg.component alias, e.g. import AmountItem from "tg.component/AmountItem") so the file uses the project's tg.* path alias convention and matches other webapp imports.webapp/src/ee/billing/administration/invoices/CarryOversSection.tsx (1)
5-5: Replace relative import with the project alias style.
./CarryOverListshould use the corresponding Tolgee alias path to match repository import conventions.As per coding guidelines: "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/CarryOversSection.tsx` at line 5, Replace the relative import of CarryOverList in CarryOversSection.tsx with the Tolgee TypeScript path alias style; update the import "import { CarryOverList } from './CarryOverList';" to use the appropriate tg.component alias (e.g., import from a tg.component... path that resolves to CarryOverList) so it follows the repository convention for webapp/**/*.{ts,tsx} imports.webapp/src/ee/billing/administration/invoices/CarryOverList.tsx (1)
6-6: Use Tolgee alias import instead of a relative path.Please replace
./CarryOverRowwith the equivalenttg.*alias import to follow the webapp import policy.As per coding guidelines: "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/CarryOverList.tsx` at line 6, Replace the relative import for the CarryOverRow component with the Tolgee alias import: update the import statement that currently references './CarryOverRow' in CarryOverList.tsx to use the tg.* path alias for the component (e.g., tg.component or the specific alias used for components in the project) so that CarryOverRow is imported via the Tolgee alias instead of a relative path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@webapp/src/ee/billing/administration/invoices/CarryOverList.tsx`:
- Line 6: Replace the relative import for the CarryOverRow component with the
Tolgee alias import: update the import statement that currently references
'./CarryOverRow' in CarryOverList.tsx to use the tg.* path alias for the
component (e.g., tg.component or the specific alias used for components in the
project) so that CarryOverRow is imported via the Tolgee alias instead of a
relative path.
In `@webapp/src/ee/billing/administration/invoices/CarryOverRow.tsx`:
- Line 8: The import in CarryOverRow.tsx currently uses a relative path for
AmountItem; update the import to use the Tolgee path alias for components
(replace "./AmountItem" with the tg.component alias, e.g. import AmountItem from
"tg.component/AmountItem") so the file uses the project's tg.* path alias
convention and matches other webapp imports.
In `@webapp/src/ee/billing/administration/invoices/CarryOversSection.tsx`:
- Line 5: Replace the relative import of CarryOverList in CarryOversSection.tsx
with the Tolgee TypeScript path alias style; update the import "import {
CarryOverList } from './CarryOverList';" to use the appropriate tg.component
alias (e.g., import from a tg.component... path that resolves to CarryOverList)
so it follows the repository convention for webapp/**/*.{ts,tsx} imports.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 11025474-a40f-4657-9826-10905a49660e
📒 Files selected for processing (26)
backend/api/src/main/kotlin/io/tolgee/hateoas/ee/uasge/proportional/UsageModel.ktbackend/data/src/main/kotlin/io/tolgee/dtos/response/PublicBillingConfigurationDTO.kte2e/cypress/support/dataCyType.d.tsee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/UsageModelAssembler.ktee/backend/app/src/main/kotlin/io/tolgee/ee/data/UsageData.ktwebapp/src/constants/links.tsxwebapp/src/ee/billing/Invoices/DownloadButton.tsxwebapp/src/ee/billing/Invoices/InvoiceUsage.tsxwebapp/src/ee/billing/Invoices/PdfDownloadButton.tsxwebapp/src/ee/billing/Invoices/useInvoicePdfDownload.tswebapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsxwebapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsxwebapp/src/ee/billing/administration/invoices/AdministrationInvoicesView.tsxwebapp/src/ee/billing/administration/invoices/AmountItem.tsxwebapp/src/ee/billing/administration/invoices/CarryOverList.tsxwebapp/src/ee/billing/administration/invoices/CarryOverRow.tsxwebapp/src/ee/billing/administration/invoices/CarryOversSection.tsxwebapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsxwebapp/src/ee/billing/common/usage/CarryOverRow.tsxwebapp/src/ee/billing/common/usage/ExpectedUsageDialogButton.tsxwebapp/src/ee/billing/common/usage/ProportionalUsageItemRow.tsxwebapp/src/ee/billing/common/usage/TotalRow.tsxwebapp/src/ee/billing/common/usage/UsageTable.tsxwebapp/src/eeSetup/eeModule.ee.tsxwebapp/src/service/apiSchema.generated.tswebapp/src/service/billingApiSchema.generated.ts
🚧 Files skipped from review as they are similar to previous changes (12)
- webapp/src/ee/billing/administration/invoices/AdministrationInvoicesView.tsx
- webapp/src/ee/billing/Invoices/PdfDownloadButton.tsx
- webapp/src/ee/billing/Invoices/InvoiceUsage.tsx
- webapp/src/ee/billing/Invoices/DownloadButton.tsx
- webapp/src/ee/billing/common/usage/CarryOverRow.tsx
- webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx
- webapp/src/ee/billing/common/usage/TotalRow.tsx
- webapp/src/service/apiSchema.generated.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/ee/uasge/proportional/UsageModel.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/UsageModelAssembler.kt
- webapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsx
- ee/backend/app/src/main/kotlin/io/tolgee/ee/data/UsageData.kt
fac99db to
7f25d0a
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx (1)
18-19: Use configuredtg.*aliases instead of relative imports.Please align these imports with the webapp alias convention.
As per coding guidelines, "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx` around lines 18 - 19, The imports in OrgInvoicesSection.tsx use relative paths for components (AdminDownloadButton, AdminInvoiceUsage); change them to use the Tolgee TypeScript path alias for components (e.g. replace the relative import paths with tg.component imports) so they follow the alias convention (use tg.component for AdminDownloadButton and AdminInvoiceUsage).webapp/src/ee/billing/Invoices/DownloadButton.tsx (1)
6-7: Switch these imports to Tolgee TS aliases.The new relative imports should follow the same alias convention used across webapp modules.
As per coding guidelines, "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/Invoices/DownloadButton.tsx` around lines 6 - 7, Replace the relative imports in DownloadButton.tsx with Tolgee TypeScript path aliases: import useInvoicePdfDownload via the appropriate tg.hooks alias and import PdfDownloadButton via the appropriate tg.component (or tg.views if components are grouped there) alias; update the import statements that reference './useInvoicePdfDownload' and './PdfDownloadButton' to their corresponding tg.* aliases while keeping the exported symbols useInvoicePdfDownload and PdfDownloadButton unchanged.webapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsx (1)
5-6: Use Tolgee path aliases instead of relative imports here.Please replace these relative imports with configured
tg.*aliases to match project conventions and keep imports stable across moves.As per coding guidelines, "
webapp/**/*.{ts,tsx}: Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@webapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsx` around lines 5 - 6, In AdminDownloadButton.tsx replace the two relative imports with the Tolgee path aliases: import useInvoicePdfDownload from the hooks alias (e.g. tg.hooks/useInvoicePdfDownload or tg.hooks) and import PdfDownloadButton from the components alias (e.g. tg.component/PdfDownloadButton or tg.component) so that useInvoicePdfDownload and PdfDownloadButton use tg.* path aliases instead of the current relative paths; update the existing import statements to reference tg.hooks and tg.component respectively and ensure the imported symbol names remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx`:
- Line 129: The translation call using t() in OrgInvoicesSection (the JSX
expression {t('billing_invoices_empty')}) lacks a fallback; update that call to
include a defaultValue option (e.g., t('billing_invoices_empty', { defaultValue:
'Your invoices will appear here.' })) so the UI shows meaningful text before
translations are available—modify the t(...) invocation in
OrgInvoicesSection.tsx accordingly.
---
Nitpick comments:
In `@webapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsx`:
- Around line 5-6: In AdminDownloadButton.tsx replace the two relative imports
with the Tolgee path aliases: import useInvoicePdfDownload from the hooks alias
(e.g. tg.hooks/useInvoicePdfDownload or tg.hooks) and import PdfDownloadButton
from the components alias (e.g. tg.component/PdfDownloadButton or tg.component)
so that useInvoicePdfDownload and PdfDownloadButton use tg.* path aliases
instead of the current relative paths; update the existing import statements to
reference tg.hooks and tg.component respectively and ensure the imported symbol
names remain unchanged.
In `@webapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsx`:
- Around line 18-19: The imports in OrgInvoicesSection.tsx use relative paths
for components (AdminDownloadButton, AdminInvoiceUsage); change them to use the
Tolgee TypeScript path alias for components (e.g. replace the relative import
paths with tg.component imports) so they follow the alias convention (use
tg.component for AdminDownloadButton and AdminInvoiceUsage).
In `@webapp/src/ee/billing/Invoices/DownloadButton.tsx`:
- Around line 6-7: Replace the relative imports in DownloadButton.tsx with
Tolgee TypeScript path aliases: import useInvoicePdfDownload via the appropriate
tg.hooks alias and import PdfDownloadButton via the appropriate tg.component (or
tg.views if components are grouped there) alias; update the import statements
that reference './useInvoicePdfDownload' and './PdfDownloadButton' to their
corresponding tg.* aliases while keeping the exported symbols
useInvoicePdfDownload and PdfDownloadButton unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 71f0a88e-38bf-4551-8807-4414249cbc5d
📒 Files selected for processing (26)
backend/api/src/main/kotlin/io/tolgee/hateoas/ee/uasge/proportional/UsageModel.ktbackend/data/src/main/kotlin/io/tolgee/dtos/response/PublicBillingConfigurationDTO.kte2e/cypress/support/dataCyType.d.tsee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/UsageModelAssembler.ktee/backend/app/src/main/kotlin/io/tolgee/ee/data/UsageData.ktwebapp/src/constants/links.tsxwebapp/src/ee/billing/Invoices/DownloadButton.tsxwebapp/src/ee/billing/Invoices/InvoiceUsage.tsxwebapp/src/ee/billing/Invoices/PdfDownloadButton.tsxwebapp/src/ee/billing/Invoices/useInvoicePdfDownload.tswebapp/src/ee/billing/administration/invoices/AdminDownloadButton.tsxwebapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsxwebapp/src/ee/billing/administration/invoices/AdministrationInvoicesView.tsxwebapp/src/ee/billing/administration/invoices/AmountItem.tsxwebapp/src/ee/billing/administration/invoices/CarryOverList.tsxwebapp/src/ee/billing/administration/invoices/CarryOverRow.tsxwebapp/src/ee/billing/administration/invoices/CarryOversSection.tsxwebapp/src/ee/billing/administration/invoices/OrgInvoicesSection.tsxwebapp/src/ee/billing/common/usage/CarryOverRow.tsxwebapp/src/ee/billing/common/usage/ExpectedUsageDialogButton.tsxwebapp/src/ee/billing/common/usage/ProportionalUsageItemRow.tsxwebapp/src/ee/billing/common/usage/TotalRow.tsxwebapp/src/ee/billing/common/usage/UsageTable.tsxwebapp/src/eeSetup/eeModule.ee.tsxwebapp/src/service/apiSchema.generated.tswebapp/src/service/billingApiSchema.generated.ts
✅ Files skipped from review due to trivial changes (7)
- webapp/src/ee/billing/administration/invoices/AmountItem.tsx
- backend/api/src/main/kotlin/io/tolgee/hateoas/ee/uasge/proportional/UsageModel.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/UsageModelAssembler.kt
- webapp/src/ee/billing/common/usage/CarryOverRow.tsx
- webapp/src/ee/billing/Invoices/PdfDownloadButton.tsx
- webapp/src/ee/billing/administration/invoices/CarryOverRow.tsx
- e2e/cypress/support/dataCyType.d.ts
🚧 Files skipped from review as they are similar to previous changes (12)
- webapp/src/ee/billing/common/usage/ExpectedUsageDialogButton.tsx
- webapp/src/eeSetup/eeModule.ee.tsx
- webapp/src/ee/billing/administration/invoices/AdministrationInvoicesView.tsx
- webapp/src/constants/links.tsx
- webapp/src/ee/billing/Invoices/useInvoicePdfDownload.ts
- backend/data/src/main/kotlin/io/tolgee/dtos/response/PublicBillingConfigurationDTO.kt
- webapp/src/ee/billing/administration/invoices/CarryOversSection.tsx
- webapp/src/service/billingApiSchema.generated.ts
- webapp/src/service/apiSchema.generated.ts
- webapp/src/ee/billing/administration/invoices/AdminInvoiceUsage.tsx
- ee/backend/app/src/main/kotlin/io/tolgee/ee/data/UsageData.kt
- webapp/src/ee/billing/common/usage/TotalRow.tsx
b2a032c to
32a34f2
Compare
740dbe4 to
af041d8
Compare
Add an administration invoices page that shows per-organization invoices and carry-over history. Refactor ProportionalUsageItemRow to accept organizationId as a prop so the row is reusable outside the org context. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add minInvoiceAmount to UsageModel (null for invoice views, populated for expected-usage endpoint). When usage-only total is below the threshold, a LabelHint question-mark tooltip on the Total row explains that the amount will be carried over and billed later. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…odel Move the carry-over threshold from the per-request UsageModel response into PublicBillingConfigurationDTO (served via init-data). TotalRow now reads the value from useGlobalContext rather than receiving it as a prop. Remove minInvoiceAmount from UsageModel and the overloaded toModel(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add carryOverTotal to UsageData/UsageModel and display a 'Deferred from previous periods' row in UsageTable when carry-over is present. The dialog total now matches the actual invoice total for invoices that settled previously deferred usage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…fix missing download button for CSV
…s on invoices page
Extract AmountItem, CarryOverRow, and CarryOverList into separate files so each TSX file contains exactly one React component. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ensure usage is billed when below the minimum threshold if total is also below it. Adjust logic to always bill usage in subscription renewal invoices to prevent unbilled usage while charging the invoice.
Update CarryOverList to use PaginatedHateoasList with page state. Update billingApiSchema to reflect paginated carry-over endpoints (PagedModelCarryOverModel with page/size/sort query params). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add test selectors to OrgInvoicesSection, CarryOversSection, and CarryOverRow for Cypress e2e test automation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Covers the new /administration/invoices page: - Invoice list renders with correct numbers and totals - Organization filter narrows results - Carry-overs active tab shows pending items - Carry-overs history tab shows settled items with links Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This reverts commit fc5c05d.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ing" This reverts commit 11f4b24.
SubscriptionType enum serializes as uppercase (CLOUD, SELF_HOSTED). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- TestDataService.cleanTestData now uses findAllByNameIncludingDeleted + deleteHard so test orgs do not accumulate as soft-deleted rows between e2e runs. - OrgInvoicesSection: show deleted orgs in the filter with a MUI Chip (via renderOption) and debounce the org search input by 500ms. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reverts the hard-delete cleanup in TestDataService.cleanTestData and the findAllByNameIncludingDeleted repository/service methods. Test-data accumulation of soft-deleted orgs will be resolved separately. - Reverts the deleted-org Chip in OrgInvoicesSection. To avoid leftover soft-deleted orgs polluting the autocomplete, the org query now passes filterDeleted=false so only live orgs are shown. - Keeps the 500ms debounce on the org search input.
ef6f45c to
13497ff
Compare
Summary by CodeRabbit
New Features
Tests