npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cbm-common/declaration-code-configuration-repository

v0.0.1

Published

Biblioteca Angular especializada en la gestión de configuraciones de códigos de declaración fiscal. Proporciona una API completa para administrar códigos de declaración bruta, neta e impositiva, organizados por país y tipo de declaración.

Readme

Declaration Code Configuration Repository

Biblioteca Angular especializada en la gestión de configuraciones de códigos de declaración fiscal. Proporciona una API completa para administrar códigos de declaración bruta, neta e impositiva, organizados por país y tipo de declaración.

📋 Características Principales

  • Gestión Completa de Códigos: Administración de códigos brutos, netos e impositivos
  • Soporte Multi-País: Configuraciones específicas por jurisdicción territorial
  • Múltiples Tipos: Diferentes categorías de códigos de declaración
  • Operaciones CRUD Completas: Crear, leer, actualizar y eliminar configuraciones
  • Filtrado Avanzado: Búsqueda por estado, nombre y otros criterios
  • Arquitectura Moderna: Basada en Angular 20.1.5 con inyección de dependencias
  • Patrón Repository: Separación clara entre lógica de negocio y acceso a datos
  • TypeScript Nativo: Interfaces tipadas para mayor seguridad y mantenibilidad

🚀 Instalación

npm install @cbm-common/declaration-code-configuration-repository

⚙️ Configuración

1. Importar el Módulo

import { CbmDeclarationCodeConfigurationModule } from '@cbm-common/declaration-code-configuration-repository';

@NgModule({
  imports: [
    CbmDeclarationCodeConfigurationModule.forRoot({
      baseUrl: 'https://api.cbm.com/declaration-codes'
    })
  ]
})
export class AppModule { }

2. Configuración Standalone (Angular 20+)

import { CbmDeclarationCodeConfigurationModule } from '@cbm-common/declaration-code-configuration-repository';

@Component({
  standalone: true,
  imports: [CbmDeclarationCodeConfigurationModule.forRoot({
    baseUrl: 'https://api.cbm.com/declaration-codes'
  })]
})
export class AppComponent { }

📚 API Reference

Interfaz del Repositorio

interface ICbmDeclarationCodeConfigurationRepository {
  // Listado con filtros
  list(params: CbmDeclarationCodeConfigurationModel.ListParams): Observable<CbmDeclarationCodeConfigurationModel.ListResponse[]>;

  // Crear nueva configuración
  save(data: CbmDeclarationCodeConfigurationModel.SaveBody): Observable<CbmDeclarationCodeConfigurationModel.ConfirmResponse>;

  // Actualizar configuración existente
  update(id: string, data: CbmDeclarationCodeConfigurationModel.UpdateBody): Observable<CbmDeclarationCodeConfigurationModel.ConfirmResponse>;

  // Obtener configuración por ID
  getOne(id: string): Observable<CbmDeclarationCodeConfigurationModel.GetOneResponse>;

  // Eliminar configuración
  delete(id: string): Observable<CbmDeclarationCodeConfigurationModel.ConfirmResponse>;
}

💡 Uso Básico

Inyección del Servicio

import { CbmDeclarationCodeConfigurationRepository } from '@cbm-common/declaration-code-configuration-repository';

@Component({
  selector: 'app-declaration-code-manager'
})
export class DeclarationCodeManagerComponent {
  codes: CbmDeclarationCodeConfigurationModel.ListResponse[] = [];

  constructor(private declarationCodeRepository: CbmDeclarationCodeConfigurationRepository) {
    this.loadCodes();
  }

  loadCodes() {
    const params: CbmDeclarationCodeConfigurationModel.ListParams = {
      enabled: true,
      name: 'IVA'
    };

    this.declarationCodeRepository.list(params).subscribe({
      next: (response) => {
        this.codes = response;
        console.log('Códigos de declaración cargados:', this.codes);
      },
      error: (error) => {
        console.error('Error al cargar códigos:', error);
      }
    });
  }
}

Crear Nueva Configuración

createNewCode() {
  const codeData: CbmDeclarationCodeConfigurationModel.SaveBody = {
    raw_code: 'IVA-001',
    net_code: 'IVA-NET-001',
    tax_code: 'IVA-TAX-001',
    description: 'Código de declaración para IVA general',
    type: 'TAX'
  };

  this.declarationCodeRepository.save(codeData).subscribe({
    next: (response) => {
      if (response.success) {
        console.log('Código creado exitosamente');
        this.loadCodes(); // Recargar lista
      }
    },
    error: (error) => console.error('Error al crear código:', error)
  });
}

Actualizar Configuración Existente

updateExistingCode(codeId: string) {
  const updateData: CbmDeclarationCodeConfigurationModel.UpdateBody = {
    description: 'Código de declaración para IVA general - Actualizado',
    raw_code: 'IVA-001-UPDATED',
    net_code: 'IVA-NET-001-UPDATED'
  };

  this.declarationCodeRepository.update(codeId, updateData).subscribe({
    next: (response) => {
      if (response.success) {
        console.log('Código actualizado exitosamente');
        this.loadCodes();
      }
    },
    error: (error) => console.error('Error al actualizar código:', error)
  });
}

Obtener Configuración Específica

loadCodeDetails(codeId: string) {
  this.declarationCodeRepository.getOne(codeId).subscribe({
    next: (response) => {
      console.log('Detalles del código:', response);
      console.log('Código bruto:', response.raw_code);
      console.log('Código neto:', response.net_code);
      console.log('Código impositivo:', response.tax_code);
      console.log('Tipo:', response.type);
      console.log('País:', response.country_id);
    },
    error: (error) => console.error('Código no encontrado:', error)
  });
}

📊 Modelos de Datos

Parámetros de Búsqueda

interface ListParams {
  enabled?: boolean;    // Filtrar por estado activo/inactivo
  name?: string;        // Filtrar por nombre o descripción
}

Configuración de Código de Declaración

interface ListResponse {
  _id: string;                    // ID único de la configuración
  country_id: string;             // ID del país
  raw_code: string;               // Código bruto de declaración
  net_code: string;               // Código neto de declaración
  tax_code?: string;              // Código impositivo (opcional)
  description: string;            // Descripción detallada
  type: string;                   // Tipo de código (ej: 'TAX', 'INCOME', etc.)
  enabled: boolean;               // Estado activo/inactivo
  deleted: boolean;               // Indicador de eliminación lógica
  created_at: number;             // Fecha de creación (timestamp)
  created_user: string;           // Usuario que creó
  updated_at?: number;            // Fecha de actualización (timestamp)
  updated_user?: string;          // Usuario que actualizó
}

Datos para Crear Nueva Configuración

interface SaveBody {
  raw_code?: string;      // Código bruto (opcional)
  net_code?: string;      // Código neto (opcional)
  tax_code?: string;      // Código impositivo (opcional)
  description: string;    // Descripción (requerido)
  type: string;           // Tipo de código (requerido)
}

Datos para Actualizar Configuración

interface UpdateBody {
  raw_code?: string;      // Código bruto (opcional)
  net_code?: string;      // Código neto (opcional)
  tax_code?: string;      // Código impositivo (opcional)
  description?: string;   // Descripción (opcional)
  type?: string;          // Tipo de código (opcional)
}

Respuesta de Confirmación

interface ConfirmResponse {
  success: boolean;       // Indicador de éxito
  message: string;        // Mensaje descriptivo
  data?: any;             // Datos adicionales (opcional)
}

Ejemplo de Datos

{
  "_id": "64f1a2b3c4d5e6f7g8h9i0j1",
  "country_id": "ecuador",
  "raw_code": "IVA-001",
  "net_code": "IVA-NET-001",
  "tax_code": "IVA-TAX-001",
  "description": "Código de declaración para IVA general",
  "type": "TAX",
  "enabled": true,
  "deleted": false,
  "created_at": 1694000000000,
  "created_user": "admin",
  "updated_at": 1694000000000,
  "updated_user": "admin"
}

🔍 Casos de Uso Comunes

1. Sistema de Gestión Fiscal

@Component({
  selector: 'app-tax-code-manager'
})
export class TaxCodeManagerComponent {
  taxCodes: CbmDeclarationCodeConfigurationModel.ListResponse[] = [];
  selectedCountry = 'ecuador';

  constructor(private declarationCodeRepository: CbmDeclarationCodeConfigurationRepository) {
    this.loadTaxCodes();
  }

  loadTaxCodes() {
    const params: CbmDeclarationCodeConfigurationModel.ListParams = {
      enabled: true
    };

    this.declarationCodeRepository.list(params).subscribe({
      next: (response) => {
        // Filtrar por país seleccionado
        this.taxCodes = response.filter(code =>
          code.country_id === this.selectedCountry && code.type === 'TAX'
        );
      }
    });
  }

  getCodesByType(type: string): CbmDeclarationCodeConfigurationModel.ListResponse[] {
    return this.taxCodes.filter(code => code.type === type);
  }
}

2. Generador de Reportes Fiscales

@Component({
  selector: 'app-fiscal-report-generator'
})
export class FiscalReportGeneratorComponent {
  reportData: any[] = [];

  constructor(private declarationCodeRepository: CbmDeclarationCodeConfigurationRepository) {}

  generateFiscalReport(countryId: string, type: string) {
    const params: CbmDeclarationCodeConfigurationModel.ListParams = {
      enabled: true
    };

    this.declarationCodeRepository.list(params).subscribe({
      next: (response) => {
        const filteredCodes = response.filter(code =>
          code.country_id === countryId &&
          code.type === type &&
          !code.deleted
        );

        this.reportData = filteredCodes.map(code => ({
          codigo_bruto: code.raw_code,
          codigo_neto: code.net_code,
          codigo_impositivo: code.tax_code,
          descripcion: code.description,
          tipo: code.type,
          pais: code.country_id
        }));

        this.exportReport();
      }
    });
  }

  private exportReport() {
    // Lógica para exportar el reporte
    console.log('Datos del reporte:', this.reportData);
  }
}

3. Validador de Códigos de Declaración

@Injectable({ providedIn: 'root' })
export class DeclarationCodeValidatorService {
  constructor(private declarationCodeRepository: CbmDeclarationCodeConfigurationRepository) {}

  validateCode(code: string, countryId: string, type: string): Observable<boolean> {
    const params: CbmDeclarationCodeConfigurationModel.ListParams = {
      enabled: true
    };

    return this.declarationCodeRepository.list(params).pipe(
      map(response => {
        return response.some(item =>
          (item.raw_code === code || item.net_code === code || item.tax_code === code) &&
          item.country_id === countryId &&
          item.type === type &&
          !item.deleted
        );
      }),
      catchError(() => of(false))
    );
  }

  getCodeByRawCode(rawCode: string): Observable<CbmDeclarationCodeConfigurationModel.ListResponse | null> {
    const params: CbmDeclarationCodeConfigurationModel.ListParams = {
      enabled: true
    };

    return this.declarationCodeRepository.list(params).pipe(
      map(response => {
        return response.find(item =>
          item.raw_code === rawCode && !item.deleted
        ) || null;
      })
    );
  }
}

4. Dashboard de Configuraciones

@Component({
  selector: 'app-configuration-dashboard'
})
export class ConfigurationDashboardComponent {
  stats = {
    totalCodes: 0,
    activeCodes: 0,
    inactiveCodes: 0,
    codesByType: new Map<string, number>(),
    codesByCountry: new Map<string, number>()
  };

  constructor(private declarationCodeRepository: CbmDeclarationCodeConfigurationRepository) {
    this.loadDashboardStats();
  }

  loadDashboardStats() {
    const params: CbmDeclarationCodeConfigurationModel.ListParams = {};

    this.declarationCodeRepository.list(params).subscribe({
      next: (response) => {
        this.calculateStats(response);
      }
    });
  }

  private calculateStats(codes: CbmDeclarationCodeConfigurationModel.ListResponse[]) {
    this.stats.totalCodes = codes.length;
    this.stats.activeCodes = codes.filter(code => code.enabled && !code.deleted).length;
    this.stats.inactiveCodes = codes.filter(code => !code.enabled || code.deleted).length;

    // Estadísticas por tipo
    codes.forEach(code => {
      const current = this.stats.codesByType.get(code.type) || 0;
      this.stats.codesByType.set(code.type, current + 1);
    });

    // Estadísticas por país
    codes.forEach(code => {
      const current = this.stats.codesByCountry.get(code.country_id) || 0;
      this.stats.codesByCountry.set(code.country_id, current + 1);
    });
  }
}

🏗️ Arquitectura y Patrones

Patrón Repository

La biblioteca implementa el patrón Repository para mantener la separación entre la lógica de negocio y el acceso a datos:

// Interfaz del repositorio
export interface ICbmDeclarationCodeConfigurationRepository {
  list(params: CbmDeclarationCodeConfigurationModel.ListParams): Observable<CbmDeclarationCodeConfigurationModel.ListResponse[]>;
  save(data: CbmDeclarationCodeConfigurationModel.SaveBody): Observable<CbmDeclarationCodeConfigurationModel.ConfirmResponse>;
  update(id: string, data: CbmDeclarationCodeConfigurationModel.UpdateBody): Observable<CbmDeclarationCodeConfigurationModel.ConfirmResponse>;
  getOne(id: string): Observable<CbmDeclarationCodeConfigurationModel.GetOneResponse>;
  delete(id: string): Observable<CbmDeclarationCodeConfigurationModel.ConfirmResponse>;
}

// Implementación del servicio
@Injectable({ providedIn: 'root' })
export class CbmDeclarationCodeConfigurationService implements ICbmDeclarationCodeConfigurationRepository {
  constructor(
    private readonly http: HttpClient,
    @Inject(DECLARATION_CODE_CONFIGURATION_MODULE_CONFIG) private readonly config: ICbmDeclarationCodeConfigurationModuleConfig
  ) {}

  list(params: CbmDeclarationCodeConfigurationModel.ListParams): Observable<CbmDeclarationCodeConfigurationModel.ListResponse[]> {
    return this.http.get<CbmDeclarationCodeConfigurationModel.ListResponse[]>(this.config.baseUrl, { params: { ...params } });
  }

  // ... otros métodos
}

// Wrapper del repositorio
@Injectable({ providedIn: 'root' })
export class CbmDeclarationCodeConfigurationRepository implements ICbmDeclarationCodeConfigurationRepository {
  constructor(private service: CbmDeclarationCodeConfigurationService) {}

  list(params: CbmDeclarationCodeConfigurationModel.ListParams): Observable<CbmDeclarationCodeConfigurationModel.ListResponse[]> {
    return this.service.list(params);
  }

  // ... delegación a service
}

Configuración Centralizada

// Configuración del módulo
@NgModule({
  imports: [
    CbmDeclarationCodeConfigurationModule.forRoot({
      baseUrl: environment.apiUrl + '/declaration-codes'
    })
  ]
})
export class AppModule {}

🔧 Mejores Prácticas

Manejo de Errores

@Component({
  selector: 'app-safe-code-handler'
})
export class SafeCodeHandlerComponent {
  constructor(private declarationCodeRepository: CbmDeclarationCodeConfigurationRepository) {}

  safeLoadCodes() {
    const params: CbmDeclarationCodeConfigurationModel.ListParams = {
      enabled: true
    };

    this.declarationCodeRepository.list(params).subscribe({
      next: (response) => {
        if (Array.isArray(response)) {
          this.processCodes(response);
        } else {
          this.showErrorMessage('Respuesta inválida del servidor');
        }
      },
      error: (error) => {
        if (error.status === 404) {
          this.showErrorMessage('Servicio de códigos no disponible');
        } else if (error.status === 500) {
          this.showErrorMessage('Error interno del servidor');
        } else {
          this.showErrorMessage('Error de conexión');
        }
      }
    });
  }

  private processCodes(codes: CbmDeclarationCodeConfigurationModel.ListResponse[]) {
    // Procesar códigos de manera segura
    codes.forEach(code => {
      if (code.raw_code && code.type) {
        // Procesar código válido
      } else {
        console.warn(`Código inválido: ${code._id}`);
      }
    });
  }

  private showErrorMessage(message: string) {
    // Mostrar mensaje de error al usuario
  }
}

Validación de Datos

@Injectable({ providedIn: 'root' })
export class CodeValidationService {
  constructor(private declarationCodeRepository: CbmDeclarationCodeConfigurationRepository) {}

  validateCodeData(data: CbmDeclarationCodeConfigurationModel.SaveBody): string[] {
    const errors: string[] = [];

    if (!data.description?.trim()) {
      errors.push('La descripción es obligatoria');
    }

    if (!data.type?.trim()) {
      errors.push('El tipo es obligatorio');
    }

    if (data.raw_code && !this.isValidCodeFormat(data.raw_code)) {
      errors.push('El formato del código bruto no es válido');
    }

    if (data.net_code && !this.isValidCodeFormat(data.net_code)) {
      errors.push('El formato del código neto no es válido');
    }

    return errors;
  }

  private isValidCodeFormat(code: string): boolean {
    // Validar formato de código (ejemplo: XXX-999)
    const codePattern = /^[A-Z]{3}-\d{3}$/;
    return codePattern.test(code);
  }

  validateAndSave(data: CbmDeclarationCodeConfigurationModel.SaveBody): Observable<boolean> {
    const errors = this.validateCodeData(data);

    if (errors.length > 0) {
      console.error('Errores de validación:', errors);
      return of(false);
    }

    return this.declarationCodeRepository.save(data).pipe(
      map(response => response.success),
      catchError(() => of(false))
    );
  }
}

Caché de Configuraciones

@Injectable({ providedIn: 'root' })
export class CodeCacheService {
  private cache = new Map<string, CbmDeclarationCodeConfigurationModel.ListResponse[]>();
  private readonly CACHE_DURATION = 30 * 60 * 1000; // 30 minutos

  constructor(private declarationCodeRepository: CbmDeclarationCodeConfigurationRepository) {}

  getCodes(params: CbmDeclarationCodeConfigurationModel.ListParams, forceRefresh = false): Observable<CbmDeclarationCodeConfigurationModel.ListResponse[]> {
    const cacheKey = JSON.stringify(params);
    const cached = this.cache.get(cacheKey);

    if (cached && !forceRefresh && !this.isCacheExpired(cached)) {
      return of(cached);
    }

    return this.declarationCodeRepository.list(params).pipe(
      tap(response => {
        this.cache.set(cacheKey, response);
      })
    );
  }

  private isCacheExpired(codes: CbmDeclarationCodeConfigurationModel.ListResponse[]): boolean {
    if (codes.length === 0) return true;
    const mostRecent = Math.max(...codes.map(code => code.updated_at || code.created_at));
    return Date.now() - mostRecent > this.CACHE_DURATION;
  }

  invalidateCache() {
    this.cache.clear();
  }
}

📋 Lista de Verificación para Implementación

  • [ ] ✅ Configurar el módulo CbmDeclarationCodeConfigurationModule.forRoot() en el AppModule
  • [ ] ✅ Inyectar CbmDeclarationCodeConfigurationRepository en los componentes que lo necesiten
  • [ ] ✅ Implementar manejo de errores para todas las operaciones CRUD
  • [ ] ✅ Validar datos antes de enviar al servidor
  • [ ] ✅ Implementar indicadores de carga durante las operaciones
  • [ ] ✅ Manejar estados de error y respuestas no exitosas
  • [ ] ✅ Considerar implementar caché para configuraciones (cambian infrequentemente)
  • [ ] ✅ Probar todas las operaciones CRUD
  • [ ] ✅ Verificar funcionamiento con diferentes países y tipos
  • [ ] ✅ Documentar casos de uso específicos de la aplicación

🔗 Dependencias

{
  "peerDependencies": {
    "@angular/common": "20.1.5",
    "@angular/core": "20.1.5",
    "@angular/common/http": "20.1.5"
  },
  "dependencies": {
    "tslib": "2.3.0"
  }
}

📝 Notas de Versión

v0.0.1

  • ✅ Implementación inicial del repositorio de códigos de declaración
  • ✅ Soporte completo para operaciones CRUD
  • ✅ Gestión de códigos brutos, netos e impositivos
  • ✅ Filtrado por estado y nombre
  • ✅ Arquitectura basada en patrón Repository
  • ✅ Configuración simplificada con forRoot()
  • ✅ Compatibilidad con Angular 20.1.5
  • ✅ Interfaces TypeScript tipadas
  • ✅ Documentación completa en español

🤝 Contribución

Para contribuir a esta biblioteca:

  1. Fork el repositorio
  2. Crear una rama para la nueva funcionalidad
  3. Implementar los cambios siguiendo los patrones establecidos
  4. Agregar pruebas unitarias si es necesario
  5. Enviar un Pull Request con descripción detallada

📞 Soporte

Para soporte técnico o consultas sobre el uso de la biblioteca, contactar al equipo de desarrollo de CBM.


CBM (Contabilidad y Facturación Moderna) - Repositorio de Códigos de Declaración v0.0.1