feat: add Warehouses + Integrations modules, /admin/configuracion page

- Schema v0.3: Warehouse + Integration models (db push applied)
- WarehousesModule: CRUD, set-default, multi-warehouse support
- IntegrationsModule: 26 keys across 7 groups (payment, notifications,
  customs, courier, marketplace, compliance, warehouse)
- AuthService: suite address pulled from default Warehouse in DB (env fallback)
- AuthModule: imports WarehousesModule
- Seed: creates default warehouse from WAREHOUSE_ADDRESS_* env vars
- Web: /admin/configuracion page (3 tabs: Bodegas, Integraciones, Estado APIs)
- Web: admin layout adds Configuracion nav link
- api.ts: warehouses + integrations client methods
This commit is contained in:
Lizandro Guarnizo
2026-06-01 16:49:19 -05:00
parent 03b18e7a84
commit b2b292c50a
15 changed files with 822 additions and 18 deletions
+2
View File
@@ -5,6 +5,7 @@ import { ConfigModule, ConfigService } from "@nestjs/config";
import { AuthController } from "./auth.controller";
import { AuthService } from "./auth.service";
import { JwtStrategy } from "./jwt.strategy";
import { WarehousesModule } from "../warehouses/warehouses.module";
@Module({
imports: [
@@ -17,6 +18,7 @@ import { JwtStrategy } from "./jwt.strategy";
signOptions: { expiresIn: config.get("JWT_EXPIRES_IN", "15m") },
}),
}),
WarehousesModule,
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
+19 -11
View File
@@ -4,6 +4,7 @@ import {
import { JwtService } from "@nestjs/jwt";
import { ConfigService } from "@nestjs/config";
import { PrismaService } from "../prisma/prisma.service";
import { WarehousesService } from "../warehouses/warehouses.service";
import { generateSuiteCode } from "../common/utils/suite-code.util";
import { RegisterDto, LoginDto } from "./dto/auth.dto";
import * as bcrypt from "bcrypt";
@@ -13,22 +14,29 @@ import { TOTP, generateSecret, generateURI, verify as totpVerify } from "otplib"
const TENANT_SLUG = "moraworld";
const BCRYPT_ROUNDS = 10;
function buildSuiteAddress(suiteCode: string, config: import("@nestjs/config").ConfigService): string {
const street = config.get("WAREHOUSE_ADDRESS_STREET", "150 N Day St");
const city = config.get("WAREHOUSE_ADDRESS_CITY", "City of Orange");
const state = config.get("WAREHOUSE_ADDRESS_STATE", "NJ");
const zip = config.get("WAREHOUSE_ADDRESS_ZIP", "07050");
return `${street}, Suite ${suiteCode}, ${city}, ${state} ${zip}, EE.UU.`;
}
@Injectable()
export class AuthService {
constructor(
private prisma: PrismaService,
private jwt: JwtService,
private config: ConfigService,
private warehouses: WarehousesService,
) {}
/** Builds the suite address from the default warehouse in DB, falls back to env vars */
private async buildSuiteAddress(suiteCode: string, tenantId: string): Promise<string> {
const wh = await this.warehouses.findDefault(tenantId);
if (wh) {
return `${wh.street}, Suite ${suiteCode}, ${wh.city}, ${wh.state} ${wh.zip}, EE.UU.`;
}
// Fallback to env vars (backwards compat during migration)
const street = this.config.get("WAREHOUSE_ADDRESS_STREET", "150 N Day St");
const city = this.config.get("WAREHOUSE_ADDRESS_CITY", "City of Orange");
const state = this.config.get("WAREHOUSE_ADDRESS_STATE", "NJ");
const zip = this.config.get("WAREHOUSE_ADDRESS_ZIP", "07050");
return `${street}, Suite ${suiteCode}, ${city}, ${state} ${zip}, EE.UU.`;
}
// ─── Register ────────────────────────────────────────────────
async register(dto: RegisterDto): Promise<any> {
const tenant = await this.prisma.client.tenant.findUnique({ where: { slug: TENANT_SLUG } });
@@ -66,7 +74,7 @@ export class AuthService {
return {
user: this.sanitizeUser(user),
suiteCode,
suiteAddress: buildSuiteAddress(suiteCode, this.config),
suiteAddress: await this.buildSuiteAddress(suiteCode, tenant.id),
...tokens,
};
}
@@ -114,7 +122,7 @@ export class AuthService {
user: this.sanitizeUser(user),
suite: suite ? {
code: suite.code,
address: buildSuiteAddress(suite.code, this.config),
address: await this.buildSuiteAddress(suite.code, tenant.id),
} : null,
...tokens,
};
@@ -186,7 +194,7 @@ export class AuthService {
...this.sanitizeUser(user),
suite: suite ? {
code: suite.code,
address: buildSuiteAddress(suite.code, this.config),
address: await this.buildSuiteAddress(suite.code, user.tenantId),
} : null,
};
}