Files
OCR/frontend/src/app/pages/account/company/subsidiary/subsidiary.component.ts
2026-05-21 22:23:19 +05:30

329 lines
12 KiB
TypeScript

import { SearchDTO } from './../../../../models/masters/masters';
import { SubsidiaryDTO } from './../../../../models/account.model';
import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
import { ConfirmationService, MessageService } from 'primeng/api';
import { TableModule } from 'primeng/table';
import { Dialog } from 'primeng/dialog';
import { Ripple } from 'primeng/ripple';
import { ButtonModule, Button } from 'primeng/button';
import { ToastModule } from 'primeng/toast';
import { ToolbarModule } from 'primeng/toolbar';
import { ConfirmDialog } from 'primeng/confirmdialog';
import { InputTextModule } from 'primeng/inputtext';
import { TextareaModule } from 'primeng/textarea';
import { CommonModule } from '@angular/common';
import { FileUpload } from 'primeng/fileupload';
import { SelectModule } from 'primeng/select';
import { Tag } from 'primeng/tag';
import { RadioButton } from 'primeng/radiobutton';
import { Rating } from 'primeng/rating';
import { Skeleton } from 'primeng/skeleton';
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { InputNumber } from 'primeng/inputnumber';
import { IconFieldModule } from 'primeng/iconfield';
import { InputIconModule } from 'primeng/inputicon';
import { Table } from 'primeng/table';
import { DropdownModule } from 'primeng/dropdown';
import { CompanyService } from '../../../../services/account/company/company.service';
import { FloatLabelModule } from "primeng/floatlabel";
import { ValidationService } from '../../../../services/utilities/validation.service';
import { TooltipModule } from 'primeng/tooltip';
import { AutoCompleteModule } from 'primeng/autocomplete';
import { MasterService } from '../../../../services/masters/master.service';
import { CityDTO } from '../../../../models/masters/masters';
import { debounceTime, Subject } from 'rxjs';
import { Request } from '../../../../models/request.model';
interface Column {
field: string;
header: string;
customExportHeader?: string;
}
interface ExportColumn {
title: string;
dataKey: string;
}
@Component({
selector: 'app-subsidiary',
templateUrl: './subsidiary.component.html',
standalone: true,
imports: [TableModule, Dialog, Ripple, SelectModule, ToastModule, ToolbarModule, ConfirmDialog, InputTextModule, TextareaModule, CommonModule, FileUpload, DropdownModule, Tag, RadioButton, Rating, InputTextModule, InputNumber, IconFieldModule, InputIconModule, Button, FloatLabelModule, FormsModule, ReactiveFormsModule, TooltipModule, Skeleton, AutoCompleteModule],
providers: [MessageService, ConfirmationService],
styleUrl: './subsidiary.component.css'
})
export class SubsidiaryComponent implements OnInit{
subsidiaryForm: FormGroup;
subsidiaryDialog: boolean = false;
subsidiaries!: SubsidiaryDTO[];
subsidiary!: SubsidiaryDTO;
selectedSubsidiaries!: SubsidiaryDTO[] | null;
submitted: boolean = false;
isLoading: boolean = true;
skeletonData: any[] = Array(10).fill({});
suggestions: CityDTO[] = [];
private searchSubject = new Subject<string>();
statuses!: any[];
@ViewChild('dt') dt!: Table;
cols!: Column[];
exportColumns!: ExportColumn[];
constructor(
private subsidiaryService: CompanyService,
private masterService: MasterService,
private messageService: MessageService,
private confirmationService: ConfirmationService,
private cd: ChangeDetectorRef,
private fb: FormBuilder,
) {
this.subsidiaryForm = this.fb.group({
id: [{ value: '', disabled: true }],
cityId: [{ value: null, disabled: true }],
code: [{ value: '', disabled: false }, [Validators.required, ValidationService.codeValidator()]],
name: [{ value: '', disabled: false }, [Validators.required, ValidationService.nameValidator()]],
officeNo: [{ value: '', disabled: false }],
street: [{ value: '', disabled: false }],
locality: [{ value: '', disabled: false }],
cityName: [{ value: '', disabled: false }],
stateName: [{ value: '', disabled: true }],
pinCode: [{ value: '', disabled: false }, [ValidationService.pincodeValidator()]],
emailId: [{ value: '', disabled: false }, [ValidationService.emailValidator()]],
contactNo: [{ value: '', disabled: false }, [ValidationService.mobileValidator()]],
contactPerson: [{ value: '', disabled: false }, [ValidationService.contactPersonValidator()]],
panNo: [{ value: '', disabled: false }, [ValidationService.panValidator()]],
cinNo: [{ value: '', disabled: false }, [ValidationService.cinValidator()]],
msmeNo: [{ value: '', disabled: false }, [ValidationService.msmeValidator()]],
stateId: [{ value: '', disabled: true }],
stateCode: [{ value: '', disabled: true }],
gstCode: [{ value: '', disabled: true }]
});
}
exportCSV() {
this.dt.exportCSV();
}
searchCities(event: any) {
const query = event.query;
this.searchSubject.next(query);
}
onSelectCity(event: any) {
const city = event.value as CityDTO;
this.subsidiaryForm.patchValue({
cityId: city.id,
stateId: city.stateId,
cityName: city.cityName,
stateName: city.stateName,
stateCode: city.stateCode,
gstCode: city.gstCode
});
}
ngOnInit() {
this.loadAllSubsidiaries();
}
loadAllSubsidiaries() {
this.isLoading = true;
this.subsidiaryService.getAllSubsidiaries().subscribe({
next: (data) => {
this.isLoading = false;
this.subsidiaries = data;
this.cd.markForCheck();
},
error: (err) => {
this.isLoading = false;
console.error(err);
}
});
this.statuses = [
{ label: 'Active', value: true },
{ label: 'Inactive', value: false }
];
this.cols = [
{ field: 'code', header: 'Code', customExportHeader: 'Code' },
{ field: 'name', header: 'Name' },
{ field: 'officeNo', header: 'Office No / Building / Floor' },
{ field: 'street', header: 'Street / Road' },
{ field: 'locality', header: 'Locality' },
{ field: 'cityName', header: 'City' },
{ field: 'emailId', header: 'Email' },
{ field: 'contactNo', header: 'Contact No' },
{ field: 'contactPerson', header: 'Contact Person' },
{ field: 'panNo', header: 'PAN No.' },
{ field: 'cinNo', header: 'CIN No.' },
{ field: 'msmeNo', header: 'MSME No.' },
{ field: 'updatedAt', header: 'Last Updated At' },
{ field: 'updatedUser', header: 'Last Updated By' }
];
this.exportColumns = this.cols.map((col) => ({ title: col.header, dataKey: col.field }));
this.searchSubject.pipe(debounceTime(300)).subscribe(query => {
if (query && query.length >= 2) {
const requestPayload: Request<SearchDTO> = {
data: {
searchBy: 'CITY',
searchValue: query
},
compressed: true,
target: 'models.commons.Search'
};
this.masterService.searchCityStates(requestPayload).subscribe({
next: (cities) => {
this.suggestions = cities.map(city => ({
...city,
display: `${city.cityName}, ${city.stateName}`
}));
this.cd.markForCheck();
},
error: (err) => {
console.error('Error searching cities', err);
this.suggestions = [];
}
});
} else {
this.suggestions = [];
}
});
}
openNew() {
this.subsidiary = {};
this.subsidiaryForm.reset();
this.submitted = false;
this.subsidiaryDialog = true;
}
editSubsidiary(subsidiary: SubsidiaryDTO) {
this.subsidiaryForm.reset();
this.subsidiary = { ...subsidiary };
this.subsidiaryForm.patchValue(subsidiary);
this.subsidiaryDialog = true;
console.log(this.subsidiaryForm.getRawValue());
}
hideDialog() {
this.subsidiaryDialog = false;
this.submitted = false;
}
toggleActive(subsidiary: SubsidiaryDTO) {
const isActivating = !subsidiary.active;
this.confirmationService.confirm({
message: `Are you sure you want to ${isActivating ? 'activate' : 'deactivate'} ` + subsidiary.name + '?',
header: 'Confirm',
icon: 'pi pi-exclamation-triangle',
rejectButtonProps: {
label: 'No',
severity: 'secondary',
variant: 'text'
},
acceptButtonProps: {
severity: isActivating ? 'success' : 'danger',
label: 'Yes'
},
accept: () => {
this.subsidiaryService.activateDeactivateSubsidiary(subsidiary.id?? '', isActivating).subscribe({
next: (updatedSubsidiary) => {
subsidiary.active = updatedSubsidiary.active;
this.subsidiaries = [...this.subsidiaries];
this.messageService.add({
severity: 'success',
summary: 'Successful',
detail: `Subsidiary ${isActivating ? 'Activated' : 'Deactivated'}`,
life: 3000
});
},
error: (err) => {
console.error('Error toggling subsidiary active status', err);
this.messageService.add({
severity: 'error',
summary: 'Error',
detail: 'Failed to update subsidiary status',
life: 3000
});
}
});
}
});
}
getSeverity(status: boolean) {
switch (status) {
case true:
return 'success';
case false:
return 'warn';
}
}
getErrorMessage(fieldName: string): string {
const control = this.subsidiaryForm.get(fieldName);
return control ? ValidationService.getErrorMessage(control, fieldName) : '';
}
isFieldInvalid(fieldName: string): boolean {
const control = this.subsidiaryForm.get(fieldName);
return !!(control && control.invalid && (control.dirty || control.touched || this.submitted));
}
saveSubsidiary() {
this.submitted = true;
if (this.subsidiaryForm.valid) {
const subsidiaryData = this.subsidiaryForm.getRawValue();
const existing = this.subsidiaries.find(sub => sub.id !== subsidiaryData.id && (sub.code === subsidiaryData.code || sub.name === subsidiaryData.name));
if (existing) {
this.messageService.add({
severity: 'error',
summary: 'Validation Error',
detail: 'Subsidiary code or name already exists',
life: 3000
});
return;
}
this.subsidiaryService.saveSubsidiary(subsidiaryData).subscribe({
next: (newSubsidiary) => {
this.subsidiaries.push(newSubsidiary);
this.subsidiaries = [...this.subsidiaries];
this.messageService.add({
severity: 'success',
summary: 'Successful',
detail: 'Subsidiary Created',
life: 3000
});
this.subsidiaryDialog = false;
this.subsidiary = {};
},
error: (err) => {
console.error('Error saving subsidiary', err);
this.messageService.add({
severity: 'error',
summary: 'Error',
detail: 'Failed to save subsidiary',
life: 3000
});
}
});
}
}
}