Compare commits

...

11 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
518abcd30d Merge pull request #917 from bigcapitalhq/20260128-195652-2287
fix: dockerfile build script
2026-01-28 23:42:24 +02:00
Ahmed Bouhuolia
7874b9f765 fix(ci): dockerfile build script 2026-01-28 23:40:32 +02:00
Ahmed Bouhuolia
02cc7e0c96 Merge pull request #916 from bigcapitalhq/20260128-181425-8b6a
fix(webapp): blueprintjs datetime version
2026-01-28 18:17:29 +02:00
Ahmed Bouhuolia
57cc513873 fix(webapp): blueprintjs datetime version 2026-01-28 18:14:44 +02:00
Ahmed Bouhuolia
f5bfdede30 Merge pull request #915 from bigcapitalhq/fix-vendor-customer-edit-opening-balance
fix(webapp): vendor/customer edit opening balance
2026-01-27 22:09:00 +02:00
Ahmed Bouhuolia
488556bb59 fix(webapp): vendor/customer edit opening balance 2026-01-27 22:06:57 +02:00
Ahmed Bouhuolia
0fc5a66e95 Merge pull request #914 from bigcapitalhq/fix-costable-inventory-transactions
fix(server): costable attr of inventory gl entries
2026-01-26 15:02:35 +02:00
Ahmed Bouhuolia
d9ae51027e fix(server): costable attr of inventory gl entries 2026-01-26 15:00:17 +02:00
Ahmed Bouhuolia
a92d6112d9 Merge pull request #913 from bigcapitalhq/feature/20260125222025
fix(server): sale receipt cost gl entries
2026-01-25 22:22:08 +02:00
Ahmed Bouhuolia
889b0cec4b fix(server): sale receipt cost gl entries 2026-01-25 22:20:28 +02:00
Ahmed Bouhuolia
1c4c41ebba Merge pull request #912 from bigcapitalhq/feature/20260125215941
fix(server): mark compute inventory cost flag
2026-01-25 22:02:13 +02:00
26 changed files with 491 additions and 479 deletions

93
.dockerignore Normal file
View File

@@ -0,0 +1,93 @@
# Dependencies
node_modules/
**/node_modules/
.pnpm-store/
# Build outputs
dist/
build/
**/dist/
**/build/
*.tsbuildinfo
# Development files
.git/
.gitignore
.vscode/
.idea/
*.swp
*.swo
*~
# Test files
test/
**/test/
**/*.spec.ts
**/*.test.ts
**/*.e2e-spec.ts
coverage/
.nyc_output/
test-results/
playwright-report/
# Documentation
*.md
!README.md
docs/
CHANGELOG.md
CONTRIBUTING.md
DISCLAIMER
LICENSE
# CI/CD
.github/
.gitpod.yml
# Environment files
.env
.env.*
!.env.example
# Logs
*.log
logs/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# OS files
.DS_Store
Thumbs.db
*.pid
*.seed
*.pid.lock
# Docker files (don't copy Dockerfiles into themselves)
docker-compose*.yml
Dockerfile*
.dockerignore
# Misc
.cache/
.temp/
tmp/
*.tmp
.qodo/
e2e/
playwright.config.ts
# Source maps (not needed in production)
*.map
# TypeScript configs (not needed at runtime)
tsconfig*.json
!tsconfig.json
# Linting/formatting
.eslintrc*
.prettierrc*
.eslintcache
# Package manager locks (we copy them explicitly)
# pnpm-lock.yaml

View File

@@ -58,6 +58,12 @@ services:
# System database
- SYSTEM_DB_NAME=${SYSTEM_DB_NAME}
# Redis
- REDIS_HOST=redis
- REDIS_PORT=6379
- QUEUE_HOST=redis
- QUEUE_PORT=6379
# Tenants databases
- TENANT_DB_NAME_PERFIX=${TENANT_DB_NAME_PERFIX}

View File

@@ -35,4 +35,4 @@ WORKDIR /app/packages/server
RUN git clone https://github.com/vishnubob/wait-for-it.git
# Once we listen the mysql port run the migration task.
CMD ./wait-for-it/wait-for-it.sh mysql:3306 -- sh -c "node ./build/commands.js system:migrate:latest && node ./build/commands.js tenants:migrate:latest"
CMD ./wait-for-it/wait-for-it.sh mysql:3306 -- sh -c "pnpm run system:migrate:latest && pnpm run tenants:migrate:latest"

View File

@@ -1,100 +1,99 @@
FROM node:18.16.0-alpine as build
# Stage 1: Build
FROM node:18.16.0-alpine AS builder
USER root
ARG MAIL_HOST= \
MAIL_USERNAME= \
MAIL_PASSWORD= \
MAIL_PORT= \
MAIL_SECURE= \
MAIL_FROM_NAME= \
MAIL_FROM_ADDRESS= \
# Database
DB_HOST= \
DB_USER= \
DB_PASSWORD= \
DB_CHARSET= \
# System database.
SYSTEM_DB_NAME= \
SYSTEM_DB_PASSWORD= \
SYSTEM_DB_USER= \
SYSTEM_DB_HOST= \
SYSTEM_DB_CHARSET= \
# Tenant databases.
TENANT_DB_USER= \
TENANT_DB_PASSWORD= \
TENANT_DB_HOST= \
TENANT_DB_NAME_PERFIX= \
TENANT_DB_CHARSET= \
# Authentication
JWT_SECRET= \
# Application
BASE_URL= \
# Sign-up restriction
SIGNUP_DISABLED= \
SIGNUP_ALLOWED_DOMAINS= \
SIGNUP_ALLOWED_EMAILS=
ENV MAIL_HOST=$MAIL_HOST \
MAIL_USERNAME=$MAIL_USERNAME \
MAIL_PASSWORD=$MAIL_PASSWORD \
MAIL_PORT=$MAIL_PORT \
MAIL_SECURE=$MAIL_SECURE \
MAIL_FROM_NAME=$MAIL_FROM_NAME \
MAIL_FROM_ADDRESS=$MAIL_FROM_ADDRESS \
# Database
DB_HOST=$DB_HOST \
DB_USER=$DB_USER \
DB_PASSWORD=$DB_PASSWORD \
DB_CHARSET=$DB_CHARSET \
# System database.
SYSTEM_DB_HOST=$SYSTEM_DB_HOST \
SYSTEM_DB_USER=$SYSTEM_DB_USER \
SYSTEM_DB_PASSWORD=$SYSTEM_DB_PASSWORD \
SYSTEM_DB_NAME=$SYSTEM_DB_NAME \
SYSTEM_DB_CHARSET=$SYSTEM_DB_CHARSET \
# Tenant databases.
TENANT_DB_NAME_PERFIX=$TENANT_DB_NAME_PERFIX \
TENANT_DB_HOST=$TENANT_DB_HOST \
TENANT_DB_PASSWORD=$TENANT_DB_PASSWORD \
TENANT_DB_USER=$TENANT_DB_USER \
TENANT_DB_CHARSET=$TENANT_DB_CHARSET \
# Authentication
JWT_SECRET=$JWT_SECRET \
# Application
BASE_URL=$BASE_URL \
# Sign-up restriction
SIGNUP_DISABLED=$SIGNUP_DISABLED \
SIGNUP_ALLOWED_DOMAINS=$SIGNUP_ALLOWED_DOMAINS \
SIGNUP_ALLOWED_EMAILS=$SIGNUP_ALLOWED_EMAILS
# New Relic config file.
ENV NEW_RELIC_NO_CONFIG_FILE=true
# Create app directory.
WORKDIR /app
RUN chown node:node /
# Install pnpm
RUN npm install -g pnpm@8.10.2
# Install pnpm
RUN npm install -g pnpm
# Install build dependencies
RUN apk add --no-cache python3 build-base chromium
# Copy application dependency manifests to the container image.
COPY --chown=node:node ./ ./
# Install application dependencies
RUN apk update
RUN apk add python3 build-base chromium
# Set PYHTON env
# Set Python environment
ENV PYTHON=/usr/bin/python3
# Install packages dependencies for production.
RUN pnpm install
# Copy package files for dependency installation
COPY --chown=node:node package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./
COPY --chown=node:node packages/server/package.json ./packages/server/
COPY --chown=node:node shared/bigcapital-utils/package.json ./shared/bigcapital-utils/
COPY --chown=node:node shared/pdf-templates/package.json ./shared/pdf-templates/
COPY --chown=node:node shared/email-components/package.json ./shared/email-components/
# Install all dependencies (including devDependencies for build)
RUN pnpm install --frozen-lockfile
# Copy source code
COPY --chown=node:node ./packages/server ./packages/server
COPY --chown=node:node ./shared/bigcapital-utils ./shared/bigcapital-utils
COPY --chown=node:node ./shared/pdf-templates ./shared/pdf-templates
COPY --chown=node:node ./shared/email-components ./shared/email-components
# # Creates a "dist" folder with the production build
# Build NestJS application
RUN pnpm run build:server --skip-nx-cache
CMD [ "node", "./packages/server/build/index.js" ]
# Stage 2: Production
FROM node:18.16.0-alpine AS production
WORKDIR /app
# Install pnpm for production
RUN npm install -g pnpm@8.10.2
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# Install build dependencies for native modules (bcrypt, etc.)
RUN apk add --no-cache python3 build-base
# Set Python environment
ENV PYTHON=/usr/bin/python3
# Copy package files for production dependency installation
COPY --chown=nodejs:nodejs package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY --chown=nodejs:nodejs packages/server/package.json ./packages/server/
COPY --chown=nodejs:nodejs shared/bigcapital-utils/package.json ./shared/bigcapital-utils/
COPY --chown=nodejs:nodejs shared/pdf-templates/package.json ./shared/pdf-templates/
COPY --chown=nodejs:nodejs shared/email-components/package.json ./shared/email-components/
# Copy .husky directory (needed for husky install command)
COPY --chown=nodejs:nodejs .husky ./.husky
# Install only production dependencies
# Install husky temporarily so prepare script can run, then remove it
RUN pnpm add -D -w husky && \
pnpm install --prod --frozen-lockfile && \
pnpm remove -w husky && \
# Remove build dependencies to reduce image size
apk del python3 build-base
# Copy built application from builder stage
COPY --from=builder --chown=nodejs:nodejs /app/packages/server/dist ./packages/server/dist
# Copy static assets (i18n, public, static directories)
COPY --from=builder --chown=nodejs:nodejs /app/packages/server/src/i18n ./packages/server/dist/i18n
COPY --from=builder --chown=nodejs:nodejs /app/packages/server/public ./packages/server/public
COPY --from=builder --chown=nodejs:nodejs /app/packages/server/static ./packages/server/static
# Copy built shared packages (dist folders and package.json for module resolution)
COPY --from=builder --chown=nodejs:nodejs /app/shared/bigcapital-utils/dist ./shared/bigcapital-utils/dist
COPY --from=builder --chown=nodejs:nodejs /app/shared/pdf-templates/dist ./shared/pdf-templates/dist
COPY --from=builder --chown=nodejs:nodejs /app/shared/email-components/dist ./shared/email-components/dist
# Set runtime environment variables (these should be provided at runtime via docker-compose or k8s)
ENV NODE_ENV=production
ENV NEW_RELIC_NO_CONFIG_FILE=true
ENV PORT=3000
# Switch to non-root user
USER nodejs
# Expose port
EXPOSE 3000
# Health check - uses /api/system_db ping endpoint
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/api/system_db', (r) => {process.exit(r.statusCode >= 200 && r.statusCode < 300 ? 0 : 1)}).on('error', () => process.exit(1))"
# Start the application
CMD [ "node", "packages/server/dist/main.js" ]

View File

@@ -17,6 +17,8 @@ import loops from './loops';
import bankfeed from './bankfeed';
import throttle from './throttle';
import cloud from './cloud';
import redis from './redis';
import queue from './queue';
export const config = [
app,
@@ -38,4 +40,6 @@ export const config = [
loops,
bankfeed,
throttle,
redis,
queue,
];

View File

@@ -0,0 +1,6 @@
import { registerAs } from '@nestjs/config';
export default registerAs('queue', () => ({
host: process.env.QUEUE_HOST || 'localhost',
port: parseInt(process.env.QUEUE_PORT, 10) || 6379,
}));

View File

@@ -33,6 +33,7 @@ export class AccountTransaction extends BaseModel {
public readonly userId!: number;
public readonly itemId!: number;
public readonly projectId!: number;
public readonly costable!: boolean;
public readonly account: Account;
/**

View File

@@ -137,8 +137,8 @@ import { AppThrottleModule } from './AppThrottle.module';
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
connection: {
host: configService.get('QUEUE_HOST'),
port: configService.get('QUEUE_PORT'),
host: configService.get('queue.host'),
port: configService.get('queue.port'),
},
}),
inject: [ConfigService],
@@ -158,8 +158,8 @@ import { AppThrottleModule } from './AppThrottle.module';
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
config: {
host: configService.get('redis.host') || 'localhost',
port: configService.get('redis.port') || 6379,
host: configService.get('redis.host'),
port: configService.get('redis.port'),
},
}),
inject: [ConfigService],

View File

@@ -35,7 +35,7 @@ export const transformLedgerEntryToTransaction = (
itemId: entry.itemId,
projectId: entry.projectId,
// costable: entry.costable,
costable: entry.costable,
taxRateId: entry.taxRateId,
taxRate: entry.taxRate,

View File

@@ -0,0 +1,143 @@
import * as R from 'ramda';
import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common';
import { TenantModelProxy } from '../System/models/TenantBaseModel';
import { InventoryCostLotTracker } from '../InventoryCost/models/InventoryCostLotTracker';
import { LedgerStorageService } from '../Ledger/LedgerStorage.service';
import { groupInventoryTransactionsByTypeId } from '../InventoryCost/utils';
import { Ledger } from '../Ledger/Ledger';
import { AccountNormal } from '@/interfaces/Account';
import { ILedgerEntry } from '../Ledger/types/Ledger.types';
import { increment } from '@/utils/increment';
@Injectable()
export class SaleReceiptCostGLEntries {
constructor(
private readonly ledgerStorage: LedgerStorageService,
@Inject(InventoryCostLotTracker.name)
private readonly inventoryCostLotTracker: TenantModelProxy<
typeof InventoryCostLotTracker
>,
) {}
/**
* Writes journal entries from sales receipts.
* @param {Date} startingDate - Starting date.
* @param {Knex.Transaction} trx - Transaction.
*/
public writeInventoryCostJournalEntries = async (
startingDate: Date,
trx?: Knex.Transaction,
): Promise<void> => {
const inventoryCostLotTrans = await this.inventoryCostLotTracker()
.query()
.where('direction', 'OUT')
.where('transaction_type', 'SaleReceipt')
.where('cost', '>', 0)
.modify('filterDateRange', startingDate)
.orderBy('date', 'ASC')
.withGraphFetched('receipt')
.withGraphFetched('item')
.withGraphFetched('itemEntry');
const ledger = this.getInventoryCostLotsLedger(inventoryCostLotTrans);
await this.ledgerStorage.commit(ledger, trx);
};
/**
* Retrieves the inventory cost lots ledger.
*/
private getInventoryCostLotsLedger = (
inventoryCostLots: InventoryCostLotTracker[],
) => {
const inventoryTransactions =
groupInventoryTransactionsByTypeId(inventoryCostLots);
const entries = inventoryTransactions
.map(this.getSaleReceiptCostGLEntries)
.flat();
return new Ledger(entries);
};
/**
* Builds the common GL entry fields for a sale receipt cost.
*/
private getReceiptCostGLCommonEntry = (
inventoryCostLot: InventoryCostLotTracker,
) => {
return {
currencyCode: inventoryCostLot.receipt.currencyCode,
exchangeRate: inventoryCostLot.receipt.exchangeRate,
transactionType: inventoryCostLot.transactionType,
transactionId: inventoryCostLot.transactionId,
transactionNumber: inventoryCostLot.receipt.receiptNumber,
referenceNumber: inventoryCostLot.receipt.referenceNo,
date: inventoryCostLot.date,
indexGroup: 20,
costable: true,
createdAt: inventoryCostLot.createdAt,
debit: 0,
credit: 0,
branchId: inventoryCostLot.receipt.branchId,
};
};
/**
* Retrieves the inventory cost GL entry for a single lot.
*/
private getInventoryCostGLEntry = R.curry(
(
getIndexIncrement: () => number,
inventoryCostLot: InventoryCostLotTracker,
): ILedgerEntry[] => {
const commonEntry = this.getReceiptCostGLCommonEntry(inventoryCostLot);
const costAccountId =
inventoryCostLot.costAccountId || inventoryCostLot.item.costAccountId;
const description = inventoryCostLot.itemEntry?.description || null;
const costEntry = {
...commonEntry,
debit: inventoryCostLot.cost,
accountId: costAccountId,
accountNormal: AccountNormal.DEBIT,
itemId: inventoryCostLot.itemId,
note: description,
index: getIndexIncrement(),
};
const inventoryEntry = {
...commonEntry,
credit: inventoryCostLot.cost,
accountId: inventoryCostLot.item.inventoryAccountId,
accountNormal: AccountNormal.DEBIT,
itemId: inventoryCostLot.itemId,
note: description,
index: getIndexIncrement(),
};
return [costEntry, inventoryEntry];
},
);
/**
* Builds GL entries for a group of sale receipt cost lots.
* - Cost of goods sold -> Debit
* - Inventory assets -> Credit
*/
public getSaleReceiptCostGLEntries = (
inventoryCostLots: InventoryCostLotTracker[],
): ILedgerEntry[] => {
const getIndexIncrement = increment(0);
const getInventoryLotEntry =
this.getInventoryCostGLEntry(getIndexIncrement);
return inventoryCostLots.map((t) => getInventoryLotEntry(t)).flat();
};
}

View File

@@ -40,6 +40,8 @@ import { SaleReceiptsImportable } from './commands/SaleReceiptsImportable';
import { GetSaleReceiptMailStateService } from './queries/GetSaleReceiptMailState.service';
import { GetSaleReceiptMailTemplateService } from './queries/GetSaleReceiptMailTemplate.service';
import { SaleReceiptAutoIncrementSubscriber } from './subscribers/SaleReceiptAutoIncrementSubscriber';
import { SaleReceiptCostGLEntriesSubscriber } from './subscribers/SaleReceiptCostGLEntriesSubscriber';
import { SaleReceiptCostGLEntries } from './SaleReceiptCostGLEntries';
import { BulkDeleteSaleReceiptsService } from './BulkDeleteSaleReceipts.service';
import { ValidateBulkDeleteSaleReceiptsService } from './ValidateBulkDeleteSaleReceipts.service';
@@ -87,6 +89,8 @@ import { ValidateBulkDeleteSaleReceiptsService } from './ValidateBulkDeleteSaleR
GetSaleReceiptMailStateService,
GetSaleReceiptMailTemplateService,
SaleReceiptAutoIncrementSubscriber,
SaleReceiptCostGLEntries,
SaleReceiptCostGLEntriesSubscriber,
BulkDeleteSaleReceiptsService,
ValidateBulkDeleteSaleReceiptsService,
],

View File

@@ -1,148 +0,0 @@
// import { Service, Inject } from 'typedi';
// import * as R from 'ramda';
// import { Knex } from 'knex';
// import { AccountNormal, IInventoryLotCost, ILedgerEntry } from '@/interfaces';
// import { increment } from 'utils';
// import HasTenancyService from '@/services/Tenancy/TenancyService';
// import Ledger from '@/services/Accounting/Ledger';
// import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
// import { groupInventoryTransactionsByTypeId } from '../../Inventory/utils';
// @Service()
// export class SaleReceiptCostGLEntries {
// @Inject()
// private tenancy: HasTenancyService;
// @Inject()
// private ledgerStorage: LedgerStorageService;
// /**
// * Writes journal entries from sales invoices.
// * @param {number} tenantId - The tenant id.
// * @param {Date} startingDate - Starting date.
// * @param {boolean} override
// */
// public writeInventoryCostJournalEntries = async (
// tenantId: number,
// startingDate: Date,
// trx?: Knex.Transaction
// ): Promise<void> => {
// const { InventoryCostLotTracker } = this.tenancy.models(tenantId);
// const inventoryCostLotTrans = await InventoryCostLotTracker.query()
// .where('direction', 'OUT')
// .where('transaction_type', 'SaleReceipt')
// .where('cost', '>', 0)
// .modify('filterDateRange', startingDate)
// .orderBy('date', 'ASC')
// .withGraphFetched('receipt')
// .withGraphFetched('item');
// const ledger = this.getInventoryCostLotsLedger(inventoryCostLotTrans);
// // Commit the ledger to the storage.
// await this.ledgerStorage.commit(tenantId, ledger, trx);
// };
// /**
// * Retrieves the inventory cost lots ledger.
// * @param {} inventoryCostLots
// * @returns {Ledger}
// */
// private getInventoryCostLotsLedger = (
// inventoryCostLots: IInventoryLotCost[]
// ) => {
// // Groups the inventory cost lots transactions.
// const inventoryTransactions =
// groupInventoryTransactionsByTypeId(inventoryCostLots);
// //
// const entries = inventoryTransactions
// .map(this.getSaleInvoiceCostGLEntries)
// .flat();
// return new Ledger(entries);
// };
// /**
// *
// * @param {IInventoryLotCost} inventoryCostLot
// * @returns {}
// */
// private getInvoiceCostGLCommonEntry = (
// inventoryCostLot: IInventoryLotCost
// ) => {
// return {
// currencyCode: inventoryCostLot.receipt.currencyCode,
// exchangeRate: inventoryCostLot.receipt.exchangeRate,
// transactionType: inventoryCostLot.transactionType,
// transactionId: inventoryCostLot.transactionId,
// date: inventoryCostLot.date,
// indexGroup: 20,
// costable: true,
// createdAt: inventoryCostLot.createdAt,
// debit: 0,
// credit: 0,
// branchId: inventoryCostLot.receipt.branchId,
// };
// };
// /**
// * Retrieves the inventory cost GL entry.
// * @param {IInventoryLotCost} inventoryLotCost
// * @returns {ILedgerEntry[]}
// */
// private getInventoryCostGLEntry = R.curry(
// (
// getIndexIncrement,
// inventoryCostLot: IInventoryLotCost
// ): ILedgerEntry[] => {
// const commonEntry = this.getInvoiceCostGLCommonEntry(inventoryCostLot);
// const costAccountId =
// inventoryCostLot.costAccountId || inventoryCostLot.item.costAccountId;
// // XXX Debit - Cost account.
// const costEntry = {
// ...commonEntry,
// debit: inventoryCostLot.cost,
// accountId: costAccountId,
// accountNormal: AccountNormal.DEBIT,
// itemId: inventoryCostLot.itemId,
// index: getIndexIncrement(),
// };
// // XXX Credit - Inventory account.
// const inventoryEntry = {
// ...commonEntry,
// credit: inventoryCostLot.cost,
// accountId: inventoryCostLot.item.inventoryAccountId,
// accountNormal: AccountNormal.DEBIT,
// itemId: inventoryCostLot.itemId,
// index: getIndexIncrement(),
// };
// return [costEntry, inventoryEntry];
// }
// );
// /**
// * Writes journal entries for given sale invoice.
// * -------
// * - Cost of goods sold -> Debit -> YYYY
// * - Inventory assets -> Credit -> YYYY
// * --------
// * @param {ISaleInvoice} saleInvoice
// * @param {JournalPoster} journal
// */
// public getSaleInvoiceCostGLEntries = (
// inventoryCostLots: IInventoryLotCost[]
// ): ILedgerEntry[] => {
// const getIndexIncrement = increment(0);
// const getInventoryLotEntry =
// this.getInventoryCostGLEntry(getIndexIncrement);
// return inventoryCostLots.map(getInventoryLotEntry).flat();
// };
// }

View File

@@ -1,36 +1,26 @@
// import { Inject, Service } from 'typedi';
// import events from '@/subscribers/events';
// import { IInventoryCostLotsGLEntriesWriteEvent } from '@/interfaces';
// import { SaleReceiptCostGLEntries } from '../SaleReceiptCostGLEntries';
import { Injectable } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { events } from '@/common/events/events';
import { IInventoryCostLotsGLEntriesWriteEvent } from '@/modules/InventoryCost/types/InventoryCost.types';
import { SaleReceiptCostGLEntries } from '../SaleReceiptCostGLEntries';
// @Service()
// export class SaleReceiptCostGLEntriesSubscriber {
// @Inject()
// private saleReceiptCostEntries: SaleReceiptCostGLEntries;
@Injectable()
export class SaleReceiptCostGLEntriesSubscriber {
constructor(
private readonly saleReceiptCostEntries: SaleReceiptCostGLEntries,
) {}
// /**
// * Attaches events.
// */
// public attach(bus) {
// bus.subscribe(
// events.inventory.onCostLotsGLEntriesWrite,
// this.writeJournalEntriesOnceWriteoffCreate
// );
// }
// /**
// * Writes the receipts cost GL entries once the inventory cost lots be written.
// * @param {IInventoryCostLotsGLEntriesWriteEvent}
// */
// private writeJournalEntriesOnceWriteoffCreate = async ({
// trx,
// startingDate,
// tenantId,
// }: IInventoryCostLotsGLEntriesWriteEvent) => {
// await this.saleReceiptCostEntries.writeInventoryCostJournalEntries(
// tenantId,
// startingDate,
// trx
// );
// };
// }
/**
* Writes the receipts cost GL entries once the inventory cost lots are written.
*/
@OnEvent(events.inventory.onCostLotsGLEntriesWrite)
async writeReceiptsCostEntriesOnCostLotsWritten({
trx,
startingDate,
}: IInventoryCostLotsGLEntriesWriteEvent) {
await this.saleReceiptCostEntries.writeInventoryCostJournalEntries(
startingDate,
trx,
);
}
}

View File

@@ -1,27 +1,47 @@
FROM node:18.16.0-alpine as build
USER root
# Stage 1: Build
FROM node:18.16.0-alpine AS builder
WORKDIR /app
# Copy application dependency manifests to the container image.
COPY . .
# Install pnpm
RUN npm install -g pnpm@8.10.2
# Install application dependencies
RUN apk update
RUN apk add python3 build-base chromium
# Install build dependencies
RUN apk add --no-cache python3 build-base chromium
# Set PYHTON env
# Set Python environment
ENV PYTHON=/usr/bin/python3
# Install pnpm packages dependencies
RUN npm install -g pnpm
# Copy package files for dependency installation
COPY --chown=node:node package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./
COPY --chown=node:node packages/webapp/package.json ./packages/webapp/
COPY --chown=node:node shared/bigcapital-utils/package.json ./shared/bigcapital-utils/
COPY --chown=node:node shared/pdf-templates/package.json ./shared/pdf-templates/
COPY --chown=node:node shared/email-components/package.json ./shared/email-components/
# Install all dependencies (including devDependencies for build)
RUN pnpm install
# Copy source code for webapp and dependencies
COPY --chown=node:node ./packages/webapp ./packages/webapp
COPY --chown=node:node ./shared/bigcapital-utils ./shared/bigcapital-utils
COPY --chown=node:node ./shared/pdf-templates ./shared/pdf-templates
COPY --chown=node:node ./shared/email-components ./shared/email-components
# Build webapp package
RUN pnpm run build:webapp
FROM nginx
# Stage 2: Nginx
FROM nginx:alpine
COPY ./packages/webapp/nginx/sites/default.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/packages/webapp/dist /usr/share/nginx/html
# Copy nginx configuration
COPY --chown=root:root ./packages/webapp/nginx/sites/default.conf /etc/nginx/conf.d/default.conf
# Copy built webapp assets from builder stage
COPY --from=builder --chown=nginx:nginx /app/packages/webapp/dist /usr/share/nginx/html
# Expose port
EXPOSE 80
# Nginx runs as nginx user by default, which is good for security
# No CMD needed as nginx base image already has it

View File

@@ -12,7 +12,7 @@
"@blueprintjs/colors": "4.1.19",
"@blueprintjs/core": "^4.20.2",
"@blueprintjs/datetime": "^4.4.37",
"@blueprintjs/datetime2": "^3.0.10",
"@blueprintjs/datetime2": "^0.9.0",
"@blueprintjs/popover2": "^1.14.11",
"@blueprintjs/select": "^4.9.24",
"@blueprintjs/table": "^4.10.12",

View File

@@ -2,7 +2,7 @@
import React, { useState } from 'react';
import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core';
import { queryCache } from 'react-query';
import { useQueryClient } from 'react-query';
import { FormattedMessage as T, AppToaster } from '@/components';
import { withAlertStoreConnect } from '@/containers/Alert/withAlertStoreConnect';
@@ -22,6 +22,7 @@ function AccountBulkActivateAlert({
requestBulkActivateAccounts,
}) {
const [isLoading, setLoading] = useState(false);
const queryClient = useQueryClient();
const selectedRowsCount = 0;
// Handle alert cancel.
@@ -38,9 +39,9 @@ function AccountBulkActivateAlert({
message: intl.get('the_accounts_has_been_successfully_activated'),
intent: Intent.SUCCESS,
});
queryCache.invalidateQueries('accounts-table');
queryClient.invalidateQueries('accounts-table');
})
.catch((errors) => { })
.catch((errors) => {})
.finally(() => {
setLoading(false);
closeAlert(name);

View File

@@ -3,7 +3,7 @@ import React, { useState } from 'react';
import { FormattedMessage as T } from '@/components';
import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core';
import { queryCache } from 'react-query';
import { useQueryClient } from 'react-query';
import { AppToaster } from '@/components';
// import { withAccountsActions } from '@/containers/Accounts/withAccountsTableActions';
@@ -22,8 +22,8 @@ function AccountBulkInactivateAlert({
closeAlert,
}) {
const [isLoading, setLoading] = useState(false);
const queryClient = useQueryClient();
const selectedRowsCount = 0;
// Handle alert cancel.
@@ -39,9 +39,9 @@ function AccountBulkInactivateAlert({
message: intl.get('the_accounts_have_been_successfully_inactivated'),
intent: Intent.SUCCESS,
});
queryCache.invalidateQueries('accounts-table');
queryClient.invalidateQueries('accounts-table');
})
.catch((errors) => { })
.catch((errors) => {})
.finally(() => {
setLoading(false);
closeAlert(name);

View File

@@ -3,7 +3,7 @@ import React, { useCallback } from 'react';
import intl from 'react-intl-universal';
import { AppToaster, FormattedMessage as T } from '@/components';
import { Intent, Alert } from '@blueprintjs/core';
import { queryCache } from 'react-query';
import { useQueryClient } from 'react-query';
import { useApproveEstimate } from '@/hooks/query';
@@ -25,6 +25,7 @@ function EstimateApproveAlert({
// #withAlertActions
closeAlert,
}) {
const queryClient = useQueryClient();
const { mutateAsync: deliverEstimateMutate, isLoading } =
useApproveEstimate();
@@ -40,7 +41,7 @@ function EstimateApproveAlert({
message: intl.get('the_estimate_has_been_approved_successfully'),
intent: Intent.SUCCESS,
});
queryCache.invalidateQueries('estimates-table');
queryClient.invalidateQueries('estimates-table');
})
.catch((error) => {})
.finally(() => {

View File

@@ -1,7 +1,7 @@
// @ts-nocheck
import React from 'react';
import { DialogContent } from '@/components';
import { useQuery, queryCache } from 'react-query';
import { useQuery, useQueryClient } from 'react-query';
import ReferenceNumberForm from '@/containers/JournalNumber/ReferenceNumberForm';
@@ -31,6 +31,7 @@ function BillNumberDialogContent({
// #withBillsActions
setBillNumberChanged,
}) {
const queryClient = useQueryClient();
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({}));
const handleSubmitForm = (values, { setSubmitting }) => {
@@ -45,7 +46,7 @@ function BillNumberDialogContent({
setBillNumberChanged(true);
setTimeout(() => {
queryCache.invalidateQueries('settings');
queryClient.invalidateQueries('settings');
}, 250);
})
.catch(() => {

View File

@@ -17,7 +17,7 @@ import {
FeatureCan,
InputPrependText,
} from '@/components';
import { FMoneyInputGroup, FFormGroup } from '@/components/Forms';
import { FMoneyInputGroup, FFormGroup, FDateInput } from '@/components/Forms';
import { useCustomerOpeningBalanceContext } from './CustomerOpeningBalanceFormProvider';
import { useSetPrimaryBranchToForm } from './utils';
@@ -59,28 +59,24 @@ function CustomerOpeningBalanceFields({
</FFormGroup>
{/*------------ Opening balance at -----------*/}
<FastField name={'opening_balance_at'}>
{({ form, field: { value } }) => (
<FormGroup
label={
<T id={'customer_opening_balance.label.opening_balance_at'} />
}
className={Classes.FILL}
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
onChange={handleDateChange((formattedDate) => {
form.setFieldValue('opening_balance_at', formattedDate);
})}
value={tansformDateValue(value)}
popoverProps={{ position: Position.BOTTOM, minimal: true }}
inputProps={{
leftIcon: <Icon icon={'date-range'} />,
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'opening_balance_at'}
label={<T id={'customer_opening_balance.label.opening_balance_at'} />}
fill
fastField
>
<FDateInput
name={'opening_balance_at'}
formatDate={(date) => date.toLocaleDateString()}
parseDate={(str) => new Date(str)}
popoverProps={{ position: Position.BOTTOM, minimal: true }}
inputProps={{
leftIcon: <Icon icon={'date-range'} />,
}}
fill
fastField
/>
</FFormGroup>
<If condition={!isEqual(base_currency, customer.currency_code)}>
{/*------------ Opening balance exchange rate -----------*/}
@@ -99,12 +95,15 @@ function CustomerOpeningBalanceFields({
<FFormGroup
label={<T id={'branch'} />}
name={'opening_balance_branch_id'}
className={classNames('form-group--select-list', Classes.FILL)}
fill
fastField
>
<BranchSelect
name={'opening_balance_branch_id'}
branches={branches}
popoverProps={{ minimal: true }}
fastField
fill
/>
</FFormGroup>
</FeatureCan>

View File

@@ -44,6 +44,7 @@ function CustomerOpeningBalanceForm({
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
const formValues = {
...values,
opening_balance_at: moment(values.opening_balance_at).format('YYYY-MM-DD'),
};
// Handle request response success.

View File

@@ -45,6 +45,7 @@ function VendorOpeningBalanceForm({
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
const formValues = {
...values,
opening_balance_at: moment(values.opening_balance_at).format('YYYY-MM-DD'),
};
// Handle request response success.

View File

@@ -17,7 +17,7 @@ import {
FeatureCan,
InputPrependText,
} from '@/components';
import { FMoneyInputGroup, FFormGroup } from '@/components/Forms';
import { FMoneyInputGroup, FFormGroup, FDateInput } from '@/components/Forms';
import { useVendorOpeningBalanceContext } from './VendorOpeningBalanceFormProvider';
import { useSetPrimaryBranchToForm } from './utils';
@@ -59,26 +59,24 @@ function VendorOpeningBalanceFormFields({
</FFormGroup>
{/*------------ Opening balance at -----------*/}
<FastField name={'opening_balance_at'}>
{({ form, field: { value } }) => (
<FormGroup
label={<T id={'vendor_opening_balance.label.opening_balance_at'} />}
className={Classes.FILL}
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
onChange={handleDateChange((formattedDate) => {
form.setFieldValue('opening_balance_at', formattedDate);
})}
value={tansformDateValue(value)}
popoverProps={{ position: Position.BOTTOM, minimal: true }}
inputProps={{
leftIcon: <Icon icon={'date-range'} />,
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'opening_balance_at'}
label={<T id={'vendor_opening_balance.label.opening_balance_at'} />}
fill
fastField
>
<FDateInput
name={'opening_balance_at'}
formatDate={(date) => date.toLocaleDateString()}
parseDate={(str) => new Date(str)}
popoverProps={{ position: Position.BOTTOM, minimal: true }}
inputProps={{
leftIcon: <Icon icon={'date-range'} />,
}}
fill
fastField
/>
</FFormGroup>
<If condition={!isEqual(base_currency, vendor.currency_code)}>
{/*------------ Opening balance exchange rate -----------*/}
@@ -97,7 +95,8 @@ function VendorOpeningBalanceFormFields({
<FFormGroup
label={<T id={'branch'} />}
name={'opening_balance_branch_id'}
className={classNames('form-group--select-list', Classes.FILL)}
fill
fastField
>
<BranchSelect
name={'opening_balance_branch_id'}

View File

@@ -180,7 +180,7 @@ export function useEditCustomerOpeningBalance(props) {
return useMutation(
([id, values]) =>
apiRequest.post(`customers/${id}/opening_balance`, values),
apiRequest.put(`customers/${id}/opening-balance`, values),
{
onSuccess: (res, [id, values]) => {
// Invalidate specific customer.

View File

@@ -167,7 +167,7 @@ export function useEditVendorOpeningBalance(props) {
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`vendors/${id}/opening_balance`, values),
([id, values]) => apiRequest.put(`vendors/${id}/opening-balance`, values),
{
onSuccess: (res, [id, values]) => {
// Invalidate specific vendor.

149
pnpm-lock.yaml generated
View File

@@ -411,7 +411,7 @@ importers:
version: 0.3.7(@babel/core@7.28.5)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
'@blueprintjs-formik/datetime':
specifier: ^0.4.0
version: 0.4.0(@babel/core@7.28.5)(@blueprintjs-formik/core@0.3.7)(@blueprintjs/core@4.20.2)(@blueprintjs/datetime2@3.0.10)(@blueprintjs/datetime@4.4.37)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
version: 0.4.0(@babel/core@7.28.5)(@blueprintjs-formik/core@0.3.7)(@blueprintjs/core@4.20.2)(@blueprintjs/datetime2@0.9.37)(@blueprintjs/datetime@4.4.37)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
'@blueprintjs-formik/select':
specifier: ^0.4.5
version: 0.4.5(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react@18.3.1)
@@ -425,8 +425,8 @@ importers:
specifier: ^4.4.37
version: 4.4.37(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/datetime2':
specifier: ^3.0.10
version: 3.0.10(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
specifier: ^0.9.0
version: 0.9.37(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/popover2':
specifier: ^1.14.11
version: 1.14.11(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
@@ -4636,7 +4636,7 @@ packages:
- react-is
dev: false
/@blueprintjs-formik/datetime@0.4.0(@babel/core@7.28.5)(@blueprintjs-formik/core@0.3.7)(@blueprintjs/core@4.20.2)(@blueprintjs/datetime2@3.0.10)(@blueprintjs/datetime@4.4.37)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1):
/@blueprintjs-formik/datetime@0.4.0(@babel/core@7.28.5)(@blueprintjs-formik/core@0.3.7)(@blueprintjs/core@4.20.2)(@blueprintjs/datetime2@0.9.37)(@blueprintjs/datetime@4.4.37)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-51RW41DSM96seIgOGz2gw2DX1SfH8+Ydi9JBCNmLaFZRqyKZgRX+qpxmltgbS97lk2IOfCEyKSxoGGfz4XlnPg==}
peerDependencies:
'@blueprintjs-formik/core': ^0.3.2 || 4 || 5
@@ -4651,7 +4651,7 @@ packages:
'@blueprintjs-formik/core': 0.3.7(@babel/core@7.28.5)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
'@blueprintjs/core': 4.20.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/datetime': 4.4.37(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/datetime2': 3.0.10(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/datetime2': 0.9.37(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/select': 4.9.24(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
formik: 2.4.6(react@18.3.1)
lodash.get: 4.4.2
@@ -4694,12 +4694,6 @@ packages:
tslib: 2.5.3
dev: false
/@blueprintjs/colors@5.1.12:
resolution: {integrity: sha512-7GQWUQ82eLE1te++DC8fRO2B31bsSwia82NLamZfKgjHY9V4zxafMT1DK5gKlmmy0nCjpdcCc+df4aVZMHGLww==}
dependencies:
tslib: 2.6.2
dev: false
/@blueprintjs/core@4.20.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-5v4Nr0jozfAjiOkjY4zvt1XSpt4ldnrSaxtwo506S2cxJYfwFeMTmDshXNPFcc8L1fjZMxi0IWI2WABXzZXS6w==}
hasBin: true
@@ -4727,51 +4721,28 @@ packages:
tslib: 2.5.3
dev: false
/@blueprintjs/core@6.4.1(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-JSA8seGiZ2dpmugO7Cea4bh0XEkTioDyzM1Z/0piFsziVv4OeV3jrmMXMegtCdHqpwpWYj8reGuPzFKHGemXXw==}
hasBin: true
/@blueprintjs/datetime2@0.9.37(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-eCoQbQK1IO5uegmYugj/K5helj6oA7s/4ZkA7dweBHBHXQ3KmZLh2Zj+O0ESOq/qqvlvCfiNCfsObk309EIbKQ==}
peerDependencies:
'@types/react': '18'
react: '18'
react-dom: '18'
'@types/react': ^16.14.32 || 17
react: ^16.8 || 17
react-dom: ^16.8 || 17
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@blueprintjs/colors': 5.1.12
'@blueprintjs/icons': 6.3.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@popperjs/core': 2.11.8
'@blueprintjs/core': 4.20.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/datetime': 4.4.37(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/popover2': 1.14.11(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/select': 4.9.24(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@types/react': 18.3.4
classnames: 2.5.1
normalize.css: 8.0.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@18.3.1)(react@18.3.1)
react-transition-group: 4.4.5(react-dom@18.3.1)(react@18.3.1)
tslib: 2.6.2
use-sync-external-store: 1.6.0(react@18.3.1)
dev: false
/@blueprintjs/datetime2@3.0.10(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-pli0hkv93aH2Ou3inZ2KIdNBLj5dYW8XVu21Rr3fSoh5b9aUsThAVDmb51LjlfNiPVi1i+y2omGuDRTKV+zUgw==}
peerDependencies:
'@types/react': '18'
react: '18'
react-dom: '18'
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@blueprintjs/colors': 5.1.12
'@blueprintjs/core': 6.4.1(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/datetime': 6.0.10(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/icons': 6.3.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@types/react': 18.3.4
date-fns: 2.30.0
date-fns-tz: 1.3.8(date-fns@2.30.0)
lodash: 4.17.21
react: 18.3.1
react-day-picker: 8.10.1(date-fns@2.30.0)(react@18.3.1)
react-dom: 18.3.1(react@18.3.1)
tslib: 2.6.2
tslib: 2.5.3
dev: false
/@blueprintjs/datetime@4.4.37(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
@@ -4793,30 +4764,6 @@ packages:
tslib: 2.5.3
dev: false
/@blueprintjs/datetime@6.0.10(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-8i8P12OwCe0JGTkX20EtHvembEjwfqkf1pQcec3lMdPDDeEpPmV3vzPWxwCS+NSc6vUGl/2aAFs+Ro7qDW1msw==}
peerDependencies:
'@types/react': '18'
react: '18'
react-dom: '18'
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@blueprintjs/core': 6.4.1(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/icons': 6.3.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/select': 6.0.10(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@types/react': 18.3.4
classnames: 2.5.1
date-fns: 2.30.0
date-fns-tz: 2.0.1(date-fns@2.30.0)
react: 18.3.1
react-day-picker: 8.10.1(date-fns@2.30.0)(react@18.3.1)
react-dom: 18.3.1(react@18.3.1)
react-innertext: 1.1.5(@types/react@18.3.4)(react@18.3.1)
tslib: 2.6.2
dev: false
/@blueprintjs/icons@4.16.0:
resolution: {integrity: sha512-cyfgjUZcZCtQrXWUV8FwqYTFEzduV4a0N7yhOU38jY+cBRCLu/sDrD0Osvfk4DGRvNe4YjY7pohVLFSxpg68Uw==}
dependencies:
@@ -4825,24 +4772,6 @@ packages:
tslib: 2.5.3
dev: false
/@blueprintjs/icons@6.3.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-rOdSg7yPmjtqy3e+wD66tXCrzt57M59htVOikwunTaCyQ61+bsF0PyqLfNlhsw1mXqZm8uxSINs1bhnwXhQCiw==}
peerDependencies:
'@types/react': '18'
react: '18'
react-dom: '18'
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@types/react': 18.3.4
change-case: 4.1.2
classnames: 2.5.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
tslib: 2.6.2
dev: false
/@blueprintjs/popover2@1.14.11(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-5XAjeb2mlWjYXC0pqrNDLzHSsX85Zaiv8jixxUN9abarMUUFKGATgGF8MRsWTLAW94Gli6CB1lzVkrYkRHHf6Q==}
peerDependencies:
@@ -4884,26 +4813,6 @@ packages:
tslib: 2.5.3
dev: false
/@blueprintjs/select@6.0.10(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-RjDuomn4KhluiN7tVofLLX6S+b+un0mLehvmOSETpqk1C8lHXCxReIXxFiWqTB+YiIgkqQ6aRNjQs35cJBbrfg==}
peerDependencies:
'@types/react': '18'
react: '18'
react-dom: '18'
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@blueprintjs/colors': 5.1.12
'@blueprintjs/core': 6.4.1(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@blueprintjs/icons': 6.3.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
'@types/react': 18.3.4
classnames: 2.5.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
tslib: 2.6.2
dev: false
/@blueprintjs/table@4.10.12(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-f5NbjuHQ/1vb5hkT+WsCnjIU3Vp2OCWdyDUopVmgj4qHIgzgX38vP2sLS8aUFlbsEQr/xAU9mfkpp4FT+65mXA==}
peerDependencies:
@@ -15031,10 +14940,10 @@ packages:
is-data-view: 1.0.1
dev: true
/date-fns-tz@2.0.1(date-fns@2.30.0):
resolution: {integrity: sha512-fJCG3Pwx8HUoLhkepdsP7Z5RsucUi+ZBOxyM5d0ZZ6c4SdYustq0VMmOu6Wf7bli+yS/Jwp91TOCqn9jMcVrUA==}
/date-fns-tz@1.3.8(date-fns@2.30.0):
resolution: {integrity: sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==}
peerDependencies:
date-fns: 2.x
date-fns: '>=2.0.0'
dependencies:
date-fns: 2.30.0
dev: false
@@ -22488,16 +22397,6 @@ packages:
react: 18.3.1
dev: false
/react-day-picker@8.10.1(date-fns@2.30.0)(react@18.3.1):
resolution: {integrity: sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==}
peerDependencies:
date-fns: ^2.28.0 || ^3.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
date-fns: 2.30.0
react: 18.3.1
dev: false
/react-docgen-typescript@2.2.2(typescript@5.6.3):
resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==}
peerDependencies:
@@ -25786,14 +25685,6 @@ packages:
tslib: 2.8.1
dev: true
/use-sync-external-store@1.6.0(react@18.3.1):
resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
dependencies:
react: 18.3.1
dev: false
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}