mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 15:20:34 +00:00
refactor(nestjs): wip
This commit is contained in:
32
packages/server/src/common/decorators/Validators.ts
Normal file
32
packages/server/src/common/decorators/Validators.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { Transform } from 'class-transformer';
|
||||||
|
import { ValidateIf, ValidationOptions } from 'class-validator';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorator that converts the property value to a number.
|
||||||
|
* @returns PropertyDecorator
|
||||||
|
*/
|
||||||
|
export function ToNumber() {
|
||||||
|
return Transform(({ value, key }) => {
|
||||||
|
const defaultValue = null;
|
||||||
|
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
// If value is an empty string or undefined/null, return it as-is (won’t pass validation)
|
||||||
|
if (value === '' || value === null || value === undefined) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
const parsed = Number(value);
|
||||||
|
return !isNaN(parsed) ? parsed : value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if the property is not empty.
|
||||||
|
* @returns PropertyDecorator
|
||||||
|
*/
|
||||||
|
export function IsOptional(validationOptions?: ValidationOptions) {
|
||||||
|
return ValidateIf((_obj, value) => {
|
||||||
|
return value !== null && value !== undefined && value !== '';
|
||||||
|
}, validationOptions);
|
||||||
|
}
|
||||||
4
packages/server/src/i18n/en/warehouses.json
Normal file
4
packages/server/src/i18n/en/warehouses.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"primary_warehouse": "Primary Warehouse"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -76,8 +76,13 @@ export class BranchesController {
|
|||||||
status: 200,
|
status: 200,
|
||||||
description: 'The branches feature has been successfully activated.',
|
description: 'The branches feature has been successfully activated.',
|
||||||
})
|
})
|
||||||
activateBranches() {
|
async activateBranches() {
|
||||||
return this.branchesApplication.activateBranches();
|
await this.branchesApplication.activateBranches();
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
message: 'The branches activated successfully.',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put(':id/mark-as-primary')
|
@Put(':id/mark-as-primary')
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export class BranchesSettingsService {
|
|||||||
const settingsStore = await this.settingsStore();
|
const settingsStore = await this.settingsStore();
|
||||||
|
|
||||||
settingsStore.set({ group: 'features', key: Features.BRANCHES, value: 1 });
|
settingsStore.set({ group: 'features', key: Features.BRANCHES, value: 1 });
|
||||||
|
|
||||||
|
await settingsStore.save();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { IsOptional } from '@/common/decorators/Validators';
|
||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import {
|
import {
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsEmail,
|
IsEmail,
|
||||||
IsNotEmpty,
|
IsNotEmpty,
|
||||||
IsOptional,
|
|
||||||
IsString,
|
IsString,
|
||||||
IsUrl,
|
IsUrl,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
|
|||||||
@@ -37,15 +37,15 @@ export class CurrenciesController {
|
|||||||
return this.currenciesApp.createCurrency(dto);
|
return this.currenciesApp.createCurrency(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put(':code')
|
@Put(':id')
|
||||||
@ApiOperation({ summary: 'Edit an existing currency' })
|
@ApiOperation({ summary: 'Edit an existing currency' })
|
||||||
@ApiParam({ name: 'id', type: Number, description: 'Currency ID' })
|
@ApiParam({ name: 'id', type: Number, description: 'Currency ID' })
|
||||||
@ApiBody({ type: EditCurrencyDto })
|
@ApiBody({ type: EditCurrencyDto })
|
||||||
@ApiOkResponse({ description: 'The currency has been successfully updated.' })
|
@ApiOkResponse({ description: 'The currency has been successfully updated.' })
|
||||||
@ApiNotFoundResponse({ description: 'Currency not found.' })
|
@ApiNotFoundResponse({ description: 'Currency not found.' })
|
||||||
@ApiBadRequestResponse({ description: 'Invalid input data.' })
|
@ApiBadRequestResponse({ description: 'Invalid input data.' })
|
||||||
edit(@Param('code') code: string, @Body() dto: EditCurrencyDto) {
|
edit(@Param('id') id: number, @Body() dto: EditCurrencyDto) {
|
||||||
return this.currenciesApp.editCurrency(code, dto);
|
return this.currenciesApp.editCurrency(id, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':code')
|
@Delete(':code')
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ export class CurrenciesApplication {
|
|||||||
/**
|
/**
|
||||||
* Edits an existing currency.
|
* Edits an existing currency.
|
||||||
*/
|
*/
|
||||||
public editCurrency(currencyCode: string, currencyDTO: EditCurrencyDto) {
|
public editCurrency(currencyId: number, currencyDTO: EditCurrencyDto) {
|
||||||
return this.editCurrencyService.editCurrency(currencyCode, currencyDTO);
|
return this.editCurrencyService.editCurrency(currencyId, currencyDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,21 +12,22 @@ export class EditCurrencyService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit details of the given currency.
|
* Edit details of the given currency.
|
||||||
* @param {number} currencyCode - Currency code.
|
* @param {number} currencyId - Currency ID.
|
||||||
* @param {ICurrencyDTO} currencyDTO - Edit currency dto.
|
* @param {ICurrencyDTO} currencyDTO - Edit currency dto.
|
||||||
*/
|
*/
|
||||||
public async editCurrency(
|
public async editCurrency(
|
||||||
currencyCode: string,
|
currencyId: number,
|
||||||
currencyDTO: EditCurrencyDto,
|
currencyDTO: EditCurrencyDto,
|
||||||
): Promise<Currency> {
|
): Promise<Currency> {
|
||||||
const foundCurrency = await this.currencyModel()
|
const foundCurrency = this.currencyModel()
|
||||||
.query()
|
.query()
|
||||||
.findOne('currencyCode', currencyCode)
|
.findById(currencyId)
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
// Directly use the provided ID to update the currency
|
||||||
const currency = await this.currencyModel()
|
const currency = await this.currencyModel()
|
||||||
.query()
|
.query()
|
||||||
.patchAndFetchById(foundCurrency.id, {
|
.patchAndFetchById(currencyId, {
|
||||||
...currencyDTO,
|
...currencyDTO,
|
||||||
});
|
});
|
||||||
return currency;
|
return currency;
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import { IsString } from 'class-validator';
|
import { IsNotEmpty } from "class-validator";
|
||||||
|
import { IsString } from "class-validator";
|
||||||
|
|
||||||
export class CreateCurrencyDto {
|
export class CreateCurrencyDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
currencyName: string;
|
currencyName: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
currencyCode: string;
|
currencyCode: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
currencySign: string;
|
currencySign: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import { IsString } from 'class-validator';
|
import { IsNotEmpty } from "class-validator";
|
||||||
|
import { IsString } from "class-validator";
|
||||||
|
|
||||||
export class EditCurrencyDto {
|
export class EditCurrencyDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
currencyName: string;
|
currencyName: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
currencySign: string;
|
currencySign: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
IsString,
|
IsString,
|
||||||
IsIn,
|
IsIn,
|
||||||
IsOptional,
|
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsNumber,
|
IsNumber,
|
||||||
IsInt,
|
IsInt,
|
||||||
@@ -9,11 +8,10 @@ import {
|
|||||||
ValidateIf,
|
ValidateIf,
|
||||||
MaxLength,
|
MaxLength,
|
||||||
Min,
|
Min,
|
||||||
Max,
|
|
||||||
IsNotEmpty,
|
IsNotEmpty,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { Type } from 'class-transformer';
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
|
||||||
|
|
||||||
export class CommandItemDto {
|
export class CommandItemDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@@ -23,6 +21,7 @@ export class CommandItemDto {
|
|||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
@IsIn(['service', 'non-inventory', 'inventory'])
|
@IsIn(['service', 'non-inventory', 'inventory'])
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'Item type',
|
description: 'Item type',
|
||||||
@@ -52,6 +51,7 @@ export class CommandItemDto {
|
|||||||
purchasable?: boolean;
|
purchasable?: boolean;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ToNumber()
|
||||||
@IsNumber({ maxDecimalPlaces: 3 })
|
@IsNumber({ maxDecimalPlaces: 3 })
|
||||||
@Min(0)
|
@Min(0)
|
||||||
@ValidateIf((o) => o.purchasable === true)
|
@ValidateIf((o) => o.purchasable === true)
|
||||||
@@ -64,6 +64,7 @@ export class CommandItemDto {
|
|||||||
costPrice?: number;
|
costPrice?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ToNumber()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@Min(0)
|
@Min(0)
|
||||||
@ValidateIf((o) => o.purchasable === true)
|
@ValidateIf((o) => o.purchasable === true)
|
||||||
@@ -86,6 +87,7 @@ export class CommandItemDto {
|
|||||||
sellable?: boolean;
|
sellable?: boolean;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ToNumber()
|
||||||
@IsNumber({ maxDecimalPlaces: 3 })
|
@IsNumber({ maxDecimalPlaces: 3 })
|
||||||
@Min(0)
|
@Min(0)
|
||||||
@ValidateIf((o) => o.sellable === true)
|
@ValidateIf((o) => o.sellable === true)
|
||||||
@@ -98,6 +100,7 @@ export class CommandItemDto {
|
|||||||
sellPrice?: number;
|
sellPrice?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ToNumber()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@Min(0)
|
@Min(0)
|
||||||
@ValidateIf((o) => o.sellable === true)
|
@ValidateIf((o) => o.sellable === true)
|
||||||
@@ -110,6 +113,7 @@ export class CommandItemDto {
|
|||||||
sellAccountId?: number;
|
sellAccountId?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ToNumber()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@Min(0)
|
@Min(0)
|
||||||
@ValidateIf((o) => o.type === 'inventory')
|
@ValidateIf((o) => o.type === 'inventory')
|
||||||
@@ -140,6 +144,7 @@ export class CommandItemDto {
|
|||||||
purchaseDescription?: string;
|
purchaseDescription?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ToNumber()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'ID of the tax rate applied to sales',
|
description: 'ID of the tax rate applied to sales',
|
||||||
@@ -149,6 +154,7 @@ export class CommandItemDto {
|
|||||||
sellTaxRateId?: number;
|
sellTaxRateId?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ToNumber()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'ID of the tax rate applied to purchases',
|
description: 'ID of the tax rate applied to purchases',
|
||||||
@@ -158,6 +164,7 @@ export class CommandItemDto {
|
|||||||
purchaseTaxRateId?: number;
|
purchaseTaxRateId?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ToNumber()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@Min(0)
|
@Min(0)
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@@ -189,7 +196,6 @@ export class CommandItemDto {
|
|||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@Type(() => Number)
|
|
||||||
@IsInt({ each: true })
|
@IsInt({ each: true })
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'IDs of media files associated with the item',
|
description: 'IDs of media files associated with the item',
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { DeleteRoleService } from './commands/DeleteRole.service';
|
|||||||
import { EditRoleService } from './commands/EditRole.service';
|
import { EditRoleService } from './commands/EditRole.service';
|
||||||
import { GetRoleService } from './queries/GetRole.service';
|
import { GetRoleService } from './queries/GetRole.service';
|
||||||
import { GetRolesService } from './queries/GetRoles.service';
|
import { GetRolesService } from './queries/GetRoles.service';
|
||||||
|
import { RolePermissionsSchema } from './queries/RolePermissionsSchema';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RolesApplication {
|
export class RolesApplication {
|
||||||
@@ -13,6 +14,7 @@ export class RolesApplication {
|
|||||||
private readonly deleteRoleService: DeleteRoleService,
|
private readonly deleteRoleService: DeleteRoleService,
|
||||||
private readonly getRoleService: GetRoleService,
|
private readonly getRoleService: GetRoleService,
|
||||||
private readonly getRolesService: GetRolesService,
|
private readonly getRolesService: GetRolesService,
|
||||||
|
private readonly getRolePermissionsSchemaService: RolePermissionsSchema,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,4 +61,12 @@ export class RolesApplication {
|
|||||||
async getRoles() {
|
async getRoles() {
|
||||||
return this.getRolesService.getRoles();
|
return this.getRolesService.getRoles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the role permissions schema.
|
||||||
|
* @returns The role permissions schema.
|
||||||
|
*/
|
||||||
|
async getRolePermissionsSchema() {
|
||||||
|
return this.getRolePermissionsSchemaService.getRolePermissionsSchema();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,9 +72,7 @@ export class RolesController {
|
|||||||
status: HttpStatus.OK,
|
status: HttpStatus.OK,
|
||||||
description: 'Role deleted successfully',
|
description: 'Role deleted successfully',
|
||||||
})
|
})
|
||||||
async deleteRole(
|
async deleteRole(@Param('id', ParseIntPipe) roleId: number) {
|
||||||
@Param('id', ParseIntPipe) roleId: number,
|
|
||||||
) {
|
|
||||||
await this.rolesApp.deleteRole(roleId);
|
await this.rolesApp.deleteRole(roleId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -83,24 +81,34 @@ export class RolesController {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('permissions/schema')
|
||||||
|
@ApiOperation({ summary: 'Get role permissions schema' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: HttpStatus.OK,
|
||||||
|
description: 'Role permissions schema',
|
||||||
|
})
|
||||||
|
async getRolePermissionsSchema() {
|
||||||
|
const schema = await this.rolesApp.getRolePermissionsSchema();
|
||||||
|
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@ApiOperation({ summary: 'Get all roles' })
|
@ApiOperation({ summary: 'Get all roles' })
|
||||||
@ApiResponse({ status: HttpStatus.OK, description: 'List of all roles' })
|
@ApiResponse({ status: HttpStatus.OK, description: 'List of all roles' })
|
||||||
async getRoles() {
|
async getRoles() {
|
||||||
const roles = await this.rolesApp.getRoles();
|
const roles = await this.rolesApp.getRoles();
|
||||||
|
|
||||||
return { roles };
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
@ApiOperation({ summary: 'Get a specific role by ID' })
|
@ApiOperation({ summary: 'Get a specific role by ID' })
|
||||||
@ApiParam({ name: 'id', description: 'Role ID' })
|
@ApiParam({ name: 'id', description: 'Role ID' })
|
||||||
@ApiResponse({ status: HttpStatus.OK, description: 'Role details' })
|
@ApiResponse({ status: HttpStatus.OK, description: 'Role details' })
|
||||||
async getRole(
|
async getRole(@Param('id', ParseIntPipe) roleId: number) {
|
||||||
@Param('id', ParseIntPipe) roleId: number,
|
|
||||||
) {
|
|
||||||
const role = await this.rolesApp.getRole(roleId);
|
const role = await this.rolesApp.getRole(roleId);
|
||||||
|
|
||||||
return { role };
|
return role;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { Role } from './models/Role.model';
|
|||||||
import { RolePermission } from './models/RolePermission.model';
|
import { RolePermission } from './models/RolePermission.model';
|
||||||
import { RolesController } from './Roles.controller';
|
import { RolesController } from './Roles.controller';
|
||||||
import { RolesApplication } from './Roles.application';
|
import { RolesApplication } from './Roles.application';
|
||||||
|
import { RolePermissionsSchema } from './queries/RolePermissionsSchema';
|
||||||
|
|
||||||
const models = [
|
const models = [
|
||||||
RegisterTenancyModel(Role),
|
RegisterTenancyModel(Role),
|
||||||
@@ -24,6 +25,7 @@ const models = [
|
|||||||
GetRoleService,
|
GetRoleService,
|
||||||
GetRolesService,
|
GetRolesService,
|
||||||
RolesApplication,
|
RolesApplication,
|
||||||
|
RolePermissionsSchema
|
||||||
],
|
],
|
||||||
controllers: [RolesController],
|
controllers: [RolesController],
|
||||||
exports: [...models],
|
exports: [...models],
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { IRoleCreatedPayload } from '../Roles.types';
|
import { IRoleCreatedPayload } from '../Roles.types';
|
||||||
import { Role } from './../models/Role.model';
|
import { Role } from './../models/Role.model';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
||||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { CreateRoleDto } from '../dtos/Role.dto';
|
import { CreateRoleDto } from '../dtos/Role.dto';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { validateInvalidPermissions } from '../utils';
|
import { validateInvalidPermissions } from '../utils';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|||||||
@@ -1,12 +1,42 @@
|
|||||||
import { AbilitySchema } from '../AbilitySchema';
|
import { AbilitySchema } from '../AbilitySchema';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { I18nService } from 'nestjs-i18n';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
import { ISubjectAbilitiesSchema } from '../Roles.types';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RolePermissionsSchema {
|
export class RolePermissionsSchema {
|
||||||
|
constructor(private readonly i18nService: I18nService) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the role permissions schema.
|
* Retrieve the role permissions schema with translated labels.
|
||||||
|
* @returns {ISubjectAbilitiesSchema[]}
|
||||||
*/
|
*/
|
||||||
getRolePermissionsSchema() {
|
getRolePermissionsSchema(): ISubjectAbilitiesSchema[] {
|
||||||
return AbilitySchema;
|
// Clone the schema to avoid modifying the original
|
||||||
|
const schema = cloneDeep(AbilitySchema);
|
||||||
|
|
||||||
|
// Apply translations to each subject and its abilities
|
||||||
|
return schema.map((subject: ISubjectAbilitiesSchema) => {
|
||||||
|
// Translate subject label
|
||||||
|
subject.subjectLabel = this.i18nService.t(subject.subjectLabel);
|
||||||
|
|
||||||
|
// Translate abilities labels
|
||||||
|
if (subject.abilities) {
|
||||||
|
subject.abilities = subject.abilities.map((ability) => ({
|
||||||
|
...ability,
|
||||||
|
label: this.i18nService.t(ability.label),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
// Translate extra abilities labels if they exist
|
||||||
|
if (subject.extraAbilities) {
|
||||||
|
subject.extraAbilities = subject.extraAbilities.map((ability) => ({
|
||||||
|
...ability,
|
||||||
|
label: this.i18nService.t(ability.label),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.dec
|
|||||||
import { ImportableModel } from '@/modules/Import/decorators/Import.decorator';
|
import { ImportableModel } from '@/modules/Import/decorators/Import.decorator';
|
||||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||||
import { SaleEstimateMeta } from './SaleEstimate.meta';
|
import { SaleEstimateMeta } from './SaleEstimate.meta';
|
||||||
|
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
||||||
|
import { Document } from '@/modules/ChromiumlyTenancy/models/Document';
|
||||||
|
import { Customer } from '@/modules/Customers/models/Customer';
|
||||||
|
|
||||||
@ExportableModel()
|
@ExportableModel()
|
||||||
@ImportableModel()
|
@ImportableModel()
|
||||||
@@ -40,6 +43,10 @@ export class SaleEstimate extends TenantBaseModel {
|
|||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
|
|
||||||
|
public entries!: ItemEntry[];
|
||||||
|
public attachments!: Document[];
|
||||||
|
public customer!: Customer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
// import { Transformer } from '@/lib/Transformer/Transformer';
|
|
||||||
// import { ItemEntryTransformer } from '../Invoices/ItemEntryTransformer';
|
|
||||||
// import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer';
|
|
||||||
|
|
||||||
import { Transformer } from '@/modules/Transformer/Transformer';
|
import { Transformer } from '@/modules/Transformer/Transformer';
|
||||||
import { SaleEstimate } from '../models/SaleEstimate';
|
import { SaleEstimate } from '../models/SaleEstimate';
|
||||||
import { ItemEntryTransformer } from '@/modules/TransactionItemEntry/ItemEntry.transformer';
|
import { ItemEntryTransformer } from '@/modules/TransactionItemEntry/ItemEntry.transformer';
|
||||||
|
import { AttachmentTransformer } from '@/modules/Attachments/Attachment.transformer';
|
||||||
|
|
||||||
export class SaleEstimateTransfromer extends Transformer {
|
export class SaleEstimateTransfromer extends Transformer {
|
||||||
/**
|
/**
|
||||||
@@ -106,9 +103,9 @@ export class SaleEstimateTransfromer extends Transformer {
|
|||||||
* @returns {}
|
* @returns {}
|
||||||
*/
|
*/
|
||||||
protected entries = (estimate: SaleEstimate) => {
|
protected entries = (estimate: SaleEstimate) => {
|
||||||
// return this.item(estimate.entries, new ItemEntryTransformer(), {
|
return this.item(estimate.entries, new ItemEntryTransformer(), {
|
||||||
// currencyCode: estimate.currencyCode,
|
currencyCode: estimate.currencyCode,
|
||||||
// });
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,6 +114,6 @@ export class SaleEstimateTransfromer extends Transformer {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
protected attachments = (estimate: SaleEstimate) => {
|
protected attachments = (estimate: SaleEstimate) => {
|
||||||
// return this.item(estimate.attachments, new AttachmentTransformer());
|
return this.item(estimate.attachments, new AttachmentTransformer());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export class WarehousesController {
|
|||||||
return this.warehousesApplication.activateWarehouses();
|
return this.warehousesApplication.activateWarehouses();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post(':id/mark-primary')
|
@Put(':id/mark-primary')
|
||||||
@ApiOperation({ summary: 'Mark a warehouse as primary' })
|
@ApiOperation({ summary: 'Mark a warehouse as primary' })
|
||||||
markWarehousePrimary(@Param('id') warehouseId: string) {
|
markWarehousePrimary(@Param('id') warehouseId: string) {
|
||||||
return this.warehousesApplication.markWarehousePrimary(Number(warehouseId));
|
return this.warehousesApplication.markWarehousePrimary(Number(warehouseId));
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export class WarehousesSettings {
|
|||||||
const settings = await this.settingsStore();
|
const settings = await this.settingsStore();
|
||||||
|
|
||||||
settings.set({ group: 'features', key: Features.WAREHOUSES, value: 1 });
|
settings.set({ group: 'features', key: Features.WAREHOUSES, value: 1 });
|
||||||
|
|
||||||
|
await settings.save();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { CreateWarehouse } from './CreateWarehouse.service';
|
import { CreateWarehouse } from './CreateWarehouse.service';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { I18nContext } from 'nestjs-i18n';
|
import { I18nService } from 'nestjs-i18n';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateInitialWarehouse {
|
export class CreateInitialWarehouse {
|
||||||
/**
|
/**
|
||||||
* @param {CreateWarehouse} createWarehouse - Create warehouse service.
|
* @param {CreateWarehouse} createWarehouse - Create warehouse service.
|
||||||
* @param {I18nContext} i18n - I18n context.
|
* @param {I18nService} i18n - I18n service.
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private readonly createWarehouse: CreateWarehouse,
|
private readonly createWarehouse: CreateWarehouse,
|
||||||
private readonly i18n: I18nContext,
|
private readonly i18n: I18nService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { IsOptional } from "@/common/decorators/Validators";
|
||||||
import { ApiProperty } from "@nestjs/swagger";
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
import { IsBoolean, IsEmail, IsOptional, IsUrl } from "class-validator";
|
import { IsBoolean, IsEmail, IsUrl } from "class-validator";
|
||||||
import { IsNotEmpty } from "class-validator";
|
import { IsNotEmpty } from "class-validator";
|
||||||
import { IsString } from "class-validator";
|
import { IsString } from "class-validator";
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function useEditBranch(props) {
|
|||||||
const apiRequest = useApiRequest();
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
return useMutation(
|
return useMutation(
|
||||||
([id, values]) => apiRequest.post(`branches/${id}`, values),
|
([id, values]) => apiRequest.put(`branches/${id}`, values),
|
||||||
{
|
{
|
||||||
onSuccess: (res, [id, values]) => {
|
onSuccess: (res, [id, values]) => {
|
||||||
// Invalidate specific branch.
|
// Invalidate specific branch.
|
||||||
@@ -79,7 +79,7 @@ export function useBranches(query, props) {
|
|||||||
[t.BRANCHES, query],
|
[t.BRANCHES, query],
|
||||||
{ method: 'get', url: 'branches', params: query },
|
{ method: 'get', url: 'branches', params: query },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.branches,
|
select: (res) => res.data,
|
||||||
defaultData: [],
|
defaultData: [],
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -95,7 +95,7 @@ export function useBranch(id, props, requestProps) {
|
|||||||
[t.BRANCH, id],
|
[t.BRANCH, id],
|
||||||
{ method: 'get', url: `branches/${id}`, ...requestProps },
|
{ method: 'get', url: `branches/${id}`, ...requestProps },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.branch,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,15 +21,15 @@ export function useCreateCurrency(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the given currency code.
|
* Edits the given currency by ID.
|
||||||
*/
|
*/
|
||||||
export function useEditCurrency(props) {
|
export function useEditCurrency(props) {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const apiRequest = useApiRequest();
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
return useMutation(
|
return useMutation(
|
||||||
([currencyCode, values]) =>
|
([currencyId, values]) =>
|
||||||
apiRequest.post(`currencies/${currencyCode}`, values),
|
apiRequest.put(`currencies/${currencyId}`, values),
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
// Invalidate currencies.
|
// Invalidate currencies.
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export function useExpense(id, props) {
|
|||||||
url: `expenses/${id}`,
|
url: `expenses/${id}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
select: (res) => res.data.expense,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export function useItemCategory(id, props) {
|
|||||||
[t.ITEM_CATEGORY, id],
|
[t.ITEM_CATEGORY, id],
|
||||||
{ method: 'get', url: `item-categories/${id}` },
|
{ method: 'get', url: `item-categories/${id}` },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.category,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ export function useJournal(id, props) {
|
|||||||
[t.MANUAL_JOURNAL, id],
|
[t.MANUAL_JOURNAL, id],
|
||||||
{ method: 'get', url: `manual-journals/${id}` },
|
{ method: 'get', url: `manual-journals/${id}` },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.manual_journal,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export function usePaymentMade(id, props) {
|
|||||||
[t.PAYMENT_MADE, id],
|
[t.PAYMENT_MADE, id],
|
||||||
{ method: 'get', url: `bill-payments/${id}` },
|
{ method: 'get', url: `bill-payments/${id}` },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.bill_payment,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ export function useReceipt(id, props) {
|
|||||||
['SALE_RECEIPT', id],
|
['SALE_RECEIPT', id],
|
||||||
{ method: 'get', url: `sale-receipts/${id}` },
|
{ method: 'get', url: `sale-receipts/${id}` },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.sale_receipt,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -211,7 +211,7 @@ export function useReceiptSMSDetail(receiptId, props, requestProps) {
|
|||||||
...requestProps,
|
...requestProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
select: (res) => res.data.data,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -304,7 +304,7 @@ export function useSaleReceiptMailState(
|
|||||||
() =>
|
() =>
|
||||||
apiRequest
|
apiRequest
|
||||||
.get(`sale-receipts/${receiptId}/mail`)
|
.get(`sale-receipts/${receiptId}/mail`)
|
||||||
.then((res) => transformToCamelCase(res.data.data)),
|
.then((res) => transformToCamelCase(res.data)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +322,7 @@ export function useGetReceiptState(
|
|||||||
() =>
|
() =>
|
||||||
apiRequest
|
apiRequest
|
||||||
.get(`/sale-receipts/state`)
|
.get(`/sale-receipts/state`)
|
||||||
.then((res) => transformToCamelCase(res.data?.data)),
|
.then((res) => transformToCamelCase(res.data)),
|
||||||
{ ...options },
|
{ ...options },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export function usePermissionsSchema(query, props) {
|
|||||||
[t.ROLES_PERMISSIONS_SCHEMA, query],
|
[t.ROLES_PERMISSIONS_SCHEMA, query],
|
||||||
{ method: 'get', url: 'roles/permissions/schema', params: query },
|
{ method: 'get', url: 'roles/permissions/schema', params: query },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.data,
|
select: (res) => res.data,
|
||||||
defaultData: {
|
defaultData: {
|
||||||
roles: [],
|
roles: [],
|
||||||
},
|
},
|
||||||
@@ -87,7 +87,7 @@ export function useRolePermission(role_id, props, requestProps) {
|
|||||||
[t.ROLE, role_id],
|
[t.ROLE, role_id],
|
||||||
{ method: 'get', url: `roles/${role_id}`, ...requestProps },
|
{ method: 'get', url: `roles/${role_id}`, ...requestProps },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.role,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -102,7 +102,7 @@ export function useRoles(props, query) {
|
|||||||
[t.ROLES, query],
|
[t.ROLES, query],
|
||||||
{ method: 'get', url: `roles`, params: query },
|
{ method: 'get', url: `roles`, params: query },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.roles,
|
select: (res) => res.data,
|
||||||
defaultData: [],
|
defaultData: [],
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export function useSaveSettings(props) {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const apiRequest = useApiRequest();
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
return useMutation((settings) => apiRequest.post('settings', settings), {
|
return useMutation((settings) => apiRequest.put('settings', settings), {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries(t.SETTING);
|
queryClient.invalidateQueries(t.SETTING);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ export function useVendorCredit(id, props, requestProps) {
|
|||||||
[t.VENDOR_CREDIT, id],
|
[t.VENDOR_CREDIT, id],
|
||||||
{ method: 'get', url: `vendor-credits/${id}`, ...requestProps },
|
{ method: 'get', url: `vendor-credits/${id}`, ...requestProps },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.data,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -232,7 +232,7 @@ export function useRefundVendorCredit(id, props, requestProps) {
|
|||||||
...requestProps,
|
...requestProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
select: (res) => res.data.data,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -298,7 +298,7 @@ export function useReconcileVendorCredit(id, props, requestProps) {
|
|||||||
...requestProps,
|
...requestProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
select: (res) => res.data.data,
|
select: (res) => res.data,
|
||||||
defaultData: [],
|
defaultData: [],
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -317,7 +317,7 @@ export function useReconcileVendorCredits(id, props, requestProps) {
|
|||||||
...requestProps,
|
...requestProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
select: (res) => res.data.data,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -359,7 +359,7 @@ export function useRefundVendorCreditTransaction(id, props, requestProps) {
|
|||||||
...requestProps,
|
...requestProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
select: (res) => res.data.refund_credit,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function useEditWarehouse(props) {
|
|||||||
const apiRequest = useApiRequest();
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
return useMutation(
|
return useMutation(
|
||||||
([id, values]) => apiRequest.post(`warehouses/${id}`, values),
|
([id, values]) => apiRequest.put(`warehouses/${id}`, values),
|
||||||
{
|
{
|
||||||
onSuccess: (res, [id, values]) => {
|
onSuccess: (res, [id, values]) => {
|
||||||
// Invalidate specific sale invoice.
|
// Invalidate specific sale invoice.
|
||||||
@@ -82,7 +82,7 @@ export function useWarehouses(query, props) {
|
|||||||
[t.WAREHOUSES, query],
|
[t.WAREHOUSES, query],
|
||||||
{ method: 'get', url: 'warehouses', params: query },
|
{ method: 'get', url: 'warehouses', params: query },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.warehouses,
|
select: (res) => res.data,
|
||||||
defaultData: [],
|
defaultData: [],
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -98,7 +98,7 @@ export function useWarehouse(id, props, requestProps) {
|
|||||||
[t.WAREHOUSE, id],
|
[t.WAREHOUSE, id],
|
||||||
{ method: 'get', url: `warehouses/${id}`, ...requestProps },
|
{ method: 'get', url: `warehouses/${id}`, ...requestProps },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.warehouse,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
@@ -128,7 +128,7 @@ export function useMarkWarehouseAsPrimary(props) {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const apiRequest = useApiRequest();
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
return useMutation((id) => apiRequest.post(`warehouses/${id}/mark-primary`), {
|
return useMutation((id) => apiRequest.put(`warehouses/${id}/mark-primary`), {
|
||||||
onSuccess: (res, id) => {
|
onSuccess: (res, id) => {
|
||||||
// Invalidate specific inventory adjustment.
|
// Invalidate specific inventory adjustment.
|
||||||
queryClient.invalidateQueries([t.WAREHOUSE, id]);
|
queryClient.invalidateQueries([t.WAREHOUSE, id]);
|
||||||
|
|||||||
Reference in New Issue
Block a user