Skip to content

feat(payment): add QR code generation#7751

Merged
uuganaa1007 merged 1 commit into
mainfrom
payment-qr-feat
May 21, 2026
Merged

feat(payment): add QR code generation#7751
uuganaa1007 merged 1 commit into
mainfrom
payment-qr-feat

Conversation

@uuganaa1007
Copy link
Copy Markdown
Collaborator

@uuganaa1007 uuganaa1007 commented May 21, 2026

Summary by Sourcery

Add QR-code based invoice ticketing, email delivery, and scanning support across payment APIs and UI.

New Features:

  • Send QR-code based invoice tickets via email after successful payments, controlled per payment method.
  • Allow scanning invoice barcodes to validate paid invoices and mark them as scanned, with GraphQL mutation, widget mutation, and subscription updates wired through backend and UI.
  • Expose invoice scanned timestamps in API, schema, and UI, including a new column in the invoice table and real-time updates via subscriptions.
  • Add client-side invoice filtering by status, payment kind, and search, with a new filter bar and kind/status-specific filters.

Enhancements:

  • Refine invoice querying and counting logic to support combined kind and search filters using transaction and payment method relations.
  • Switch invoice paid callbacks to use a worker queue API for more robust background processing with retries.
  • Make email delivery records support system-initiated emails by allowing userId to be optional.
  • Extend payment method configuration to support a sendEmailOnPayment flag across backend types, schema, and settings UI.
  • Harden client portal contact user creation by handling username separately and normalizing email usage.

Summary by CodeRabbit

  • New Features
    • Invoice barcode scanning - scan invoice barcodes to update payment status with real-time tracking of scanned events
    • Payment email configuration - new "Send email on payment" setting to control email delivery for payment methods
    • Scanned invoice tracking - displays scanned timestamp on invoices with live subscription-based updates
    • Enhanced invoice filtering - comprehensive filtering by invoice status and payment method kind

Review Change Stack

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 21, 2026

Reviewer's Guide

Adds QR-code-based ticketing for invoices, including email delivery on successful payment, barcode scanning workflow with real-time updates, and enhanced invoice filtering and payment configuration, while refactoring invoice kind filtering logic and relaxing email delivery user requirements.

Sequence diagram for invoice QR email on successful payment

sequenceDiagram
  participant Client as ClientPortal
  participant InvoicesResolver as invoicesCheck
  participant InvoicesModel as models.Invoices
  participant PaymentMethodsModel as models.PaymentMethods
  participant QRMailer as sendInvoiceBarcodeEmail
  participant Notifications as sendTRPCMessage
  participant QRCode as QRCode

  Client->>InvoicesResolver: invoicesCheck(_id)
  InvoicesResolver->>InvoicesModel: getInvoice({ _id }, true)
  InvoicesModel-->>InvoicesResolver: invoice
  InvoicesResolver->>PaymentMethodsModel: findOne({ _id: paymentId }).lean()
  PaymentMethodsModel-->>InvoicesResolver: payment
  InvoicesResolver->>InvoicesResolver: updateOne({ _id }, { sendEmailOnPayment: true })
  InvoicesResolver->>QRMailer: sendInvoiceBarcodeEmail(subdomain, invoice)
  QRMailer->>QRCode: create(ticketCode, { errorCorrectionLevel: 'M' })
  QRMailer->>Notifications: sendTRPCMessage({ pluginName: core, module: notifications, action: sendEmail })
Loading

Sequence diagram for invoice barcode scanning and real-time updates

sequenceDiagram
  actor Scanner as ScannerClient
  participant GQLAPI as invoiceScanBarcode
  participant InvoicesModel as models.Invoices
  participant PubSub as graphqlPubsub
  participant UI as useInvoices.subscribeToMore

  Scanner->>GQLAPI: invoiceScanBarcode(code)
  GQLAPI->>InvoicesModel: findOne({ invoiceNumber: code }).lean()
  InvoicesModel-->>GQLAPI: invoice
  GQLAPI->>InvoicesModel: scanBarcode(code)
  InvoicesModel-->>GQLAPI: scanned
  GQLAPI->>PubSub: publish(invoiceUpdated:scanned._id, { invoiceUpdated: scanned })
  GQLAPI->>PubSub: publish(invoiceScanned, { invoiceScanned: scanned })
  PubSub-->>Scanner: invoiceScanBarcode response (scanned)

  UI->>UI: useInvoices()
  UI->>UI: subscribeToMore({ document: INVOICE_SCANNED_SUBSCRIPTION })
  PubSub-->>UI: INVOICE_SCANNED_SUBSCRIPTION
  UI->>UI: updateQuery(prev, subscriptionData)
Loading

File-Level Changes

Change Details Files
Send QR-code ticket emails when invoices are marked as paid, controlled by a per-payment-method flag, and refactor worker callback dispatching to use a queue API.
  • Introduce sendInvoiceBarcodeEmail helper that generates an HTML email with a rendered QR code table and sends it via TRPC notifications
  • On invoicesCheck when status becomes paid, load the primary payment method, gate email sending by payment.sendEmailOnPayment, persist sendEmailOnPayment flag on the invoice, and fire-and-forget QR email sending
  • Replace sendWorkerMessage with sendWorkerQueue(...).add(...) for the payments callback worker, carrying subdomain and invoice data, and adjust error logging message
  • Extend payment mutation and schema to accept sendEmailOnPayment and persist it in the PaymentMethods model and schema, defaulting to true
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/invoices.ts
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/payments.ts
backend/plugins/payment_api/src/modules/payment/graphql/schemas/payment.ts
backend/plugins/payment_api/src/modules/payment/db/definitions/payment.ts
backend/plugins/payment_api/src/modules/payment/@types/payment.ts
Allow invoices to be scanned via QR/barcode, tracking scan time, validating invoice status, and broadcasting updates via GraphQL subscriptions to both widget and UI.
  • Add scannedAt field to invoice schema, types, and API responses across backend and frontend models
  • Implement Invoices.scanBarcode static method that atomically marks an invoice as scanned once, with specific errors for missing or already-scanned barcodes
  • Add invoiceScanBarcode GraphQL mutation and resolver that validates invoice existence and paid status, calls scanBarcode, and publishes invoiceUpdated and invoiceScanned events via graphqlPubsub
  • Expose SCAN_BARCODE / INVOICE_SCAN_BARCODE mutations in widget and payment UI GraphQL layers, including scannedAt in selections
  • Register invoiceScanned subscription in the payment Apollo subscription schema and wire it to graphqlPubsub
backend/plugins/payment_api/src/modules/payment/db/definitions/invoices.ts
backend/plugins/payment_api/src/modules/payment/db/models/Invoices.ts
backend/plugins/payment_api/src/modules/payment/graphql/schemas/invoices.ts
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/invoices.ts
backend/plugins/payment_api/src/widget/src/lib/graphql.ts
frontend/plugins/payment_ui/src/modules/payment/graphql/mutations.ts
frontend/plugins/payment_ui/src/modules/payment/graphql/queries.ts
backend/plugins/payment_api/src/apollo/subscription.ts
backend/plugins/payment_api/src/widget/src/types/index.ts
frontend/plugins/payment_ui/src/modules/payment/types/Payment.ts
backend/plugins/payment_api/src/modules/payment/@types/invoices.ts
Update invoice listing UI with real-time scan updates, filter bar for status and kind, and a column showing scan status.
  • Extend useInvoices hook to sync status and kind query params, pass them as variables, switch to network-only fetch policy, and subscribe to INVOICE_SCANNED_SUBSCRIPTION to merge scan updates into the list
  • Add InvoiceFilterBar component with Filter/Combobox-based controls for search, status, and kind, backed by URL query state and cursor session key
  • Introduce InvoiceStatusFilter and InvoiceKindFilter components using Command and PAYMENT_KINDS as sources
  • Include InvoiceFilterBar in InvoiceRecordTable and add a scannedAt column to InvoiceColumns with a QR icon, showing relative scan time or a 'Not scanned' badge
frontend/plugins/payment_ui/src/modules/payment/hooks/use-invoices.tsx
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceRecordTable.tsx
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceColumns.tsx
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceFilterBar.tsx
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceStatusFilter.tsx
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceKindFilter.tsx
frontend/plugins/payment_ui/src/modules/payment/graphql/queries.ts
frontend/plugins/payment_ui/src/modules/payment/types/Payment.ts
Enhance payment method form to control whether emails are sent on payment and correctly separate top-level fields from config.
  • Initialize new payments with sendEmailOnPayment defaulting to true and map existing payment.sendEmailOnPayment !== false when editing
  • Persist sendEmailOnPayment (normalized to boolean) when submitting the form
  • Introduce a topLevelKeys set including sendEmailOnPayment to avoid leaking it into config
  • Add a UI switch field with explanatory text to toggle email sending after successful payment
frontend/plugins/payment_ui/src/modules/settings/payment/components/PaymentForm.tsx
Refine invoice filtering by kind and search, and adjust counts aggregation logic to work with the new kind model.
  • Replace simple paymentKind filter with buildKindQuery that derives invoice IDs from Transactions and paymentIds from PaymentMethods for a given kind, and compose these into an $or filter or an empty result when none found
  • Adapt generateFilterQuery to be async and accept models, injecting the buildKindQuery result, and enhance searchValue to match both description and invoiceNumber while correctly combining with existing $or via $and
  • Update invoices and cpInvoices resolvers to await generateFilterQuery
  • Rewrite paymentsTotalCount byKind loop to use buildKindQuery and combine with other filters via $and when needed, respecting params.kind
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/queries/invoices.ts
Relax and harden some ancillary behaviors: make email deliveries not require userId and make CP user creation safer with username handling.
  • Make userId optional (non-required) in emailDeliverySchema and type to support system emails without a user
  • Adjust CP contact/user creation to omit username from the spread, then re-add it only when non-null, for both customer and company users
  • Minor formatting cleanup in contactService
backend/erxes-api-shared/src/core-modules/notifications/definitions/emailDeliveries.ts
backend/core-api/src/modules/clientportal/services/user/contactService.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR adds invoice barcode scanning with real-time subscription updates, introduces configurable email sending on payments, improves invoice filtering, and includes minor schema updates for email delivery and contact handling across backend and frontend.

Changes

Invoice Barcode Scanning Feature

Layer / File(s) Summary
Invoice model barcode scanning
backend/plugins/payment_api/src/modules/payment/@types/invoices.ts, backend/plugins/payment_api/src/modules/payment/db/definitions/invoices.ts, backend/plugins/payment_api/src/modules/payment/db/models/Invoices.ts
IInvoice extended with optional scannedAt?: Date field. Mongoose schema adds corresponding date field. Model gains scanBarcode(code) method that atomically sets scan timestamp when unset, distinguishing between not-found and already-scanned invoice states.
GraphQL subscription and barcode mutation schema
backend/plugins/payment_api/src/apollo/subscription.ts, backend/plugins/payment_api/src/modules/payment/graphql/schemas/invoices.ts
GraphQL subscription for invoiceScanned: JSON event added. Invoice schema extended with scannedAt: Date field and new invoiceScanBarcode(code: String!): Invoice mutation.
Invoice barcode scan mutation resolver
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/invoices.ts
New invoiceScanBarcode mutation resolver validates invoice existence and paid status, invokes model scanBarcode method, publishes invoiceUpdated:<id> and invoiceScanned subscription events, and includes skipPermission: true wrapper config.
Invoice paid status side effects
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/invoices.ts
invoicesCheck payment flow enhanced: conditionally sends barcode email via new sendInvoiceBarcodeEmail helper (generates QR code and sends via TRPC), sets sendEmailOnPayment from payment method config, enqueues worker job with retry/backoff instead of direct dispatch, and includes explicit enqueue error handling.
Invoice query filtering by kind, status, and search
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/queries/invoices.ts
Async buildKindQuery helper derives invoice IDs from Transactions and PaymentMethods. generateFilterQuery converted to async, accepts models parameter, and uses kind-based querying. searchValue builds regex $or over description/invoiceNumber with collision-safe $and wrapping. Resolvers await async filter builder. invoicesTotalCount refactored to compute per-kind and per-status metrics using combined $and queries.
Frontend GraphQL client for barcode scan
backend/plugins/payment_api/src/widget/src/lib/graphql.ts, frontend/plugins/payment_ui/src/modules/payment/graphql/mutations.ts, frontend/plugins/payment_ui/src/modules/payment/graphql/queries.ts
New SCAN_BARCODE mutation, INVOICE_SCAN_BARCODE mutation, and INVOICE_SCANNED_SUBSCRIPTION subscription exports. INVOICES query extended to include scannedAt field. Frontend types updated with optional scannedAt?: Date on Invoice and Payment types.
Invoice table display with scanned status
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceColumns.tsx
New scannedAt column renders relative-date badge when scanned, or "Not scanned" outline badge when absent. Includes IconQrcode icon import.
Invoice filter bar and status/kind filters
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceFilterBar.tsx, frontend/plugins/payment_ui/src/modules/payment/components/InvoiceStatusFilter.tsx, frontend/plugins/payment_ui/src/modules/payment/components/InvoiceKindFilter.tsx, frontend/plugins/payment_ui/src/modules/payment/components/InvoiceRecordTable.tsx
New InvoiceFilterBar component manages status/kind/searchValue query state with popover menu and bar items. InvoiceStatusFilter provides fixed status options with check icon for selected state. InvoiceKindFilter lists payment kinds from constants with selection indicator. FilterBar rendered above invoice record table.
useInvoices hook with filtering and subscriptions
frontend/plugins/payment_ui/src/modules/payment/hooks/use-invoices.tsx
Hook extended to maintain searchValue, status, kind filter state and pass into INVOICES query. Adds useEffect subscription to INVOICE_SCANNED_SUBSCRIPTION that merges scanned invoice data into cached invoices.list by matching _id, enabling real-time list updates.

Payment Method Email Configuration

Layer / File(s) Summary
Payment type and schema with email flag
backend/plugins/payment_api/src/modules/payment/@types/payment.ts, backend/plugins/payment_api/src/modules/payment/db/definitions/payment.ts, backend/plugins/payment_api/src/modules/payment/graphql/schemas/payment.ts
IPayment interface extended with optional sendEmailOnPayment?: boolean. Mongoose schema adds field with default: true. GraphQL Payment type and PaymentInput input type both include optional sendEmailOnPayment: Boolean.
Payment edit mutation resolver
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/payments.ts
paymentEdit resolver now destructures and conditionally includes sendEmailOnPayment in update document payload.
Payment form UI with email toggle
frontend/plugins/payment_ui/src/modules/settings/payment/components/PaymentForm.tsx
Switch component imported. New form field for sendEmailOnPayment with default value true. Field initialized from existing payment when editing or set to true for new payment. Submitted in top-level IPayment input via updated topLevelKeys set to exclude from config nesting.

Supporting Updates

Layer / File(s) Summary
Email delivery and contact service
backend/erxes-api-shared/src/core-modules/notifications/definitions/emailDeliveries.ts, backend/core-api/src/modules/clientportal/services/user/contactService.ts
Email delivery userId field changed from required to optional in both interface and schema. Contact service handleCustomerUser and handleCompanyUser refactored to explicitly handle username field: excluded from spread, then conditionally re-added only when not null.

🎯 4 (Complex) | ⏱️ ~60 minutes

🐰 A barcode hopped into the invoice store,
With scans and subscriptions to explore,
Emails dance when payments arise,
Filtering kinds through the backend skies,
Real-time updates, the frontend soars!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title "feat(payment): add QR code generation" accurately captures the main feature added, which includes barcode/QR code functionality throughout the payment module.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch payment-qr-feat

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

@github-actions
Copy link
Copy Markdown

🌗 Pull Request Overview

This PR adds QR code generation functionality for payment invoices, including barcode scanning capabilities, email notifications with QR codes upon successful payment, and filtering enhancements for invoice management. It introduces a new scannedAt field to track when invoices are scanned and a sendEmailOnPayment configuration option.

Reviewed Changes
Kimi performed full review on 25 changed files and found 3 issues.

Show a summary per file
File Description
backend/core-api/src/modules/clientportal/services/user/contactService.ts Refactors username handling to conditionally include only non-null values in user/company creation
backend/erxes-api-shared/src/core-modules/notifications/definitions/emailDeliveries.ts Makes userId field optional in email delivery schema
backend/plugins/payment_api/src/apollo/subscription.ts Adds invoiceScanned GraphQL subscription for real-time scan notifications
backend/plugins/payment_api/src/modules/payment/@types/invoices.ts Adds scannedAt?: Date field to invoice type definition
backend/plugins/payment_api/src/modules/payment/@types/payment.ts Adds sendEmailOnPayment?: boolean field to payment type
backend/plugins/payment_api/src/modules/payment/db/definitions/invoices.ts Adds scannedAt field to Mongoose invoice schema
backend/plugins/payment_api/src/modules/payment/db/definitions/payment.ts Adds sendEmailOnPayment boolean field with default true to payment schema
backend/plugins/payment_api/src/modules/payment/db/models/Invoices.ts Adds scanBarcode static method for marking invoices as scanned
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/invoices.ts Implements QR code email generation and invoiceScanBarcode mutation
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/payments.ts Adds sendEmailOnPayment support to payment edit mutation
backend/plugins/payment_api/src/modules/payment/graphql/resolvers/queries/invoices.ts Refactors kind-based filtering to use transactions and payment methods lookup
backend/plugins/payment_api/src/modules/payment/graphql/schemas/invoices.ts Adds scannedAt field and invoiceScanBarcode mutation to schema
backend/plugins/payment_api/src/modules/payment/graphql/schemas/payment.ts Adds sendEmailOnPayment field to payment type and input definitions
backend/plugins/payment_api/src/widget/src/lib/graphql.ts Adds SCAN_BARCODE GraphQL mutation for widget
backend/plugins/payment_api/src/widget/src/types/index.ts Adds scannedAt field to Invoice type
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceColumns.tsx Adds new column displaying scan status with QR icon
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceFilterBar.tsx New file: filter bar component for invoice filtering by status and kind
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceKindFilter.tsx New file: payment kind filter dropdown component
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceRecordTable.tsx Integrates InvoiceFilterBar into the record table
frontend/plugins/payment_ui/src/modules/payment/components/InvoiceStatusFilter.tsx New file: invoice status filter dropdown component
frontend/plugins/payment_ui/src/modules/payment/graphql/mutations.ts Adds INVOICE_SCAN_BARCODE mutation definition
frontend/plugins/payment_ui/src/modules/payment/graphql/queries.ts Adds INVOICE_SCANNED_SUBSCRIPTION subscription and scannedAt field
frontend/plugins/payment_ui/src/modules/payment/hooks/use-invoices.tsx Adds subscription handling and multi-query state for filters
frontend/plugins/payment_ui/src/modules/payment/types/Payment.ts Adds sendEmailOnPayment to IPayment and scannedAt to IInvoice
frontend/plugins/payment_ui/src/modules/settings/payment/components/PaymentForm.tsx Adds toggle switch for sendEmailOnPayment configuration

📋 Review Findings

📄 backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/invoices.ts

🟠 HIGH bug: Potential unhandled promise rejection in QR code generation

Lines 25-90

The sendInvoiceBarcodeEmail function throws an error if QR code generation fails (line 88), but this function is called in a fire-and-forget pattern without proper error handling. While there's a .catch(() => undefined) on the promise, the throw new Error inside the try-catch block creates an unhandled rejection when the async function rejects.

💡 Suggested fix:

Wrap the entire email sending logic in a try-catch to prevent unhandled rejections:

async function sendInvoiceBarcodeEmail(...) {
  try {
    const ticketCode = invoice.invoiceNumber || invoice._id;
    // ... QR generation code ...
    
    if (!ticketCode) {
      console.error('No ticket code available for invoice:', invoice._id);
      return;
    }
    
    // ... rest of the function ...
  } catch (err) {
    console.error(`Failed to send barcode email for invoice ${invoice?._id}:`, err);
    // Don't throw - this is fire-and-forget
  }
}

🟡 MEDIUM performance: Missing database index for invoiceNumber lookups

Lines 358-361, 375-377

The scanBarcode method and invoiceScanBarcode resolver both query by invoiceNumber field. Without an index, this will cause collection scans on large datasets.

💡 Suggested fix:

Add an index to the invoice schema in backend/plugins/payment_api/src/modules/payment/db/definitions/invoices.ts:

export const invoiceSchema = schemaWrapper(
  new Schema({
    // ... existing fields ...
    invoiceNumber: { 
      type: String, 
      index: true  // Add this
    },
    // ... rest of schema ...
  })
);

📄 backend/plugins/payment_api/src/modules/payment/graphql/resolvers/queries/invoices.ts

🟡 MEDIUM performance: N+1 query pattern in invoice counting

Lines 113-125

The invoicesTotalCount resolver loops through all payment kinds and executes separate database queries for each. With many payment kinds, this creates unnecessary database load.

💡 Suggested fix:

Consider using aggregation pipeline to count all kinds in a single query:

// Instead of looping and querying individually:
const results = await models.Invoices.aggregate([
  { $match: qry },
  { $group: { 
      _id: '$paymentKind', 
      count: { $sum: 1 } 
  }}
]);
// Then map results to the counts object

📄 frontend/plugins/payment_ui/src/modules/settings/payment/components/PaymentForm.tsx

🔵 LOW maintainability: Redundant boolean comparison

Line 432

The checked prop uses field.value !== false comparison which is unnecessary since the form uses sendEmailOnPayment: true as default.

💡 Suggested fix:

Simplify to direct boolean:

<Switch
  checked={!!field.value}
  onCheckedChange={field.onChange}
/>

Or if you want to ensure explicit true/false:

<Switch
  checked={field.value === true}
  onCheckedChange={field.onChange}
/>

📄 backend/plugins/payment_api/src/modules/payment/db/models/Invoices.ts

No issues found. The scanBarcode method properly uses atomic findOneAndUpdate with the {scannedAt: null} condition to prevent race conditions when multiple scanners attempt to scan the same barcode simultaneously.


📄 frontend/plugins/payment_ui/src/modules/payment/hooks/use-invoices.tsx

No issues found. The subscription implementation correctly handles cleanup via the returned unsubscribe function from useEffect, and the updateQuery function properly merges subscription data with existing cache.


📄 backend/plugins/payment_api/src/modules/payment/graphql/resolvers/mutations/invoices.ts

Good practice: The fire-and-forget worker queue usage with proper error logging (lines 227-244) is well-implemented. Using sendWorkerQueue instead of sendWorkerMessage provides better reliability with built-in retry mechanisms.


Powered by Kimi | Model: kimi-k2.5

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The sendInvoiceBarcodeEmail helper in invoices.ts mixes QR generation logic and a large inline HTML template inside the resolver; consider extracting the email template and QR table rendering into a separate utility/module and guard against missing invoice.email before calling sendTRPCMessage.
  • generateFilterQuery/buildKindQuery now run multiple distinct queries per request and again inside invoicesTotalCount for each kind, which can become N+1 style DB calls; consider caching the buildKindQuery result per request or restructuring the aggregation to avoid repeated Transactions/PaymentMethods lookups for each kind.
  • In InvoiceStatusFilter and InvoiceKindFilter, setQueries({ status: ... }) / setQueries({ kind: ... }) may overwrite other query params (e.g. searchValue or the other filter); if useMultiQueryState does not merge by default, switch to an updater function that preserves existing keys when applying a single filter.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `sendInvoiceBarcodeEmail` helper in `invoices.ts` mixes QR generation logic and a large inline HTML template inside the resolver; consider extracting the email template and QR table rendering into a separate utility/module and guard against missing `invoice.email` before calling `sendTRPCMessage`.
- `generateFilterQuery`/`buildKindQuery` now run multiple `distinct` queries per request and again inside `invoicesTotalCount` for each kind, which can become N+1 style DB calls; consider caching the `buildKindQuery` result per request or restructuring the aggregation to avoid repeated `Transactions`/`PaymentMethods` lookups for each kind.
- In `InvoiceStatusFilter` and `InvoiceKindFilter`, `setQueries({ status: ... })` / `setQueries({ kind: ... })` may overwrite other query params (e.g. `searchValue` or the other filter); if `useMultiQueryState` does not merge by default, switch to an updater function that preserves existing keys when applying a single filter.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

} from 'erxes-api-shared/utils';
import { IContext } from '~/connectionResolvers';
import { IInvoice } from '~/modules/payment/@types/invoices';
import { IInvoice, IInvoiceDocument } from '~/modules/payment/@types/invoices';
Comment on lines +1 to +5
import {
IconProgressCheck,
IconSearch,
IconWallet,
} from '@tabler/icons-react';
@sonarqubecloud
Copy link
Copy Markdown

@uuganaa1007 uuganaa1007 merged commit d3827af into main May 21, 2026
30 of 34 checks passed
@uuganaa1007 uuganaa1007 deleted the payment-qr-feat branch May 21, 2026 08:22
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