cloud-ide-fees 0.0.30 → 0.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,30 +1,30 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, inject, Injectable, DestroyRef, viewChild, signal, computed, input, ChangeDetectorRef, ViewChild, output } from '@angular/core';
2
+ import { Component, inject, Injectable, DestroyRef, viewChild, signal, computed, input, output, effect, ChangeDetectorRef, ViewChild, Input } from '@angular/core';
3
3
  import { authGuard } from 'cloud-ide-auth';
4
4
  import { HttpClient } from '@angular/common/http';
5
- import { generateStringFromObject, cidePath, hostManagerRoutesUrl, feesRoutesUrl, MFeeStructure, generateObjectFromString, AcaClassPrgBranchListPayload, academicsRoutesUrl, MPrgTrmSection, FeeStructureSaveUpdatePayload, MFeePayment, MFeePaymentInsertUpdatePayload, MFeeReceiptTemplateInsertUpdatePayload, MFeeReceiptTemplate, MFeeReceiptTemplateGetByIdPayload, coreRoutesUrl } from 'cloud-ide-lms-model';
5
+ import { generateStringFromObject, cidePath, hostManagerRoutesUrl, feesRoutesUrl, MFeeStructure, generateObjectFromString, AcaClassPrgBranchListPayload, academicsRoutesUrl, MPrgTrmSection, FeeStructureSaveUpdatePayload, MFeePayment, MFeeReceiptTemplateInsertUpdatePayload, MFeeReceiptTemplate, MFeeReceiptTemplateGetByIdPayload, coreRoutesUrl } from 'cloud-ide-lms-model';
6
6
  import * as i1 from '@angular/common';
7
- import { CommonModule, DatePipe } from '@angular/common';
7
+ import { CommonModule, CurrencyPipe, DatePipe } from '@angular/common';
8
8
  import * as i1$1 from '@angular/forms';
9
9
  import { FormsModule, FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
10
10
  import { Router, ActivatedRoute } from '@angular/router';
11
11
  import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
12
- import { ConfirmationService, NotificationService, CideIconComponent, CideEleButtonComponent, CideEleDataGridComponent, CideEleDropdownComponent, CideInputComponent, CideTextareaComponent, CideEleTabComponent, CideSelectComponent, CideFormFieldErrorComponent, CurrencyPipe } from 'cloud-ide-element';
12
+ import { ConfirmationService, NotificationService, CideIconComponent, CideEleButtonComponent, CideEleDataGridComponent, CideEleDropdownComponent, CideInputComponent, CideTextareaComponent, CideEleTabComponent, CideSelectComponent, CideFormFieldErrorComponent, CideEleFloatingContainerService, CurrencyPipe as CurrencyPipe$1 } from 'cloud-ide-element';
13
13
  import { AppStateHelperService, RightsService, CideLytSharedWrapperComponent, AppStateService, ComponentContextService } from 'cloud-ide-layout';
14
- import { ENTITY_SERVICE_TOKEN, ACADEMIC_YEAR_SERVICE_TOKEN, CLASS_PROGRAM_MASTER_SERVICE_TOKEN, PROGRAM_TERM_SECTION_SERVICE_TOKEN, GENERAL_MASTER_SERVICE_TOKEN, ProgramSectionSelectorWrapperComponent } from 'cloud-ide-shared';
14
+ import { ENTITY_SERVICE_TOKEN, CLASS_PROGRAM_MASTER_SERVICE_TOKEN, PROGRAM_TERM_SECTION_SERVICE_TOKEN, GENERAL_MASTER_SERVICE_TOKEN, ProgramSectionSelectorWrapperComponent, ACADEMIC_YEAR_SERVICE_TOKEN } from 'cloud-ide-shared';
15
15
  import { forkJoin, startWith } from 'rxjs';
16
16
  import { CideCoreUserMasterService } from 'cloud-ide-core';
17
17
  import { DomSanitizer } from '@angular/platform-browser';
18
18
 
19
19
  class CloudIdeFees {
20
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CloudIdeFees, deps: [], target: i0.ɵɵFactoryTarget.Component });
21
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.7", type: CloudIdeFees, isStandalone: true, selector: "lib-cloud-ide-fees", ngImport: i0, template: `
20
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CloudIdeFees, deps: [], target: i0.ɵɵFactoryTarget.Component });
21
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: CloudIdeFees, isStandalone: true, selector: "lib-cloud-ide-fees", ngImport: i0, template: `
22
22
  <p>
23
23
  cloud-ide-fees works!
24
24
  </p>
25
25
  `, isInline: true, styles: [""] });
26
26
  }
27
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CloudIdeFees, decorators: [{
27
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CloudIdeFees, decorators: [{
28
28
  type: Component,
29
29
  args: [{ selector: 'lib-cloud-ide-fees', imports: [], template: `
30
30
  <p>
@@ -233,10 +233,10 @@ class CideFeeFeeStructureService {
233
233
  console.log('🔄 Making PATCH request to toggle fee structure status:', { url, payload });
234
234
  return this.http.patch(url, payload);
235
235
  }
236
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideFeeFeeStructureService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
237
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideFeeFeeStructureService, providedIn: 'root' });
236
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideFeeFeeStructureService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
237
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideFeeFeeStructureService, providedIn: 'root' });
238
238
  }
239
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideFeeFeeStructureService, decorators: [{
239
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideFeeFeeStructureService, decorators: [{
240
240
  type: Injectable,
241
241
  args: [{
242
242
  providedIn: 'root'
@@ -401,13 +401,19 @@ class FeeStructureListComponent {
401
401
  }), ...(ngDevMode ? [{ debugName: "gridConfig" }] : []));
402
402
  // Rights computed signals
403
403
  canCreate = computed(() => this.rightsService.hasRight('CREATE'), ...(ngDevMode ? [{ debugName: "canCreate" }] : []));
404
- canEdit = computed(() => this.rightsService.hasRight('EDIT'), ...(ngDevMode ? [{ debugName: "canEdit" }] : []));
404
+ canEdit = computed(() => this.rightsService.hasRight('EDIT') || this.rightsService.hasRight('UPDATE'), ...(ngDevMode ? [{ debugName: "canEdit" }] : []));
405
405
  canDelete = computed(() => this.rightsService.hasRight('DELETE'), ...(ngDevMode ? [{ debugName: "canDelete" }] : []));
406
406
  canView = computed(() => this.rightsService.hasRight('VIEW'), ...(ngDevMode ? [{ debugName: "canView" }] : []));
407
407
  ngOnInit() {
408
408
  // Initialize rights for fee structure management
409
409
  this.rightsService.initializeRights('fee_structure');
410
410
  console.log('💰 Fee Structure List Component initialized');
411
+ // Diagnostic logging for rights
412
+ setTimeout(() => {
413
+ console.log('🔐 Debug: Current Page Code:', this.rightsService.getCurrentPageCode());
414
+ console.log('🔐 Debug: All loaded rights for fee_structure:', this.rightsService.getRights());
415
+ console.log('🔐 Debug: canEdit evaluation:', this.canEdit());
416
+ }, 1000);
411
417
  this.initializeBreadcrumbData();
412
418
  this.loadFeeStructures();
413
419
  }
@@ -434,6 +440,7 @@ class FeeStructureListComponent {
434
440
  pageIndex: this.currentPage(),
435
441
  pageSize: this.pageSize(),
436
442
  query: this.searchQuery() || "",
443
+ fees_entity_id_syen: this.appState.activeEntity()?._id || "",
437
444
  sort: {
438
445
  key: this.sortColumn(),
439
446
  order: this.sortDirection()
@@ -807,10 +814,10 @@ class FeeStructureListComponent {
807
814
  return category;
808
815
  return category.sygms_title || category.sygms_code || '-';
809
816
  }
810
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeStructureListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
811
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: FeeStructureListComponent, isStandalone: true, selector: "cide-fee-structure-list", viewQueries: [{ propertyName: "feeStructureDetailsRendererTemplate", first: true, predicate: ["feeStructureDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "statusRendererTemplate", first: true, predicate: ["statusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "academicYearRendererTemplate", first: true, predicate: ["academicYearRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "classProgramRendererTemplate", first: true, predicate: ["classProgramRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "reservationCategoryRendererTemplate", first: true, predicate: ["reservationCategoryRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Fee Structure Container -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_structure' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"createFeeStructure()\">\n Create Fee Structure\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n\n <!-- Data Grid Component -->\n <div class=\"tw-h-full tw-overflow-auto\">\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n\n </div>\n </div>\n\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #feeStructureDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-w-full\">\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.fees_structure_name || 'N/A' }}</div>\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">{{ row.fees_structure_description || 'No description' }}</div>\n </div>\n</ng-template>\n\n\n<ng-template #statusRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-gap-1 tw-items-center\">\n <!-- Active/Inactive Status Badge -->\n <span class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\n [ngClass]=\"getStatusBadgeClass(row)\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\n {{ row.fees_is_active ? 'check_circle' : 'cancel' }}\n </cide-ele-icon>\n {{ getStatusText(row) }}\n </span>\n \n <!-- Template Badge -->\n @if (row.is_template) {\n <span\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-purple-100 tw-text-purple-800 tw-text-center\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">description</cide-ele-icon>\n Template\n </span>\n }\n </div>\n</ng-template>\n\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\n <cide-ele-dropdown \n [items]=\"getActionDropdownItems(row)\"\n [config]=\"getDropdownConfig()\"\n (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>\n\n<ng-template #academicYearRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-900\">{{ getAcademicYearName(row) }}</span>\n </div>\n</ng-template>\n\n<ng-template #classProgramRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-text-gray-700\">{{ getClassProgramName(row) }}</span>\n </div>\n</ng-template>\n\n<ng-template #reservationCategoryRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-text-gray-700\">{{ getReservationCategoryName(row) }}</span>\n </div>\n</ng-template>\n\n", styles: [".fee-structure-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
817
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeStructureListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
818
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FeeStructureListComponent, isStandalone: true, selector: "cide-fee-structure-list", viewQueries: [{ propertyName: "feeStructureDetailsRendererTemplate", first: true, predicate: ["feeStructureDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "statusRendererTemplate", first: true, predicate: ["statusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "academicYearRendererTemplate", first: true, predicate: ["academicYearRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "classProgramRendererTemplate", first: true, predicate: ["classProgramRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "reservationCategoryRendererTemplate", first: true, predicate: ["reservationCategoryRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Fee Structure Container -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_structure' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"createFeeStructure()\">\n Create Fee Structure\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n\n <!-- Data Grid Component -->\n <div class=\"tw-h-full tw-overflow-auto\">\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n\n </div>\n </div>\n\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #feeStructureDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-w-full\">\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.fees_structure_name || 'N/A' }}</div>\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">{{ row.fees_structure_description || 'No description' }}</div>\n </div>\n</ng-template>\n\n\n<ng-template #statusRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-gap-1 tw-items-center\">\n <!-- Active/Inactive Status Badge -->\n <span class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\n [ngClass]=\"getStatusBadgeClass(row)\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\n {{ row.fees_is_active ? 'check_circle' : 'cancel' }}\n </cide-ele-icon>\n {{ getStatusText(row) }}\n </span>\n \n <!-- Template Badge -->\n @if (row.is_template) {\n <span\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-purple-100 tw-text-purple-800 tw-text-center\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">description</cide-ele-icon>\n Template\n </span>\n }\n </div>\n</ng-template>\n\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\n <cide-ele-dropdown \n [items]=\"getActionDropdownItems(row)\"\n [config]=\"getDropdownConfig()\"\n (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>\n\n<ng-template #academicYearRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-900\">{{ getAcademicYearName(row) }}</span>\n </div>\n</ng-template>\n\n<ng-template #classProgramRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-text-gray-700\">{{ getClassProgramName(row) }}</span>\n </div>\n</ng-template>\n\n<ng-template #reservationCategoryRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-text-gray-700\">{{ getReservationCategoryName(row) }}</span>\n </div>\n</ng-template>\n\n", styles: [".fee-structure-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
812
819
  }
813
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeStructureListComponent, decorators: [{
820
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeStructureListComponent, decorators: [{
814
821
  type: Component,
815
822
  args: [{ selector: 'cide-fee-structure-list', standalone: true, imports: [
816
823
  CommonModule,
@@ -821,7 +828,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
821
828
  CideEleDropdownComponent,
822
829
  CideLytSharedWrapperComponent
823
830
  ], template: "<!-- Fee Structure Container -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_structure' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"createFeeStructure()\">\n Create Fee Structure\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n\n <!-- Data Grid Component -->\n <div class=\"tw-h-full tw-overflow-auto\">\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n\n </div>\n </div>\n\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #feeStructureDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-w-full\">\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.fees_structure_name || 'N/A' }}</div>\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">{{ row.fees_structure_description || 'No description' }}</div>\n </div>\n</ng-template>\n\n\n<ng-template #statusRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-gap-1 tw-items-center\">\n <!-- Active/Inactive Status Badge -->\n <span class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\n [ngClass]=\"getStatusBadgeClass(row)\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\n {{ row.fees_is_active ? 'check_circle' : 'cancel' }}\n </cide-ele-icon>\n {{ getStatusText(row) }}\n </span>\n \n <!-- Template Badge -->\n @if (row.is_template) {\n <span\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-purple-100 tw-text-purple-800 tw-text-center\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">description</cide-ele-icon>\n Template\n </span>\n }\n </div>\n</ng-template>\n\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\n <cide-ele-dropdown \n [items]=\"getActionDropdownItems(row)\"\n [config]=\"getDropdownConfig()\"\n (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>\n\n<ng-template #academicYearRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-900\">{{ getAcademicYearName(row) }}</span>\n </div>\n</ng-template>\n\n<ng-template #classProgramRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-text-gray-700\">{{ getClassProgramName(row) }}</span>\n </div>\n</ng-template>\n\n<ng-template #reservationCategoryRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-text-gray-700\">{{ getReservationCategoryName(row) }}</span>\n </div>\n</ng-template>\n\n", styles: [".fee-structure-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"] }]
824
- }] });
831
+ }], propDecorators: { feeStructureDetailsRendererTemplate: [{ type: i0.ViewChild, args: ['feeStructureDetailsRendererTemplate', { isSignal: true }] }], statusRendererTemplate: [{ type: i0.ViewChild, args: ['statusRendererTemplate', { isSignal: true }] }], actionsDropdownRendererTemplate: [{ type: i0.ViewChild, args: ['actionsDropdownRendererTemplate', { isSignal: true }] }], academicYearRendererTemplate: [{ type: i0.ViewChild, args: ['academicYearRendererTemplate', { isSignal: true }] }], classProgramRendererTemplate: [{ type: i0.ViewChild, args: ['classProgramRendererTemplate', { isSignal: true }] }], reservationCategoryRendererTemplate: [{ type: i0.ViewChild, args: ['reservationCategoryRendererTemplate', { isSignal: true }] }] } });
825
832
 
826
833
  var feeStructureList_component = /*#__PURE__*/Object.freeze({
827
834
  __proto__: null,
@@ -834,7 +841,6 @@ class FeeStructureCreateComponent {
834
841
  fb = inject(FormBuilder);
835
842
  feeStructureService = inject(CideFeeFeeStructureService);
836
843
  entityService = inject(ENTITY_SERVICE_TOKEN);
837
- academicYearService = inject(ACADEMIC_YEAR_SERVICE_TOKEN);
838
844
  classProgramMasterService = inject(CLASS_PROGRAM_MASTER_SERVICE_TOKEN);
839
845
  programTermSectionService = inject(PROGRAM_TERM_SECTION_SERVICE_TOKEN);
840
846
  generalMasterService = inject(GENERAL_MASTER_SERVICE_TOKEN);
@@ -858,9 +864,7 @@ class FeeStructureCreateComponent {
858
864
  breadcrumbData = signal([], ...(ngDevMode ? [{ debugName: "breadcrumbData" }] : []));
859
865
  // Dropdown options
860
866
  entityOptions = signal([], ...(ngDevMode ? [{ debugName: "entityOptions" }] : []));
861
- academicYearOptions = signal([], ...(ngDevMode ? [{ debugName: "academicYearOptions" }] : []));
862
867
  entityLoading = signal(false, ...(ngDevMode ? [{ debugName: "entityLoading" }] : []));
863
- academicYearLoading = signal(false, ...(ngDevMode ? [{ debugName: "academicYearLoading" }] : []));
864
868
  // Class Program Master options
865
869
  classProgramMasters = signal([], ...(ngDevMode ? [{ debugName: "classProgramMasters" }] : []));
866
870
  classProgramMastersLoading = signal(false, ...(ngDevMode ? [{ debugName: "classProgramMastersLoading" }] : []));
@@ -976,7 +980,7 @@ class FeeStructureCreateComponent {
976
980
  fees_class_program_term_id_acapt: [''],
977
981
  fees_program_term_section_id_acapts: [''],
978
982
  fees_student_category_id_sygms: [''],
979
- fees_academic_year_id_acayr: [''],
983
+ fees_academic_year_id_acayr: [this.appStateService.activeAcademicYear()?._id || ''],
980
984
  fees_entity_id_syen: [''], // Will be set from active entity
981
985
  fees_is_active: [true],
982
986
  // Fee Items
@@ -1353,6 +1357,14 @@ class FeeStructureCreateComponent {
1353
1357
  ngOnInit() {
1354
1358
  // Initialize rights for fee structure management
1355
1359
  this.rightsService.initializeRights('fee_structure');
1360
+ // Diagnostic logging for rights
1361
+ setTimeout(() => {
1362
+ console.log('💰 Fee Structure Create Component initialized');
1363
+ console.log('🔐 Debug: Current Page Code:', this.rightsService.getCurrentPageCode());
1364
+ console.log('🔐 Debug: All loaded rights for fee_structure:', this.rightsService.getRights());
1365
+ const hasEditAccess = this.rightsService.hasRight('EDIT') || this.rightsService.hasRight('UPDATE');
1366
+ console.log('🔐 Debug: Edit/Update access evaluation:', hasEditAccess);
1367
+ }, 1000);
1356
1368
  this.initializeComponent();
1357
1369
  }
1358
1370
  ngOnDestroy() {
@@ -1424,33 +1436,7 @@ class FeeStructureCreateComponent {
1424
1436
  this.loadStudentCategories();
1425
1437
  this.loadFeeCategories();
1426
1438
  }, 100);
1427
- // Load academic year options and set current one
1428
- this.academicYearLoading.set(true);
1429
- const academicYearPayload = {
1430
- pageIndex: 1,
1431
- pageSize: 100,
1432
- pagination: false
1433
- };
1434
- this.academicYearService.getAcademicYearList(academicYearPayload).subscribe({
1435
- next: (response) => {
1436
- if (response?.success && response.data) {
1437
- this.academicYearOptions.set(response.data);
1438
- // Find and set current academic year (where acayr_iscurrent is true)
1439
- const currentAcademicYear = response.data.find((ay) => ay.acayr_iscurrent === true);
1440
- if (currentAcademicYear?._id) {
1441
- this.feeStructureForm.patchValue({
1442
- fees_academic_year_id_acayr: currentAcademicYear._id
1443
- });
1444
- // Disable academic year control
1445
- this.feeStructureForm.get('fees_academic_year_id_acayr')?.disable();
1446
- }
1447
- }
1448
- this.academicYearLoading.set(false);
1449
- },
1450
- error: () => {
1451
- this.academicYearLoading.set(false);
1452
- }
1453
- });
1439
+ // academicYearLoading.set(true); removed as we use appState
1454
1440
  }
1455
1441
  /**
1456
1442
  * Load class program masters
@@ -2113,9 +2099,12 @@ class FeeStructureCreateComponent {
2113
2099
  * Handle form submission
2114
2100
  */
2115
2101
  onSubmit() {
2116
- const requiredRight = this.isEditMode() ? 'EDIT' : 'CREATE';
2117
- if (!this.rightsService.hasRight(requiredRight)) {
2118
- this.notificationService.error(`You do not have permission to ${this.isEditMode() ? 'edit' : 'create'} fee structures`);
2102
+ const isEdit = this.isEditMode();
2103
+ const hasPermission = isEdit
2104
+ ? (this.rightsService.hasRight('EDIT') || this.rightsService.hasRight('UPDATE'))
2105
+ : this.rightsService.hasRight('CREATE');
2106
+ if (!hasPermission) {
2107
+ this.notificationService.error(`You do not have permission to ${isEdit ? 'edit' : 'create'} fee structures`);
2119
2108
  return;
2120
2109
  }
2121
2110
  if (this.submitting()) {
@@ -2225,6 +2214,8 @@ class FeeStructureCreateComponent {
2225
2214
  // Show success toast notification
2226
2215
  this.notificationService.success(`Fee structure ${this.isEditMode() ? 'updated' : 'created'} successfully!`, { icon: 'done' });
2227
2216
  this.submitting.set(false);
2217
+ // Navigate to listing page on success
2218
+ this.componentContextService.close(['/control-panel/structure']);
2228
2219
  });
2229
2220
  }
2230
2221
  else {
@@ -2335,13 +2326,11 @@ class FeeStructureCreateComponent {
2335
2326
  }));
2336
2327
  }
2337
2328
  /**
2338
- * Get academic year options for select
2329
+ * Get academic year name from app state
2339
2330
  */
2340
- getAcademicYearOptions() {
2341
- return this.academicYearOptions().map(ay => ({
2342
- value: ay._id || '',
2343
- label: `${ay.acayr_name || ''} (${ay.acayr_code || ''})`
2344
- }));
2331
+ getAcademicYearName() {
2332
+ const activeYear = this.appStateService.activeAcademicYear();
2333
+ return activeYear?.acayr_name || activeYear?.acayr_code || '-';
2345
2334
  }
2346
2335
  /**
2347
2336
  * Format currency
@@ -2383,10 +2372,10 @@ class FeeStructureCreateComponent {
2383
2372
  }
2384
2373
  this.breadcrumbData.set(additionalItems);
2385
2374
  }
2386
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeStructureCreateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2387
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: FeeStructureCreateComponent, isStandalone: true, selector: "lib-cide-fee-structure-create", ngImport: i0, template: "<!-- Fee Structure Form -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_structure' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n \n <!-- Back Button in Breadcrumb Area (View Mode Only) -->\n @if (isViewMode()) {\n <div breadcrumb-actions>\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"arrow_back\">\n Back to List\n </button>\n </div>\n }\n \n <div class=\"tw-w-full tw-h-full\">\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"feeStructureForm\" \n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n\n <!-- Tab Navigation -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-2 tw-py-0\">\n <cide-ele-tab [tabs]=\"feeStructureTabs()\" [activeTabId]=\"activeTab()\" size=\"sm\" variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-4 tw-py-4\">\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n @switch (activeTab()) {\n\n @case ('basic') {\n <!-- Basic Information -->\n <div class=\"tw-space-y-4\">\n <!-- First Row: Fee Code (small), Fee Name, Academic Year - Always on one row -->\n <div class=\"tw-grid\" style=\"grid-template-columns: 170px 1fr 1fr; gap: 1rem;\">\n <cide-ele-input label=\"Fee Structure Code\" formControlName=\"fees_structure_code\"\n placeholder=\"Auto-generated by API\" size=\"sm\" [disabled]=\"isEditMode()\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Fee Structure Name\" formControlName=\"fees_structure_name\"\n placeholder=\"e.g., Grade 10 Fee Structure 2024-25\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-select \n label=\"Academic Year\" \n formControlName=\"fees_academic_year_id_acayr\"\n [options]=\"getAcademicYearOptions()\"\n [loading]=\"academicYearLoading()\"\n [disabled]=\"true\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div>\n <cide-ele-textarea label=\"Description\" formControlName=\"fees_structure_description\"\n placeholder=\"Enter detailed description of the fee structure...\"\n rows=\"2\" size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n <!-- Academic Dropdowns - Using Program Section Selector Component -->\n \n <cide-shared-program-section-selector-wrapper\n [formGroup]=\"feeStructureForm\"\n [classProgramControlName]=\"'fees_class_program_id_acacpm'\"\n [branchControlName]=\"'fees_class_program_branch_id_acabrn'\"\n [termControlName]=\"'fees_class_program_term_id_acapt'\"\n [sectionControlName]=\"'fees_program_term_section_id_acapts'\"\n [academicYearId]=\"feeStructureForm.get('fees_academic_year_id_acayr')?.value\"\n [entityId]=\"feeStructureForm.get('fees_entity_id_syen')?.value\"\n [disabled]=\"isViewMode()\"\n [showLabels]=\"true\"\n [gridCols]=\"'tw-grid-cols-1 md:tw-grid-cols-3'\">\n </cide-shared-program-section-selector-wrapper>\n\n <!-- Reservation Category Dropdown -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-4 tw-mt-4\">\n <cide-ele-select \n label=\"Reservation Category\" \n formControlName=\"fees_student_category_id_sygms\"\n [options]=\"studentCategories()\"\n [loading]=\"studentCategoriesLoading()\"\n placeholder=\"Select reservation category\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\n <cide-ele-input formControlName=\"fees_is_active\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Active</span>\n <span class=\"tw-text-xs tw-text-gray-500\">Enable/disable this fee structure</span>\n </div>\n </div>\n </div>\n }\n\n @case ('items') {\n <!-- Fee Items Section -->\n <div class=\"tw-space-y-3\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <div>\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 tw-m-0\">Fee Items</h6>\n <p class=\"tw-text-xs tw-text-gray-500 tw-m-0\">Configure individual fee items for this structure</p>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-text-right\">\n <div class=\"tw-text-xs tw-text-gray-500\">Total Amount</div>\n <div class=\"tw-text-base tw-font-bold tw-text-green-600\">{{ formatCurrency(totalAmount()) }}</div>\n </div>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" leftIcon=\"add\"\n (click)=\"addFeeItem()\">\n Add Fee Item\n </button>\n </div>\n </div>\n\n <div formArrayName=\"fee_items\" class=\"tw-space-y-2 tw-pr-2\">\n @for (item of feeItemsArray.controls; track $index; let itemIndex = $index) {\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm hover:tw-shadow-md tw-transition-shadow tw-p-3\"\n [formGroupName]=\"itemIndex\">\n \n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-bg-blue-100 tw-p-1.5 tw-rounded\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">receipt</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-900\">Item #{{ itemIndex + 1 }}</h6>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1\">\n @if (itemIndex > 0) {\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" \n (click)=\"moveItemUp(itemIndex)\" title=\"Move Up\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_upward</cide-ele-icon>\n </button>\n }\n @if (itemIndex < feeItemsArray.length - 1) {\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" \n (click)=\"moveItemDown(itemIndex)\" title=\"Move Down\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_downward</cide-ele-icon>\n </button>\n }\n <button cideEleButton type=\"button\" variant=\"danger\" size=\"xs\" leftIcon=\"delete\"\n (click)=\"removeFeeItem(itemIndex)\"\n [disabled]=\"feeItemsArray.length === 1\">\n Remove\n </button>\n </div>\n </div>\n\n <!-- Category, Code, Name in one row -->\n <div class=\"tw-grid\" style=\"grid-template-columns: 1fr 170px 1fr; gap: 1rem;\">\n <cide-ele-select \n label=\"Category\" \n formControlName=\"feesi_category_id_sygms\"\n [options]=\"feeCategoriesOptions()\"\n [loading]=\"feeCategoriesLoading()\"\n size=\"sm\"\n placeholder=\"Select Fee Category\">\n </cide-ele-select>\n\n <cide-ele-input \n label=\"Item Code\" \n formControlName=\"feesi_item_code\"\n size=\"sm\"\n placeholder=\"Auto-filled from category\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Item Name\" \n formControlName=\"feesi_item_name\"\n size=\"sm\"\n placeholder=\"Auto-filled from category\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-mt-2\">\n <cide-ele-textarea \n label=\"Description\" \n formControlName=\"feesi_description\"\n rows=\"1\" \n size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n <!-- Amount Section -->\n <div class=\"tw-mt-2\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2\">\n <cide-ele-input \n [label]=\"item.get('feesi_is_amount_editable')?.value ? 'Base Amount (Default)' : 'Amount'\" \n formControlName=\"feesi_amount\"\n type=\"number\"\n size=\"sm\"\n [title]=\"item.get('feesi_is_amount_editable')?.value ? 'Default amount used when applying fee. Can be edited per student if editable.' : 'Fixed fee amount'\">\n </cide-ele-input>\n </div>\n\n <!-- Amount Editable Option -->\n <div class=\"tw-mt-2 tw-p-2 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mb-2\">\n <cide-ele-input formControlName=\"feesi_is_amount_editable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <div class=\"tw-flex-1\">\n <span class=\"tw-text-xs tw-font-semibold tw-text-blue-900\">Allow Amount to be Edited</span>\n <p class=\"tw-text-xs tw-text-blue-700 tw-mt-0.5\">\n Enable this for fees that vary per student (e.g., Transport fee based on distance). \n When applying fees, you'll be asked to enter the amount within the specified range.\n </p>\n </div>\n </div>\n\n <!-- Min/Max Amount Fields (shown when editable is checked) -->\n @if (item.get('feesi_is_amount_editable')?.value) {\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n <cide-ele-input \n label=\"Minimum Amount\" \n formControlName=\"feesi_min_amount\"\n type=\"number\"\n size=\"sm\"\n placeholder=\"No minimum\"\n title=\"Minimum amount allowed when editing (leave empty for no minimum)\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Maximum Amount\" \n formControlName=\"feesi_max_amount\"\n type=\"number\"\n size=\"sm\"\n placeholder=\"No maximum\"\n title=\"Maximum amount allowed when editing (leave empty for no maximum)\">\n </cide-ele-input>\n </div>\n }\n </div>\n </div>\n\n <!-- Additional Options -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-2 tw-mt-2\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_mandatory\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Mandatory</span>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_refundable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Refundable</span>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_installment_allowed\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Installment Allowed</span>\n </div>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n <cide-ele-input \n label=\"Installment Count\" \n formControlName=\"feesi_installment_count\"\n type=\"number\"\n size=\"sm\">\n </cide-ele-input>\n }\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_tax_applicable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Tax Applicable</span>\n </div>\n </div>\n\n @if (item.get('feesi_tax_applicable')?.value) {\n <div class=\"tw-mt-2\">\n <cide-ele-input \n label=\"Tax Percentage\" \n formControlName=\"feesi_tax_percentage\"\n type=\"number\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n }\n\n <!-- Installment Details Table -->\n <div class=\"tw-mt-4 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">schedule</cide-ele-icon>\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n Installment Details ({{ item.get('feesi_installment_count')?.value || 1 }} Installments)\n } @else {\n Payment Details (Single Payment)\n }\n </h6>\n </div>\n </div>\n\n <div formArrayName=\"installments\" class=\"tw-space-y-3\">\n @for (installment of getInstallmentsArray(itemIndex).controls; track $index; let installmentIndex = $index) {\n <div class=\"tw-bg-white tw-rounded tw-border tw-border-gray-300 tw-p-3\"\n [formGroupName]=\"installmentIndex\">\n \n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-bg-blue-100 tw-p-1 tw-rounded\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">payments</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-900\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n Installment #{{ installment.get('installment_number')?.value }}\n } @else {\n Payment Details\n }\n </h6>\n </div>\n <div class=\"tw-text-sm tw-font-medium tw-text-green-600\">\n Amount: {{ formatCurrency(installment.get('installment_amount')?.value || 0) }}\n </div>\n </div>\n\n <!-- Installment Amount Distribution -->\n @if (item.get('feesi_is_installment_allowed')?.value) {\n <div class=\"tw-p-2 tw-bg-yellow-50 tw-rounded tw-border tw-border-yellow-200 tw-mb-2\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-2\">\n <cide-ele-select \n label=\"Distribution Type\" \n formControlName=\"distribution_type\"\n [options]=\"distributionTypeOptions\"\n size=\"sm\">\n </cide-ele-select>\n\n @if (installment.get('distribution_type')?.value === 'PERCENTAGE') {\n <cide-ele-input \n label=\"Percentage (%)\" \n formControlName=\"percentage\"\n type=\"number\"\n size=\"sm\"\n title=\"Percentage of total amount for this installment\">\n </cide-ele-input>\n <div class=\"tw-flex tw-flex-col tw-items-end tw-justify-end tw-gap-1\">\n @if (installmentIndex > 0) {\n <div class=\"tw-text-xs tw-text-blue-600 tw-font-medium\">\n Previous: {{ getPreviousInstallmentsPercentage(itemIndex, installmentIndex) }}%\n </div>\n }\n <div class=\"tw-text-xs tw-text-gray-600\">\n Calculated: {{ formatCurrency((item.get('feesi_amount')?.value || 0) * (installment.get('percentage')?.value || 0) / 100) }}\n </div>\n @if (installmentIndex === getInstallmentsArray(itemIndex).length - 1 && installmentIndex > 0) {\n <div class=\"tw-text-xs tw-font-semibold\" [class.tw-text-green-600]=\"(getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0)) === 100\" [class.tw-text-red-600]=\"(getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0)) !== 100\">\n Total: {{ getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0) }}%\n </div>\n }\n </div>\n }\n\n @if (installment.get('distribution_type')?.value === 'FIXED_AMOUNT') {\n <cide-ele-input \n label=\"Fixed Amount\" \n formControlName=\"fixed_amount\"\n type=\"number\"\n size=\"sm\"\n title=\"Fixed amount for this installment\">\n </cide-ele-input>\n }\n </div>\n </div>\n }\n\n <!-- Due Date Fields -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mb-2\">\n <cide-ele-input \n label=\"Due Date Offset (Days from Assignment)\" \n formControlName=\"due_date_offset_days\"\n type=\"number\"\n size=\"sm\"\n title=\"Days from assignment date\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Due Date (Fixed Date - Alternative)\" \n formControlName=\"due_date\"\n type=\"date\"\n size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n </div>\n\n <!-- Collection Window -->\n <div class=\"tw-p-2 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-1.5 tw-mb-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-3 tw-h-3\">schedule</cide-ele-icon>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-blue-900 tw-m-0\">Collection Window</h6>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2\">\n <cide-ele-input \n label=\"Start Offset (Days from Assignment)\" \n formControlName=\"collection_start_offset_days\"\n type=\"number\"\n size=\"sm\"\n title=\"Days from assignment date when collection can start\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"End Offset (Days from Assignment)\" \n formControlName=\"collection_end_offset_days\"\n type=\"number\"\n size=\"sm\"\n title=\"Days from assignment date when collection window ends\">\n </cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n <cide-ele-input \n label=\"Start Date (Fixed Date - Alternative)\" \n formControlName=\"collection_start_date\"\n type=\"date\"\n size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"End Date (Fixed Date - Alternative)\" \n formControlName=\"collection_end_date\"\n type=\"date\"\n size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (feeItemsArray.length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <div class=\"tw-bg-white tw-p-3 tw-rounded-full tw-w-12 tw-h-12 tw-mx-auto tw-mb-3 tw-flex tw-items-center tw-justify-center\">\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-gray-400\">receipt</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-600 tw-mb-1\">No Fee Items Yet</h6>\n <p class=\"tw-text-xs tw-text-gray-500\">Click \"Add Fee Item\" to start adding fee items to this structure.</p>\n </div>\n }\n </div>\n }\n }\n \n <!-- Form Validation Errors -->\n @if (!isViewMode()) {\n <!-- Form Field Errors -->\n <div class=\"tw-w-full tw-mb-4\">\n <cide-form-field-error [formGroup]=\"feeStructureForm\"></cide-form-field-error>\n </div>\n \n <!-- Action Buttons -->\n <div class=\"tw-flex tw-justify-end tw-gap-3 tw-mt-6\">\n @if (!isEditMode()) {\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n }\n\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"close\"\n [disabled]=\"loading()\">\n Cancel\n </button>\n\n @if (!isInstallmentPercentagesValid()) {\n <div class=\"tw-w-full tw-mb-3 tw-p-2 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded tw-text-sm\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-text-red-700\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">error</cide-ele-icon>\n <span class=\"tw-font-medium\">Validation Error:</span>\n </div>\n <p class=\"tw-text-red-600 tw-mt-1 tw-ml-6\">\n All installment percentages must total exactly 100% before saving. Please adjust the percentages to continue.\n </p>\n </div>\n }\n \n <button cideEleButton type=\"submit\" variant=\"primary\" size=\"sm\" \n [disabled]=\"submitting() || loading() || !isInstallmentPercentagesValid()\" \n [loading]=\"submitting()\" \n leftIcon=\"save\">\n {{ isEditMode() ? 'Update Fee Structure' : 'Create Fee Structure' }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n </form>\n </div>\n</cide-lyt-shared-wrapper>\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideTextareaComponent, selector: "cide-ele-textarea", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "minlength", "maxlength", "rows", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleTabComponent, selector: "cide-ele-tab", inputs: ["tabs", "activeTabId", "size", "variant", "fullWidth", "disabled"], outputs: ["tabChange"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }, { kind: "component", type: ProgramSectionSelectorWrapperComponent, selector: "cide-shared-program-section-selector-wrapper", inputs: ["formGroup", "classProgramControlName", "branchControlName", "termControlName", "sectionControlName", "academicYearId", "entityId", "disabled", "showLabels", "gridCols", "showAllPrograms", "includeInactive"], outputs: ["valuesChange"] }, { kind: "component", type: CideFormFieldErrorComponent, selector: "cide-form-field-error", inputs: ["control", "formGroup", "fieldName", "customMessages"] }] });
2375
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeStructureCreateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2376
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FeeStructureCreateComponent, isStandalone: true, selector: "lib-cide-fee-structure-create", ngImport: i0, template: "<!-- Fee Structure Form -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_structure' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n\n <!-- Back Button in Breadcrumb Area (View Mode Only) -->\n @if (isViewMode()) {\n <div breadcrumb-actions>\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"arrow_back\">\n Back to List\n </button>\n </div>\n }\n\n <div class=\"tw-w-full tw-h-full\">\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"feeStructureForm\"\n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n\n <!-- Tab Navigation -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-2 tw-py-0\">\n <cide-ele-tab [tabs]=\"feeStructureTabs()\" [activeTabId]=\"activeTab()\" size=\"sm\" variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-4 tw-py-4\">\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n @switch (activeTab()) {\n\n @case ('basic') {\n <!-- Basic Information -->\n <div class=\"tw-space-y-4\">\n <!-- First Row: Fee Code (small), Fee Name - Always on one row -->\n <div class=\"tw-grid\" style=\"grid-template-columns: 170px 1fr; gap: 1rem;\">\n <cide-ele-input label=\"Fee Structure Code\" formControlName=\"fees_structure_code\"\n placeholder=\"Auto-generated by API\" size=\"sm\" [disabled]=\"isEditMode()\">\n </cide-ele-input>\n <cide-ele-input label=\"Fee Structure Name\" formControlName=\"fees_structure_name\"\n placeholder=\"e.g., Grade 10 Fee Structure 2024-25\" size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div>\n <cide-ele-textarea label=\"Description\" formControlName=\"fees_structure_description\"\n placeholder=\"Enter detailed description of the fee structure...\" rows=\"2\" size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n <!-- Academic Dropdowns - Using Program Section Selector Component -->\n\n <cide-shared-program-section-selector-wrapper [formGroup]=\"feeStructureForm\"\n [classProgramControlName]=\"'fees_class_program_id_acacpm'\"\n [branchControlName]=\"'fees_class_program_branch_id_acabrn'\"\n [termControlName]=\"'fees_class_program_term_id_acapt'\"\n [sectionControlName]=\"'fees_program_term_section_id_acapts'\"\n [academicYearId]=\"feeStructureForm.get('fees_academic_year_id_acayr')?.value\"\n [entityId]=\"feeStructureForm.get('fees_entity_id_syen')?.value\" [disabled]=\"isViewMode()\"\n [showLabels]=\"true\" [gridCols]=\"'tw-grid-cols-1 md:tw-grid-cols-3'\">\n </cide-shared-program-section-selector-wrapper>\n\n <!-- Reservation Category Dropdown -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-4 tw-mt-4\">\n <cide-ele-select label=\"Reservation Category\" formControlName=\"fees_student_category_id_sygms\"\n [options]=\"studentCategories()\" [loading]=\"studentCategoriesLoading()\"\n placeholder=\"Select reservation category\" size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div\n class=\"tw-flex tw-items-center tw-gap-3 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\n <cide-ele-input formControlName=\"fees_is_active\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Active</span>\n <span class=\"tw-text-xs tw-text-gray-500\">Enable/disable this fee structure</span>\n </div>\n </div>\n </div>\n }\n\n @case ('items') {\n <!-- Fee Items Section -->\n <div class=\"tw-space-y-3\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <div>\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 tw-m-0\">Fee Items</h6>\n <p class=\"tw-text-xs tw-text-gray-500 tw-m-0\">Configure individual fee items for this structure</p>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-text-right\">\n <div class=\"tw-text-xs tw-text-gray-500\">Total Amount</div>\n <div class=\"tw-text-base tw-font-bold tw-text-green-600\">{{ formatCurrency(totalAmount()) }}</div>\n </div>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"addFeeItem()\">\n Add Fee Item\n </button>\n </div>\n </div>\n\n <div formArrayName=\"fee_items\" class=\"tw-space-y-2 tw-pr-2\">\n @for (item of feeItemsArray.controls; track $index; let itemIndex = $index) {\n <div\n class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm hover:tw-shadow-md tw-transition-shadow tw-p-3\"\n [formGroupName]=\"itemIndex\">\n\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-bg-blue-100 tw-p-1.5 tw-rounded\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">receipt</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-900\">Item #{{ itemIndex + 1 }}</h6>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1\">\n @if (itemIndex > 0) {\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"moveItemUp(itemIndex)\"\n title=\"Move Up\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_upward</cide-ele-icon>\n </button>\n }\n @if (itemIndex < feeItemsArray.length - 1) { <button cideEleButton type=\"button\" variant=\"ghost\"\n size=\"xs\" (click)=\"moveItemDown(itemIndex)\" title=\"Move Down\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_downward</cide-ele-icon>\n </button>\n }\n <button cideEleButton type=\"button\" variant=\"danger\" size=\"xs\" leftIcon=\"delete\"\n (click)=\"removeFeeItem(itemIndex)\" [disabled]=\"feeItemsArray.length === 1\">\n Remove\n </button>\n </div>\n </div>\n\n <!-- Category, Code, Name in one row -->\n <div class=\"tw-grid\" style=\"grid-template-columns: 1fr 170px 1fr; gap: 1rem;\">\n <cide-ele-select label=\"Category\" formControlName=\"feesi_category_id_sygms\"\n [options]=\"feeCategoriesOptions()\" [loading]=\"feeCategoriesLoading()\" size=\"sm\"\n placeholder=\"Select Fee Category\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Item Code\" formControlName=\"feesi_item_code\" size=\"sm\"\n placeholder=\"Auto-filled from category\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Item Name\" formControlName=\"feesi_item_name\" size=\"sm\"\n placeholder=\"Auto-filled from category\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-mt-2\">\n <cide-ele-textarea label=\"Description\" formControlName=\"feesi_description\" rows=\"1\" size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n <!-- Amount Section -->\n <div class=\"tw-mt-2\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2\">\n <cide-ele-input\n [label]=\"item.get('feesi_is_amount_editable')?.value ? 'Base Amount (Default)' : 'Amount'\"\n formControlName=\"feesi_amount\" type=\"number\" size=\"sm\"\n [title]=\"item.get('feesi_is_amount_editable')?.value ? 'Default amount used when applying fee. Can be edited per student if editable.' : 'Fixed fee amount'\">\n </cide-ele-input>\n </div>\n\n <!-- Amount Editable Option -->\n <div class=\"tw-mt-2 tw-p-2 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mb-2\">\n <cide-ele-input formControlName=\"feesi_is_amount_editable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <div class=\"tw-flex-1\">\n <span class=\"tw-text-xs tw-font-semibold tw-text-blue-900\">Allow Amount to be Edited</span>\n <p class=\"tw-text-xs tw-text-blue-700 tw-mt-0.5\">\n Enable this for fees that vary per student (e.g., Transport fee based on distance).\n When applying fees, you'll be asked to enter the amount within the specified range.\n </p>\n </div>\n </div>\n\n <!-- Min/Max Amount Fields (shown when editable is checked) -->\n @if (item.get('feesi_is_amount_editable')?.value) {\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n <cide-ele-input label=\"Minimum Amount\" formControlName=\"feesi_min_amount\" type=\"number\"\n size=\"sm\" placeholder=\"No minimum\"\n title=\"Minimum amount allowed when editing (leave empty for no minimum)\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Maximum Amount\" formControlName=\"feesi_max_amount\" type=\"number\"\n size=\"sm\" placeholder=\"No maximum\"\n title=\"Maximum amount allowed when editing (leave empty for no maximum)\">\n </cide-ele-input>\n </div>\n }\n </div>\n </div>\n\n <!-- Additional Options -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-2 tw-mt-2\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_mandatory\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Mandatory</span>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_refundable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Refundable</span>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_installment_allowed\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Installment Allowed</span>\n </div>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n <cide-ele-input label=\"Installment Count\" formControlName=\"feesi_installment_count\" type=\"number\"\n size=\"sm\">\n </cide-ele-input>\n }\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_tax_applicable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Tax Applicable</span>\n </div>\n </div>\n\n @if (item.get('feesi_tax_applicable')?.value) {\n <div class=\"tw-mt-2\">\n <cide-ele-input label=\"Tax Percentage\" formControlName=\"feesi_tax_percentage\" type=\"number\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n }\n\n <!-- Installment Details Table -->\n <div class=\"tw-mt-4 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">schedule</cide-ele-icon>\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n Installment Details ({{ item.get('feesi_installment_count')?.value || 1 }} Installments)\n } @else {\n Payment Details (Single Payment)\n }\n </h6>\n </div>\n </div>\n\n <div formArrayName=\"installments\" class=\"tw-space-y-3\">\n @for (installment of getInstallmentsArray(itemIndex).controls; track $index; let installmentIndex\n = $index) {\n <div class=\"tw-bg-white tw-rounded tw-border tw-border-gray-300 tw-p-3\"\n [formGroupName]=\"installmentIndex\">\n\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-bg-blue-100 tw-p-1 tw-rounded\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">payments</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-900\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n Installment #{{ installment.get('installment_number')?.value }}\n } @else {\n Payment Details\n }\n </h6>\n </div>\n <div class=\"tw-text-sm tw-font-medium tw-text-green-600\">\n Amount: {{ formatCurrency(installment.get('installment_amount')?.value || 0) }}\n </div>\n </div>\n\n <!-- Installment Amount Distribution -->\n @if (item.get('feesi_is_installment_allowed')?.value) {\n <div class=\"tw-p-2 tw-bg-yellow-50 tw-rounded tw-border tw-border-yellow-200 tw-mb-2\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-2\">\n <cide-ele-select label=\"Distribution Type\" formControlName=\"distribution_type\"\n [options]=\"distributionTypeOptions\" size=\"sm\">\n </cide-ele-select>\n\n @if (installment.get('distribution_type')?.value === 'PERCENTAGE') {\n <cide-ele-input label=\"Percentage (%)\" formControlName=\"percentage\" type=\"number\" size=\"sm\"\n title=\"Percentage of total amount for this installment\">\n </cide-ele-input>\n <div class=\"tw-flex tw-flex-col tw-items-end tw-justify-end tw-gap-1\">\n @if (installmentIndex > 0) {\n <div class=\"tw-text-xs tw-text-blue-600 tw-font-medium\">\n Previous: {{ getPreviousInstallmentsPercentage(itemIndex, installmentIndex) }}%\n </div>\n }\n <div class=\"tw-text-xs tw-text-gray-600\">\n Calculated: {{ formatCurrency((item.get('feesi_amount')?.value || 0) *\n (installment.get('percentage')?.value || 0) / 100) }}\n </div>\n @if (installmentIndex === getInstallmentsArray(itemIndex).length - 1 && installmentIndex >\n 0) {\n <div class=\"tw-text-xs tw-font-semibold\"\n [class.tw-text-green-600]=\"(getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0)) === 100\"\n [class.tw-text-red-600]=\"(getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0)) !== 100\">\n Total: {{ getPreviousInstallmentsPercentage(itemIndex, installmentIndex) +\n (installment.get('percentage')?.value || 0) }}%\n </div>\n }\n </div>\n }\n\n @if (installment.get('distribution_type')?.value === 'FIXED_AMOUNT') {\n <cide-ele-input label=\"Fixed Amount\" formControlName=\"fixed_amount\" type=\"number\" size=\"sm\"\n title=\"Fixed amount for this installment\">\n </cide-ele-input>\n }\n </div>\n </div>\n }\n\n <!-- Due Date Fields -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mb-2\">\n <cide-ele-input label=\"Due Date Offset (Days from Assignment)\"\n formControlName=\"due_date_offset_days\" type=\"number\" size=\"sm\"\n title=\"Days from assignment date\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Due Date (Fixed Date - Alternative)\" formControlName=\"due_date\"\n type=\"date\" size=\"sm\" title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n </div>\n\n <!-- Collection Window -->\n <div class=\"tw-p-2 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-1.5 tw-mb-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-3 tw-h-3\">schedule</cide-ele-icon>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-blue-900 tw-m-0\">Collection Window</h6>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2\">\n <cide-ele-input label=\"Start Offset (Days from Assignment)\"\n formControlName=\"collection_start_offset_days\" type=\"number\" size=\"sm\"\n title=\"Days from assignment date when collection can start\">\n </cide-ele-input>\n\n <cide-ele-input label=\"End Offset (Days from Assignment)\"\n formControlName=\"collection_end_offset_days\" type=\"number\" size=\"sm\"\n title=\"Days from assignment date when collection window ends\">\n </cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n <cide-ele-input label=\"Start Date (Fixed Date - Alternative)\"\n formControlName=\"collection_start_date\" type=\"date\" size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n\n <cide-ele-input label=\"End Date (Fixed Date - Alternative)\"\n formControlName=\"collection_end_date\" type=\"date\" size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (feeItemsArray.length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <div\n class=\"tw-bg-white tw-p-3 tw-rounded-full tw-w-12 tw-h-12 tw-mx-auto tw-mb-3 tw-flex tw-items-center tw-justify-center\">\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-gray-400\">receipt</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-600 tw-mb-1\">No Fee Items Yet</h6>\n <p class=\"tw-text-xs tw-text-gray-500\">Click \"Add Fee Item\" to start adding fee items to this structure.\n </p>\n </div>\n }\n </div>\n }\n }\n\n <!-- Form Validation Errors -->\n @if (!isViewMode()) {\n <!-- Form Field Errors -->\n <div class=\"tw-w-full tw-mb-4\">\n <cide-form-field-error [formGroup]=\"feeStructureForm\"></cide-form-field-error>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"tw-flex tw-justify-end tw-gap-3 tw-mt-6\">\n @if (!isEditMode()) {\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n }\n\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"close\"\n [disabled]=\"loading()\">\n Cancel\n </button>\n\n @if (!isInstallmentPercentagesValid()) {\n <div class=\"tw-w-full tw-mb-3 tw-p-2 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded tw-text-sm\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-text-red-700\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">error</cide-ele-icon>\n <span class=\"tw-font-medium\">Validation Error:</span>\n </div>\n <p class=\"tw-text-red-600 tw-mt-1 tw-ml-6\">\n All installment percentages must total exactly 100% before saving. Please adjust the percentages to\n continue.\n </p>\n </div>\n }\n\n <button cideEleButton type=\"submit\" variant=\"primary\" size=\"sm\"\n [disabled]=\"submitting() || loading() || !isInstallmentPercentagesValid()\" [loading]=\"submitting()\"\n leftIcon=\"save\">\n {{ isEditMode() ? 'Update Fee Structure' : 'Create Fee Structure' }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n </form>\n </div>\n</cide-lyt-shared-wrapper>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideTextareaComponent, selector: "cide-ele-textarea", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "minlength", "maxlength", "rows", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleTabComponent, selector: "cide-ele-tab", inputs: ["tabs", "activeTabId", "size", "variant", "fullWidth", "disabled"], outputs: ["tabChange"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }, { kind: "component", type: ProgramSectionSelectorWrapperComponent, selector: "cide-shared-program-section-selector-wrapper", inputs: ["formGroup", "classProgramControlName", "branchControlName", "termControlName", "sectionControlName", "academicYearId", "entityId", "disabled", "showLabels", "gridCols", "showAllPrograms", "includeInactive"], outputs: ["valuesChange"] }, { kind: "component", type: CideFormFieldErrorComponent, selector: "cide-form-field-error", inputs: ["control", "formGroup", "fieldName", "customMessages"] }] });
2388
2377
  }
2389
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeStructureCreateComponent, decorators: [{
2378
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeStructureCreateComponent, decorators: [{
2390
2379
  type: Component,
2391
2380
  args: [{ selector: 'lib-cide-fee-structure-create', standalone: true, imports: [
2392
2381
  CommonModule,
@@ -2400,7 +2389,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
2400
2389
  CideLytSharedWrapperComponent,
2401
2390
  ProgramSectionSelectorWrapperComponent,
2402
2391
  CideFormFieldErrorComponent
2403
- ], template: "<!-- Fee Structure Form -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_structure' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n \n <!-- Back Button in Breadcrumb Area (View Mode Only) -->\n @if (isViewMode()) {\n <div breadcrumb-actions>\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"arrow_back\">\n Back to List\n </button>\n </div>\n }\n \n <div class=\"tw-w-full tw-h-full\">\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"feeStructureForm\" \n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n\n <!-- Tab Navigation -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-2 tw-py-0\">\n <cide-ele-tab [tabs]=\"feeStructureTabs()\" [activeTabId]=\"activeTab()\" size=\"sm\" variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-4 tw-py-4\">\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n @switch (activeTab()) {\n\n @case ('basic') {\n <!-- Basic Information -->\n <div class=\"tw-space-y-4\">\n <!-- First Row: Fee Code (small), Fee Name, Academic Year - Always on one row -->\n <div class=\"tw-grid\" style=\"grid-template-columns: 170px 1fr 1fr; gap: 1rem;\">\n <cide-ele-input label=\"Fee Structure Code\" formControlName=\"fees_structure_code\"\n placeholder=\"Auto-generated by API\" size=\"sm\" [disabled]=\"isEditMode()\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Fee Structure Name\" formControlName=\"fees_structure_name\"\n placeholder=\"e.g., Grade 10 Fee Structure 2024-25\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-select \n label=\"Academic Year\" \n formControlName=\"fees_academic_year_id_acayr\"\n [options]=\"getAcademicYearOptions()\"\n [loading]=\"academicYearLoading()\"\n [disabled]=\"true\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div>\n <cide-ele-textarea label=\"Description\" formControlName=\"fees_structure_description\"\n placeholder=\"Enter detailed description of the fee structure...\"\n rows=\"2\" size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n <!-- Academic Dropdowns - Using Program Section Selector Component -->\n \n <cide-shared-program-section-selector-wrapper\n [formGroup]=\"feeStructureForm\"\n [classProgramControlName]=\"'fees_class_program_id_acacpm'\"\n [branchControlName]=\"'fees_class_program_branch_id_acabrn'\"\n [termControlName]=\"'fees_class_program_term_id_acapt'\"\n [sectionControlName]=\"'fees_program_term_section_id_acapts'\"\n [academicYearId]=\"feeStructureForm.get('fees_academic_year_id_acayr')?.value\"\n [entityId]=\"feeStructureForm.get('fees_entity_id_syen')?.value\"\n [disabled]=\"isViewMode()\"\n [showLabels]=\"true\"\n [gridCols]=\"'tw-grid-cols-1 md:tw-grid-cols-3'\">\n </cide-shared-program-section-selector-wrapper>\n\n <!-- Reservation Category Dropdown -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-4 tw-mt-4\">\n <cide-ele-select \n label=\"Reservation Category\" \n formControlName=\"fees_student_category_id_sygms\"\n [options]=\"studentCategories()\"\n [loading]=\"studentCategoriesLoading()\"\n placeholder=\"Select reservation category\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\n <cide-ele-input formControlName=\"fees_is_active\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Active</span>\n <span class=\"tw-text-xs tw-text-gray-500\">Enable/disable this fee structure</span>\n </div>\n </div>\n </div>\n }\n\n @case ('items') {\n <!-- Fee Items Section -->\n <div class=\"tw-space-y-3\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <div>\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 tw-m-0\">Fee Items</h6>\n <p class=\"tw-text-xs tw-text-gray-500 tw-m-0\">Configure individual fee items for this structure</p>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-text-right\">\n <div class=\"tw-text-xs tw-text-gray-500\">Total Amount</div>\n <div class=\"tw-text-base tw-font-bold tw-text-green-600\">{{ formatCurrency(totalAmount()) }}</div>\n </div>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" leftIcon=\"add\"\n (click)=\"addFeeItem()\">\n Add Fee Item\n </button>\n </div>\n </div>\n\n <div formArrayName=\"fee_items\" class=\"tw-space-y-2 tw-pr-2\">\n @for (item of feeItemsArray.controls; track $index; let itemIndex = $index) {\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm hover:tw-shadow-md tw-transition-shadow tw-p-3\"\n [formGroupName]=\"itemIndex\">\n \n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-bg-blue-100 tw-p-1.5 tw-rounded\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">receipt</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-900\">Item #{{ itemIndex + 1 }}</h6>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1\">\n @if (itemIndex > 0) {\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" \n (click)=\"moveItemUp(itemIndex)\" title=\"Move Up\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_upward</cide-ele-icon>\n </button>\n }\n @if (itemIndex < feeItemsArray.length - 1) {\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" \n (click)=\"moveItemDown(itemIndex)\" title=\"Move Down\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_downward</cide-ele-icon>\n </button>\n }\n <button cideEleButton type=\"button\" variant=\"danger\" size=\"xs\" leftIcon=\"delete\"\n (click)=\"removeFeeItem(itemIndex)\"\n [disabled]=\"feeItemsArray.length === 1\">\n Remove\n </button>\n </div>\n </div>\n\n <!-- Category, Code, Name in one row -->\n <div class=\"tw-grid\" style=\"grid-template-columns: 1fr 170px 1fr; gap: 1rem;\">\n <cide-ele-select \n label=\"Category\" \n formControlName=\"feesi_category_id_sygms\"\n [options]=\"feeCategoriesOptions()\"\n [loading]=\"feeCategoriesLoading()\"\n size=\"sm\"\n placeholder=\"Select Fee Category\">\n </cide-ele-select>\n\n <cide-ele-input \n label=\"Item Code\" \n formControlName=\"feesi_item_code\"\n size=\"sm\"\n placeholder=\"Auto-filled from category\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Item Name\" \n formControlName=\"feesi_item_name\"\n size=\"sm\"\n placeholder=\"Auto-filled from category\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-mt-2\">\n <cide-ele-textarea \n label=\"Description\" \n formControlName=\"feesi_description\"\n rows=\"1\" \n size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n <!-- Amount Section -->\n <div class=\"tw-mt-2\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2\">\n <cide-ele-input \n [label]=\"item.get('feesi_is_amount_editable')?.value ? 'Base Amount (Default)' : 'Amount'\" \n formControlName=\"feesi_amount\"\n type=\"number\"\n size=\"sm\"\n [title]=\"item.get('feesi_is_amount_editable')?.value ? 'Default amount used when applying fee. Can be edited per student if editable.' : 'Fixed fee amount'\">\n </cide-ele-input>\n </div>\n\n <!-- Amount Editable Option -->\n <div class=\"tw-mt-2 tw-p-2 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mb-2\">\n <cide-ele-input formControlName=\"feesi_is_amount_editable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <div class=\"tw-flex-1\">\n <span class=\"tw-text-xs tw-font-semibold tw-text-blue-900\">Allow Amount to be Edited</span>\n <p class=\"tw-text-xs tw-text-blue-700 tw-mt-0.5\">\n Enable this for fees that vary per student (e.g., Transport fee based on distance). \n When applying fees, you'll be asked to enter the amount within the specified range.\n </p>\n </div>\n </div>\n\n <!-- Min/Max Amount Fields (shown when editable is checked) -->\n @if (item.get('feesi_is_amount_editable')?.value) {\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n <cide-ele-input \n label=\"Minimum Amount\" \n formControlName=\"feesi_min_amount\"\n type=\"number\"\n size=\"sm\"\n placeholder=\"No minimum\"\n title=\"Minimum amount allowed when editing (leave empty for no minimum)\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Maximum Amount\" \n formControlName=\"feesi_max_amount\"\n type=\"number\"\n size=\"sm\"\n placeholder=\"No maximum\"\n title=\"Maximum amount allowed when editing (leave empty for no maximum)\">\n </cide-ele-input>\n </div>\n }\n </div>\n </div>\n\n <!-- Additional Options -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-2 tw-mt-2\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_mandatory\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Mandatory</span>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_refundable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Refundable</span>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_installment_allowed\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Installment Allowed</span>\n </div>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n <cide-ele-input \n label=\"Installment Count\" \n formControlName=\"feesi_installment_count\"\n type=\"number\"\n size=\"sm\">\n </cide-ele-input>\n }\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_tax_applicable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Tax Applicable</span>\n </div>\n </div>\n\n @if (item.get('feesi_tax_applicable')?.value) {\n <div class=\"tw-mt-2\">\n <cide-ele-input \n label=\"Tax Percentage\" \n formControlName=\"feesi_tax_percentage\"\n type=\"number\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n }\n\n <!-- Installment Details Table -->\n <div class=\"tw-mt-4 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">schedule</cide-ele-icon>\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n Installment Details ({{ item.get('feesi_installment_count')?.value || 1 }} Installments)\n } @else {\n Payment Details (Single Payment)\n }\n </h6>\n </div>\n </div>\n\n <div formArrayName=\"installments\" class=\"tw-space-y-3\">\n @for (installment of getInstallmentsArray(itemIndex).controls; track $index; let installmentIndex = $index) {\n <div class=\"tw-bg-white tw-rounded tw-border tw-border-gray-300 tw-p-3\"\n [formGroupName]=\"installmentIndex\">\n \n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-bg-blue-100 tw-p-1 tw-rounded\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">payments</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-900\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n Installment #{{ installment.get('installment_number')?.value }}\n } @else {\n Payment Details\n }\n </h6>\n </div>\n <div class=\"tw-text-sm tw-font-medium tw-text-green-600\">\n Amount: {{ formatCurrency(installment.get('installment_amount')?.value || 0) }}\n </div>\n </div>\n\n <!-- Installment Amount Distribution -->\n @if (item.get('feesi_is_installment_allowed')?.value) {\n <div class=\"tw-p-2 tw-bg-yellow-50 tw-rounded tw-border tw-border-yellow-200 tw-mb-2\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-2\">\n <cide-ele-select \n label=\"Distribution Type\" \n formControlName=\"distribution_type\"\n [options]=\"distributionTypeOptions\"\n size=\"sm\">\n </cide-ele-select>\n\n @if (installment.get('distribution_type')?.value === 'PERCENTAGE') {\n <cide-ele-input \n label=\"Percentage (%)\" \n formControlName=\"percentage\"\n type=\"number\"\n size=\"sm\"\n title=\"Percentage of total amount for this installment\">\n </cide-ele-input>\n <div class=\"tw-flex tw-flex-col tw-items-end tw-justify-end tw-gap-1\">\n @if (installmentIndex > 0) {\n <div class=\"tw-text-xs tw-text-blue-600 tw-font-medium\">\n Previous: {{ getPreviousInstallmentsPercentage(itemIndex, installmentIndex) }}%\n </div>\n }\n <div class=\"tw-text-xs tw-text-gray-600\">\n Calculated: {{ formatCurrency((item.get('feesi_amount')?.value || 0) * (installment.get('percentage')?.value || 0) / 100) }}\n </div>\n @if (installmentIndex === getInstallmentsArray(itemIndex).length - 1 && installmentIndex > 0) {\n <div class=\"tw-text-xs tw-font-semibold\" [class.tw-text-green-600]=\"(getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0)) === 100\" [class.tw-text-red-600]=\"(getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0)) !== 100\">\n Total: {{ getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0) }}%\n </div>\n }\n </div>\n }\n\n @if (installment.get('distribution_type')?.value === 'FIXED_AMOUNT') {\n <cide-ele-input \n label=\"Fixed Amount\" \n formControlName=\"fixed_amount\"\n type=\"number\"\n size=\"sm\"\n title=\"Fixed amount for this installment\">\n </cide-ele-input>\n }\n </div>\n </div>\n }\n\n <!-- Due Date Fields -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mb-2\">\n <cide-ele-input \n label=\"Due Date Offset (Days from Assignment)\" \n formControlName=\"due_date_offset_days\"\n type=\"number\"\n size=\"sm\"\n title=\"Days from assignment date\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Due Date (Fixed Date - Alternative)\" \n formControlName=\"due_date\"\n type=\"date\"\n size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n </div>\n\n <!-- Collection Window -->\n <div class=\"tw-p-2 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-1.5 tw-mb-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-3 tw-h-3\">schedule</cide-ele-icon>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-blue-900 tw-m-0\">Collection Window</h6>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2\">\n <cide-ele-input \n label=\"Start Offset (Days from Assignment)\" \n formControlName=\"collection_start_offset_days\"\n type=\"number\"\n size=\"sm\"\n title=\"Days from assignment date when collection can start\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"End Offset (Days from Assignment)\" \n formControlName=\"collection_end_offset_days\"\n type=\"number\"\n size=\"sm\"\n title=\"Days from assignment date when collection window ends\">\n </cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n <cide-ele-input \n label=\"Start Date (Fixed Date - Alternative)\" \n formControlName=\"collection_start_date\"\n type=\"date\"\n size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"End Date (Fixed Date - Alternative)\" \n formControlName=\"collection_end_date\"\n type=\"date\"\n size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (feeItemsArray.length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <div class=\"tw-bg-white tw-p-3 tw-rounded-full tw-w-12 tw-h-12 tw-mx-auto tw-mb-3 tw-flex tw-items-center tw-justify-center\">\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-gray-400\">receipt</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-600 tw-mb-1\">No Fee Items Yet</h6>\n <p class=\"tw-text-xs tw-text-gray-500\">Click \"Add Fee Item\" to start adding fee items to this structure.</p>\n </div>\n }\n </div>\n }\n }\n \n <!-- Form Validation Errors -->\n @if (!isViewMode()) {\n <!-- Form Field Errors -->\n <div class=\"tw-w-full tw-mb-4\">\n <cide-form-field-error [formGroup]=\"feeStructureForm\"></cide-form-field-error>\n </div>\n \n <!-- Action Buttons -->\n <div class=\"tw-flex tw-justify-end tw-gap-3 tw-mt-6\">\n @if (!isEditMode()) {\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n }\n\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"close\"\n [disabled]=\"loading()\">\n Cancel\n </button>\n\n @if (!isInstallmentPercentagesValid()) {\n <div class=\"tw-w-full tw-mb-3 tw-p-2 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded tw-text-sm\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-text-red-700\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">error</cide-ele-icon>\n <span class=\"tw-font-medium\">Validation Error:</span>\n </div>\n <p class=\"tw-text-red-600 tw-mt-1 tw-ml-6\">\n All installment percentages must total exactly 100% before saving. Please adjust the percentages to continue.\n </p>\n </div>\n }\n \n <button cideEleButton type=\"submit\" variant=\"primary\" size=\"sm\" \n [disabled]=\"submitting() || loading() || !isInstallmentPercentagesValid()\" \n [loading]=\"submitting()\" \n leftIcon=\"save\">\n {{ isEditMode() ? 'Update Fee Structure' : 'Create Fee Structure' }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n </form>\n </div>\n</cide-lyt-shared-wrapper>\n\n" }]
2392
+ ], template: "<!-- Fee Structure Form -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_structure' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n\n <!-- Back Button in Breadcrumb Area (View Mode Only) -->\n @if (isViewMode()) {\n <div breadcrumb-actions>\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"arrow_back\">\n Back to List\n </button>\n </div>\n }\n\n <div class=\"tw-w-full tw-h-full\">\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"feeStructureForm\"\n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n\n <!-- Tab Navigation -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-2 tw-py-0\">\n <cide-ele-tab [tabs]=\"feeStructureTabs()\" [activeTabId]=\"activeTab()\" size=\"sm\" variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-4 tw-py-4\">\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n @switch (activeTab()) {\n\n @case ('basic') {\n <!-- Basic Information -->\n <div class=\"tw-space-y-4\">\n <!-- First Row: Fee Code (small), Fee Name - Always on one row -->\n <div class=\"tw-grid\" style=\"grid-template-columns: 170px 1fr; gap: 1rem;\">\n <cide-ele-input label=\"Fee Structure Code\" formControlName=\"fees_structure_code\"\n placeholder=\"Auto-generated by API\" size=\"sm\" [disabled]=\"isEditMode()\">\n </cide-ele-input>\n <cide-ele-input label=\"Fee Structure Name\" formControlName=\"fees_structure_name\"\n placeholder=\"e.g., Grade 10 Fee Structure 2024-25\" size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div>\n <cide-ele-textarea label=\"Description\" formControlName=\"fees_structure_description\"\n placeholder=\"Enter detailed description of the fee structure...\" rows=\"2\" size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n <!-- Academic Dropdowns - Using Program Section Selector Component -->\n\n <cide-shared-program-section-selector-wrapper [formGroup]=\"feeStructureForm\"\n [classProgramControlName]=\"'fees_class_program_id_acacpm'\"\n [branchControlName]=\"'fees_class_program_branch_id_acabrn'\"\n [termControlName]=\"'fees_class_program_term_id_acapt'\"\n [sectionControlName]=\"'fees_program_term_section_id_acapts'\"\n [academicYearId]=\"feeStructureForm.get('fees_academic_year_id_acayr')?.value\"\n [entityId]=\"feeStructureForm.get('fees_entity_id_syen')?.value\" [disabled]=\"isViewMode()\"\n [showLabels]=\"true\" [gridCols]=\"'tw-grid-cols-1 md:tw-grid-cols-3'\">\n </cide-shared-program-section-selector-wrapper>\n\n <!-- Reservation Category Dropdown -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-4 tw-mt-4\">\n <cide-ele-select label=\"Reservation Category\" formControlName=\"fees_student_category_id_sygms\"\n [options]=\"studentCategories()\" [loading]=\"studentCategoriesLoading()\"\n placeholder=\"Select reservation category\" size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div\n class=\"tw-flex tw-items-center tw-gap-3 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\n <cide-ele-input formControlName=\"fees_is_active\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Active</span>\n <span class=\"tw-text-xs tw-text-gray-500\">Enable/disable this fee structure</span>\n </div>\n </div>\n </div>\n }\n\n @case ('items') {\n <!-- Fee Items Section -->\n <div class=\"tw-space-y-3\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <div>\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 tw-m-0\">Fee Items</h6>\n <p class=\"tw-text-xs tw-text-gray-500 tw-m-0\">Configure individual fee items for this structure</p>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-text-right\">\n <div class=\"tw-text-xs tw-text-gray-500\">Total Amount</div>\n <div class=\"tw-text-base tw-font-bold tw-text-green-600\">{{ formatCurrency(totalAmount()) }}</div>\n </div>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"addFeeItem()\">\n Add Fee Item\n </button>\n </div>\n </div>\n\n <div formArrayName=\"fee_items\" class=\"tw-space-y-2 tw-pr-2\">\n @for (item of feeItemsArray.controls; track $index; let itemIndex = $index) {\n <div\n class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm hover:tw-shadow-md tw-transition-shadow tw-p-3\"\n [formGroupName]=\"itemIndex\">\n\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-bg-blue-100 tw-p-1.5 tw-rounded\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">receipt</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-900\">Item #{{ itemIndex + 1 }}</h6>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1\">\n @if (itemIndex > 0) {\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"moveItemUp(itemIndex)\"\n title=\"Move Up\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_upward</cide-ele-icon>\n </button>\n }\n @if (itemIndex < feeItemsArray.length - 1) { <button cideEleButton type=\"button\" variant=\"ghost\"\n size=\"xs\" (click)=\"moveItemDown(itemIndex)\" title=\"Move Down\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_downward</cide-ele-icon>\n </button>\n }\n <button cideEleButton type=\"button\" variant=\"danger\" size=\"xs\" leftIcon=\"delete\"\n (click)=\"removeFeeItem(itemIndex)\" [disabled]=\"feeItemsArray.length === 1\">\n Remove\n </button>\n </div>\n </div>\n\n <!-- Category, Code, Name in one row -->\n <div class=\"tw-grid\" style=\"grid-template-columns: 1fr 170px 1fr; gap: 1rem;\">\n <cide-ele-select label=\"Category\" formControlName=\"feesi_category_id_sygms\"\n [options]=\"feeCategoriesOptions()\" [loading]=\"feeCategoriesLoading()\" size=\"sm\"\n placeholder=\"Select Fee Category\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Item Code\" formControlName=\"feesi_item_code\" size=\"sm\"\n placeholder=\"Auto-filled from category\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Item Name\" formControlName=\"feesi_item_name\" size=\"sm\"\n placeholder=\"Auto-filled from category\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-mt-2\">\n <cide-ele-textarea label=\"Description\" formControlName=\"feesi_description\" rows=\"1\" size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n <!-- Amount Section -->\n <div class=\"tw-mt-2\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2\">\n <cide-ele-input\n [label]=\"item.get('feesi_is_amount_editable')?.value ? 'Base Amount (Default)' : 'Amount'\"\n formControlName=\"feesi_amount\" type=\"number\" size=\"sm\"\n [title]=\"item.get('feesi_is_amount_editable')?.value ? 'Default amount used when applying fee. Can be edited per student if editable.' : 'Fixed fee amount'\">\n </cide-ele-input>\n </div>\n\n <!-- Amount Editable Option -->\n <div class=\"tw-mt-2 tw-p-2 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mb-2\">\n <cide-ele-input formControlName=\"feesi_is_amount_editable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <div class=\"tw-flex-1\">\n <span class=\"tw-text-xs tw-font-semibold tw-text-blue-900\">Allow Amount to be Edited</span>\n <p class=\"tw-text-xs tw-text-blue-700 tw-mt-0.5\">\n Enable this for fees that vary per student (e.g., Transport fee based on distance).\n When applying fees, you'll be asked to enter the amount within the specified range.\n </p>\n </div>\n </div>\n\n <!-- Min/Max Amount Fields (shown when editable is checked) -->\n @if (item.get('feesi_is_amount_editable')?.value) {\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n <cide-ele-input label=\"Minimum Amount\" formControlName=\"feesi_min_amount\" type=\"number\"\n size=\"sm\" placeholder=\"No minimum\"\n title=\"Minimum amount allowed when editing (leave empty for no minimum)\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Maximum Amount\" formControlName=\"feesi_max_amount\" type=\"number\"\n size=\"sm\" placeholder=\"No maximum\"\n title=\"Maximum amount allowed when editing (leave empty for no maximum)\">\n </cide-ele-input>\n </div>\n }\n </div>\n </div>\n\n <!-- Additional Options -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-2 tw-mt-2\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_mandatory\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Mandatory</span>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_refundable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Refundable</span>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_is_installment_allowed\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Installment Allowed</span>\n </div>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n <cide-ele-input label=\"Installment Count\" formControlName=\"feesi_installment_count\" type=\"number\"\n size=\"sm\">\n </cide-ele-input>\n }\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"feesi_tax_applicable\" type=\"checkbox\" size=\"sm\">\n </cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Tax Applicable</span>\n </div>\n </div>\n\n @if (item.get('feesi_tax_applicable')?.value) {\n <div class=\"tw-mt-2\">\n <cide-ele-input label=\"Tax Percentage\" formControlName=\"feesi_tax_percentage\" type=\"number\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n }\n\n <!-- Installment Details Table -->\n <div class=\"tw-mt-4 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">schedule</cide-ele-icon>\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n Installment Details ({{ item.get('feesi_installment_count')?.value || 1 }} Installments)\n } @else {\n Payment Details (Single Payment)\n }\n </h6>\n </div>\n </div>\n\n <div formArrayName=\"installments\" class=\"tw-space-y-3\">\n @for (installment of getInstallmentsArray(itemIndex).controls; track $index; let installmentIndex\n = $index) {\n <div class=\"tw-bg-white tw-rounded tw-border tw-border-gray-300 tw-p-3\"\n [formGroupName]=\"installmentIndex\">\n\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-bg-blue-100 tw-p-1 tw-rounded\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">payments</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-900\">\n @if (item.get('feesi_is_installment_allowed')?.value) {\n Installment #{{ installment.get('installment_number')?.value }}\n } @else {\n Payment Details\n }\n </h6>\n </div>\n <div class=\"tw-text-sm tw-font-medium tw-text-green-600\">\n Amount: {{ formatCurrency(installment.get('installment_amount')?.value || 0) }}\n </div>\n </div>\n\n <!-- Installment Amount Distribution -->\n @if (item.get('feesi_is_installment_allowed')?.value) {\n <div class=\"tw-p-2 tw-bg-yellow-50 tw-rounded tw-border tw-border-yellow-200 tw-mb-2\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-2\">\n <cide-ele-select label=\"Distribution Type\" formControlName=\"distribution_type\"\n [options]=\"distributionTypeOptions\" size=\"sm\">\n </cide-ele-select>\n\n @if (installment.get('distribution_type')?.value === 'PERCENTAGE') {\n <cide-ele-input label=\"Percentage (%)\" formControlName=\"percentage\" type=\"number\" size=\"sm\"\n title=\"Percentage of total amount for this installment\">\n </cide-ele-input>\n <div class=\"tw-flex tw-flex-col tw-items-end tw-justify-end tw-gap-1\">\n @if (installmentIndex > 0) {\n <div class=\"tw-text-xs tw-text-blue-600 tw-font-medium\">\n Previous: {{ getPreviousInstallmentsPercentage(itemIndex, installmentIndex) }}%\n </div>\n }\n <div class=\"tw-text-xs tw-text-gray-600\">\n Calculated: {{ formatCurrency((item.get('feesi_amount')?.value || 0) *\n (installment.get('percentage')?.value || 0) / 100) }}\n </div>\n @if (installmentIndex === getInstallmentsArray(itemIndex).length - 1 && installmentIndex >\n 0) {\n <div class=\"tw-text-xs tw-font-semibold\"\n [class.tw-text-green-600]=\"(getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0)) === 100\"\n [class.tw-text-red-600]=\"(getPreviousInstallmentsPercentage(itemIndex, installmentIndex) + (installment.get('percentage')?.value || 0)) !== 100\">\n Total: {{ getPreviousInstallmentsPercentage(itemIndex, installmentIndex) +\n (installment.get('percentage')?.value || 0) }}%\n </div>\n }\n </div>\n }\n\n @if (installment.get('distribution_type')?.value === 'FIXED_AMOUNT') {\n <cide-ele-input label=\"Fixed Amount\" formControlName=\"fixed_amount\" type=\"number\" size=\"sm\"\n title=\"Fixed amount for this installment\">\n </cide-ele-input>\n }\n </div>\n </div>\n }\n\n <!-- Due Date Fields -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mb-2\">\n <cide-ele-input label=\"Due Date Offset (Days from Assignment)\"\n formControlName=\"due_date_offset_days\" type=\"number\" size=\"sm\"\n title=\"Days from assignment date\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Due Date (Fixed Date - Alternative)\" formControlName=\"due_date\"\n type=\"date\" size=\"sm\" title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n </div>\n\n <!-- Collection Window -->\n <div class=\"tw-p-2 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-1.5 tw-mb-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-3 tw-h-3\">schedule</cide-ele-icon>\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-blue-900 tw-m-0\">Collection Window</h6>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2\">\n <cide-ele-input label=\"Start Offset (Days from Assignment)\"\n formControlName=\"collection_start_offset_days\" type=\"number\" size=\"sm\"\n title=\"Days from assignment date when collection can start\">\n </cide-ele-input>\n\n <cide-ele-input label=\"End Offset (Days from Assignment)\"\n formControlName=\"collection_end_offset_days\" type=\"number\" size=\"sm\"\n title=\"Days from assignment date when collection window ends\">\n </cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2 tw-mt-2\">\n <cide-ele-input label=\"Start Date (Fixed Date - Alternative)\"\n formControlName=\"collection_start_date\" type=\"date\" size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n\n <cide-ele-input label=\"End Date (Fixed Date - Alternative)\"\n formControlName=\"collection_end_date\" type=\"date\" size=\"sm\"\n title=\"Use fixed date instead of offset\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (feeItemsArray.length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <div\n class=\"tw-bg-white tw-p-3 tw-rounded-full tw-w-12 tw-h-12 tw-mx-auto tw-mb-3 tw-flex tw-items-center tw-justify-center\">\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-gray-400\">receipt</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-600 tw-mb-1\">No Fee Items Yet</h6>\n <p class=\"tw-text-xs tw-text-gray-500\">Click \"Add Fee Item\" to start adding fee items to this structure.\n </p>\n </div>\n }\n </div>\n }\n }\n\n <!-- Form Validation Errors -->\n @if (!isViewMode()) {\n <!-- Form Field Errors -->\n <div class=\"tw-w-full tw-mb-4\">\n <cide-form-field-error [formGroup]=\"feeStructureForm\"></cide-form-field-error>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"tw-flex tw-justify-end tw-gap-3 tw-mt-6\">\n @if (!isEditMode()) {\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n }\n\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"close\"\n [disabled]=\"loading()\">\n Cancel\n </button>\n\n @if (!isInstallmentPercentagesValid()) {\n <div class=\"tw-w-full tw-mb-3 tw-p-2 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded tw-text-sm\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-text-red-700\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">error</cide-ele-icon>\n <span class=\"tw-font-medium\">Validation Error:</span>\n </div>\n <p class=\"tw-text-red-600 tw-mt-1 tw-ml-6\">\n All installment percentages must total exactly 100% before saving. Please adjust the percentages to\n continue.\n </p>\n </div>\n }\n\n <button cideEleButton type=\"submit\" variant=\"primary\" size=\"sm\"\n [disabled]=\"submitting() || loading() || !isInstallmentPercentagesValid()\" [loading]=\"submitting()\"\n leftIcon=\"save\">\n {{ isEditMode() ? 'Update Fee Structure' : 'Create Fee Structure' }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n </form>\n </div>\n</cide-lyt-shared-wrapper>" }]
2404
2393
  }], ctorParameters: () => [] });
2405
2394
 
2406
2395
  var feeStructureCreate_component = /*#__PURE__*/Object.freeze({
@@ -2484,10 +2473,10 @@ class CideFeeFeeAssignmentService {
2484
2473
  ]);
2485
2474
  return this.http.patch(url, { feeas_id: assignmentId });
2486
2475
  }
2487
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideFeeFeeAssignmentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2488
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideFeeFeeAssignmentService, providedIn: 'root' });
2476
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideFeeFeeAssignmentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2477
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideFeeFeeAssignmentService, providedIn: 'root' });
2489
2478
  }
2490
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideFeeFeeAssignmentService, decorators: [{
2479
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideFeeFeeAssignmentService, decorators: [{
2491
2480
  type: Injectable,
2492
2481
  args: [{
2493
2482
  providedIn: 'root'
@@ -2502,10 +2491,13 @@ class FeeAssignmentListComponent {
2502
2491
  notificationService = inject(NotificationService);
2503
2492
  academicYearService = inject(ACADEMIC_YEAR_SERVICE_TOKEN);
2504
2493
  classProgramService = inject(CLASS_PROGRAM_MASTER_SERVICE_TOKEN);
2494
+ programTermSectionService = inject(PROGRAM_TERM_SECTION_SERVICE_TOKEN);
2505
2495
  feeAssignmentService = inject(CideFeeFeeAssignmentService);
2506
2496
  rightsService = inject(RightsService);
2497
+ appStateService = inject(AppStateService);
2507
2498
  studentDetailsRendererTemplate = viewChild.required('studentDetailsRendererTemplate');
2508
2499
  amountRendererTemplate = viewChild.required('amountRendererTemplate');
2500
+ dateRendererTemplate = viewChild.required('dateRendererTemplate');
2509
2501
  statusRendererTemplate = viewChild.required('statusRendererTemplate');
2510
2502
  actionsDropdownRendererTemplate = viewChild.required('actionsDropdownRendererTemplate');
2511
2503
  // Breadcrumb data for shared wrapper
@@ -2536,15 +2528,6 @@ class FeeAssignmentListComponent {
2536
2528
  gridConfig = computed(() => ({
2537
2529
  id: 'fee-assignment-list-grid',
2538
2530
  columns: [
2539
- {
2540
- key: 'student_id',
2541
- header: 'Student ID',
2542
- type: 'text',
2543
- width: '120px',
2544
- truncate: true,
2545
- align: 'left',
2546
- sortable: true
2547
- },
2548
2531
  {
2549
2532
  key: 'student',
2550
2533
  header: 'Student Details',
@@ -2577,10 +2560,11 @@ class FeeAssignmentListComponent {
2577
2560
  {
2578
2561
  key: 'feeas_due_date',
2579
2562
  header: 'Due Date',
2580
- type: 'date',
2563
+ type: 'custom',
2581
2564
  width: '120px',
2582
2565
  truncate: false,
2583
2566
  align: 'left',
2567
+ renderer: 'dateRenderer',
2584
2568
  sortable: true
2585
2569
  },
2586
2570
  {
@@ -2671,8 +2655,15 @@ class FeeAssignmentListComponent {
2671
2655
  // Cleanup if needed
2672
2656
  }
2673
2657
  loadDropdownOptions() {
2658
+ const entityId = this.appStateService.getActiveEntityValue()?._id;
2674
2659
  // Load academic years
2675
- this.academicYearService.getAcademicYearList({ pageIndex: 1, pageSize: 100, pagination: false }).subscribe({
2660
+ this.academicYearService.getAcademicYearList({
2661
+ pageIndex: 1,
2662
+ pageSize: 100,
2663
+ pagination: false,
2664
+ // Assuming academic year service might accept entity filter if updated, but keeping standard for now
2665
+ // If backend supports filtering ACAYR by entity, add it here.
2666
+ }).subscribe({
2676
2667
  next: (response) => {
2677
2668
  if (response?.success && response.data) {
2678
2669
  this.academicYearOptions.set(response.data.map(ay => ({
@@ -2682,8 +2673,12 @@ class FeeAssignmentListComponent {
2682
2673
  }
2683
2674
  }
2684
2675
  });
2685
- // Load class programs
2686
- this.classProgramService.searchClassProgramMasters({ pagination: false }).subscribe({
2676
+ // Load class programs with Entity Context
2677
+ const classPayload = { pagination: false };
2678
+ if (entityId) {
2679
+ classPayload.acacpm_entity_id_syen = entityId;
2680
+ }
2681
+ this.classProgramService.searchClassProgramMasters(classPayload).subscribe({
2687
2682
  next: (response) => {
2688
2683
  if (response?.success && response.data) {
2689
2684
  this.classOptions.set(response.data.map(cp => ({
@@ -2697,12 +2692,17 @@ class FeeAssignmentListComponent {
2697
2692
  loadFeeAssignments() {
2698
2693
  this.loading.set(true);
2699
2694
  this.error.set(null);
2695
+ const entityId = this.appStateService.getActiveEntityValue()?._id;
2700
2696
  const payload = {
2701
2697
  pagination: true,
2702
2698
  pageIndex: this.currentPage(),
2703
2699
  pageSize: this.pageSize(),
2704
2700
  query: this.searchQuery() || '',
2705
- feeas_status: this.selectedStatusFilter() || undefined
2701
+ feeas_payment_status: this.selectedStatusFilter() || undefined,
2702
+ feeas_academic_year_id_acayr: this.selectedAcademicYearFilter() || undefined,
2703
+ feeas_class_program_id_acacpm: this.selectedClassFilter() || undefined,
2704
+ feeas_section_id_acapts: this.selectedSectionFilter() || undefined,
2705
+ feeas_entity_id_syen: entityId || undefined
2706
2706
  };
2707
2707
  this.feeAssignmentService.getFeeAssignmentList(payload).subscribe({
2708
2708
  next: (response) => {
@@ -2710,17 +2710,23 @@ class FeeAssignmentListComponent {
2710
2710
  // Transform API response to component format
2711
2711
  this.feeAssignments.set(response.data.map((item) => ({
2712
2712
  _id: item._id,
2713
- feeas_student_id: item.feeas_student_id,
2714
- student_name: item.student_name || item.feeas_student_id?.name || 'N/A',
2715
- student_id: item.student_id || item.feeas_student_id?._id || '',
2716
- class: item.class || item.feeas_student_id?.class || 'N/A',
2717
- section: item.section || item.feeas_student_id?.section || 'N/A',
2718
- fee_structure_name: item.fee_structure_name || item.feeas_structure_id_fees?.fees_structure_name || 'N/A',
2719
- feeas_amount_original: item.feeas_amount_original || 0,
2720
- feeas_amount_paid: item.feeas_amount_paid || 0,
2721
- feeas_amount_remaining: item.feeas_amount_remaining || item.feeas_final_amount || 0,
2713
+ feeas_student_id_auth: item.feeas_student_id_auth,
2714
+ student_name: item.student_name ||
2715
+ (item.feeas_admission_id_admap ?
2716
+ [item.feeas_admission_id_admap.admap_first_name, item.feeas_admission_id_admap.admap_middle_name, item.feeas_admission_id_admap.admap_last_name]
2717
+ .filter(n => !!n).join(' ') : null) ||
2718
+ item.feeas_student_id_auth?.name ||
2719
+ 'N/A',
2720
+ student_id: (typeof item.feeas_student_id_auth === 'string' ? item.feeas_student_id_auth : item.feeas_student_id_auth?._id) || '',
2721
+ class: this.formatClassDetails(item),
2722
+ section: item.section || item.feeas_section_id_acapts?.acapts_name || 'N/A',
2723
+ fee_structure_name: item.fee_structure_name || item.feeas_fee_structure_id_feest?.fees_structure_name || item.feeas_fee_name || 'N/A',
2724
+ feeas_amount_original: item.feeas_original_amount || item.feeas_total_amount || 0,
2725
+ feeas_amount_discount: item.feeas_discount_amount || 0,
2726
+ feeas_amount_paid: item.feeas_paid_amount || 0,
2727
+ feeas_amount_remaining: item.feeas_outstanding_amount !== undefined ? item.feeas_outstanding_amount : ((item.feeas_total_amount || 0) - (item.feeas_paid_amount || 0)),
2722
2728
  feeas_due_date: item.feeas_due_date ? new Date(item.feeas_due_date) : undefined,
2723
- feeas_status: item.feeas_status || 'PENDING'
2729
+ feeas_status: item.feeas_status || item.feeas_payment_status || 'PENDING'
2724
2730
  })));
2725
2731
  this.totalItems.set(response.total || response.data.length);
2726
2732
  this.totalPages.set(Math.ceil((response.total || response.data.length) / this.pageSize()));
@@ -2747,6 +2753,7 @@ class FeeAssignmentListComponent {
2747
2753
  templateRenderers = computed(() => ({
2748
2754
  studentDetailsRenderer: this.studentDetailsRendererTemplate(),
2749
2755
  amountRenderer: this.amountRendererTemplate(),
2756
+ dateRenderer: this.dateRendererTemplate(),
2750
2757
  statusRenderer: this.statusRendererTemplate(),
2751
2758
  actionsDropdownRenderer: this.actionsDropdownRendererTemplate()
2752
2759
  }), ...(ngDevMode ? [{ debugName: "templateRenderers" }] : []));
@@ -2798,6 +2805,42 @@ class FeeAssignmentListComponent {
2798
2805
  this.selectedClassFilter.set(String(value || ''));
2799
2806
  this.currentPage.set(1);
2800
2807
  this.loadFeeAssignments();
2808
+ // Load sections when class filter changes
2809
+ this.selectedSectionFilter.set(''); // Reset section filter
2810
+ this.loadSections();
2811
+ }
2812
+ loadSections() {
2813
+ const classProgramId = this.selectedClassFilter();
2814
+ const entityId = this.appStateService.getActiveEntityValue()?._id;
2815
+ if (!classProgramId) {
2816
+ this.sectionOptions.set([]);
2817
+ return;
2818
+ }
2819
+ const payload = {
2820
+ pagination: false,
2821
+ acapts_program_id_acacpm: classProgramId,
2822
+ acapts_is_active: true
2823
+ };
2824
+ if (entityId) {
2825
+ payload.acapts_entity_id_syen = entityId;
2826
+ }
2827
+ this.programTermSectionService.getProgramTermSectionList(payload).subscribe({
2828
+ next: (response) => {
2829
+ if (response?.success && response.data) {
2830
+ this.sectionOptions.set(response.data.map(sec => ({
2831
+ value: sec._id || '',
2832
+ label: sec.acapts_name || ''
2833
+ })));
2834
+ }
2835
+ else {
2836
+ this.sectionOptions.set([]);
2837
+ }
2838
+ },
2839
+ error: (err) => {
2840
+ console.error('Error loading sections:', err);
2841
+ this.sectionOptions.set([]);
2842
+ }
2843
+ });
2801
2844
  }
2802
2845
  onSectionFilterChange(value) {
2803
2846
  this.selectedSectionFilter.set(String(value || ''));
@@ -2966,10 +3009,27 @@ class FeeAssignmentListComponent {
2966
3009
  getStatusText(assignment) {
2967
3010
  return assignment.feeas_status || 'Unknown';
2968
3011
  }
2969
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeAssignmentListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2970
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.1.7", type: FeeAssignmentListComponent, isStandalone: true, selector: "cide-fee-assignment-list", viewQueries: [{ propertyName: "studentDetailsRendererTemplate", first: true, predicate: ["studentDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "amountRendererTemplate", first: true, predicate: ["amountRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "statusRendererTemplate", first: true, predicate: ["statusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Fee Assignment Container -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_assignment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"navigateToAssign()\">\n Assign Fees\n </button>\n <button cideEleButton variant=\"secondary\" size=\"sm\" leftIcon=\"group_add\" (click)=\"bulkAssign()\">\n Bulk Assignment\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Stats Row -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-px-6 tw-py-4 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 sm:tw-grid-cols-4 tw-gap-4\">\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Total Assigned</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-gray-900\">{{ stats().total }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Pending</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-yellow-600\">{{ stats().pending }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Partially Paid</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-blue-600\">{{ stats().partial }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Paid</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-green-600\">{{ stats().paid }}</div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Filters Row -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-px-6 tw-py-4 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-4 tw-gap-4\">\n <cide-ele-select \n label=\"Academic Year\" \n [options]=\"academicYearOptions()\"\n [ngModel]=\"selectedAcademicYearFilter()\"\n (ngModelChange)=\"onAcademicYearFilterChange($event)\"\n size=\"sm\"\n placeholder=\"All Academic Years\">\n </cide-ele-select>\n\n <cide-ele-select \n label=\"Class/Program\" \n [options]=\"classOptions()\"\n [ngModel]=\"selectedClassFilter()\"\n (ngModelChange)=\"onClassFilterChange($event)\"\n size=\"sm\"\n placeholder=\"All Classes\">\n </cide-ele-select>\n\n <cide-ele-select \n label=\"Section\" \n [options]=\"sectionOptions()\"\n [ngModel]=\"selectedSectionFilter()\"\n (ngModelChange)=\"onSectionFilterChange($event)\"\n size=\"sm\"\n placeholder=\"All Sections\">\n </cide-ele-select>\n\n <cide-ele-select \n label=\"Status\" \n [options]=\"[\n {value: '', label: 'All Status'},\n {value: 'PENDING', label: 'Pending'},\n {value: 'PARTIALLY_PAID', label: 'Partially Paid'},\n {value: 'PAID', label: 'Paid'},\n {value: 'WAIVED', label: 'Waived'}\n ]\"\n [ngModel]=\"selectedStatusFilter()\"\n (ngModelChange)=\"onStatusFilterChange($event)\"\n size=\"sm\"\n placeholder=\"All Status\">\n </cide-ele-select>\n </div>\n <div class=\"tw-mt-3\">\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"clearFilters()\">\n Clear Filters\n </button>\n </div>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n\n <!-- Data Grid Component -->\n <div class=\"tw-h-full tw-overflow-auto\">\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n\n </div>\n </div>\n\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #studentDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-w-full\">\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.student_name || 'N/A' }}</div>\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">{{ row.class || '' }} / {{ row.section || '' }}</div>\n </div>\n</ng-template>\n\n<ng-template #amountRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-text-sm tw-items-end\">\n <span class=\"tw-text-gray-900 tw-font-semibold\">{{ formatCurrency(row.feeas_amount_original) }}</span>\n <div class=\"tw-text-xs tw-text-gray-500\">\n Paid: {{ formatCurrency(row.feeas_amount_paid) }}\n </div>\n <div class=\"tw-text-xs tw-font-semibold\" [ngClass]=\"row.feeas_amount_remaining > 0 ? 'tw-text-red-600' : 'tw-text-green-600'\">\n Outstanding: {{ formatCurrency(row.feeas_amount_remaining) }}\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusRendererTemplate let-row=\"row\">\n <span class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\n [ngClass]=\"getStatusBadgeClass(row)\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\n {{ row.feeas_status === 'PAID' ? 'check_circle' : \n row.feeas_status === 'PARTIALLY_PAID' ? 'schedule' : \n row.feeas_status === 'PENDING' ? 'pending' : 'cancel' }}\n </cide-ele-icon>\n {{ getStatusText(row) }}\n </span>\n</ng-template>\n\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\n <cide-ele-dropdown \n [items]=\"getActionDropdownItems(row)\"\n [config]=\"getDropdownConfig()\"\n (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>\n\n", styles: [".fee-assignment-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
3012
+ formatClassDetails(item) {
3013
+ if (item.feeas_admission_id_admap) {
3014
+ const admission = item.feeas_admission_id_admap;
3015
+ const program = admission.admap_class_program_id_acacpm?.acacpm_alise_title || '';
3016
+ const term = admission.admap_class_program_term_id_acapt?.acapt_name || '';
3017
+ const branch = admission.admap_class_program_branch_id_acabrn?.acabrn_name || '';
3018
+ let details = program;
3019
+ if (term)
3020
+ details += ` (${term})`;
3021
+ if (branch)
3022
+ details += ` - ${branch}`;
3023
+ if (details)
3024
+ return details;
3025
+ }
3026
+ // Fallback
3027
+ return item.class || item.feeas_class_program_id_acacpm?.acacpm_alise_title || 'N/A';
3028
+ }
3029
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeAssignmentListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3030
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FeeAssignmentListComponent, isStandalone: true, selector: "cide-fee-assignment-list", viewQueries: [{ propertyName: "studentDetailsRendererTemplate", first: true, predicate: ["studentDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "amountRendererTemplate", first: true, predicate: ["amountRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "dateRendererTemplate", first: true, predicate: ["dateRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "statusRendererTemplate", first: true, predicate: ["statusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Fee Assignment Container -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_assignment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n\n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions class=\"tw-flex tw-items-center tw-gap-2\">\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"navigateToAssign()\">\n Assign Fees\n </button>\n <button cideEleButton variant=\"secondary\" size=\"sm\" leftIcon=\"group_add\" (click)=\"bulkAssign()\">\n Bulk Assignment\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Stats Row -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-px-6 tw-py-4 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 sm:tw-grid-cols-4 tw-gap-4\">\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Total Assigned</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-gray-900\">{{ stats().total }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Pending</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-yellow-600\">{{ stats().pending }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Partially Paid</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-blue-600\">{{ stats().partial }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Paid</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-green-600\">{{ stats().paid }}</div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Filters Row -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-px-6 tw-py-4 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-4 tw-gap-4\">\n <cide-ele-select label=\"Academic Year\" [options]=\"academicYearOptions()\"\n [ngModel]=\"selectedAcademicYearFilter()\" (ngModelChange)=\"onAcademicYearFilterChange($event)\" size=\"sm\"\n placeholder=\"All Academic Years\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Class/Program\" [options]=\"classOptions()\" [ngModel]=\"selectedClassFilter()\"\n (ngModelChange)=\"onClassFilterChange($event)\" size=\"sm\" placeholder=\"All Classes\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Section\" [options]=\"sectionOptions()\" [ngModel]=\"selectedSectionFilter()\"\n (ngModelChange)=\"onSectionFilterChange($event)\" size=\"sm\" placeholder=\"All Sections\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Status\" [options]=\"[\n {value: '', label: 'All Status'},\n {value: 'PENDING', label: 'Pending'},\n {value: 'PARTIALLY_PAID', label: 'Partially Paid'},\n {value: 'PAID', label: 'Paid'},\n {value: 'WAIVED', label: 'Waived'}\n ]\" [ngModel]=\"selectedStatusFilter()\" (ngModelChange)=\"onStatusFilterChange($event)\" size=\"sm\"\n placeholder=\"All Status\">\n </cide-ele-select>\n </div>\n <div class=\"tw-mt-3\">\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"clearFilters()\">\n Clear Filters\n </button>\n </div>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n\n <!-- Data Grid Component -->\n <div class=\"tw-h-full tw-overflow-auto\">\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n\n </div>\n </div>\n\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #studentDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-w-full\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <span class=\"tw-font-medium tw-text-gray-900\">{{ row.student_name || 'N/A' }}</span>\n @if (row.student_id) {\n <span class=\"tw-px-1.5 tw-py-0.5 tw-rounded tw-bg-gray-100 tw-text-gray-600 tw-text-[10px] tw-font-medium\">\n {{ row.student_id }}\n </span>\n }\n </div>\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate tw-mt-0.5\">\n @if (row.class || row.section) {\n {{ row.class || '' }} {{ row.section !== 'N/A' && row.section ? '/ ' + row.section : '' }}\n } @else {\n -\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #amountRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-text-sm tw-items-end\">\n <span class=\"tw-text-gray-900 tw-font-semibold\">{{ formatCurrency(row.feeas_amount_original) }}</span>\n @if (row.feeas_amount_discount > 0) {\n <div class=\"tw-text-xs tw-text-blue-600\">\n Discount: {{ formatCurrency(row.feeas_amount_discount) }}\n </div>\n }\n <div class=\"tw-text-xs tw-text-gray-500\">\n Paid: {{ formatCurrency(row.feeas_amount_paid) }}\n </div>\n <div class=\"tw-text-xs tw-font-semibold\"\n [ngClass]=\"row.feeas_amount_remaining > 0 ? 'tw-text-red-600' : 'tw-text-green-600'\">\n Outstanding: {{ formatCurrency(row.feeas_amount_remaining) }}\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateRendererTemplate let-row=\"row\">\n <div class=\"tw-text-sm tw-text-gray-900\">{{ formatDate(row.feeas_due_date) }}</div>\n</ng-template>\n\n<ng-template #statusRendererTemplate let-row=\"row\">\n <span\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\n [ngClass]=\"getStatusBadgeClass(row)\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\n {{ row.feeas_status === 'PAID' ? 'check_circle' :\n row.feeas_status === 'PARTIALLY_PAID' ? 'schedule' :\n row.feeas_status === 'PENDING' ? 'pending' : 'cancel' }}\n </cide-ele-icon>\n {{ getStatusText(row) }}\n </span>\n</ng-template>\n\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\n <cide-ele-dropdown [items]=\"getActionDropdownItems(row)\" [config]=\"getDropdownConfig()\"\n (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>", styles: [".fee-assignment-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
2971
3031
  }
2972
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeAssignmentListComponent, decorators: [{
3032
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeAssignmentListComponent, decorators: [{
2973
3033
  type: Component,
2974
3034
  args: [{ selector: 'cide-fee-assignment-list', standalone: true, imports: [
2975
3035
  CommonModule,
@@ -2980,14 +3040,659 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
2980
3040
  CideEleDropdownComponent,
2981
3041
  CideSelectComponent,
2982
3042
  CideLytSharedWrapperComponent
2983
- ], template: "<!-- Fee Assignment Container -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_assignment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"navigateToAssign()\">\n Assign Fees\n </button>\n <button cideEleButton variant=\"secondary\" size=\"sm\" leftIcon=\"group_add\" (click)=\"bulkAssign()\">\n Bulk Assignment\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Stats Row -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-px-6 tw-py-4 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 sm:tw-grid-cols-4 tw-gap-4\">\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Total Assigned</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-gray-900\">{{ stats().total }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Pending</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-yellow-600\">{{ stats().pending }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Partially Paid</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-blue-600\">{{ stats().partial }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Paid</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-green-600\">{{ stats().paid }}</div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Filters Row -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-px-6 tw-py-4 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-4 tw-gap-4\">\n <cide-ele-select \n label=\"Academic Year\" \n [options]=\"academicYearOptions()\"\n [ngModel]=\"selectedAcademicYearFilter()\"\n (ngModelChange)=\"onAcademicYearFilterChange($event)\"\n size=\"sm\"\n placeholder=\"All Academic Years\">\n </cide-ele-select>\n\n <cide-ele-select \n label=\"Class/Program\" \n [options]=\"classOptions()\"\n [ngModel]=\"selectedClassFilter()\"\n (ngModelChange)=\"onClassFilterChange($event)\"\n size=\"sm\"\n placeholder=\"All Classes\">\n </cide-ele-select>\n\n <cide-ele-select \n label=\"Section\" \n [options]=\"sectionOptions()\"\n [ngModel]=\"selectedSectionFilter()\"\n (ngModelChange)=\"onSectionFilterChange($event)\"\n size=\"sm\"\n placeholder=\"All Sections\">\n </cide-ele-select>\n\n <cide-ele-select \n label=\"Status\" \n [options]=\"[\n {value: '', label: 'All Status'},\n {value: 'PENDING', label: 'Pending'},\n {value: 'PARTIALLY_PAID', label: 'Partially Paid'},\n {value: 'PAID', label: 'Paid'},\n {value: 'WAIVED', label: 'Waived'}\n ]\"\n [ngModel]=\"selectedStatusFilter()\"\n (ngModelChange)=\"onStatusFilterChange($event)\"\n size=\"sm\"\n placeholder=\"All Status\">\n </cide-ele-select>\n </div>\n <div class=\"tw-mt-3\">\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"clearFilters()\">\n Clear Filters\n </button>\n </div>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n\n <!-- Data Grid Component -->\n <div class=\"tw-h-full tw-overflow-auto\">\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n\n </div>\n </div>\n\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #studentDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-w-full\">\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.student_name || 'N/A' }}</div>\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">{{ row.class || '' }} / {{ row.section || '' }}</div>\n </div>\n</ng-template>\n\n<ng-template #amountRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-text-sm tw-items-end\">\n <span class=\"tw-text-gray-900 tw-font-semibold\">{{ formatCurrency(row.feeas_amount_original) }}</span>\n <div class=\"tw-text-xs tw-text-gray-500\">\n Paid: {{ formatCurrency(row.feeas_amount_paid) }}\n </div>\n <div class=\"tw-text-xs tw-font-semibold\" [ngClass]=\"row.feeas_amount_remaining > 0 ? 'tw-text-red-600' : 'tw-text-green-600'\">\n Outstanding: {{ formatCurrency(row.feeas_amount_remaining) }}\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusRendererTemplate let-row=\"row\">\n <span class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\n [ngClass]=\"getStatusBadgeClass(row)\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\n {{ row.feeas_status === 'PAID' ? 'check_circle' : \n row.feeas_status === 'PARTIALLY_PAID' ? 'schedule' : \n row.feeas_status === 'PENDING' ? 'pending' : 'cancel' }}\n </cide-ele-icon>\n {{ getStatusText(row) }}\n </span>\n</ng-template>\n\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\n <cide-ele-dropdown \n [items]=\"getActionDropdownItems(row)\"\n [config]=\"getDropdownConfig()\"\n (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>\n\n", styles: [".fee-assignment-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"] }]
2984
- }] });
3043
+ ], template: "<!-- Fee Assignment Container -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_assignment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n\n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions class=\"tw-flex tw-items-center tw-gap-2\">\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"navigateToAssign()\">\n Assign Fees\n </button>\n <button cideEleButton variant=\"secondary\" size=\"sm\" leftIcon=\"group_add\" (click)=\"bulkAssign()\">\n Bulk Assignment\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Stats Row -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-px-6 tw-py-4 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 sm:tw-grid-cols-4 tw-gap-4\">\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Total Assigned</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-gray-900\">{{ stats().total }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Pending</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-yellow-600\">{{ stats().pending }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Partially Paid</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-blue-600\">{{ stats().partial }}</div>\n </div>\n <div class=\"tw-bg-white tw-p-4 tw-rounded-lg tw-border tw-border-gray-200\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Paid</div>\n <div class=\"tw-text-2xl tw-font-bold tw-text-green-600\">{{ stats().paid }}</div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Filters Row -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-px-6 tw-py-4 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-4 tw-gap-4\">\n <cide-ele-select label=\"Academic Year\" [options]=\"academicYearOptions()\"\n [ngModel]=\"selectedAcademicYearFilter()\" (ngModelChange)=\"onAcademicYearFilterChange($event)\" size=\"sm\"\n placeholder=\"All Academic Years\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Class/Program\" [options]=\"classOptions()\" [ngModel]=\"selectedClassFilter()\"\n (ngModelChange)=\"onClassFilterChange($event)\" size=\"sm\" placeholder=\"All Classes\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Section\" [options]=\"sectionOptions()\" [ngModel]=\"selectedSectionFilter()\"\n (ngModelChange)=\"onSectionFilterChange($event)\" size=\"sm\" placeholder=\"All Sections\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Status\" [options]=\"[\n {value: '', label: 'All Status'},\n {value: 'PENDING', label: 'Pending'},\n {value: 'PARTIALLY_PAID', label: 'Partially Paid'},\n {value: 'PAID', label: 'Paid'},\n {value: 'WAIVED', label: 'Waived'}\n ]\" [ngModel]=\"selectedStatusFilter()\" (ngModelChange)=\"onStatusFilterChange($event)\" size=\"sm\"\n placeholder=\"All Status\">\n </cide-ele-select>\n </div>\n <div class=\"tw-mt-3\">\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"clearFilters()\">\n Clear Filters\n </button>\n </div>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n\n <!-- Data Grid Component -->\n <div class=\"tw-h-full tw-overflow-auto\">\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n\n </div>\n </div>\n\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #studentDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-w-full\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <span class=\"tw-font-medium tw-text-gray-900\">{{ row.student_name || 'N/A' }}</span>\n @if (row.student_id) {\n <span class=\"tw-px-1.5 tw-py-0.5 tw-rounded tw-bg-gray-100 tw-text-gray-600 tw-text-[10px] tw-font-medium\">\n {{ row.student_id }}\n </span>\n }\n </div>\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate tw-mt-0.5\">\n @if (row.class || row.section) {\n {{ row.class || '' }} {{ row.section !== 'N/A' && row.section ? '/ ' + row.section : '' }}\n } @else {\n -\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #amountRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-flex-col tw-text-sm tw-items-end\">\n <span class=\"tw-text-gray-900 tw-font-semibold\">{{ formatCurrency(row.feeas_amount_original) }}</span>\n @if (row.feeas_amount_discount > 0) {\n <div class=\"tw-text-xs tw-text-blue-600\">\n Discount: {{ formatCurrency(row.feeas_amount_discount) }}\n </div>\n }\n <div class=\"tw-text-xs tw-text-gray-500\">\n Paid: {{ formatCurrency(row.feeas_amount_paid) }}\n </div>\n <div class=\"tw-text-xs tw-font-semibold\"\n [ngClass]=\"row.feeas_amount_remaining > 0 ? 'tw-text-red-600' : 'tw-text-green-600'\">\n Outstanding: {{ formatCurrency(row.feeas_amount_remaining) }}\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateRendererTemplate let-row=\"row\">\n <div class=\"tw-text-sm tw-text-gray-900\">{{ formatDate(row.feeas_due_date) }}</div>\n</ng-template>\n\n<ng-template #statusRendererTemplate let-row=\"row\">\n <span\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\n [ngClass]=\"getStatusBadgeClass(row)\">\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\n {{ row.feeas_status === 'PAID' ? 'check_circle' :\n row.feeas_status === 'PARTIALLY_PAID' ? 'schedule' :\n row.feeas_status === 'PENDING' ? 'pending' : 'cancel' }}\n </cide-ele-icon>\n {{ getStatusText(row) }}\n </span>\n</ng-template>\n\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\n <cide-ele-dropdown [items]=\"getActionDropdownItems(row)\" [config]=\"getDropdownConfig()\"\n (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>", styles: [".fee-assignment-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"] }]
3044
+ }], propDecorators: { studentDetailsRendererTemplate: [{ type: i0.ViewChild, args: ['studentDetailsRendererTemplate', { isSignal: true }] }], amountRendererTemplate: [{ type: i0.ViewChild, args: ['amountRendererTemplate', { isSignal: true }] }], dateRendererTemplate: [{ type: i0.ViewChild, args: ['dateRendererTemplate', { isSignal: true }] }], statusRendererTemplate: [{ type: i0.ViewChild, args: ['statusRendererTemplate', { isSignal: true }] }], actionsDropdownRendererTemplate: [{ type: i0.ViewChild, args: ['actionsDropdownRendererTemplate', { isSignal: true }] }] } });
2985
3045
 
2986
3046
  var feeAssignmentList_component = /*#__PURE__*/Object.freeze({
2987
3047
  __proto__: null,
2988
3048
  FeeAssignmentListComponent: FeeAssignmentListComponent
2989
3049
  });
2990
3050
 
3051
+ class FeeApplicableFeesComponent {
3052
+ destroyRef = inject(DestroyRef);
3053
+ fb = inject(FormBuilder);
3054
+ feeStructureService = inject(CideFeeFeeStructureService);
3055
+ assignmentService = inject(CideFeeFeeAssignmentService);
3056
+ notificationService = inject(NotificationService);
3057
+ floatingContainerService = inject(CideEleFloatingContainerService);
3058
+ currencyPipe = inject(CurrencyPipe);
3059
+ // Inputs as Signals
3060
+ entityId = input(null, ...(ngDevMode ? [{ debugName: "entityId" }] : []));
3061
+ academicYearId = input('', ...(ngDevMode ? [{ debugName: "academicYearId" }] : []));
3062
+ classProgramId = input('', ...(ngDevMode ? [{ debugName: "classProgramId" }] : []));
3063
+ termId = input('', ...(ngDevMode ? [{ debugName: "termId" }] : []));
3064
+ branchId = input(null, ...(ngDevMode ? [{ debugName: "branchId" }] : []));
3065
+ sectionId = input(null, ...(ngDevMode ? [{ debugName: "sectionId" }] : []));
3066
+ studentId = input(null, ...(ngDevMode ? [{ debugName: "studentId" }] : []));
3067
+ // Outputs as Signals
3068
+ feesCalculated = output();
3069
+ // State
3070
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
3071
+ applicableFees = signal([], ...(ngDevMode ? [{ debugName: "applicableFees" }] : []));
3072
+ existingAssignments = signal([], ...(ngDevMode ? [{ debugName: "existingAssignments" }] : []));
3073
+ feeStructureGroups = signal([], ...(ngDevMode ? [{ debugName: "feeStructureGroups" }] : []));
3074
+ selectedFeeStructureId = signal(null, ...(ngDevMode ? [{ debugName: "selectedFeeStructureId" }] : []));
3075
+ feeDiscountScholarshipData = signal(new Map(), ...(ngDevMode ? [{ debugName: "feeDiscountScholarshipData" }] : []));
3076
+ viewingFeeDetails = signal(null, ...(ngDevMode ? [{ debugName: "viewingFeeDetails" }] : []));
3077
+ onStructureChange(value) {
3078
+ this.selectedFeeStructureId.set(value ? String(value) : null);
3079
+ }
3080
+ constructor() {
3081
+ // Auto emit when calculations change
3082
+ effect(() => {
3083
+ const fees = this.getSelectedFeeStructureFees();
3084
+ if (fees.length > 0) {
3085
+ this.emitFeeData();
3086
+ }
3087
+ else {
3088
+ // Emit empty if no fees
3089
+ this.feesCalculated.emit({
3090
+ fees: [],
3091
+ totalOriginal: 0,
3092
+ totalDiscount: 0,
3093
+ totalScholarship: 0,
3094
+ totalFinal: 0,
3095
+ structureId: this.selectedFeeStructureId()
3096
+ });
3097
+ }
3098
+ });
3099
+ }
3100
+ ngOnInit() {
3101
+ this.registerFloatingContainerComponents();
3102
+ }
3103
+ async registerFloatingContainerComponents() {
3104
+ // Register fee discount form component
3105
+ if (!this.floatingContainerService.isComponentRegistered('fee-discount-form')) {
3106
+ try {
3107
+ const module = await import('./cloud-ide-fees-fee-discount-form.component-R_yZNKM-.mjs');
3108
+ this.floatingContainerService.registerComponent('fee-discount-form', module.FeeDiscountFormComponent);
3109
+ }
3110
+ catch (error) {
3111
+ console.error('❌ Failed to register fee discount form component:', error);
3112
+ }
3113
+ }
3114
+ // Register fee scholarship form component
3115
+ if (!this.floatingContainerService.isComponentRegistered('fee-scholarship-form')) {
3116
+ try {
3117
+ const module = await import('./cloud-ide-fees-fee-scholarship-form.component-C2eJrtQT.mjs');
3118
+ this.floatingContainerService.registerComponent('fee-scholarship-form', module.FeeScholarshipFormComponent);
3119
+ }
3120
+ catch (error) {
3121
+ console.error('❌ Failed to register fee scholarship form component:', error);
3122
+ }
3123
+ }
3124
+ // Register fee details viewer component (using wrapper to avoid direct import circular dependency issues if any)
3125
+ if (!this.floatingContainerService.isComponentRegistered('fee-details-viewer')) {
3126
+ try {
3127
+ const module = await import('cloud-ide-shared');
3128
+ if (module.FeeDetailsViewerWrapperComponent) {
3129
+ this.floatingContainerService.registerComponent('fee-details-viewer', module.FeeDetailsViewerWrapperComponent);
3130
+ }
3131
+ }
3132
+ catch (error) {
3133
+ console.error('❌ Failed to register fee details viewer component:', error);
3134
+ }
3135
+ }
3136
+ }
3137
+ // Initial Load / Reactivity Effect
3138
+ triggerLoadEffect = effect(() => {
3139
+ const cpId = this.classProgramId();
3140
+ const termId = this.termId();
3141
+ const entityId = this.entityId();
3142
+ const ayId = this.academicYearId();
3143
+ const branchId = this.branchId();
3144
+ const sectionId = this.sectionId();
3145
+ console.log(cpId, "g", termId, "d", entityId, ayId, branchId, sectionId, "signa rights");
3146
+ // Only trigger if minimal required fields are present
3147
+ if (cpId && entityId && ayId) {
3148
+ this.loadApplicableFees();
3149
+ }
3150
+ else {
3151
+ // Should we clear if invalid? Or just keep?
3152
+ // Usually clear to avoid stale data if filters are cleared.
3153
+ this.applicableFees.set([]);
3154
+ }
3155
+ }, ...(ngDevMode ? [{ debugName: "triggerLoadEffect", allowSignalWrites: true }] : [{ allowSignalWrites: true }]));
3156
+ loadApplicableFees() {
3157
+ if (!this.classProgramId() || !this.entityId() || !this.academicYearId()) {
3158
+ // Missing required fields
3159
+ this.applicableFees.set([]);
3160
+ return;
3161
+ }
3162
+ this.loading.set(true);
3163
+ const payloadData = {
3164
+ fees_class_program_id_acacpm: this.classProgramId(),
3165
+ fees_class_program_term_id_acapt: this.termId(),
3166
+ fees_entity_id_syen: this.entityId() || undefined,
3167
+ fees_academic_year_id_acayr: this.academicYearId(),
3168
+ fees_is_active: true,
3169
+ pagination: false
3170
+ };
3171
+ if (this.branchId()) {
3172
+ payloadData.fees_class_program_branch_id_acabrn = this.branchId() || undefined;
3173
+ }
3174
+ if (this.sectionId()) {
3175
+ payloadData.fees_program_term_section_id_acapts = this.sectionId() || undefined;
3176
+ }
3177
+ const payload = new MFeeStructure(payloadData);
3178
+ // Load assignments in parallel if studentId exists
3179
+ if (this.studentId()) {
3180
+ this.loadExistingAssignments();
3181
+ }
3182
+ this.feeStructureService.getFeeStructureList(payload)
3183
+ .pipe(takeUntilDestroyed(this.destroyRef))
3184
+ .subscribe({
3185
+ next: (response) => {
3186
+ if (response?.success && response?.data) {
3187
+ const feeStructures = Array.isArray(response.data) ? response.data : [];
3188
+ if (feeStructures.length === 0) {
3189
+ this.applicableFees.set([]);
3190
+ this.loading.set(false);
3191
+ return;
3192
+ }
3193
+ const feeItemRequests = feeStructures.map(structure => this.feeStructureService.getFeeStructureById({ fees_id: structure._id || '' })
3194
+ .pipe(takeUntilDestroyed(this.destroyRef)));
3195
+ forkJoin(feeItemRequests).subscribe({
3196
+ next: (responses) => {
3197
+ const allFeeItems = [];
3198
+ responses.forEach((itemResponse, index) => {
3199
+ if (itemResponse?.success && itemResponse?.data) {
3200
+ const structure = feeStructures[index];
3201
+ const isFeeStructureByIdResponse = (data) => {
3202
+ return data && 'fee_structure' in data;
3203
+ };
3204
+ let feeItems = [];
3205
+ if (isFeeStructureByIdResponse(itemResponse.data)) {
3206
+ feeItems = itemResponse.data.fee_structure_items || [];
3207
+ }
3208
+ feeItems.forEach(item => {
3209
+ if (item.feesi_is_active !== false) {
3210
+ // Extract category name
3211
+ let categoryName = 'N/A';
3212
+ if (item.feesi_category_id_sygms) {
3213
+ if (typeof item.feesi_category_id_sygms === 'object' && item.feesi_category_id_sygms !== null) {
3214
+ categoryName = item.feesi_category_id_sygms?.sygms_title ||
3215
+ item.feesi_category_id_sygms?.sygms_name ||
3216
+ item.feesi_item_code ||
3217
+ item.feesi_item_name ||
3218
+ 'N/A';
3219
+ }
3220
+ else if (typeof item.feesi_category_id_sygms === 'string') {
3221
+ categoryName = item.feesi_item_code || item.feesi_item_name || 'N/A';
3222
+ }
3223
+ }
3224
+ else {
3225
+ categoryName = item.feesi_item_code || item.feesi_item_name || 'N/A';
3226
+ }
3227
+ // Create deep copy of item data
3228
+ const feeItemDataCopy = {
3229
+ ...item,
3230
+ // Ensure needed fields
3231
+ feesi_category_id_sygms: item.feesi_category_id_sygms,
3232
+ feesi_item_name: item.feesi_item_name || '',
3233
+ feesi_item_code: item.feesi_item_code || '',
3234
+ feesi_amount: item.feesi_amount || 0
3235
+ };
3236
+ const feeItem = {
3237
+ ...structure,
3238
+ _id: item._id || '',
3239
+ fees_structure_id: structure._id,
3240
+ fees_structure_name: structure.fees_structure_name || 'N/A',
3241
+ fees_structure_code: structure.fees_structure_code || '',
3242
+ fees_category_name: categoryName,
3243
+ fees_amount: item.feesi_amount || 0,
3244
+ fees_total_amount: item.feesi_amount || 0,
3245
+ _feeItemData: feeItemDataCopy
3246
+ };
3247
+ allFeeItems.push(feeItem);
3248
+ }
3249
+ });
3250
+ }
3251
+ });
3252
+ this.applicableFees.set(allFeeItems);
3253
+ this.regroupFees(allFeeItems);
3254
+ // Auto-select first structure if not set
3255
+ const groups = this.feeStructureGroups();
3256
+ if (groups.length > 0 && !this.selectedFeeStructureId()) {
3257
+ this.selectedFeeStructureId.set(groups[0].structure_id);
3258
+ }
3259
+ this.loading.set(false);
3260
+ this.updateAssignmentStatus();
3261
+ },
3262
+ error: (err) => {
3263
+ console.error('Error loading fee items:', err);
3264
+ this.notificationService.error('Failed to load fee details.');
3265
+ this.loading.set(false);
3266
+ }
3267
+ });
3268
+ }
3269
+ else {
3270
+ this.applicableFees.set([]);
3271
+ this.loading.set(false);
3272
+ }
3273
+ },
3274
+ error: (err) => {
3275
+ console.error('Error loading fee structures:', err);
3276
+ this.notificationService.error('Failed to load fee structures.');
3277
+ this.loading.set(false);
3278
+ }
3279
+ });
3280
+ }
3281
+ loadExistingAssignments() {
3282
+ const payload = {
3283
+ feeas_student_id_auth: this.studentId() || undefined,
3284
+ fees_academic_year_id_acayr: this.academicYearId(), // inherited from MFeeStructure
3285
+ pagination: false
3286
+ };
3287
+ this.assignmentService.getFeeAssignmentList(payload)
3288
+ .pipe(takeUntilDestroyed(this.destroyRef))
3289
+ .subscribe({
3290
+ next: (res) => {
3291
+ if (res.success && res.data) {
3292
+ this.existingAssignments.set(res.data);
3293
+ this.updateAssignmentStatus();
3294
+ }
3295
+ }
3296
+ });
3297
+ }
3298
+ updateAssignmentStatus() {
3299
+ const fees = this.applicableFees();
3300
+ const assignments = this.existingAssignments();
3301
+ if (fees.length === 0)
3302
+ return; // No fees to mark, but assignments might exist
3303
+ // Note: Even if assignments is empty, we should run this to clear is_assigned status if it was previously set
3304
+ const updatedFees = fees.map(fee => {
3305
+ const isAssigned = assignments.some(a => {
3306
+ const assignmentItemId = (typeof a.feeas_fee_structure_item_id_feesi === 'object' && a.feeas_fee_structure_item_id_feesi !== null)
3307
+ ? a.feeas_fee_structure_item_id_feesi._id
3308
+ : a.feeas_fee_structure_item_id_feesi;
3309
+ return assignmentItemId === fee._id;
3310
+ });
3311
+ return { ...fee, is_assigned: isAssigned };
3312
+ });
3313
+ // Update checks by value, if different set signal
3314
+ // Simple optimization: check if any status changed. For now just set.
3315
+ this.applicableFees.set(updatedFees);
3316
+ this.regroupFees(updatedFees);
3317
+ }
3318
+ regroupFees(allFeeItems) {
3319
+ const groupedFees = new Map();
3320
+ allFeeItems.forEach((fee) => {
3321
+ const structureId = fee.fees_structure_id || 'unknown';
3322
+ if (!groupedFees.has(structureId)) {
3323
+ groupedFees.set(structureId, {
3324
+ structure_id: structureId,
3325
+ structure_name: fee.fees_structure_name || 'Unknown Structure',
3326
+ structure_code: fee.fees_structure_code,
3327
+ fees: [],
3328
+ total_amount: 0
3329
+ });
3330
+ }
3331
+ const group = groupedFees.get(structureId);
3332
+ group.fees.push(fee);
3333
+ group.total_amount += fee.fees_amount || 0;
3334
+ });
3335
+ const groups = Array.from(groupedFees.values());
3336
+ this.feeStructureGroups.set(groups);
3337
+ }
3338
+ getFeeStructureOptions() {
3339
+ return this.feeStructureGroups().map(group => ({
3340
+ value: group.structure_id,
3341
+ label: `${group.structure_name}${group.structure_code ? ' (' + group.structure_code + ')' : ''} - Total: ${this.currencyPipe.transform(group.total_amount, 'INR')}`
3342
+ }));
3343
+ }
3344
+ getSelectedFeeStructureFees() {
3345
+ const selectedId = this.selectedFeeStructureId();
3346
+ if (!selectedId)
3347
+ return [];
3348
+ // Return fees filtered by selected structure
3349
+ const fees = this.applicableFees().filter(f => f.fees_structure_id === selectedId);
3350
+ return fees;
3351
+ }
3352
+ getFeeId(fee) {
3353
+ return fee._id || '';
3354
+ }
3355
+ // --- Calculations ---
3356
+ getDiscountData(feeId) {
3357
+ return this.feeDiscountScholarshipData().get(feeId)?.discount;
3358
+ }
3359
+ getScholarshipData(feeId) {
3360
+ return this.feeDiscountScholarshipData().get(feeId)?.scholarship;
3361
+ }
3362
+ calculateFinalAmount(fee) {
3363
+ const feeId = this.getFeeId(fee);
3364
+ const originalAmount = fee.fees_amount || 0;
3365
+ const discountData = this.getDiscountData(feeId);
3366
+ const scholarshipData = this.getScholarshipData(feeId);
3367
+ let discountAmount = 0;
3368
+ if (discountData) {
3369
+ discountAmount = discountData.discount_amount;
3370
+ }
3371
+ let scholarshipAmount = 0;
3372
+ if (scholarshipData) {
3373
+ scholarshipAmount = scholarshipData.scholarship_amount;
3374
+ }
3375
+ return Math.max(0, originalAmount - discountAmount - scholarshipAmount);
3376
+ }
3377
+ // Totals for current selection
3378
+ totalOriginalAmount = computed(() => {
3379
+ return this.getSelectedFeeStructureFees().reduce((sum, fee) => sum + (fee.fees_amount || 0), 0);
3380
+ }, ...(ngDevMode ? [{ debugName: "totalOriginalAmount" }] : []));
3381
+ totalDiscount = computed(() => {
3382
+ return this.getSelectedFeeStructureFees().reduce((sum, fee) => {
3383
+ const discount = this.getDiscountData(this.getFeeId(fee));
3384
+ return sum + (discount?.discount_amount || 0);
3385
+ }, 0);
3386
+ }, ...(ngDevMode ? [{ debugName: "totalDiscount" }] : []));
3387
+ totalScholarship = computed(() => {
3388
+ return this.getSelectedFeeStructureFees().reduce((sum, fee) => {
3389
+ const scholarship = this.getScholarshipData(this.getFeeId(fee));
3390
+ return sum + (scholarship?.scholarship_amount || 0);
3391
+ }, 0);
3392
+ }, ...(ngDevMode ? [{ debugName: "totalScholarship" }] : []));
3393
+ totalFinalAmount = computed(() => {
3394
+ return this.getSelectedFeeStructureFees().reduce((sum, fee) => sum + this.calculateFinalAmount(fee), 0);
3395
+ }, ...(ngDevMode ? [{ debugName: "totalFinalAmount" }] : []));
3396
+ // --- Actions ---
3397
+ async openDiscountManagement(feeId) {
3398
+ const fee = this.applicableFees().find(f => this.getFeeId(f) === feeId);
3399
+ if (!fee)
3400
+ return;
3401
+ // Ensure component is registered
3402
+ if (!this.floatingContainerService.isComponentRegistered('fee-discount-form')) {
3403
+ await this.registerFloatingContainerComponents();
3404
+ }
3405
+ const currentDiscount = this.getDiscountData(feeId);
3406
+ const containerId = this.floatingContainerService.show({
3407
+ id: `discount-form-${feeId}-${Date.now()}`,
3408
+ title: currentDiscount ? 'Edit Discount' : 'Add Discount',
3409
+ icon: 'local_offer',
3410
+ width: '500px',
3411
+ height: '600px',
3412
+ minWidth: '400px',
3413
+ minHeight: '400px',
3414
+ maxWidth: '90vw',
3415
+ maxHeight: '90vh',
3416
+ resizable: true,
3417
+ draggable: true,
3418
+ closable: true,
3419
+ minimizable: true,
3420
+ maximizable: true,
3421
+ backdrop: false,
3422
+ componentId: 'fee-discount-form',
3423
+ componentConfig: {
3424
+ inputs: {
3425
+ feeId: signal(feeId),
3426
+ feeName: signal(fee.fees_structure_name || 'Fee'),
3427
+ feeAmount: signal(fee.fees_amount || 0),
3428
+ existingDiscount: signal(currentDiscount),
3429
+ discountReasonOptions: signal(this.getDiscountReasonOptions()) // We need to check if this method exists or needs adding
3430
+ },
3431
+ outputs: {
3432
+ saved: (result) => {
3433
+ this.applyDiscount(feeId, result, fee.fees_amount || 0);
3434
+ this.floatingContainerService.hide(containerId);
3435
+ },
3436
+ cancelled: () => {
3437
+ this.floatingContainerService.hide(containerId);
3438
+ }
3439
+ }
3440
+ }
3441
+ });
3442
+ this.floatingContainerService.bringToFront(containerId);
3443
+ }
3444
+ removeDiscount(feeId) {
3445
+ this.updateFeeData(feeId, { discount: undefined });
3446
+ }
3447
+ async openScholarshipManagement(feeId) {
3448
+ const fee = this.applicableFees().find(f => this.getFeeId(f) === feeId);
3449
+ if (!fee)
3450
+ return;
3451
+ // Ensure component is registered
3452
+ if (!this.floatingContainerService.isComponentRegistered('fee-scholarship-form')) {
3453
+ await this.registerFloatingContainerComponents();
3454
+ }
3455
+ const currentScholarship = this.getScholarshipData(feeId);
3456
+ const containerId = this.floatingContainerService.show({
3457
+ id: `scholarship-form-${feeId}-${Date.now()}`,
3458
+ title: currentScholarship ? 'Edit Scholarship' : 'Add Scholarship',
3459
+ icon: 'school',
3460
+ width: '500px',
3461
+ height: '650px',
3462
+ minWidth: '400px',
3463
+ minHeight: '450px',
3464
+ maxWidth: '90vw',
3465
+ maxHeight: '90vh',
3466
+ resizable: true,
3467
+ draggable: true,
3468
+ closable: true,
3469
+ minimizable: true,
3470
+ maximizable: true,
3471
+ backdrop: false,
3472
+ componentId: 'fee-scholarship-form',
3473
+ componentConfig: {
3474
+ inputs: {
3475
+ feeId: signal(feeId),
3476
+ feeName: signal(fee.fees_structure_name || 'Fee'),
3477
+ feeAmount: signal(fee.fees_amount || 0),
3478
+ existingScholarship: signal(currentScholarship),
3479
+ scholarshipTypeOptions: signal(this.getScholarshipTypeOptions()) // We need to check if this method exists or needs adding
3480
+ },
3481
+ outputs: {
3482
+ saved: (result) => {
3483
+ this.applyScholarship(feeId, result, fee.fees_amount || 0);
3484
+ this.floatingContainerService.hide(containerId);
3485
+ },
3486
+ cancelled: () => {
3487
+ this.floatingContainerService.hide(containerId);
3488
+ }
3489
+ }
3490
+ }
3491
+ });
3492
+ this.floatingContainerService.bringToFront(containerId);
3493
+ }
3494
+ removeScholarship(feeId) {
3495
+ this.updateFeeData(feeId, { scholarship: undefined });
3496
+ }
3497
+ applyDiscount(feeId, data, feeAmount) {
3498
+ let discountAmount = 0;
3499
+ if (data.discount_type === 'PERCENTAGE') {
3500
+ discountAmount = (feeAmount * data.discount_value) / 100;
3501
+ }
3502
+ else {
3503
+ discountAmount = data.discount_value;
3504
+ }
3505
+ // Cap at fee amount
3506
+ discountAmount = Math.min(discountAmount, feeAmount);
3507
+ const discountData = {
3508
+ fee_id: feeId,
3509
+ discount_type: data.discount_type,
3510
+ discount_value: data.discount_value,
3511
+ discount_amount: discountAmount,
3512
+ discount_reason_id: data.discount_reason_id,
3513
+ notes: data.notes
3514
+ };
3515
+ this.updateFeeData(feeId, { discount: discountData });
3516
+ }
3517
+ applyScholarship(feeId, data, feeAmount) {
3518
+ let scholarshipAmount = 0;
3519
+ if (data.scholarship_category === 'FULL') {
3520
+ scholarshipAmount = feeAmount;
3521
+ }
3522
+ else if (data.scholarship_category === 'PARTIAL' && data.scholarship_percentage) {
3523
+ scholarshipAmount = (feeAmount * data.scholarship_percentage) / 100;
3524
+ }
3525
+ else {
3526
+ scholarshipAmount = data.scholarship_amount || 0;
3527
+ }
3528
+ // Cap at fee amount (considering discount?)
3529
+ scholarshipAmount = Math.min(scholarshipAmount, feeAmount);
3530
+ const scholarshipData = {
3531
+ fee_id: feeId,
3532
+ scholarship_type_id: data.scholarship_type_id,
3533
+ scholarship_category: data.scholarship_category,
3534
+ scholarship_percentage: data.scholarship_percentage,
3535
+ scholarship_amount: scholarshipAmount,
3536
+ notes: data.notes
3537
+ };
3538
+ this.updateFeeData(feeId, { scholarship: scholarshipData });
3539
+ }
3540
+ updateFeeData(feeId, changes) {
3541
+ const currentMap = this.feeDiscountScholarshipData();
3542
+ const currentData = currentMap.get(feeId) || {};
3543
+ const newData = {
3544
+ ...currentData,
3545
+ ...changes
3546
+ };
3547
+ if (!newData.discount && !newData.scholarship) {
3548
+ currentMap.delete(feeId);
3549
+ }
3550
+ else {
3551
+ currentMap.set(feeId, newData);
3552
+ }
3553
+ this.feeDiscountScholarshipData.set(new Map(currentMap));
3554
+ this.emitFeeData();
3555
+ }
3556
+ emitFeeData() {
3557
+ const fees = this.getSelectedFeeStructureFees();
3558
+ // Enrich with calculated values
3559
+ const enrichedFees = fees.map(f => {
3560
+ const feeId = this.getFeeId(f);
3561
+ const discount = this.getDiscountData(feeId)?.discount_amount || 0;
3562
+ const scholarship = this.getScholarshipData(feeId)?.scholarship_amount || 0;
3563
+ return {
3564
+ ...f,
3565
+ discount: discount,
3566
+ scholarship: scholarship,
3567
+ final_amount: this.calculateFinalAmount(f)
3568
+ };
3569
+ });
3570
+ this.feesCalculated.emit({
3571
+ fees: enrichedFees,
3572
+ totalOriginal: this.totalOriginalAmount(),
3573
+ totalDiscount: this.totalDiscount(),
3574
+ totalScholarship: this.totalScholarship(),
3575
+ totalFinal: this.totalFinalAmount(),
3576
+ structureId: this.selectedFeeStructureId()
3577
+ });
3578
+ }
3579
+ // --- Insights / Detailed View ---
3580
+ // --- Insights / Detailed View ---
3581
+ async viewFeeDetails(fee) {
3582
+ const feeData = this.getFeeDataForViewer(fee);
3583
+ if (!feeData)
3584
+ return;
3585
+ // Ensure component is registered
3586
+ if (!this.floatingContainerService.isComponentRegistered('fee-details-viewer')) {
3587
+ await this.registerFloatingContainerComponents();
3588
+ }
3589
+ const containerId = this.floatingContainerService.show({
3590
+ id: `fee-details-${fee._id}-${Date.now()}`,
3591
+ title: `Complete Fee Details - ${feeData.fees_structure_name || 'Fee'}`,
3592
+ icon: 'receipt_long',
3593
+ width: '750px',
3594
+ height: '700px',
3595
+ minWidth: '600px',
3596
+ minHeight: '500px',
3597
+ maxWidth: '90vw',
3598
+ maxHeight: '90vh',
3599
+ resizable: true,
3600
+ draggable: true,
3601
+ closable: true,
3602
+ minimizable: true,
3603
+ maximizable: true,
3604
+ backdrop: false,
3605
+ componentId: 'fee-details-viewer',
3606
+ componentConfig: {
3607
+ inputs: {
3608
+ isOpen: signal(true),
3609
+ feeData: signal(feeData),
3610
+ assignmentDate: signal(new Date()),
3611
+ discount: signal(feeData.discount || 0)
3612
+ },
3613
+ outputs: {
3614
+ closed: () => {
3615
+ this.floatingContainerService.hide(containerId);
3616
+ }
3617
+ }
3618
+ }
3619
+ });
3620
+ this.floatingContainerService.bringToFront(containerId);
3621
+ }
3622
+ // Helper methods for viewer
3623
+ getFeeDataForViewer(fee) {
3624
+ if (!fee)
3625
+ return null;
3626
+ const feeId = this.getFeeId(fee);
3627
+ const originalAmount = fee.fees_amount || 0;
3628
+ const discountData = this.getDiscountData(feeId);
3629
+ const discountAmount = discountData?.discount_amount || 0;
3630
+ const finalAmount = this.calculateFinalAmount(fee);
3631
+ // Get the original fee item data
3632
+ let feeItemData = fee._feeItemData;
3633
+ // If _feeItemData is missing or empty, construct a robust fallback to prevent viewer errors
3634
+ if (!feeItemData || Object.keys(feeItemData).length === 0) {
3635
+ feeItemData = {
3636
+ feesi_item_name: fee.fees_structure_name || 'N/A',
3637
+ feesi_item_code: fee.fees_structure_code || 'N/A',
3638
+ feesi_amount: originalAmount,
3639
+ feesi_description: 'No description available',
3640
+ feesi_category_id_sygms: null,
3641
+ feesi_is_mandatory: false,
3642
+ feesi_is_refundable: false,
3643
+ feesi_is_amount_editable: false,
3644
+ feesi_is_installment_allowed: false,
3645
+ feesi_installment_count: 1,
3646
+ feesi_due_date_offset_days: 0,
3647
+ feesi_collection_start_offset_days: 0,
3648
+ feesi_collection_end_offset_days: 30,
3649
+ feesi_tax_applicable: false,
3650
+ feesi_tax_percentage: 0,
3651
+ feesi_display_order: 0
3652
+ };
3653
+ }
3654
+ else {
3655
+ // Ensure essential fields exist even if _feeItemData is partial
3656
+ feeItemData.feesi_item_name = feeItemData.feesi_item_name || fee.fees_structure_name || 'N/A';
3657
+ feeItemData.feesi_amount = feeItemData.feesi_amount ?? originalAmount;
3658
+ }
3659
+ return {
3660
+ _id: fee._id,
3661
+ fees_structure_name: fee.fees_structure_name || 'N/A',
3662
+ fees_structure_code: fee.fees_structure_code || 'N/A',
3663
+ fees_category_name: fee.fees_category_name || 'N/A',
3664
+ fees_amount: originalAmount,
3665
+ fees_total_amount: originalAmount,
3666
+ discount: discountAmount,
3667
+ finalAmount: finalAmount,
3668
+ _feeItemData: feeItemData
3669
+ };
3670
+ }
3671
+ // Stub methods for missing service calls (since we don't have GeneralMasterService here yet)
3672
+ // These should ideally load from an API or service
3673
+ getDiscountReasonOptions() {
3674
+ return [];
3675
+ }
3676
+ getScholarshipTypeOptions() {
3677
+ return [];
3678
+ }
3679
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeApplicableFeesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3680
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FeeApplicableFeesComponent, isStandalone: true, selector: "cide-fee-applicable-fees", inputs: { entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: false, transformFunction: null }, academicYearId: { classPropertyName: "academicYearId", publicName: "academicYearId", isSignal: true, isRequired: false, transformFunction: null }, classProgramId: { classPropertyName: "classProgramId", publicName: "classProgramId", isSignal: true, isRequired: false, transformFunction: null }, termId: { classPropertyName: "termId", publicName: "termId", isSignal: true, isRequired: false, transformFunction: null }, branchId: { classPropertyName: "branchId", publicName: "branchId", isSignal: true, isRequired: false, transformFunction: null }, sectionId: { classPropertyName: "sectionId", publicName: "sectionId", isSignal: true, isRequired: false, transformFunction: null }, studentId: { classPropertyName: "studentId", publicName: "studentId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { feesCalculated: "feesCalculated" }, providers: [CurrencyPipe], ngImport: i0, template: "<div class=\"tw-w-full\">\r\n <!-- Loading State -->\r\n @if (loading()) {\r\n <div class=\"tw-text-center tw-py-6 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-gray-400 tw-animate-spin tw-mx-auto tw-mb-2\">refresh</cide-ele-icon>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Loading applicable fees...</span>\r\n </div>\r\n } @else if (applicableFees().length > 0) {\r\n <!-- Fee Structure Selection (if multiple structures) -->\r\n @if (feeStructureGroups().length > 1) {\r\n <div class=\"tw-mb-3 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <label class=\"tw-text-xs tw-font-semibold tw-text-gray-700 tw-mb-2 tw-block\">Select Fee Structure</label>\r\n <cide-ele-select [options]=\"getFeeStructureOptions()\" [ngModel]=\"selectedFeeStructureId() || ''\"\r\n (ngModelChange)=\"onStructureChange($event)\" placeholder=\"Select a fee structure\">\r\n </cide-ele-select>\r\n </div>\r\n }\r\n\r\n <!-- Fee Items Table -->\r\n @if (getSelectedFeeStructureFees().length > 0) {\r\n <div class=\"tw-overflow-x-auto tw-rounded-lg tw-border tw-border-gray-200\">\r\n <table class=\"tw-min-w-full tw-divide-y tw-divide-gray-200 tw-bg-white\">\r\n <thead class=\"tw-bg-gray-50\">\r\n <tr>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-min-w-[250px]\">\r\n Fee Name</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-whitespace-nowrap\">\r\n Category</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-whitespace-nowrap tw-min-w-[120px]\">\r\n Original Amount</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-min-w-[160px]\">\r\n Discount</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-min-w-[160px]\">\r\n Scholarship</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-whitespace-nowrap tw-min-w-[120px]\">\r\n Final Amount</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-w-[80px]\">\r\n Actions</th>\r\n </tr>\r\n </thead>\r\n <tbody class=\"tw-bg-white tw-divide-y tw-divide-gray-200\">\r\n @for (fee of getSelectedFeeStructureFees(); track fee._id) {\r\n <tr class=\"tw-bg-white hover:tw-bg-gray-50 tw-transition-colors\">\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-medium tw-text-gray-900 tw-bg-white\">\r\n {{ fee.fees_structure_name || 'N/A' }}\r\n @if (fee.fees_structure_code) {\r\n <span class=\"tw-text-gray-500 tw-ms-1\">({{ fee.fees_structure_code }})</span>\r\n }\r\n @if (fee.is_assigned) {\r\n <span\r\n class=\"tw-ml-2 tw-px-2 tw-py-0.5 tw-bg-yellow-100 tw-text-yellow-800 tw-text-xs tw-font-semibold tw-rounded-full\">\r\n Assigned\r\n </span>\r\n }\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-text-gray-600 tw-bg-white\">{{ fee.fees_category_name ||\r\n 'N/A' }}</td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-text-gray-900 tw-text-right tw-font-medium tw-bg-white\">{{\r\n fee.fees_amount | currency }}</td>\r\n <td class=\"tw-px-4 tw-py-3 tw-bg-white\">\r\n @if (getDiscountData(getFeeId(fee)); as discount) {\r\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-justify-end\">\r\n <span class=\"tw-text-xs tw-text-gray-600\">\r\n {{ discount.discount_amount | currency }}\r\n @if (discount.discount_type === 'PERCENTAGE') {\r\n <span class=\"tw-text-gray-400\">({{ discount.discount_value }}%)</span>\r\n }\r\n </span>\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"xs\"\r\n (click)=\"openDiscountManagement(getFeeId(fee))\" title=\"Edit Discount\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">edit</cide-ele-icon>\r\n </button>\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"xs\"\r\n (click)=\"removeDiscount(getFeeId(fee))\" title=\"Remove Discount\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">close</cide-ele-icon>\r\n </button>\r\n </div>\r\n } @else {\r\n <button type=\"button\" cideEleButton variant=\"outline\" size=\"xs\"\r\n (click)=\"openDiscountManagement(getFeeId(fee))\" class=\"tw-ml-auto\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">add</cide-ele-icon>\r\n Add Discount\r\n </button>\r\n }\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-bg-white\">\r\n @if (getScholarshipData(getFeeId(fee)); as scholarship) {\r\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-justify-end\">\r\n <span class=\"tw-text-xs tw-text-gray-600\">\r\n {{ scholarship.scholarship_amount | currency }}\r\n @if (scholarship.scholarship_category === 'PARTIAL' &&\r\n scholarship.scholarship_percentage) {\r\n <span class=\"tw-text-gray-400\">({{ scholarship.scholarship_percentage }}%)</span>\r\n } @else if (scholarship.scholarship_category === 'FULL') {\r\n <span class=\"tw-text-gray-400\">(Full)</span>\r\n }\r\n </span>\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"xs\"\r\n (click)=\"openScholarshipManagement(getFeeId(fee))\" title=\"Edit Scholarship\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">edit</cide-ele-icon>\r\n </button>\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"xs\"\r\n (click)=\"removeScholarship(getFeeId(fee))\" title=\"Remove Scholarship\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">close</cide-ele-icon>\r\n </button>\r\n </div>\r\n } @else {\r\n <button type=\"button\" cideEleButton variant=\"outline\" size=\"xs\"\r\n (click)=\"openScholarshipManagement(getFeeId(fee))\" class=\"tw-ml-auto\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">add</cide-ele-icon>\r\n Add Scholarship\r\n </button>\r\n }\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-semibold tw-text-gray-900 tw-text-right tw-bg-white\">\r\n {{ calculateFinalAmount(fee) | currency }}\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-center tw-bg-white\">\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"sm\" (click)=\"viewFeeDetails(fee)\"\r\n title=\"View Details\">\r\n <cide-ele-icon>visibility</cide-ele-icon>\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n <tfoot class=\"tw-bg-gray-50 tw-border-t-2 tw-border-gray-200\">\r\n <tr>\r\n <td colspan=\"3\" class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-bold tw-text-gray-900 tw-text-right\">\r\n Total:</td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-bold tw-text-blue-600 tw-text-right\">\r\n {{ totalDiscount() | currency }}\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-bold tw-text-purple-600 tw-text-right\">\r\n {{ totalScholarship() | currency }}\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-base tw-font-bold tw-text-green-600 tw-text-right\">\r\n {{ totalFinalAmount() | currency }}\r\n </td>\r\n <td></td>\r\n </tr>\r\n </tfoot>\r\n </table>\r\n </div>\r\n } @else {\r\n <div class=\"tw-text-center tw-py-6 tw-bg-white tw-rounded-lg tw-border-2 tw-border-dashed tw-border-gray-200\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400 tw-mx-auto tw-mb-2\">account_balance</cide-ele-icon>\r\n <p class=\"tw-text-sm tw-text-gray-600\">No fees available for selected structure.</p>\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"tw-text-center tw-py-6 tw-bg-white tw-rounded-lg tw-border-2 tw-border-dashed tw-border-gray-200\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400 tw-mx-auto tw-mb-2\">search_off</cide-ele-icon>\r\n <p class=\"tw-text-sm tw-text-gray-600\">No applicable fees found.</p>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">Please ensure Class Program, Term, and Academic Year are\r\n selected.</p>\r\n </div>\r\n }\r\n</div>", styles: [":host{display:block}.fee-structure-select-container{max-width:400px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "pipe", type: i1.CurrencyPipe, name: "currency" }] });
3681
+ }
3682
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeApplicableFeesComponent, decorators: [{
3683
+ type: Component,
3684
+ args: [{ selector: 'cide-fee-applicable-fees', standalone: true, imports: [
3685
+ CommonModule,
3686
+ FormsModule,
3687
+ ReactiveFormsModule,
3688
+ CideIconComponent,
3689
+ CideEleButtonComponent,
3690
+ CideSelectComponent,
3691
+ CurrencyPipe,
3692
+ // FeeDetailsViewerComponent
3693
+ ], providers: [CurrencyPipe], template: "<div class=\"tw-w-full\">\r\n <!-- Loading State -->\r\n @if (loading()) {\r\n <div class=\"tw-text-center tw-py-6 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-gray-400 tw-animate-spin tw-mx-auto tw-mb-2\">refresh</cide-ele-icon>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Loading applicable fees...</span>\r\n </div>\r\n } @else if (applicableFees().length > 0) {\r\n <!-- Fee Structure Selection (if multiple structures) -->\r\n @if (feeStructureGroups().length > 1) {\r\n <div class=\"tw-mb-3 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <label class=\"tw-text-xs tw-font-semibold tw-text-gray-700 tw-mb-2 tw-block\">Select Fee Structure</label>\r\n <cide-ele-select [options]=\"getFeeStructureOptions()\" [ngModel]=\"selectedFeeStructureId() || ''\"\r\n (ngModelChange)=\"onStructureChange($event)\" placeholder=\"Select a fee structure\">\r\n </cide-ele-select>\r\n </div>\r\n }\r\n\r\n <!-- Fee Items Table -->\r\n @if (getSelectedFeeStructureFees().length > 0) {\r\n <div class=\"tw-overflow-x-auto tw-rounded-lg tw-border tw-border-gray-200\">\r\n <table class=\"tw-min-w-full tw-divide-y tw-divide-gray-200 tw-bg-white\">\r\n <thead class=\"tw-bg-gray-50\">\r\n <tr>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-min-w-[250px]\">\r\n Fee Name</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-whitespace-nowrap\">\r\n Category</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-whitespace-nowrap tw-min-w-[120px]\">\r\n Original Amount</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-min-w-[160px]\">\r\n Discount</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-min-w-[160px]\">\r\n Scholarship</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-whitespace-nowrap tw-min-w-[120px]\">\r\n Final Amount</th>\r\n <th\r\n class=\"tw-px-4 tw-py-3 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700 tw-uppercase tw-tracking-wider tw-border-b tw-border-gray-200 tw-w-[80px]\">\r\n Actions</th>\r\n </tr>\r\n </thead>\r\n <tbody class=\"tw-bg-white tw-divide-y tw-divide-gray-200\">\r\n @for (fee of getSelectedFeeStructureFees(); track fee._id) {\r\n <tr class=\"tw-bg-white hover:tw-bg-gray-50 tw-transition-colors\">\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-medium tw-text-gray-900 tw-bg-white\">\r\n {{ fee.fees_structure_name || 'N/A' }}\r\n @if (fee.fees_structure_code) {\r\n <span class=\"tw-text-gray-500 tw-ms-1\">({{ fee.fees_structure_code }})</span>\r\n }\r\n @if (fee.is_assigned) {\r\n <span\r\n class=\"tw-ml-2 tw-px-2 tw-py-0.5 tw-bg-yellow-100 tw-text-yellow-800 tw-text-xs tw-font-semibold tw-rounded-full\">\r\n Assigned\r\n </span>\r\n }\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-text-gray-600 tw-bg-white\">{{ fee.fees_category_name ||\r\n 'N/A' }}</td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-text-gray-900 tw-text-right tw-font-medium tw-bg-white\">{{\r\n fee.fees_amount | currency }}</td>\r\n <td class=\"tw-px-4 tw-py-3 tw-bg-white\">\r\n @if (getDiscountData(getFeeId(fee)); as discount) {\r\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-justify-end\">\r\n <span class=\"tw-text-xs tw-text-gray-600\">\r\n {{ discount.discount_amount | currency }}\r\n @if (discount.discount_type === 'PERCENTAGE') {\r\n <span class=\"tw-text-gray-400\">({{ discount.discount_value }}%)</span>\r\n }\r\n </span>\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"xs\"\r\n (click)=\"openDiscountManagement(getFeeId(fee))\" title=\"Edit Discount\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">edit</cide-ele-icon>\r\n </button>\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"xs\"\r\n (click)=\"removeDiscount(getFeeId(fee))\" title=\"Remove Discount\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">close</cide-ele-icon>\r\n </button>\r\n </div>\r\n } @else {\r\n <button type=\"button\" cideEleButton variant=\"outline\" size=\"xs\"\r\n (click)=\"openDiscountManagement(getFeeId(fee))\" class=\"tw-ml-auto\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">add</cide-ele-icon>\r\n Add Discount\r\n </button>\r\n }\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-bg-white\">\r\n @if (getScholarshipData(getFeeId(fee)); as scholarship) {\r\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-justify-end\">\r\n <span class=\"tw-text-xs tw-text-gray-600\">\r\n {{ scholarship.scholarship_amount | currency }}\r\n @if (scholarship.scholarship_category === 'PARTIAL' &&\r\n scholarship.scholarship_percentage) {\r\n <span class=\"tw-text-gray-400\">({{ scholarship.scholarship_percentage }}%)</span>\r\n } @else if (scholarship.scholarship_category === 'FULL') {\r\n <span class=\"tw-text-gray-400\">(Full)</span>\r\n }\r\n </span>\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"xs\"\r\n (click)=\"openScholarshipManagement(getFeeId(fee))\" title=\"Edit Scholarship\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">edit</cide-ele-icon>\r\n </button>\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"xs\"\r\n (click)=\"removeScholarship(getFeeId(fee))\" title=\"Remove Scholarship\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">close</cide-ele-icon>\r\n </button>\r\n </div>\r\n } @else {\r\n <button type=\"button\" cideEleButton variant=\"outline\" size=\"xs\"\r\n (click)=\"openScholarshipManagement(getFeeId(fee))\" class=\"tw-ml-auto\">\r\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">add</cide-ele-icon>\r\n Add Scholarship\r\n </button>\r\n }\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-semibold tw-text-gray-900 tw-text-right tw-bg-white\">\r\n {{ calculateFinalAmount(fee) | currency }}\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-center tw-bg-white\">\r\n <button type=\"button\" cideEleButton variant=\"ghost\" size=\"sm\" (click)=\"viewFeeDetails(fee)\"\r\n title=\"View Details\">\r\n <cide-ele-icon>visibility</cide-ele-icon>\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n <tfoot class=\"tw-bg-gray-50 tw-border-t-2 tw-border-gray-200\">\r\n <tr>\r\n <td colspan=\"3\" class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-bold tw-text-gray-900 tw-text-right\">\r\n Total:</td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-bold tw-text-blue-600 tw-text-right\">\r\n {{ totalDiscount() | currency }}\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-sm tw-font-bold tw-text-purple-600 tw-text-right\">\r\n {{ totalScholarship() | currency }}\r\n </td>\r\n <td class=\"tw-px-4 tw-py-3 tw-text-base tw-font-bold tw-text-green-600 tw-text-right\">\r\n {{ totalFinalAmount() | currency }}\r\n </td>\r\n <td></td>\r\n </tr>\r\n </tfoot>\r\n </table>\r\n </div>\r\n } @else {\r\n <div class=\"tw-text-center tw-py-6 tw-bg-white tw-rounded-lg tw-border-2 tw-border-dashed tw-border-gray-200\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400 tw-mx-auto tw-mb-2\">account_balance</cide-ele-icon>\r\n <p class=\"tw-text-sm tw-text-gray-600\">No fees available for selected structure.</p>\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"tw-text-center tw-py-6 tw-bg-white tw-rounded-lg tw-border-2 tw-border-dashed tw-border-gray-200\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400 tw-mx-auto tw-mb-2\">search_off</cide-ele-icon>\r\n <p class=\"tw-text-sm tw-text-gray-600\">No applicable fees found.</p>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">Please ensure Class Program, Term, and Academic Year are\r\n selected.</p>\r\n </div>\r\n }\r\n</div>", styles: [":host{display:block}.fee-structure-select-container{max-width:400px}\n"] }]
3694
+ }], ctorParameters: () => [], propDecorators: { entityId: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityId", required: false }] }], academicYearId: [{ type: i0.Input, args: [{ isSignal: true, alias: "academicYearId", required: false }] }], classProgramId: [{ type: i0.Input, args: [{ isSignal: true, alias: "classProgramId", required: false }] }], termId: [{ type: i0.Input, args: [{ isSignal: true, alias: "termId", required: false }] }], branchId: [{ type: i0.Input, args: [{ isSignal: true, alias: "branchId", required: false }] }], sectionId: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionId", required: false }] }], studentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "studentId", required: false }] }], feesCalculated: [{ type: i0.Output, args: ["feesCalculated"] }] } });
3695
+
2991
3696
  class FeeAssignmentCreateComponent {
2992
3697
  destroyRef = inject(DestroyRef);
2993
3698
  fb = inject(FormBuilder);
@@ -3001,6 +3706,7 @@ class FeeAssignmentCreateComponent {
3001
3706
  feeAssignmentService = inject(CideFeeFeeAssignmentService);
3002
3707
  userMasterService = inject(CideCoreUserMasterService);
3003
3708
  componentContextService = inject(ComponentContextService);
3709
+ appStateService = inject(AppStateService);
3004
3710
  assignmentForm;
3005
3711
  loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
3006
3712
  submitting = signal(false, ...(ngDevMode ? [{ debugName: "submitting" }] : []));
@@ -3010,16 +3716,13 @@ class FeeAssignmentCreateComponent {
3010
3716
  // Breadcrumb data for shared wrapper
3011
3717
  breadcrumbData = signal([], ...(ngDevMode ? [{ debugName: "breadcrumbData" }] : []));
3012
3718
  entityOptions = signal([], ...(ngDevMode ? [{ debugName: "entityOptions" }] : []));
3013
- academicYearOptions = signal([], ...(ngDevMode ? [{ debugName: "academicYearOptions" }] : []));
3014
3719
  feeStructureOptions = signal([], ...(ngDevMode ? [{ debugName: "feeStructureOptions" }] : []));
3015
3720
  entityLoading = signal(false, ...(ngDevMode ? [{ debugName: "entityLoading" }] : []));
3016
- academicYearLoading = signal(false, ...(ngDevMode ? [{ debugName: "academicYearLoading" }] : []));
3017
3721
  feeStructureLoading = signal(false, ...(ngDevMode ? [{ debugName: "feeStructureLoading" }] : []));
3018
- // Fee insights
3019
- applicableFees = signal([], ...(ngDevMode ? [{ debugName: "applicableFees" }] : []));
3020
- feesLoading = signal(false, ...(ngDevMode ? [{ debugName: "feesLoading" }] : []));
3021
- discountControls = signal(new Map(), ...(ngDevMode ? [{ debugName: "discountControls" }] : []));
3022
- scholarshipControls = signal(new Map(), ...(ngDevMode ? [{ debugName: "scholarshipControls" }] : []));
3722
+ // Fee insights - Removed old signals, now using selectedFeeItems from child component
3723
+ selectedFeeItems = signal([], ...(ngDevMode ? [{ debugName: "selectedFeeItems" }] : []));
3724
+ triggerLoad = signal(false, ...(ngDevMode ? [{ debugName: "triggerLoad" }] : [])); // Trigger for child component
3725
+ selectedStudent = signal(null, ...(ngDevMode ? [{ debugName: "selectedStudent" }] : []));
3023
3726
  feeSourceOptions = [
3024
3727
  { value: 'STRUCTURE', label: 'From Fee Structure' },
3025
3728
  { value: 'CUSTOM', label: 'Custom Fee' }
@@ -3038,16 +3741,27 @@ class FeeAssignmentCreateComponent {
3038
3741
  { value: 'ONE_TIME', label: 'One Time' },
3039
3742
  { value: 'RECURRING', label: 'Recurring' }
3040
3743
  ];
3744
+ // Create signals for form values to use in computed
3745
+ feeSource = signal('STRUCTURE', ...(ngDevMode ? [{ debugName: "feeSource" }] : []));
3746
+ originalAmount = signal(0, ...(ngDevMode ? [{ debugName: "originalAmount" }] : []));
3747
+ discountAmount = signal(0, ...(ngDevMode ? [{ debugName: "discountAmount" }] : []));
3748
+ scholarshipAmount = signal(0, ...(ngDevMode ? [{ debugName: "scholarshipAmount" }] : []));
3749
+ // Signals for Structure IDs (to ensure reactive template bindings)
3750
+ classProgramId = signal('', ...(ngDevMode ? [{ debugName: "classProgramId" }] : []));
3751
+ branchId = signal('', ...(ngDevMode ? [{ debugName: "branchId" }] : []));
3752
+ termId = signal('', ...(ngDevMode ? [{ debugName: "termId" }] : []));
3753
+ sectionId = signal('', ...(ngDevMode ? [{ debugName: "sectionId" }] : []));
3754
+ studentId = signal('', ...(ngDevMode ? [{ debugName: "studentId" }] : []));
3041
3755
  showCustomFeeFields = computed(() => {
3042
- return this.assignmentForm?.get('fee_source')?.value === 'CUSTOM';
3756
+ return this.feeSource() === 'CUSTOM';
3043
3757
  }, ...(ngDevMode ? [{ debugName: "showCustomFeeFields" }] : []));
3044
3758
  showFeeStructureField = computed(() => {
3045
- return this.assignmentForm?.get('fee_source')?.value === 'STRUCTURE';
3759
+ return this.feeSource() === 'STRUCTURE';
3046
3760
  }, ...(ngDevMode ? [{ debugName: "showFeeStructureField" }] : []));
3047
3761
  totalAmount = computed(() => {
3048
- const original = parseFloat(this.assignmentForm?.get('feeas_original_amount')?.value || '0') || 0;
3049
- const discount = parseFloat(this.assignmentForm?.get('feeas_discount_amount')?.value || '0') || 0;
3050
- const scholarship = parseFloat(this.assignmentForm?.get('feeas_scholarship_amount')?.value || '0') || 0;
3762
+ const original = this.originalAmount() || 0;
3763
+ const discount = this.discountAmount() || 0;
3764
+ const scholarship = this.scholarshipAmount() || 0;
3051
3765
  return Math.max(0, original - discount - scholarship);
3052
3766
  }, ...(ngDevMode ? [{ debugName: "totalAmount" }] : []));
3053
3767
  constructor() {
@@ -3057,7 +3771,6 @@ class FeeAssignmentCreateComponent {
3057
3771
  this.assignmentForm = this.fb.group({
3058
3772
  // Student Information
3059
3773
  student_id: ['', [Validators.required]],
3060
- student_search: [''],
3061
3774
  feeas_academic_year_id_acayr: ['', [Validators.required]],
3062
3775
  feeas_entity_id_syen: ['', [Validators.required]],
3063
3776
  // Academic Information (for fee structure loading)
@@ -3086,6 +3799,7 @@ class FeeAssignmentCreateComponent {
3086
3799
  this.assignmentForm.get('fee_source')?.valueChanges
3087
3800
  .pipe(takeUntilDestroyed(this.destroyRef))
3088
3801
  .subscribe(source => {
3802
+ this.feeSource.set(source); // Update signal
3089
3803
  if (source === 'STRUCTURE') {
3090
3804
  this.assignmentForm.get('feeas_fee_structure_id_feest')?.setValidators([Validators.required]);
3091
3805
  this.assignmentForm.get('feeas_fee_category_sygms')?.clearValidators();
@@ -3100,26 +3814,40 @@ class FeeAssignmentCreateComponent {
3100
3814
  }
3101
3815
  this.assignmentForm.updateValueAndValidity();
3102
3816
  });
3103
- // Watch for program/term/section changes to load fees
3817
+ // Update amount signals
3818
+ this.assignmentForm.get('feeas_original_amount')?.valueChanges
3819
+ .pipe(takeUntilDestroyed(this.destroyRef))
3820
+ .subscribe(val => this.originalAmount.set(parseFloat(val || '0')));
3821
+ this.assignmentForm.get('feeas_discount_amount')?.valueChanges
3822
+ .pipe(takeUntilDestroyed(this.destroyRef))
3823
+ .subscribe(val => this.discountAmount.set(parseFloat(val || '0')));
3824
+ this.assignmentForm.get('feeas_scholarship_amount')?.valueChanges
3825
+ .pipe(takeUntilDestroyed(this.destroyRef))
3826
+ .subscribe(val => this.scholarshipAmount.set(parseFloat(val || '0')));
3827
+ // Watch for program/term/section changes to update signals
3828
+ this.assignmentForm.get('class_program_id')?.valueChanges
3829
+ .pipe(takeUntilDestroyed(this.destroyRef))
3830
+ .subscribe(val => this.classProgramId.set(val || ''));
3831
+ this.assignmentForm.get('branch_id')?.valueChanges
3832
+ .pipe(takeUntilDestroyed(this.destroyRef))
3833
+ .subscribe(val => this.branchId.set(val || ''));
3104
3834
  this.assignmentForm.get('term_id')?.valueChanges
3105
3835
  .pipe(takeUntilDestroyed(this.destroyRef))
3106
- .subscribe(() => {
3107
- if (this.assignmentForm.get('fee_source')?.value === 'STRUCTURE') {
3108
- this.loadApplicableFees();
3109
- }
3110
- });
3836
+ .subscribe(val => this.termId.set(val || ''));
3111
3837
  this.assignmentForm.get('section_id')?.valueChanges
3112
3838
  .pipe(takeUntilDestroyed(this.destroyRef))
3113
- .subscribe(() => {
3114
- if (this.assignmentForm.get('fee_source')?.value === 'STRUCTURE' && this.assignmentForm.get('term_id')?.value) {
3115
- this.loadApplicableFees();
3116
- }
3117
- });
3118
- // Watch for student search changes
3119
- this.assignmentForm.get('student_search')?.valueChanges
3839
+ .subscribe(val => this.sectionId.set(val || ''));
3840
+ // Listen for student changes to update display card and signal
3841
+ this.assignmentForm.get('student_id')?.valueChanges
3120
3842
  .pipe(takeUntilDestroyed(this.destroyRef))
3121
- .subscribe((value) => {
3122
- this.onStudentSearch(value);
3843
+ .subscribe(id => {
3844
+ this.studentId.set(id || '');
3845
+ if (!id) {
3846
+ this.selectedStudent.set(null);
3847
+ }
3848
+ else {
3849
+ this.loadStudentDetails(id);
3850
+ }
3123
3851
  });
3124
3852
  }
3125
3853
  rightsService = inject(RightsService);
@@ -3159,7 +3887,12 @@ class FeeAssignmentCreateComponent {
3159
3887
  this.updateBreadcrumbData();
3160
3888
  }
3161
3889
  loadDropdownOptions() {
3162
- // Load entity options
3890
+ const entityId = this.appStateService.getActiveEntityValue()?._id;
3891
+ // Set entity ID in form
3892
+ if (entityId) {
3893
+ this.assignmentForm.patchValue({ feeas_entity_id_syen: entityId });
3894
+ }
3895
+ // Load entity options (optional, mainly for admin reference)
3163
3896
  this.entityLoading.set(true);
3164
3897
  this.entityService.getEntityList({}).subscribe({
3165
3898
  next: (response) => {
@@ -3173,31 +3906,22 @@ class FeeAssignmentCreateComponent {
3173
3906
  }
3174
3907
  });
3175
3908
  // Load academic year options
3176
- this.academicYearLoading.set(true);
3177
- const academicYearPayload = {
3178
- pageIndex: 1,
3179
- pageSize: 100,
3180
- pagination: false
3181
- };
3182
- this.academicYearService.getAcademicYearList(academicYearPayload).subscribe({
3183
- next: (response) => {
3184
- if (response?.success && response.data) {
3185
- this.academicYearOptions.set(response.data);
3186
- }
3187
- this.academicYearLoading.set(false);
3188
- },
3189
- error: () => {
3190
- this.academicYearLoading.set(false);
3191
- }
3192
- });
3909
+ const academicYearId = this.appStateService.getActiveAcademicYearValue()?._id;
3910
+ if (academicYearId) {
3911
+ this.assignmentForm.patchValue({ feeas_academic_year_id_acayr: academicYearId });
3912
+ }
3193
3913
  // Load fee structure options
3194
- this.loadFeeStructures();
3914
+ this.loadFeeStructures(entityId);
3915
+ // Load student options
3916
+ this.onStudentSearch('');
3195
3917
  }
3196
- loadFeeStructures() {
3918
+ loadFeeStructures(entityId) {
3919
+ const currentEntityId = entityId || this.appStateService.getActiveEntityValue()?._id;
3197
3920
  this.feeStructureLoading.set(true);
3198
3921
  const payload = new MFeeStructure({
3199
3922
  fees_is_active: true,
3200
- pagination: false
3923
+ pagination: false,
3924
+ fees_entity_id_syen: currentEntityId
3201
3925
  });
3202
3926
  this.feeStructureService.getFeeStructureList(payload).subscribe({
3203
3927
  next: (response) => {
@@ -3214,7 +3938,8 @@ class FeeAssignmentCreateComponent {
3214
3938
  },
3215
3939
  error: (err) => {
3216
3940
  console.error('Error loading fee structures:', err);
3217
- this.notificationService.error('Failed to load fee structures');
3941
+ // Silent error or specific notification?
3942
+ // this.notificationService.error('Failed to load fee structures');
3218
3943
  this.feeStructureOptions.set([]);
3219
3944
  },
3220
3945
  complete: () => {
@@ -3233,7 +3958,7 @@ class FeeAssignmentCreateComponent {
3233
3958
  ? data.feeas_fee_structure_id_feest
3234
3959
  : data.feeas_fee_structure_id_feest?._id || '';
3235
3960
  this.assignmentForm.patchValue({
3236
- student_id: data.feeas_student_id || '',
3961
+ student_id: data.feeas_student_id_auth || '',
3237
3962
  fee_source: feeStructureId ? 'STRUCTURE' : 'CUSTOM',
3238
3963
  feeas_fee_structure_id_feest: feeStructureId || '',
3239
3964
  feeas_fee_category_sygms: data.feeas_fee_category_sygms || '',
@@ -3247,6 +3972,26 @@ class FeeAssignmentCreateComponent {
3247
3972
  feeas_installment_count: data.feeas_installment_count || 1,
3248
3973
  feeas_remarks: data.feeas_remarks || ''
3249
3974
  });
3975
+ // Populate student dropdown for edit mode
3976
+ if (data.feeas_student_id_auth) {
3977
+ let studentLabel = '';
3978
+ if (typeof data.feeas_student_id_auth === 'string') {
3979
+ studentLabel = data.feeas_student_id_auth;
3980
+ }
3981
+ else {
3982
+ studentLabel = data.feeas_student_id_auth?.name || data.feeas_student_id_auth?._id || '';
3983
+ }
3984
+ // Try to get name from admission if populated
3985
+ const admission = data.feeas_admission_id_admap;
3986
+ if (admission && (admission.admap_first_name || admission.admap_last_name)) {
3987
+ studentLabel = `${admission.admap_first_name || ''} ${admission.admap_last_name || ''}`.trim() +
3988
+ (admission.admap_application_number ? ` (${admission.admap_application_number})` : '');
3989
+ }
3990
+ this.studentListOptions.set([{
3991
+ label: studentLabel,
3992
+ value: typeof data.feeas_student_id_auth === 'string' ? data.feeas_student_id_auth : data.feeas_student_id_auth?._id || ''
3993
+ }]);
3994
+ }
3250
3995
  }
3251
3996
  },
3252
3997
  error: (err) => {
@@ -3258,283 +4003,90 @@ class FeeAssignmentCreateComponent {
3258
4003
  }
3259
4004
  });
3260
4005
  }
3261
- onStudentSearch(query) {
3262
- const searchQuery = String(query || '');
3263
- if (searchQuery.length < 3) {
3264
- this.assignmentForm.patchValue({ student_id: '' });
3265
- return;
3266
- }
3267
- this.loading.set(true);
3268
- // Search for students using user master service
4006
+ loadStudentDetails(studentId) {
3269
4007
  const payload = {
3270
- query: searchQuery,
3271
- pageIndex: 1,
3272
- pageSize: 10,
3273
- pagination: true
4008
+ _id: studentId, // Query by ID
4009
+ pagination: false,
4010
+ syenm_entity_id_syen: this.appStateService.getActiveEntityValue()?._id || '',
4011
+ syutm_user_type: 'STUDENT'
3274
4012
  };
3275
- this.userMasterService.getUserList(payload)
3276
- .pipe(takeUntilDestroyed(this.destroyRef))
3277
- .subscribe({
4013
+ this.userMasterService.getUserList(payload).subscribe({
3278
4014
  next: (response) => {
3279
4015
  if (response?.success && response?.data) {
3280
- // Filter for students only
3281
- const students = response.data.filter((user) => user.user_type_mapping?.syutm_user_type === 'STUDENT');
3282
- if (students.length === 0) {
3283
- this.notificationService.warning('No students found matching your search.');
3284
- this.assignmentForm.patchValue({ student_id: '' });
3285
- this.loading.set(false);
3286
- return;
3287
- }
3288
- // Use first matching student (or could show dropdown for multiple matches)
3289
- const student = students[0];
3290
- const studentId = student._id || '';
3291
- if (studentId) {
3292
- this.assignmentForm.patchValue({ student_id: studentId });
3293
- this.notificationService.success(`Student found: ${student.user_fullname || 'Unknown'}`);
3294
- }
3295
- else {
3296
- this.notificationService.warning('Student ID not found.');
3297
- this.assignmentForm.patchValue({ student_id: '' });
4016
+ const data = Array.isArray(response.data) ? response.data : [response.data];
4017
+ if (data.length > 0) {
4018
+ const student = data[0];
4019
+ this.selectedStudent.set({
4020
+ name: (student.admap_first_name || student.user_fullname || 'Unknown') + ' ' + (student.admap_last_name || ''),
4021
+ student_id: student.admap_student_id || student.user_type_mapping?.syutm_type_specific_id || student._id || '',
4022
+ class: student.class || 'N/A',
4023
+ section: student.section || 'N/A'
4024
+ });
3298
4025
  }
3299
4026
  }
3300
- else {
3301
- this.notificationService.warning('No students found matching your search.');
3302
- this.assignmentForm.patchValue({ student_id: '' });
3303
- }
3304
- this.loading.set(false);
3305
- },
3306
- error: (err) => {
3307
- console.error('Error searching for students:', err);
3308
- this.notificationService.error('Failed to search for students. Please try again.');
3309
- this.assignmentForm.patchValue({ student_id: '' });
3310
- this.loading.set(false);
3311
4027
  }
3312
4028
  });
3313
4029
  }
3314
- /**
3315
- * Handler for program section selector value changes
3316
- */
3317
- onProgramSectionValuesChange(values) {
3318
- if (this.assignmentForm.get('fee_source')?.value === 'STRUCTURE') {
3319
- this.loadApplicableFees();
3320
- }
3321
- }
3322
- /**
3323
- * Load applicable fees based on selected program/term/section
3324
- */
3325
- loadApplicableFees() {
3326
- const classProgramId = this.assignmentForm.get('class_program_id')?.value;
3327
- const branchId = this.assignmentForm.get('branch_id')?.value;
3328
- const programTermId = this.assignmentForm.get('term_id')?.value;
3329
- const sectionId = this.assignmentForm.get('section_id')?.value;
3330
- const entityId = this.assignmentForm.get('feeas_entity_id_syen')?.value;
3331
- const academicYearId = this.assignmentForm.get('feeas_academic_year_id_acayr')?.value;
3332
- if (!classProgramId || !programTermId || !entityId || !academicYearId) {
3333
- this.applicableFees.set([]);
3334
- return;
3335
- }
3336
- this.feesLoading.set(true);
3337
- // Build payload with all academic filters
3338
- const payloadData = {
3339
- fees_class_program_id_acacpm: classProgramId,
3340
- fees_class_program_term_id_acapt: programTermId,
3341
- fees_entity_id_syen: entityId,
3342
- fees_academic_year_id_acayr: academicYearId,
3343
- fees_is_active: true,
3344
- pagination: false,
4030
+ studentListOptions = signal([], ...(ngDevMode ? [{ debugName: "studentListOptions" }] : []));
4031
+ onStudentSearch(event) {
4032
+ const searchQuery = typeof event === 'object' ? event?.query || '' : String(event || '');
4033
+ this.loading.set(true);
4034
+ // Search for students using user master service
4035
+ const payload = {
4036
+ query: searchQuery,
3345
4037
  pageIndex: 1,
3346
- pageSize: 100
4038
+ pageSize: 50, // Increase page size for dropdown
4039
+ pagination: true,
4040
+ syenm_entity_id_syen: this.appStateService.getActiveEntityValue()?._id || '',
4041
+ syutm_user_type: 'STUDENT' // Filter by student type on backend
3347
4042
  };
3348
- // Include branch if selected
3349
- if (branchId) {
3350
- payloadData.fees_class_program_branch_id_acabrn = branchId;
3351
- }
3352
- // Include section if selected
3353
- if (sectionId) {
3354
- payloadData.fees_program_term_section_id_acapts = sectionId;
3355
- }
3356
- const payload = new MFeeStructure(payloadData);
3357
- this.feeStructureService.getFeeStructureList(payload)
4043
+ this.userMasterService.getUserList(payload)
3358
4044
  .pipe(takeUntilDestroyed(this.destroyRef))
3359
4045
  .subscribe({
3360
4046
  next: (response) => {
3361
4047
  if (response?.success && response?.data) {
3362
- const feeStructures = Array.isArray(response.data) ? response.data : [];
3363
- if (feeStructures.length === 0) {
3364
- this.applicableFees.set([]);
3365
- this.feesLoading.set(false);
3366
- return;
3367
- }
3368
- // Fetch fee items for all structures in parallel
3369
- const feeItemRequests = feeStructures.map(structure => this.feeStructureService.getFeeStructureById({ fees_id: structure._id || '' })
3370
- .pipe(takeUntilDestroyed(this.destroyRef)));
3371
- forkJoin(feeItemRequests).subscribe({
3372
- next: (responses) => {
3373
- const allFeeItems = [];
3374
- responses.forEach((itemResponse, index) => {
3375
- if (itemResponse?.success && itemResponse?.data) {
3376
- const structure = feeStructures[index];
3377
- const isFeeStructureByIdResponse = (data) => {
3378
- return data !== null && typeof data === 'object' && 'fee_structure' in data;
3379
- };
3380
- let feeItems = [];
3381
- if (isFeeStructureByIdResponse(itemResponse.data)) {
3382
- feeItems = itemResponse.data.fee_structure_items || [];
3383
- }
3384
- // Transform fee items to FeeAssignmentFeeItem format
3385
- feeItems.forEach(item => {
3386
- if (item.feesi_is_active !== false) {
3387
- let categoryName = 'N/A';
3388
- if (item.feesi_category_id_sygms) {
3389
- if (typeof item.feesi_category_id_sygms === 'object' && item.feesi_category_id_sygms !== null) {
3390
- categoryName = item.feesi_category_id_sygms?.sygms_title ||
3391
- item.feesi_category_id_sygms?.sygms_name ||
3392
- item.feesi_item_code ||
3393
- 'N/A';
3394
- }
3395
- }
3396
- else {
3397
- categoryName = item.feesi_item_code || 'N/A';
3398
- }
3399
- const feeItem = {
3400
- ...item,
3401
- fees_structure_id: structure._id,
3402
- fees_structure_name: structure.fees_structure_name || '',
3403
- fees_category_name: categoryName,
3404
- fees_amount: item.feesi_amount || 0,
3405
- fees_total_amount: item.feesi_amount || 0,
3406
- discount_amount: 0,
3407
- scholarship_amount: 0
3408
- };
3409
- allFeeItems.push(feeItem);
3410
- // Create discount and scholarship controls for each fee item
3411
- const feeId = item._id || '';
3412
- if (feeId && !this.discountControls().has(feeId)) {
3413
- const discountControl = this.fb.control(0, [Validators.min(0)]);
3414
- this.discountControls.update(map => {
3415
- const newMap = new Map(map);
3416
- newMap.set(feeId, discountControl);
3417
- return newMap;
3418
- });
3419
- this.assignmentForm.addControl(`discount_${feeId}`, discountControl);
3420
- }
3421
- if (feeId && !this.scholarshipControls().has(feeId)) {
3422
- const scholarshipControl = this.fb.control(0, [Validators.min(0)]);
3423
- this.scholarshipControls.update(map => {
3424
- const newMap = new Map(map);
3425
- newMap.set(feeId, scholarshipControl);
3426
- return newMap;
3427
- });
3428
- this.assignmentForm.addControl(`scholarship_${feeId}`, scholarshipControl);
3429
- }
3430
- }
3431
- });
3432
- }
3433
- });
3434
- this.applicableFees.set(allFeeItems);
3435
- },
3436
- error: (err) => {
3437
- console.error('Error loading fee items:', err);
3438
- this.notificationService.error('Failed to load fee items');
3439
- this.applicableFees.set([]);
3440
- },
3441
- complete: () => {
3442
- this.feesLoading.set(false);
3443
- }
4048
+ // Map results to dropdown options
4049
+ // Relaxed client-side filtering: Trust backend filtering or check if it looks like a student
4050
+ // We use the data returned by the API directly
4051
+ const options = response.data.map((user) => {
4052
+ const studentName = user.user_fullname || 'Unknown';
4053
+ const specificId = user.user_type_mapping?.syutm_type_specific_id || '';
4054
+ const userId = user._id || '';
4055
+ return {
4056
+ label: `${studentName}${specificId ? ' (' + specificId + ')' : ''}`,
4057
+ value: userId
4058
+ };
3444
4059
  });
4060
+ this.studentListOptions.set(options);
4061
+ if (options.length === 0) {
4062
+ // Optional: notification or just empty dropdown
4063
+ }
3445
4064
  }
3446
4065
  else {
3447
- this.applicableFees.set([]);
3448
- this.feesLoading.set(false);
4066
+ this.studentListOptions.set([]);
3449
4067
  }
4068
+ this.loading.set(false);
3450
4069
  },
3451
4070
  error: (err) => {
3452
- console.error('Error loading fee structures:', err);
3453
- this.notificationService.error('Failed to load fee structures');
3454
- this.applicableFees.set([]);
3455
- this.feesLoading.set(false);
4071
+ console.error('Error searching for students:', err);
4072
+ this.studentListOptions.set([]);
4073
+ this.loading.set(false);
3456
4074
  }
3457
4075
  });
3458
4076
  }
3459
4077
  /**
3460
- * Get discount control for a fee item
3461
- */
3462
- getDiscountControl(feeId) {
3463
- return this.discountControls().get(feeId) || this.fb.control(0);
3464
- }
3465
- /**
3466
- * Get scholarship control for a fee item
3467
- */
3468
- getScholarshipControl(feeId) {
3469
- return this.scholarshipControls().get(feeId) || this.fb.control(0);
3470
- }
3471
- /**
3472
- * Get fee ID for tracking
3473
- */
3474
- getFeeId(fee) {
3475
- return fee._id || '';
3476
- }
3477
- /**
3478
- * Get fee name
3479
- */
3480
- getFeeName(fee) {
3481
- return fee.feesi_item_name || fee.feesi_item_code || 'N/A';
3482
- }
3483
- /**
3484
- * Get fee category
3485
- */
3486
- getFeeCategory(fee) {
3487
- return fee.fees_category_name || 'N/A';
3488
- }
3489
- /**
3490
- * Get fee amount
4078
+ * Handler for program section selector value changes
4079
+ * Note: We don't trigger load here anymore as form value changes drive the signals
3491
4080
  */
3492
- getFeeAmount(fee) {
3493
- return fee.fees_amount || fee.fees_total_amount || 0;
4081
+ onProgramSectionValuesChange(values) {
4082
+ // No-op: Signals handle reactivity now
3494
4083
  }
3495
- /**
3496
- * Calculate final amount for a fee item
3497
- */
3498
- calculateFinalAmount(fee) {
3499
- const original = this.getFeeAmount(fee);
3500
- const discount = parseFloat(this.getDiscountControl(this.getFeeId(fee))?.value || '0') || 0;
3501
- const scholarship = parseFloat(this.getScholarshipControl(this.getFeeId(fee))?.value || '0') || 0;
3502
- return Math.max(0, original - discount - scholarship);
4084
+ onFeesCalculated(data) {
4085
+ this.selectedFeeItems.set(data.fees);
3503
4086
  }
3504
4087
  /**
3505
- * Calculate total original amount
3506
- */
3507
- totalOriginalAmount = computed(() => {
3508
- return this.applicableFees().reduce((sum, fee) => {
3509
- return sum + this.getFeeAmount(fee);
3510
- }, 0);
3511
- }, ...(ngDevMode ? [{ debugName: "totalOriginalAmount" }] : []));
3512
- /**
3513
- * Calculate total discount
3514
- */
3515
- totalDiscount = computed(() => {
3516
- return this.applicableFees().reduce((sum, fee) => {
3517
- const discount = parseFloat(this.getDiscountControl(this.getFeeId(fee))?.value || '0') || 0;
3518
- return sum + discount;
3519
- }, 0);
3520
- }, ...(ngDevMode ? [{ debugName: "totalDiscount" }] : []));
3521
- /**
3522
- * Calculate total scholarship
3523
- */
3524
- totalScholarship = computed(() => {
3525
- return this.applicableFees().reduce((sum, fee) => {
3526
- const scholarship = parseFloat(this.getScholarshipControl(this.getFeeId(fee))?.value || '0') || 0;
3527
- return sum + scholarship;
3528
- }, 0);
3529
- }, ...(ngDevMode ? [{ debugName: "totalScholarship" }] : []));
3530
- /**
3531
- * Calculate total final amount
4088
+ * Load applicable fees based on selected program/term/section
3532
4089
  */
3533
- totalFinalAmount = computed(() => {
3534
- return this.applicableFees().reduce((sum, fee) => {
3535
- return sum + this.calculateFinalAmount(fee);
3536
- }, 0);
3537
- }, ...(ngDevMode ? [{ debugName: "totalFinalAmount" }] : []));
3538
4090
  onSubmit() {
3539
4091
  const requiredRight = this.isEditMode() ? 'EDIT' : 'CREATE';
3540
4092
  if (!this.rightsService.hasRight(requiredRight)) {
@@ -3549,16 +4101,17 @@ class FeeAssignmentCreateComponent {
3549
4101
  this.submitting.set(true);
3550
4102
  const formValue = this.assignmentForm.getRawValue();
3551
4103
  // If using fee structure, create assignments for each fee item
3552
- if (formValue.fee_source === 'STRUCTURE' && this.applicableFees().length > 0) {
4104
+ // If using fee structure, create assignments for each fee item
4105
+ if (formValue.fee_source === 'STRUCTURE' && this.selectedFeeItems().length > 0) {
3553
4106
  // Create multiple fee assignments for each fee item
3554
- const assignments = this.applicableFees().map(fee => {
3555
- const discount = parseFloat(this.getDiscountControl(this.getFeeId(fee))?.value || '0') || 0;
3556
- const scholarship = parseFloat(this.getScholarshipControl(this.getFeeId(fee))?.value || '0') || 0;
3557
- const originalAmount = this.getFeeAmount(fee);
3558
- const finalAmount = Math.max(0, originalAmount - discount - scholarship);
4107
+ const assignments = this.selectedFeeItems().map(fee => {
4108
+ const discount = fee.discount || 0;
4109
+ const scholarship = fee.scholarship || 0;
4110
+ const originalAmount = fee.fees_amount || 0;
4111
+ const finalAmount = fee.final_amount !== undefined ? fee.final_amount : Math.max(0, originalAmount - discount - scholarship);
3559
4112
  return {
3560
4113
  _id: this.isEditMode() ? this.assignmentId() : undefined,
3561
- feeas_student_id: formValue.student_id,
4114
+ feeas_student_id_auth: formValue.student_id,
3562
4115
  feeas_fee_structure_id_feest: fee.fees_structure_id,
3563
4116
  feeas_fee_structure_item_id_feesi: fee._id,
3564
4117
  feeas_academic_year_id_acayr: formValue.feeas_academic_year_id_acayr,
@@ -3599,7 +4152,7 @@ class FeeAssignmentCreateComponent {
3599
4152
  // Custom fee assignment
3600
4153
  const payload = {
3601
4154
  _id: this.isEditMode() ? this.assignmentId() : undefined,
3602
- feeas_student_id: formValue.student_id,
4155
+ feeas_student_id_auth: formValue.student_id,
3603
4156
  feeas_fee_structure_id_feest: undefined,
3604
4157
  feeas_fee_structure_item_id_feesi: undefined,
3605
4158
  feeas_academic_year_id_acayr: formValue.feeas_academic_year_id_acayr,
@@ -3684,12 +4237,6 @@ class FeeAssignmentCreateComponent {
3684
4237
  this.componentContextService.close(['/fees/assignment']);
3685
4238
  }
3686
4239
  }
3687
- getAcademicYearOptions() {
3688
- return this.academicYearOptions().map(ay => ({
3689
- value: ay._id || '',
3690
- label: `${ay.acayr_name || ''} (${ay.acayr_code || ''})`
3691
- }));
3692
- }
3693
4240
  getFeeStructureOptions() {
3694
4241
  return this.feeStructureOptions().map(fs => ({
3695
4242
  value: fs._id || '',
@@ -3733,10 +4280,10 @@ class FeeAssignmentCreateComponent {
3733
4280
  }
3734
4281
  this.breadcrumbData.set(additionalItems);
3735
4282
  }
3736
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeAssignmentCreateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3737
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: FeeAssignmentCreateComponent, isStandalone: true, selector: "cide-fee-assignment-create", ngImport: i0, template: "<!-- Fee Assignment Form -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_assignment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n <div class=\"tw-w-full tw-h-full\">\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"assignmentForm\" \n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n\n <!-- Form Content -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-6\">\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n <div class=\"tw-space-y-6\">\n\n <!-- Student Information -->\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-mb-3\">Student Information</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <div>\n <cide-ele-input \n label=\"Student\" \n formControlName=\"student_search\"\n placeholder=\"Search student by name or ID...\"\n size=\"sm\"\n leadingIcon=\"search\">\n </cide-ele-input>\n </div>\n\n <cide-ele-select \n label=\"Academic Year\" \n formControlName=\"feeas_academic_year_id_acayr\"\n [options]=\"getAcademicYearOptions()\"\n [loading]=\"academicYearLoading()\"\n size=\"sm\"\n leadingIcon=\"calendar_today\">\n </cide-ele-select>\n </div>\n \n <!-- Hidden entity field (populated from app state) -->\n <input type=\"hidden\" formControlName=\"feeas_entity_id_syen\">\n </div>\n\n <!-- Academic Information (for fee structure loading) -->\n @if (showFeeStructureField()) {\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-pb-2 tw-border-b-2 tw-border-indigo-200 dark:tw-border-indigo-800 tw-mb-4\">\n <cide-ele-icon class=\"tw-w-5 tw-h-5 tw-text-indigo-600 dark:tw-text-indigo-400\">school</cide-ele-icon>\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100\">Academic Information</h6>\n </div>\n \n <cide-shared-program-section-selector-wrapper\n [formGroup]=\"assignmentForm\"\n classProgramControlName=\"class_program_id\"\n branchControlName=\"branch_id\"\n termControlName=\"term_id\"\n sectionControlName=\"section_id\"\n [academicYearId]=\"assignmentForm.get('feeas_academic_year_id_acayr')?.value\"\n [entityId]=\"assignmentForm.get('feeas_entity_id_syen')?.value\"\n [disabled]=\"isViewMode()\"\n (valuesChange)=\"onProgramSectionValuesChange($event)\">\n </cide-shared-program-section-selector-wrapper>\n </div>\n }\n\n <!-- Fee Information -->\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-mb-3\">Fee Information</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select \n label=\"Fee Source\" \n formControlName=\"fee_source\"\n [options]=\"feeSourceOptions\"\n size=\"sm\"\n leadingIcon=\"source\">\n </cide-ele-select>\n </div>\n\n <!-- Custom Fee Fields -->\n @if (showCustomFeeFields()) {\n <div class=\"tw-mt-4 tw-space-y-4\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select \n label=\"Fee Category\" \n formControlName=\"feeas_fee_category_sygms\"\n [options]=\"feeCategoryOptions\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-input \n label=\"Fee Name\" \n formControlName=\"feeas_fee_name\"\n placeholder=\"Enter fee name\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select \n label=\"Fee Type\" \n formControlName=\"feeas_fee_type\"\n [options]=\"feeTypeOptions\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-input \n label=\"Amount\" \n formControlName=\"feeas_original_amount\"\n type=\"number\"\n placeholder=\"0.00\"\n size=\"sm\"\n leadingIcon=\"currency_rupee\">\n </cide-ele-input>\n </div>\n </div>\n }\n </div>\n\n <!-- Payment Details -->\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-mb-3\">Payment Details</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-input \n label=\"Due Date\" \n formControlName=\"feeas_due_date\"\n type=\"date\"\n size=\"sm\"\n leadingIcon=\"calendar_today\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Installments\" \n formControlName=\"feeas_installment_count\"\n type=\"number\"\n placeholder=\"1\"\n min=\"1\"\n max=\"12\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Fee Insights (for fee structure) -->\n @if (showFeeStructureField() && assignmentForm.get('term_id')?.value) {\n <div class=\"tw-bg-blue-50 dark:tw-bg-blue-900/20 tw-rounded-lg tw-border tw-border-blue-200 dark:tw-border-blue-800 tw-p-4\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-w-5 tw-h-5 tw-text-blue-600 dark:tw-text-blue-400\">account_balance</cide-ele-icon>\n Fee Insights\n </h6>\n @if (feesLoading()) {\n <span class=\"tw-text-sm tw-text-gray-500 dark:tw-text-gray-400\">Loading fees...</span>\n }\n </div>\n\n @if (feesLoading()) {\n <div class=\"tw-text-center tw-py-4\">\n <span class=\"tw-text-sm tw-text-gray-500 dark:tw-text-gray-400\">Loading applicable fees...</span>\n </div>\n } @else if (applicableFees().length > 0) {\n <div class=\"tw-overflow-x-auto\">\n <table class=\"tw-min-w-full tw-divide-y tw-divide-gray-200 dark:tw-divide-gray-700\">\n <thead class=\"tw-bg-gray-50 dark:tw-bg-gray-800\">\n <tr>\n <th class=\"tw-px-4 tw-py-2 tw-text-left tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Fee Name</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-left tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Category</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-right tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Original Amount</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-right tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Discount</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-right tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Scholarship</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-right tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Final Amount</th>\n </tr>\n </thead>\n <tbody class=\"tw-bg-white dark:tw-bg-gray-800 tw-divide-y tw-divide-gray-200 dark:tw-divide-gray-700\">\n @for (fee of applicableFees(); track getFeeId(fee)) {\n <tr>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-text-gray-900 dark:tw-text-gray-100\">{{ getFeeName(fee) }}</td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-text-gray-600 dark:tw-text-gray-400\">{{ getFeeCategory(fee) }}</td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-text-gray-900 dark:tw-text-gray-100 tw-text-right\">{{ formatCurrency(getFeeAmount(fee)) }}</td>\n <td class=\"tw-px-4 tw-py-2\">\n <cide-ele-input\n type=\"number\"\n [formControl]=\"getDiscountControl(getFeeId(fee))\"\n placeholder=\"0.00\"\n size=\"sm\"\n class=\"tw-w-24\"\n [disabled]=\"isViewMode()\">\n </cide-ele-input>\n </td>\n <td class=\"tw-px-4 tw-py-2\">\n <cide-ele-input\n type=\"number\"\n [formControl]=\"getScholarshipControl(getFeeId(fee))\"\n placeholder=\"0.00\"\n size=\"sm\"\n class=\"tw-w-24\"\n [disabled]=\"isViewMode()\">\n </cide-ele-input>\n </td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-text-right\">\n {{ formatCurrency(calculateFinalAmount(fee)) }}\n </td>\n </tr>\n }\n </tbody>\n <tfoot class=\"tw-bg-gray-50 dark:tw-bg-gray-800\">\n <tr>\n <td colspan=\"2\" class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-text-right\">Total:</td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-text-right\">\n {{ formatCurrency(totalOriginalAmount()) }}\n </td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-blue-600 dark:tw-text-blue-400 tw-text-right\">\n {{ formatCurrency(totalDiscount()) }}\n </td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-purple-600 dark:tw-text-purple-400 tw-text-right\">\n {{ formatCurrency(totalScholarship()) }}\n </td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-bold tw-text-green-600 dark:tw-text-green-400 tw-text-right\">\n {{ formatCurrency(totalFinalAmount()) }}\n </td>\n </tr>\n </tfoot>\n </table>\n </div>\n } @else {\n <div class=\"tw-text-center tw-py-4 tw-text-sm tw-text-gray-500 dark:tw-text-gray-400\">\n No fee structure found for the selected program/term. Please select a program and term to view applicable fees.\n </div>\n }\n </div>\n }\n\n <!-- Discounts & Scholarships (for custom fees) -->\n @if (showCustomFeeFields()) {\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-mb-3\">Discounts & Scholarships</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-input \n label=\"Discount Amount\" \n formControlName=\"feeas_discount_amount\"\n type=\"number\"\n placeholder=\"0.00\"\n min=\"0\"\n size=\"sm\"\n leadingIcon=\"percent\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Scholarship Amount\" \n formControlName=\"feeas_scholarship_amount\"\n type=\"number\"\n placeholder=\"0.00\"\n min=\"0\"\n size=\"sm\"\n leadingIcon=\"school\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Amount Summary (for custom fees) -->\n <div class=\"tw-bg-gradient-to-r tw-from-blue-50 dark:tw-from-blue-900/20 tw-to-indigo-50 dark:tw-to-indigo-900/20 tw-rounded-lg tw-border tw-border-blue-200 dark:tw-border-blue-800 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-blue-900 dark:tw-text-blue-100 tw-mb-3\">Amount Summary</h6>\n \n <div class=\"tw-space-y-2\">\n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-1\">\n <span class=\"tw-text-sm tw-text-gray-700 dark:tw-text-gray-300\">Original Amount:</span>\n <span class=\"tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100\">{{ formatCurrency(assignmentForm.get('feeas_original_amount')?.value || 0) }}</span>\n </div>\n \n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-1\">\n <span class=\"tw-text-sm tw-text-gray-700 dark:tw-text-gray-300\">Discount:</span>\n <span class=\"tw-font-semibold tw-text-red-600 dark:tw-text-red-400\">-{{ formatCurrency(assignmentForm.get('feeas_discount_amount')?.value || 0) }}</span>\n </div>\n \n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-1\">\n <span class=\"tw-text-sm tw-text-gray-700 dark:tw-text-gray-300\">Scholarship:</span>\n <span class=\"tw-font-semibold tw-text-red-600 dark:tw-text-red-400\">-{{ formatCurrency(assignmentForm.get('feeas_scholarship_amount')?.value || 0) }}</span>\n </div>\n \n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-2 tw-border-t-2 tw-border-blue-300 dark:tw-border-blue-700 tw-mt-2\">\n <span class=\"tw-text-base tw-font-bold tw-text-blue-900 dark:tw-text-blue-100\">Total Amount:</span>\n <span class=\"tw-text-xl tw-font-bold tw-text-blue-700 dark:tw-text-blue-300\">{{ formatCurrency(totalAmount()) }}</span>\n </div>\n </div>\n </div>\n }\n\n <!-- Remarks -->\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <cide-ele-textarea \n label=\"Remarks\" \n formControlName=\"feeas_remarks\"\n placeholder=\"Enter any additional remarks...\"\n rows=\"2\" \n size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n </div>\n\n <!-- Form Validation Errors -->\n @if (!isViewMode()) {\n <div class=\"tw-w-full tw-mt-6\">\n <cide-form-field-error [formGroup]=\"assignmentForm\"></cide-form-field-error>\n </div>\n \n <!-- Action Buttons -->\n <div class=\"tw-flex tw-justify-end tw-gap-3 tw-mt-6\">\n @if (!isEditMode()) {\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n }\n\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"close\"\n [disabled]=\"loading()\">\n Cancel\n </button>\n\n <button cideEleButton type=\"submit\" variant=\"primary\" size=\"sm\" \n [disabled]=\"submitting() || assignmentForm.invalid || loading()\" \n [loading]=\"submitting()\" \n leftIcon=\"save\">\n {{ isEditMode() ? 'Update Assignment' : 'Assign Fee' }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n </form>\n </div>\n</cide-lyt-shared-wrapper>\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideTextareaComponent, selector: "cide-ele-textarea", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "minlength", "maxlength", "rows", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }, { kind: "component", type: ProgramSectionSelectorWrapperComponent, selector: "cide-shared-program-section-selector-wrapper", inputs: ["formGroup", "classProgramControlName", "branchControlName", "termControlName", "sectionControlName", "academicYearId", "entityId", "disabled", "showLabels", "gridCols", "showAllPrograms", "includeInactive"], outputs: ["valuesChange"] }, { kind: "component", type: CideFormFieldErrorComponent, selector: "cide-form-field-error", inputs: ["control", "formGroup", "fieldName", "customMessages"] }] });
4283
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeAssignmentCreateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4284
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FeeAssignmentCreateComponent, isStandalone: true, selector: "cide-fee-assignment-create", ngImport: i0, template: "<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_assignment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n\n <!-- Main Grid Layout -->\n <div class=\"tw-p-4 tw-grid tw-grid-cols-1 lg:tw-grid-cols-12 tw-gap-4 tw-h-[calc(100vh-140px)] tw-overflow-hidden\">\n\n <!-- Left Column: Forms (Col 8) -->\n <div class=\"lg:tw-col-span-8 tw-flex tw-flex-col tw-gap-4 tw-overflow-y-auto tw-pr-2\">\n\n <!-- Section 1: Student Context -->\n <div class=\"glass-card tw-rounded-xl tw-p-4 tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">person_search</cide-ele-icon>\n Student Context\n </h3>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4 tw-items-start\" [formGroup]=\"assignmentForm\">\n <div>\n <cide-ele-select label=\"Select Student\" formControlName=\"student_id\" [options]=\"studentListOptions()\"\n size=\"sm\" leadingIcon=\"person\" placeholder=\"Search student name or ID...\"\n (searchChange)=\"onStudentSearch($event)\">\n </cide-ele-select>\n </div>\n\n <!-- Selected Student Display -->\n @if (selectedStudent()) {\n <div\n class=\"premium-gradient tw-p-3 tw-rounded-lg tw-border tw-border-blue-100 tw-flex tw-items-center tw-gap-4\">\n <div\n class=\"tw-h-12 tw-w-12 tw-rounded-full tw-bg-blue-600 tw-flex tw-items-center tw-justify-center tw-text-white tw-font-bold tw-text-xl\">\n {{ selectedStudent()?.name?.[0] || '?' }}\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-sm tw-font-bold tw-text-gray-900\">{{ selectedStudent()?.name }}</div>\n <div class=\"tw-text-xs tw-text-gray-500\">ID: {{ selectedStudent()?.student_id }}</div>\n <div class=\"tw-text-[10px] tw-text-blue-600 tw-font-medium tw-mt-1\">\n {{ selectedStudent()?.class }} | {{ selectedStudent()?.section }}\n </div>\n </div>\n </div>\n } @else {\n <div\n class=\"tw-border tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-p-3 tw-flex tw-items-center tw-justify-center tw-text-gray-400 tw-text-xs\">\n Select a student to view details\n </div>\n }\n </div>\n\n <!-- Academic Placement (Conditional for Structure) -->\n @if (showFeeStructureField()) {\n <div class=\"tw-mt-4 tw-pt-4 tw-border-t tw-border-gray-100\">\n <label class=\"tw-block tw-text-xs tw-font-medium tw-text-gray-500 tw-mb-2\">\n ACADEMIC PLACEMENT filters (Required for Fee Structure)\n </label>\n <cide-shared-program-section-selector-wrapper [formGroup]=\"assignmentForm\"\n classProgramControlName=\"class_program_id\" branchControlName=\"branch_id\" termControlName=\"term_id\"\n sectionControlName=\"section_id\" [academicYearId]=\"assignmentForm.get('feeas_academic_year_id_acayr')?.value\"\n [entityId]=\"assignmentForm.get('feeas_entity_id_syen')?.value\" [disabled]=\"isViewMode()\"\n (valuesChange)=\"onProgramSectionValuesChange($event)\">\n </cide-shared-program-section-selector-wrapper>\n </div>\n }\n </div>\n\n <!-- Section 2: Fee Configuration -->\n <div class=\"glass-card tw-rounded-xl tw-p-4 tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">settings</cide-ele-icon>\n Fee Configuration\n </h3>\n </div>\n\n <div class=\"tw-space-y-4\" [formGroup]=\"assignmentForm\">\n <!-- Source Selection -->\n <div class=\"tw-w-full md:tw-w-1/2\">\n <cide-ele-select label=\"Fee Assignment Mode\" formControlName=\"fee_source\" [options]=\"feeSourceOptions\"\n size=\"sm\" leadingIcon=\"tune\">\n </cide-ele-select>\n </div>\n\n <!-- Mode: Structure -->\n @if (showFeeStructureField()) {\n <div>\n <cide-fee-applicable-fees [entityId]=\"assignmentForm.get('feeas_entity_id_syen')?.value\"\n [academicYearId]=\"assignmentForm.get('feeas_academic_year_id_acayr')?.value\"\n [classProgramId]=\"classProgramId()\" [termId]=\"termId()\" [branchId]=\"branchId()\" [sectionId]=\"sectionId()\"\n [studentId]=\"studentId()\" (feesCalculated)=\"onFeesCalculated($event)\">\n </cide-fee-applicable-fees>\n </div>\n }\n\n <!-- Mode: Custom -->\n @if (showCustomFeeFields()) {\n <div class=\"tw-space-y-4\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select label=\"Category\" formControlName=\"feeas_fee_category_sygms\"\n [options]=\"feeCategoryOptions\" size=\"sm\"></cide-ele-select>\n <cide-ele-input label=\"Fee Name\" formControlName=\"feeas_fee_name\" placeholder=\"e.g. Late Fee\"\n size=\"sm\"></cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-input label=\"Amount\" formControlName=\"feeas_original_amount\" type=\"number\" placeholder=\"0.00\"\n size=\"sm\" leadingIcon=\"currency_rupee\"></cide-ele-input>\n <cide-ele-select label=\"Type\" formControlName=\"feeas_fee_type\" [options]=\"feeTypeOptions\"\n size=\"sm\"></cide-ele-select>\n </div>\n\n <!-- Custom Discounts -->\n <div class=\"tw-bg-gray-50 tw-rounded tw-p-3 tw-border tw-border-gray-200\">\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-500 tw-uppercase tw-mb-3\">Manual Adjustments</h6>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-input label=\"Discount\" formControlName=\"feeas_discount_amount\" type=\"number\" placeholder=\"0\"\n size=\"sm\"></cide-ele-input>\n <cide-ele-input label=\"Scholarship\" formControlName=\"feeas_scholarship_amount\" type=\"number\"\n placeholder=\"0\" size=\"sm\"></cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Right Column: Summary & Actions (Col 4) -->\n <div class=\"lg:tw-col-span-4 tw-h-full\">\n <div\n class=\"glass-card tw-rounded-xl tw-h-full tw-flex tw-flex-col tw-overflow-hidden tw-border tw-border-gray-200\">\n\n <!-- Header -->\n <div class=\"tw-p-4 tw-bg-blue-600 tw-text-white\">\n <h3 class=\"tw-text-lg tw-font-bold\">Assignment Summary</h3>\n <p class=\"tw-text-blue-100 tw-text-xs\">Review terms and confirm assignment</p>\n </div>\n\n <div class=\"tw-flex-1 tw-p-4 tw-overflow-y-auto tw-space-y-4\" [formGroup]=\"assignmentForm\">\n\n <!-- Payment Terms Inputs -->\n <div class=\"tw-space-y-3\">\n <h6 class=\"tw-text-xs tw-font-bold tw-text-gray-700 tw-uppercase\">Payment Terms</h6>\n <cide-ele-input label=\"Due Date\" formControlName=\"feeas_due_date\" type=\"date\" size=\"sm\"></cide-ele-input>\n <cide-ele-input label=\"Installments\" formControlName=\"feeas_installment_count\" type=\"number\" placeholder=\"1\"\n min=\"1\" max=\"12\" size=\"sm\"></cide-ele-input>\n </div>\n\n <div class=\"tw-border-t tw-border-gray-100 tw-my-4\"></div>\n\n <!-- Totals -->\n <div class=\"tw-space-y-2\">\n @if(showCustomFeeFields()) {\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Original Amount</span>\n <span class=\"tw-font-medium\">{{ formatCurrency(assignmentForm.get('feeas_original_amount')?.value || 0)\n }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Adjustments</span>\n <span class=\"tw-text-red-500 tw-font-medium\">\n - {{ formatCurrency((assignmentForm.get('feeas_discount_amount')?.value || 0) +\n (assignmentForm.get('feeas_scholarship_amount')?.value || 0)) }}\n </span>\n </div>\n <div class=\"tw-border-t tw-border-gray-100 tw-pt-2 tw-mt-2\">\n <div class=\"tw-flex tw-justify-between tw-items-center\">\n <span class=\"tw-text-base tw-font-bold tw-text-gray-800\">Total Payable</span>\n <span class=\"tw-text-xl tw-font-bold tw-text-blue-600\">{{ formatCurrency(totalAmount()) }}</span>\n </div>\n </div>\n } @else {\n <!-- Structure Mode Totals (calculated by child component usually, but we have selectedFeeItems signal) -->\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Items Selected</span>\n <span class=\"tw-font-medium\">{{ selectedFeeItems().length }}</span>\n </div>\n\n <!-- Note: Ideally we'd sum up selectedFeeItems here for a live total, similar to Fee Payment Process -->\n <!-- For now, just showing item count as specific amounts are handled inside the child component mostly -->\n }\n </div>\n\n <!-- Remarks -->\n <div class=\"tw-mt-4\">\n <cide-ele-textarea label=\"Remarks\" formControlName=\"feeas_remarks\" placeholder=\"Optional notes...\"\n [rows]=\"3\" size=\"sm\"></cide-ele-textarea>\n </div>\n\n </div>\n\n <!-- Footer Actions -->\n <div class=\"tw-p-4 tw-bg-gray-50 tw-border-t tw-border-gray-100 tw-flex tw-flex-col tw-gap-2\">\n <button cideEleButton variant=\"primary\" class=\"tw-w-full tw-py-3\" [loading]=\"submitting()\"\n [disabled]=\"submitting() || assignmentForm.invalid || loading()\" (click)=\"onSubmit()\">\n {{ isEditMode() ? 'Update Assignment' : 'Confirm Assignment' }}\n </button>\n\n <div class=\"tw-grid tw-grid-cols-2 tw-gap-2\">\n @if (!isEditMode()) {\n <button cideEleButton variant=\"ghost\" (click)=\"resetForm()\" [disabled]=\"loading()\">Reset</button>\n }\n <button cideEleButton variant=\"ghost\" (click)=\"onCancel()\" [disabled]=\"submitting()\">Cancel</button>\n </div>\n </div>\n\n </div>\n </div>\n\n </div>\n</cide-lyt-shared-wrapper>", styles: [".glass-card{background:#ffffffe6;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.2);box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.premium-gradient{background:linear-gradient(135deg,#f8fafc,#eff6ff)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideTextareaComponent, selector: "cide-ele-textarea", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "minlength", "maxlength", "rows", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }, { kind: "component", type: ProgramSectionSelectorWrapperComponent, selector: "cide-shared-program-section-selector-wrapper", inputs: ["formGroup", "classProgramControlName", "branchControlName", "termControlName", "sectionControlName", "academicYearId", "entityId", "disabled", "showLabels", "gridCols", "showAllPrograms", "includeInactive"], outputs: ["valuesChange"] }, { kind: "component", type: FeeApplicableFeesComponent, selector: "cide-fee-applicable-fees", inputs: ["entityId", "academicYearId", "classProgramId", "termId", "branchId", "sectionId", "studentId"], outputs: ["feesCalculated"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
3738
4285
  }
3739
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeAssignmentCreateComponent, decorators: [{
4286
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeAssignmentCreateComponent, decorators: [{
3740
4287
  type: Component,
3741
4288
  args: [{ selector: 'cide-fee-assignment-create', standalone: true, imports: [
3742
4289
  CommonModule,
@@ -3745,11 +4292,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
3745
4292
  CideTextareaComponent,
3746
4293
  CideEleButtonComponent,
3747
4294
  CideSelectComponent,
3748
- CideIconComponent,
4295
+ CideLytSharedWrapperComponent,
3749
4296
  CideLytSharedWrapperComponent,
3750
4297
  ProgramSectionSelectorWrapperComponent,
3751
- CideFormFieldErrorComponent
3752
- ], template: "<!-- Fee Assignment Form -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_assignment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n <div class=\"tw-w-full tw-h-full\">\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"assignmentForm\" \n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n\n <!-- Form Content -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-6\">\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n <div class=\"tw-space-y-6\">\n\n <!-- Student Information -->\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-mb-3\">Student Information</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <div>\n <cide-ele-input \n label=\"Student\" \n formControlName=\"student_search\"\n placeholder=\"Search student by name or ID...\"\n size=\"sm\"\n leadingIcon=\"search\">\n </cide-ele-input>\n </div>\n\n <cide-ele-select \n label=\"Academic Year\" \n formControlName=\"feeas_academic_year_id_acayr\"\n [options]=\"getAcademicYearOptions()\"\n [loading]=\"academicYearLoading()\"\n size=\"sm\"\n leadingIcon=\"calendar_today\">\n </cide-ele-select>\n </div>\n \n <!-- Hidden entity field (populated from app state) -->\n <input type=\"hidden\" formControlName=\"feeas_entity_id_syen\">\n </div>\n\n <!-- Academic Information (for fee structure loading) -->\n @if (showFeeStructureField()) {\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-pb-2 tw-border-b-2 tw-border-indigo-200 dark:tw-border-indigo-800 tw-mb-4\">\n <cide-ele-icon class=\"tw-w-5 tw-h-5 tw-text-indigo-600 dark:tw-text-indigo-400\">school</cide-ele-icon>\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100\">Academic Information</h6>\n </div>\n \n <cide-shared-program-section-selector-wrapper\n [formGroup]=\"assignmentForm\"\n classProgramControlName=\"class_program_id\"\n branchControlName=\"branch_id\"\n termControlName=\"term_id\"\n sectionControlName=\"section_id\"\n [academicYearId]=\"assignmentForm.get('feeas_academic_year_id_acayr')?.value\"\n [entityId]=\"assignmentForm.get('feeas_entity_id_syen')?.value\"\n [disabled]=\"isViewMode()\"\n (valuesChange)=\"onProgramSectionValuesChange($event)\">\n </cide-shared-program-section-selector-wrapper>\n </div>\n }\n\n <!-- Fee Information -->\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-mb-3\">Fee Information</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select \n label=\"Fee Source\" \n formControlName=\"fee_source\"\n [options]=\"feeSourceOptions\"\n size=\"sm\"\n leadingIcon=\"source\">\n </cide-ele-select>\n </div>\n\n <!-- Custom Fee Fields -->\n @if (showCustomFeeFields()) {\n <div class=\"tw-mt-4 tw-space-y-4\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select \n label=\"Fee Category\" \n formControlName=\"feeas_fee_category_sygms\"\n [options]=\"feeCategoryOptions\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-input \n label=\"Fee Name\" \n formControlName=\"feeas_fee_name\"\n placeholder=\"Enter fee name\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select \n label=\"Fee Type\" \n formControlName=\"feeas_fee_type\"\n [options]=\"feeTypeOptions\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-input \n label=\"Amount\" \n formControlName=\"feeas_original_amount\"\n type=\"number\"\n placeholder=\"0.00\"\n size=\"sm\"\n leadingIcon=\"currency_rupee\">\n </cide-ele-input>\n </div>\n </div>\n }\n </div>\n\n <!-- Payment Details -->\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-mb-3\">Payment Details</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-input \n label=\"Due Date\" \n formControlName=\"feeas_due_date\"\n type=\"date\"\n size=\"sm\"\n leadingIcon=\"calendar_today\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Installments\" \n formControlName=\"feeas_installment_count\"\n type=\"number\"\n placeholder=\"1\"\n min=\"1\"\n max=\"12\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Fee Insights (for fee structure) -->\n @if (showFeeStructureField() && assignmentForm.get('term_id')?.value) {\n <div class=\"tw-bg-blue-50 dark:tw-bg-blue-900/20 tw-rounded-lg tw-border tw-border-blue-200 dark:tw-border-blue-800 tw-p-4\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-w-5 tw-h-5 tw-text-blue-600 dark:tw-text-blue-400\">account_balance</cide-ele-icon>\n Fee Insights\n </h6>\n @if (feesLoading()) {\n <span class=\"tw-text-sm tw-text-gray-500 dark:tw-text-gray-400\">Loading fees...</span>\n }\n </div>\n\n @if (feesLoading()) {\n <div class=\"tw-text-center tw-py-4\">\n <span class=\"tw-text-sm tw-text-gray-500 dark:tw-text-gray-400\">Loading applicable fees...</span>\n </div>\n } @else if (applicableFees().length > 0) {\n <div class=\"tw-overflow-x-auto\">\n <table class=\"tw-min-w-full tw-divide-y tw-divide-gray-200 dark:tw-divide-gray-700\">\n <thead class=\"tw-bg-gray-50 dark:tw-bg-gray-800\">\n <tr>\n <th class=\"tw-px-4 tw-py-2 tw-text-left tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Fee Name</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-left tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Category</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-right tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Original Amount</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-right tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Discount</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-right tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Scholarship</th>\n <th class=\"tw-px-4 tw-py-2 tw-text-right tw-text-xs tw-font-medium tw-text-gray-700 dark:tw-text-gray-300 tw-uppercase\">Final Amount</th>\n </tr>\n </thead>\n <tbody class=\"tw-bg-white dark:tw-bg-gray-800 tw-divide-y tw-divide-gray-200 dark:tw-divide-gray-700\">\n @for (fee of applicableFees(); track getFeeId(fee)) {\n <tr>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-text-gray-900 dark:tw-text-gray-100\">{{ getFeeName(fee) }}</td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-text-gray-600 dark:tw-text-gray-400\">{{ getFeeCategory(fee) }}</td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-text-gray-900 dark:tw-text-gray-100 tw-text-right\">{{ formatCurrency(getFeeAmount(fee)) }}</td>\n <td class=\"tw-px-4 tw-py-2\">\n <cide-ele-input\n type=\"number\"\n [formControl]=\"getDiscountControl(getFeeId(fee))\"\n placeholder=\"0.00\"\n size=\"sm\"\n class=\"tw-w-24\"\n [disabled]=\"isViewMode()\">\n </cide-ele-input>\n </td>\n <td class=\"tw-px-4 tw-py-2\">\n <cide-ele-input\n type=\"number\"\n [formControl]=\"getScholarshipControl(getFeeId(fee))\"\n placeholder=\"0.00\"\n size=\"sm\"\n class=\"tw-w-24\"\n [disabled]=\"isViewMode()\">\n </cide-ele-input>\n </td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-text-right\">\n {{ formatCurrency(calculateFinalAmount(fee)) }}\n </td>\n </tr>\n }\n </tbody>\n <tfoot class=\"tw-bg-gray-50 dark:tw-bg-gray-800\">\n <tr>\n <td colspan=\"2\" class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-text-right\">Total:</td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-text-right\">\n {{ formatCurrency(totalOriginalAmount()) }}\n </td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-blue-600 dark:tw-text-blue-400 tw-text-right\">\n {{ formatCurrency(totalDiscount()) }}\n </td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-semibold tw-text-purple-600 dark:tw-text-purple-400 tw-text-right\">\n {{ formatCurrency(totalScholarship()) }}\n </td>\n <td class=\"tw-px-4 tw-py-2 tw-text-sm tw-font-bold tw-text-green-600 dark:tw-text-green-400 tw-text-right\">\n {{ formatCurrency(totalFinalAmount()) }}\n </td>\n </tr>\n </tfoot>\n </table>\n </div>\n } @else {\n <div class=\"tw-text-center tw-py-4 tw-text-sm tw-text-gray-500 dark:tw-text-gray-400\">\n No fee structure found for the selected program/term. Please select a program and term to view applicable fees.\n </div>\n }\n </div>\n }\n\n <!-- Discounts & Scholarships (for custom fees) -->\n @if (showCustomFeeFields()) {\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100 tw-mb-3\">Discounts & Scholarships</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-input \n label=\"Discount Amount\" \n formControlName=\"feeas_discount_amount\"\n type=\"number\"\n placeholder=\"0.00\"\n min=\"0\"\n size=\"sm\"\n leadingIcon=\"percent\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Scholarship Amount\" \n formControlName=\"feeas_scholarship_amount\"\n type=\"number\"\n placeholder=\"0.00\"\n min=\"0\"\n size=\"sm\"\n leadingIcon=\"school\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Amount Summary (for custom fees) -->\n <div class=\"tw-bg-gradient-to-r tw-from-blue-50 dark:tw-from-blue-900/20 tw-to-indigo-50 dark:tw-to-indigo-900/20 tw-rounded-lg tw-border tw-border-blue-200 dark:tw-border-blue-800 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-blue-900 dark:tw-text-blue-100 tw-mb-3\">Amount Summary</h6>\n \n <div class=\"tw-space-y-2\">\n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-1\">\n <span class=\"tw-text-sm tw-text-gray-700 dark:tw-text-gray-300\">Original Amount:</span>\n <span class=\"tw-font-semibold tw-text-gray-900 dark:tw-text-gray-100\">{{ formatCurrency(assignmentForm.get('feeas_original_amount')?.value || 0) }}</span>\n </div>\n \n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-1\">\n <span class=\"tw-text-sm tw-text-gray-700 dark:tw-text-gray-300\">Discount:</span>\n <span class=\"tw-font-semibold tw-text-red-600 dark:tw-text-red-400\">-{{ formatCurrency(assignmentForm.get('feeas_discount_amount')?.value || 0) }}</span>\n </div>\n \n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-1\">\n <span class=\"tw-text-sm tw-text-gray-700 dark:tw-text-gray-300\">Scholarship:</span>\n <span class=\"tw-font-semibold tw-text-red-600 dark:tw-text-red-400\">-{{ formatCurrency(assignmentForm.get('feeas_scholarship_amount')?.value || 0) }}</span>\n </div>\n \n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-2 tw-border-t-2 tw-border-blue-300 dark:tw-border-blue-700 tw-mt-2\">\n <span class=\"tw-text-base tw-font-bold tw-text-blue-900 dark:tw-text-blue-100\">Total Amount:</span>\n <span class=\"tw-text-xl tw-font-bold tw-text-blue-700 dark:tw-text-blue-300\">{{ formatCurrency(totalAmount()) }}</span>\n </div>\n </div>\n </div>\n }\n\n <!-- Remarks -->\n <div class=\"tw-bg-white dark:tw-bg-gray-800 tw-rounded-lg tw-border tw-border-gray-200 dark:tw-border-gray-700 tw-p-4\">\n <cide-ele-textarea \n label=\"Remarks\" \n formControlName=\"feeas_remarks\"\n placeholder=\"Enter any additional remarks...\"\n rows=\"2\" \n size=\"sm\">\n </cide-ele-textarea>\n </div>\n\n </div>\n\n <!-- Form Validation Errors -->\n @if (!isViewMode()) {\n <div class=\"tw-w-full tw-mt-6\">\n <cide-form-field-error [formGroup]=\"assignmentForm\"></cide-form-field-error>\n </div>\n \n <!-- Action Buttons -->\n <div class=\"tw-flex tw-justify-end tw-gap-3 tw-mt-6\">\n @if (!isEditMode()) {\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n }\n\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"close\"\n [disabled]=\"loading()\">\n Cancel\n </button>\n\n <button cideEleButton type=\"submit\" variant=\"primary\" size=\"sm\" \n [disabled]=\"submitting() || assignmentForm.invalid || loading()\" \n [loading]=\"submitting()\" \n leftIcon=\"save\">\n {{ isEditMode() ? 'Update Assignment' : 'Assign Fee' }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n </form>\n </div>\n</cide-lyt-shared-wrapper>\n\n" }]
4298
+ FeeApplicableFeesComponent,
4299
+ CideIconComponent
4300
+ // CideFormFieldErrorComponent
4301
+ ], template: "<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_assignment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n\n <!-- Main Grid Layout -->\n <div class=\"tw-p-4 tw-grid tw-grid-cols-1 lg:tw-grid-cols-12 tw-gap-4 tw-h-[calc(100vh-140px)] tw-overflow-hidden\">\n\n <!-- Left Column: Forms (Col 8) -->\n <div class=\"lg:tw-col-span-8 tw-flex tw-flex-col tw-gap-4 tw-overflow-y-auto tw-pr-2\">\n\n <!-- Section 1: Student Context -->\n <div class=\"glass-card tw-rounded-xl tw-p-4 tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">person_search</cide-ele-icon>\n Student Context\n </h3>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4 tw-items-start\" [formGroup]=\"assignmentForm\">\n <div>\n <cide-ele-select label=\"Select Student\" formControlName=\"student_id\" [options]=\"studentListOptions()\"\n size=\"sm\" leadingIcon=\"person\" placeholder=\"Search student name or ID...\"\n (searchChange)=\"onStudentSearch($event)\">\n </cide-ele-select>\n </div>\n\n <!-- Selected Student Display -->\n @if (selectedStudent()) {\n <div\n class=\"premium-gradient tw-p-3 tw-rounded-lg tw-border tw-border-blue-100 tw-flex tw-items-center tw-gap-4\">\n <div\n class=\"tw-h-12 tw-w-12 tw-rounded-full tw-bg-blue-600 tw-flex tw-items-center tw-justify-center tw-text-white tw-font-bold tw-text-xl\">\n {{ selectedStudent()?.name?.[0] || '?' }}\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-sm tw-font-bold tw-text-gray-900\">{{ selectedStudent()?.name }}</div>\n <div class=\"tw-text-xs tw-text-gray-500\">ID: {{ selectedStudent()?.student_id }}</div>\n <div class=\"tw-text-[10px] tw-text-blue-600 tw-font-medium tw-mt-1\">\n {{ selectedStudent()?.class }} | {{ selectedStudent()?.section }}\n </div>\n </div>\n </div>\n } @else {\n <div\n class=\"tw-border tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-p-3 tw-flex tw-items-center tw-justify-center tw-text-gray-400 tw-text-xs\">\n Select a student to view details\n </div>\n }\n </div>\n\n <!-- Academic Placement (Conditional for Structure) -->\n @if (showFeeStructureField()) {\n <div class=\"tw-mt-4 tw-pt-4 tw-border-t tw-border-gray-100\">\n <label class=\"tw-block tw-text-xs tw-font-medium tw-text-gray-500 tw-mb-2\">\n ACADEMIC PLACEMENT filters (Required for Fee Structure)\n </label>\n <cide-shared-program-section-selector-wrapper [formGroup]=\"assignmentForm\"\n classProgramControlName=\"class_program_id\" branchControlName=\"branch_id\" termControlName=\"term_id\"\n sectionControlName=\"section_id\" [academicYearId]=\"assignmentForm.get('feeas_academic_year_id_acayr')?.value\"\n [entityId]=\"assignmentForm.get('feeas_entity_id_syen')?.value\" [disabled]=\"isViewMode()\"\n (valuesChange)=\"onProgramSectionValuesChange($event)\">\n </cide-shared-program-section-selector-wrapper>\n </div>\n }\n </div>\n\n <!-- Section 2: Fee Configuration -->\n <div class=\"glass-card tw-rounded-xl tw-p-4 tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">settings</cide-ele-icon>\n Fee Configuration\n </h3>\n </div>\n\n <div class=\"tw-space-y-4\" [formGroup]=\"assignmentForm\">\n <!-- Source Selection -->\n <div class=\"tw-w-full md:tw-w-1/2\">\n <cide-ele-select label=\"Fee Assignment Mode\" formControlName=\"fee_source\" [options]=\"feeSourceOptions\"\n size=\"sm\" leadingIcon=\"tune\">\n </cide-ele-select>\n </div>\n\n <!-- Mode: Structure -->\n @if (showFeeStructureField()) {\n <div>\n <cide-fee-applicable-fees [entityId]=\"assignmentForm.get('feeas_entity_id_syen')?.value\"\n [academicYearId]=\"assignmentForm.get('feeas_academic_year_id_acayr')?.value\"\n [classProgramId]=\"classProgramId()\" [termId]=\"termId()\" [branchId]=\"branchId()\" [sectionId]=\"sectionId()\"\n [studentId]=\"studentId()\" (feesCalculated)=\"onFeesCalculated($event)\">\n </cide-fee-applicable-fees>\n </div>\n }\n\n <!-- Mode: Custom -->\n @if (showCustomFeeFields()) {\n <div class=\"tw-space-y-4\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select label=\"Category\" formControlName=\"feeas_fee_category_sygms\"\n [options]=\"feeCategoryOptions\" size=\"sm\"></cide-ele-select>\n <cide-ele-input label=\"Fee Name\" formControlName=\"feeas_fee_name\" placeholder=\"e.g. Late Fee\"\n size=\"sm\"></cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-input label=\"Amount\" formControlName=\"feeas_original_amount\" type=\"number\" placeholder=\"0.00\"\n size=\"sm\" leadingIcon=\"currency_rupee\"></cide-ele-input>\n <cide-ele-select label=\"Type\" formControlName=\"feeas_fee_type\" [options]=\"feeTypeOptions\"\n size=\"sm\"></cide-ele-select>\n </div>\n\n <!-- Custom Discounts -->\n <div class=\"tw-bg-gray-50 tw-rounded tw-p-3 tw-border tw-border-gray-200\">\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-gray-500 tw-uppercase tw-mb-3\">Manual Adjustments</h6>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-input label=\"Discount\" formControlName=\"feeas_discount_amount\" type=\"number\" placeholder=\"0\"\n size=\"sm\"></cide-ele-input>\n <cide-ele-input label=\"Scholarship\" formControlName=\"feeas_scholarship_amount\" type=\"number\"\n placeholder=\"0\" size=\"sm\"></cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Right Column: Summary & Actions (Col 4) -->\n <div class=\"lg:tw-col-span-4 tw-h-full\">\n <div\n class=\"glass-card tw-rounded-xl tw-h-full tw-flex tw-flex-col tw-overflow-hidden tw-border tw-border-gray-200\">\n\n <!-- Header -->\n <div class=\"tw-p-4 tw-bg-blue-600 tw-text-white\">\n <h3 class=\"tw-text-lg tw-font-bold\">Assignment Summary</h3>\n <p class=\"tw-text-blue-100 tw-text-xs\">Review terms and confirm assignment</p>\n </div>\n\n <div class=\"tw-flex-1 tw-p-4 tw-overflow-y-auto tw-space-y-4\" [formGroup]=\"assignmentForm\">\n\n <!-- Payment Terms Inputs -->\n <div class=\"tw-space-y-3\">\n <h6 class=\"tw-text-xs tw-font-bold tw-text-gray-700 tw-uppercase\">Payment Terms</h6>\n <cide-ele-input label=\"Due Date\" formControlName=\"feeas_due_date\" type=\"date\" size=\"sm\"></cide-ele-input>\n <cide-ele-input label=\"Installments\" formControlName=\"feeas_installment_count\" type=\"number\" placeholder=\"1\"\n min=\"1\" max=\"12\" size=\"sm\"></cide-ele-input>\n </div>\n\n <div class=\"tw-border-t tw-border-gray-100 tw-my-4\"></div>\n\n <!-- Totals -->\n <div class=\"tw-space-y-2\">\n @if(showCustomFeeFields()) {\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Original Amount</span>\n <span class=\"tw-font-medium\">{{ formatCurrency(assignmentForm.get('feeas_original_amount')?.value || 0)\n }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Adjustments</span>\n <span class=\"tw-text-red-500 tw-font-medium\">\n - {{ formatCurrency((assignmentForm.get('feeas_discount_amount')?.value || 0) +\n (assignmentForm.get('feeas_scholarship_amount')?.value || 0)) }}\n </span>\n </div>\n <div class=\"tw-border-t tw-border-gray-100 tw-pt-2 tw-mt-2\">\n <div class=\"tw-flex tw-justify-between tw-items-center\">\n <span class=\"tw-text-base tw-font-bold tw-text-gray-800\">Total Payable</span>\n <span class=\"tw-text-xl tw-font-bold tw-text-blue-600\">{{ formatCurrency(totalAmount()) }}</span>\n </div>\n </div>\n } @else {\n <!-- Structure Mode Totals (calculated by child component usually, but we have selectedFeeItems signal) -->\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Items Selected</span>\n <span class=\"tw-font-medium\">{{ selectedFeeItems().length }}</span>\n </div>\n\n <!-- Note: Ideally we'd sum up selectedFeeItems here for a live total, similar to Fee Payment Process -->\n <!-- For now, just showing item count as specific amounts are handled inside the child component mostly -->\n }\n </div>\n\n <!-- Remarks -->\n <div class=\"tw-mt-4\">\n <cide-ele-textarea label=\"Remarks\" formControlName=\"feeas_remarks\" placeholder=\"Optional notes...\"\n [rows]=\"3\" size=\"sm\"></cide-ele-textarea>\n </div>\n\n </div>\n\n <!-- Footer Actions -->\n <div class=\"tw-p-4 tw-bg-gray-50 tw-border-t tw-border-gray-100 tw-flex tw-flex-col tw-gap-2\">\n <button cideEleButton variant=\"primary\" class=\"tw-w-full tw-py-3\" [loading]=\"submitting()\"\n [disabled]=\"submitting() || assignmentForm.invalid || loading()\" (click)=\"onSubmit()\">\n {{ isEditMode() ? 'Update Assignment' : 'Confirm Assignment' }}\n </button>\n\n <div class=\"tw-grid tw-grid-cols-2 tw-gap-2\">\n @if (!isEditMode()) {\n <button cideEleButton variant=\"ghost\" (click)=\"resetForm()\" [disabled]=\"loading()\">Reset</button>\n }\n <button cideEleButton variant=\"ghost\" (click)=\"onCancel()\" [disabled]=\"submitting()\">Cancel</button>\n </div>\n </div>\n\n </div>\n </div>\n\n </div>\n</cide-lyt-shared-wrapper>", styles: [".glass-card{background:#ffffffe6;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.2);box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.premium-gradient{background:linear-gradient(135deg,#f8fafc,#eff6ff)}\n"] }]
3753
4302
  }], ctorParameters: () => [] });
3754
4303
 
3755
4304
  var feeAssignmentCreate_component = /*#__PURE__*/Object.freeze({
@@ -3820,10 +4369,10 @@ class CideFeeFeePaymentService {
3820
4369
  ]);
3821
4370
  return this.http.delete(url);
3822
4371
  }
3823
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideFeeFeePaymentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3824
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideFeeFeePaymentService, providedIn: 'root' });
4372
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideFeeFeePaymentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4373
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideFeeFeePaymentService, providedIn: 'root' });
3825
4374
  }
3826
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideFeeFeePaymentService, decorators: [{
4375
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideFeeFeePaymentService, decorators: [{
3827
4376
  type: Injectable,
3828
4377
  args: [{
3829
4378
  providedIn: 'root'
@@ -3838,6 +4387,9 @@ class FeePaymentListComponent {
3838
4387
  confirmationService = inject(ConfirmationService);
3839
4388
  notificationService = inject(NotificationService);
3840
4389
  rightsService = inject(RightsService);
4390
+ appStateService = inject(AppStateService);
4391
+ // Breadcrumb data for shared wrapper
4392
+ breadcrumbData = signal([], ...(ngDevMode ? [{ debugName: "breadcrumbData" }] : []));
3841
4393
  paymentDetailsRendererTemplate = viewChild.required('paymentDetailsRendererTemplate');
3842
4394
  amountRendererTemplate = viewChild.required('amountRendererTemplate');
3843
4395
  statusRendererTemplate = viewChild.required('statusRendererTemplate');
@@ -3974,8 +4526,19 @@ class FeePaymentListComponent {
3974
4526
  // Initialize rights for fee payment management
3975
4527
  this.rightsService.initializeRights('fee_payment');
3976
4528
  console.log('💰 Fee Payment List Component initialized');
4529
+ this.initializeBreadcrumbData();
3977
4530
  this.loadFeePayments();
3978
4531
  }
4532
+ initializeBreadcrumbData() {
4533
+ this.breadcrumbData.set([
4534
+ {
4535
+ id: 'list',
4536
+ label: 'List',
4537
+ icon: 'list',
4538
+ url: undefined
4539
+ }
4540
+ ]);
4541
+ }
3979
4542
  ngOnDestroy() {
3980
4543
  // Cleanup if needed
3981
4544
  }
@@ -4207,10 +4770,10 @@ class FeePaymentListComponent {
4207
4770
  getStatusText(payment) {
4208
4771
  return payment.feepay_status || 'Unknown';
4209
4772
  }
4210
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeePaymentListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4211
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: FeePaymentListComponent, isStandalone: true, selector: "cide-fee-payment-list", viewQueries: [{ propertyName: "paymentDetailsRendererTemplate", first: true, predicate: ["paymentDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "amountRendererTemplate", first: true, predicate: ["amountRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "statusRendererTemplate", first: true, predicate: ["statusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Fee Payment Container -->\r\n<div class=\"tw-table tw-w-full tw-h-full\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n\r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">payment</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Payment Management</h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"processPayment()\">\r\n Record Payment\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Area -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-h-full tw-relative\">\r\n\r\n <!-- Data Grid Component -->\r\n <div class=\"tw-h-full tw-overflow-auto\">\r\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n</div>\r\n\r\n<!-- Template Renderers -->\r\n<ng-template #paymentDetailsRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-w-full\">\r\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.student_name || 'N/A' }}</div>\r\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">ID: {{ row.feepay_student_id || 'N/A' }}</div>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #amountRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-text-sm tw-items-end\">\r\n <span class=\"tw-text-gray-900 tw-font-semibold\">{{ formatCurrency(row.feepay_total_amount) }}</span>\r\n @if (row.feepay_late_fee_amount && row.feepay_late_fee_amount > 0) {\r\n <span class=\"tw-text-xs tw-text-red-600\">Late Fee: {{ formatCurrency(row.feepay_late_fee_amount) }}</span>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #statusRendererTemplate let-row=\"row\">\r\n <span class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\r\n [ngClass]=\"getStatusBadgeClass(row)\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\r\n {{ row.feepay_status === 'SUCCESS' || row.feepay_status === 'COMPLETED' ? 'check_circle' : \r\n row.feepay_status === 'PENDING' ? 'schedule' : 'error' }}\r\n </cide-ele-icon>\r\n {{ getStatusText(row) }}\r\n </span>\r\n</ng-template>\r\n\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown \r\n [items]=\"getActionDropdownItems(row)\"\r\n [config]=\"getDropdownConfig()\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template>\r\n\r\n", styles: [".fee-payment-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }] });
4773
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeePaymentListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4774
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FeePaymentListComponent, isStandalone: true, selector: "cide-fee-payment-list", viewQueries: [{ propertyName: "paymentDetailsRendererTemplate", first: true, predicate: ["paymentDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "amountRendererTemplate", first: true, predicate: ["amountRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "statusRendererTemplate", first: true, predicate: ["statusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Fee Payment Container -->\r\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_payment' }\"\r\n [breadcrumb_data]=\"breadcrumbData()\">\r\n\r\n <!-- Action Buttons in Breadcrumb Area -->\r\n <div breadcrumb-actions class=\"tw-flex tw-items-center tw-gap-2\">\r\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"processPayment()\">\r\n Record Payment\r\n </button>\r\n </div>\r\n\r\n <div class=\"tw-table tw-w-full tw-h-full\">\r\n <!-- Main Content Area -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-h-full tw-relative\">\r\n\r\n <!-- Data Grid Component -->\r\n <div class=\"tw-h-full tw-overflow-auto\">\r\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n </div>\r\n</cide-lyt-shared-wrapper>\r\n\r\n<!-- Template Renderers -->\r\n<ng-template #paymentDetailsRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-w-full\">\r\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.student_name || 'N/A' }}</div>\r\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">ID: {{ row.feepay_student_id || 'N/A' }}</div>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #amountRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-text-sm tw-items-end\">\r\n <span class=\"tw-text-gray-900 tw-font-semibold\">{{ formatCurrency(row.feepay_total_amount) }}</span>\r\n @if (row.feepay_late_fee_amount && row.feepay_late_fee_amount > 0) {\r\n <span class=\"tw-text-xs tw-text-red-600\">Late Fee: {{ formatCurrency(row.feepay_late_fee_amount) }}</span>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #statusRendererTemplate let-row=\"row\">\r\n <span\r\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\r\n [ngClass]=\"getStatusBadgeClass(row)\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\r\n {{ row.feepay_status === 'SUCCESS' || row.feepay_status === 'COMPLETED' ? 'check_circle' :\r\n row.feepay_status === 'PENDING' ? 'schedule' : 'error' }}\r\n </cide-ele-icon>\r\n {{ getStatusText(row) }}\r\n </span>\r\n</ng-template>\r\n\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown [items]=\"getActionDropdownItems(row)\" [config]=\"getDropdownConfig()\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template>", styles: [".fee-payment-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
4212
4775
  }
4213
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeePaymentListComponent, decorators: [{
4776
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeePaymentListComponent, decorators: [{
4214
4777
  type: Component,
4215
4778
  args: [{ selector: 'cide-fee-payment-list', standalone: true, imports: [
4216
4779
  CommonModule,
@@ -4218,9 +4781,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
4218
4781
  CideIconComponent,
4219
4782
  CideEleButtonComponent,
4220
4783
  CideEleDataGridComponent,
4221
- CideEleDropdownComponent
4222
- ], template: "<!-- Fee Payment Container -->\r\n<div class=\"tw-table tw-w-full tw-h-full\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n\r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">payment</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Payment Management</h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"processPayment()\">\r\n Record Payment\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Area -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-h-full tw-relative\">\r\n\r\n <!-- Data Grid Component -->\r\n <div class=\"tw-h-full tw-overflow-auto\">\r\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n</div>\r\n\r\n<!-- Template Renderers -->\r\n<ng-template #paymentDetailsRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-w-full\">\r\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.student_name || 'N/A' }}</div>\r\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">ID: {{ row.feepay_student_id || 'N/A' }}</div>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #amountRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-text-sm tw-items-end\">\r\n <span class=\"tw-text-gray-900 tw-font-semibold\">{{ formatCurrency(row.feepay_total_amount) }}</span>\r\n @if (row.feepay_late_fee_amount && row.feepay_late_fee_amount > 0) {\r\n <span class=\"tw-text-xs tw-text-red-600\">Late Fee: {{ formatCurrency(row.feepay_late_fee_amount) }}</span>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #statusRendererTemplate let-row=\"row\">\r\n <span class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\r\n [ngClass]=\"getStatusBadgeClass(row)\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\r\n {{ row.feepay_status === 'SUCCESS' || row.feepay_status === 'COMPLETED' ? 'check_circle' : \r\n row.feepay_status === 'PENDING' ? 'schedule' : 'error' }}\r\n </cide-ele-icon>\r\n {{ getStatusText(row) }}\r\n </span>\r\n</ng-template>\r\n\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown \r\n [items]=\"getActionDropdownItems(row)\"\r\n [config]=\"getDropdownConfig()\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template>\r\n\r\n", styles: [".fee-payment-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"] }]
4223
- }] });
4784
+ CideEleDropdownComponent,
4785
+ CideLytSharedWrapperComponent
4786
+ ], template: "<!-- Fee Payment Container -->\r\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_payment' }\"\r\n [breadcrumb_data]=\"breadcrumbData()\">\r\n\r\n <!-- Action Buttons in Breadcrumb Area -->\r\n <div breadcrumb-actions class=\"tw-flex tw-items-center tw-gap-2\">\r\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"processPayment()\">\r\n Record Payment\r\n </button>\r\n </div>\r\n\r\n <div class=\"tw-table tw-w-full tw-h-full\">\r\n <!-- Main Content Area -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-h-full tw-relative\">\r\n\r\n <!-- Data Grid Component -->\r\n <div class=\"tw-h-full tw-overflow-auto\">\r\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n </div>\r\n</cide-lyt-shared-wrapper>\r\n\r\n<!-- Template Renderers -->\r\n<ng-template #paymentDetailsRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-w-full\">\r\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.student_name || 'N/A' }}</div>\r\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">ID: {{ row.feepay_student_id || 'N/A' }}</div>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #amountRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-text-sm tw-items-end\">\r\n <span class=\"tw-text-gray-900 tw-font-semibold\">{{ formatCurrency(row.feepay_total_amount) }}</span>\r\n @if (row.feepay_late_fee_amount && row.feepay_late_fee_amount > 0) {\r\n <span class=\"tw-text-xs tw-text-red-600\">Late Fee: {{ formatCurrency(row.feepay_late_fee_amount) }}</span>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #statusRendererTemplate let-row=\"row\">\r\n <span\r\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\r\n [ngClass]=\"getStatusBadgeClass(row)\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\r\n {{ row.feepay_status === 'SUCCESS' || row.feepay_status === 'COMPLETED' ? 'check_circle' :\r\n row.feepay_status === 'PENDING' ? 'schedule' : 'error' }}\r\n </cide-ele-icon>\r\n {{ getStatusText(row) }}\r\n </span>\r\n</ng-template>\r\n\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown [items]=\"getActionDropdownItems(row)\" [config]=\"getDropdownConfig()\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template>", styles: [".fee-payment-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"] }]
4787
+ }], propDecorators: { paymentDetailsRendererTemplate: [{ type: i0.ViewChild, args: ['paymentDetailsRendererTemplate', { isSignal: true }] }], amountRendererTemplate: [{ type: i0.ViewChild, args: ['amountRendererTemplate', { isSignal: true }] }], statusRendererTemplate: [{ type: i0.ViewChild, args: ['statusRendererTemplate', { isSignal: true }] }], actionsDropdownRendererTemplate: [{ type: i0.ViewChild, args: ['actionsDropdownRendererTemplate', { isSignal: true }] }] } });
4224
4788
 
4225
4789
  var feePaymentList_component = /*#__PURE__*/Object.freeze({
4226
4790
  __proto__: null,
@@ -4237,12 +4801,14 @@ class FeePaymentProcessComponent {
4237
4801
  notificationService = inject(NotificationService);
4238
4802
  confirmationService = inject(ConfirmationService);
4239
4803
  rightsService = inject(RightsService);
4804
+ appStateService = inject(AppStateService);
4805
+ generalMasterService = inject(GENERAL_MASTER_SERVICE_TOKEN);
4240
4806
  paymentForm = this.fb.group({
4241
4807
  student_id: ['', [Validators.required]],
4242
4808
  student_search: [''],
4243
4809
  feepay_payment_date: [new Date().toISOString().split('T')[0], [Validators.required]],
4244
- feepay_payment_mode: ['CASH', [Validators.required]],
4245
- feepay_payment_method: ['CASH', [Validators.required]],
4810
+ feepay_payment_mode: ['OFFLINE'],
4811
+ feepay_payment_method: ['', [Validators.required]],
4246
4812
  feepay_payment_reference: [''],
4247
4813
  feepay_bank_name: [''],
4248
4814
  feepay_bank_branch_name: [''],
@@ -4253,7 +4819,7 @@ class FeePaymentProcessComponent {
4253
4819
  feepay_bank_account_number: [''],
4254
4820
  feepay_transaction_reference: [''],
4255
4821
  feepay_discount_percentage: [0, [Validators.min(0), Validators.max(100)]],
4256
- feepay_discount_on: [''],
4822
+ feepay_discount_on: ['SUB_TOTAL'],
4257
4823
  feepay_discount_reason: [''],
4258
4824
  feepay_remarks: [''],
4259
4825
  pay_full_outstanding: [false],
@@ -4265,51 +4831,83 @@ class FeePaymentProcessComponent {
4265
4831
  outstandingFees = signal([], ...(ngDevMode ? [{ debugName: "outstandingFees" }] : []));
4266
4832
  showChequeDetails = signal(false, ...(ngDevMode ? [{ debugName: "showChequeDetails" }] : []));
4267
4833
  showBankDetails = signal(false, ...(ngDevMode ? [{ debugName: "showBankDetails" }] : []));
4268
- // Payment method options
4269
- paymentMethodOptions = [
4270
- { value: 'CASH', label: 'Cash' },
4271
- { value: 'CHEQUE', label: 'Cheque' },
4272
- { value: 'DD', label: 'DD' },
4273
- { value: 'ONLINE', label: 'Online' },
4274
- { value: 'CARD', label: 'Card' },
4275
- { value: 'UPI', label: 'UPI' },
4276
- { value: 'NET_BANKING', label: 'Net Banking' },
4277
- { value: 'BANK_TRANSFER', label: 'Bank Transfer' }
4278
- ];
4834
+ // Grid ViewChilds for templates
4835
+ selectTemplate = viewChild('selectTemplate', ...(ngDevMode ? [{ debugName: "selectTemplate" }] : []));
4836
+ amountPaidTemplate = viewChild('amountPaidTemplate', ...(ngDevMode ? [{ debugName: "amountPaidTemplate" }] : []));
4837
+ outstandingTemplate = viewChild('outstandingTemplate', ...(ngDevMode ? [{ debugName: "outstandingTemplate" }] : []));
4838
+ dateTemplate = viewChild('dateTemplate', ...(ngDevMode ? [{ debugName: "dateTemplate" }] : []));
4839
+ templateRenderers = computed(() => ({
4840
+ selectRenderer: this.selectTemplate(),
4841
+ amountPaidRenderer: this.amountPaidTemplate(),
4842
+ outstandingRenderer: this.outstandingTemplate(),
4843
+ dateRenderer: this.dateTemplate()
4844
+ }), ...(ngDevMode ? [{ debugName: "templateRenderers" }] : []));
4845
+ gridConfig = computed(() => ({
4846
+ id: 'outstanding-fees-grid',
4847
+ columns: [
4848
+ { key: 'is_selected', header: '', type: 'custom', width: '40px', renderer: 'selectRenderer', align: 'center' },
4849
+ { key: 'fee_head', header: 'Fee Head', type: 'text', width: 'auto' },
4850
+ { key: 'fee_category', header: 'Category', type: 'text', width: '120px' },
4851
+ { key: 'due_date', header: 'Due Date', type: 'custom', width: '100px', renderer: 'dateRenderer' },
4852
+ { key: 'outstanding_amount', header: 'Outstanding', type: 'custom', width: '110px', renderer: 'outstandingRenderer', align: 'right' },
4853
+ { key: 'late_fee', header: 'Late Fee', type: 'number', width: '80px', align: 'right' },
4854
+ { key: 'amount_paid', header: 'Amount to Pay', type: 'custom', width: '130px', renderer: 'amountPaidRenderer', align: 'right' }
4855
+ ],
4856
+ data: this.outstandingFees(),
4857
+ trackBy: 'id',
4858
+ pagination: { enabled: false, pageSize: 100, pageSizeOptions: [100], showQuickJump: false, showPageInfo: false, showRefresh: false },
4859
+ search: { enabled: false, placeholder: '', searchableColumns: [] },
4860
+ loading: { useDefer: true, skeletonRows: 3, showOverlay: this.loading() },
4861
+ bordered: true,
4862
+ compact: true,
4863
+ striped: true,
4864
+ responsive: true,
4865
+ tableClass: 'tw-text-xs'
4866
+ }), ...(ngDevMode ? [{ debugName: "gridConfig" }] : []));
4867
+ // Track form values for reactive computations
4868
+ formValues = toSignal(this.paymentForm.valueChanges, { initialValue: this.paymentForm.value });
4869
+ // Breadcrumb data for shared wrapper
4870
+ breadcrumbData = signal([], ...(ngDevMode ? [{ debugName: "breadcrumbData" }] : []));
4871
+ // Payment method options from General Master
4872
+ paymentMethodOptions = signal([], ...(ngDevMode ? [{ debugName: "paymentMethodOptions" }] : []));
4873
+ paymentMethodsRaw = signal([], ...(ngDevMode ? [{ debugName: "paymentMethodsRaw" }] : []));
4874
+ paymentStatusesRaw = signal([], ...(ngDevMode ? [{ debugName: "paymentStatusesRaw" }] : []));
4875
+ studentListOptions = signal([], ...(ngDevMode ? [{ debugName: "studentListOptions" }] : []));
4279
4876
  // Computed values
4280
4877
  selectedFeeItems = computed(() => {
4281
- const items = this.feeItemsArray.controls;
4282
- return items.filter((control, index) => {
4283
- const isSelected = control.get('is_selected')?.value;
4284
- return isSelected;
4285
- });
4878
+ const values = this.formValues();
4879
+ const items = values.fee_items || [];
4880
+ return items.filter((item) => item.is_selected);
4286
4881
  }, ...(ngDevMode ? [{ debugName: "selectedFeeItems" }] : []));
4287
4882
  totalFeeAmount = computed(() => {
4288
- let total = 0;
4289
- this.feeItemsArray.controls.forEach(control => {
4290
- if (control.get('is_selected')?.value) {
4291
- total += parseFloat(control.get('amount_paid')?.value || '0');
4883
+ const values = this.formValues(); // usage tracks dependency
4884
+ const items = values.fee_items || [];
4885
+ return items.reduce((acc, item) => {
4886
+ if (item.is_selected) {
4887
+ return acc + (parseFloat(String(item.amount_paid || '0')) || 0);
4292
4888
  }
4293
- });
4294
- return total;
4889
+ return acc;
4890
+ }, 0);
4295
4891
  }, ...(ngDevMode ? [{ debugName: "totalFeeAmount" }] : []));
4296
4892
  totalLateFee = computed(() => {
4297
- let total = 0;
4298
- this.feeItemsArray.controls.forEach(control => {
4299
- if (control.get('is_selected')?.value) {
4300
- total += parseFloat(control.get('late_fee')?.value || '0');
4893
+ const values = this.formValues();
4894
+ const items = values.fee_items || [];
4895
+ return items.reduce((acc, item) => {
4896
+ if (item.is_selected) {
4897
+ return acc + (parseFloat(String(item.late_fee || '0')) || 0);
4301
4898
  }
4302
- });
4303
- return total;
4899
+ return acc;
4900
+ }, 0);
4304
4901
  }, ...(ngDevMode ? [{ debugName: "totalLateFee" }] : []));
4305
4902
  totalPenalty = computed(() => {
4306
- let total = 0;
4307
- this.feeItemsArray.controls.forEach(control => {
4308
- if (control.get('is_selected')?.value) {
4309
- total += parseFloat(control.get('penalty')?.value || '0');
4903
+ const values = this.formValues();
4904
+ const items = values.fee_items || [];
4905
+ return items.reduce((acc, item) => {
4906
+ if (item.is_selected) {
4907
+ return acc + (parseFloat(String(item.penalty || '0')) || 0);
4310
4908
  }
4311
- });
4312
- return total;
4909
+ return acc;
4910
+ }, 0);
4313
4911
  }, ...(ngDevMode ? [{ debugName: "totalPenalty" }] : []));
4314
4912
  totalPayable = computed(() => {
4315
4913
  return this.totalFeeAmount() + this.totalLateFee() + this.totalPenalty();
@@ -4319,100 +4917,152 @@ class FeePaymentProcessComponent {
4319
4917
  return this.paymentForm.get('fee_items');
4320
4918
  }
4321
4919
  ngOnInit() {
4322
- // Initialize rights for fee payment management
4323
- this.rightsService.initializeRights('fee_payment');
4920
+ console.log('💰 Fee Payment Process Component initialized');
4921
+ this.updateBreadcrumbData();
4922
+ this.loadPaymentMethodMasters();
4923
+ this.loadPaymentStatusMasters();
4924
+ this.setupFormListeners();
4324
4925
  this.setupPaymentMethodListener();
4325
4926
  }
4927
+ loadPaymentStatusMasters() {
4928
+ this.generalMasterService.getMasterList({ sygmt_code: 'payment_status' }).subscribe({
4929
+ next: (response) => {
4930
+ if (response?.success && response?.data) {
4931
+ this.paymentStatusesRaw.set(Array.isArray(response.data) ? response.data : [response.data]);
4932
+ }
4933
+ }
4934
+ });
4935
+ }
4936
+ loadPaymentMethodMasters() {
4937
+ this.generalMasterService.getMasterList({ sygmt_code: 'payment_method' }).subscribe({
4938
+ next: (response) => {
4939
+ if (response?.success && response?.data) {
4940
+ const data = Array.isArray(response.data) ? response.data : [response.data];
4941
+ this.paymentMethodsRaw.set(data);
4942
+ const options = data.map((item) => ({
4943
+ label: item.sygms_title || '',
4944
+ value: item._id || ''
4945
+ }));
4946
+ this.paymentMethodOptions.set(options);
4947
+ if (options.length > 0 && !this.paymentForm.get('feepay_payment_method')?.value) {
4948
+ this.paymentForm.patchValue({ feepay_payment_method: options[0].value });
4949
+ }
4950
+ }
4951
+ },
4952
+ error: (err) => console.error('Error loading payment methods:', err)
4953
+ });
4954
+ }
4955
+ setupFormListeners() {
4956
+ this.rightsService.initializeRights('fee_payment');
4957
+ this.onSearchStudents('');
4958
+ this.paymentForm.get('student_id')?.valueChanges
4959
+ .pipe(takeUntilDestroyed(this.destroyRef))
4960
+ .subscribe(studentId => {
4961
+ if (studentId) {
4962
+ this.loadStudentDetails(studentId);
4963
+ }
4964
+ else {
4965
+ this.selectedStudent.set(null);
4966
+ this.outstandingFees.set([]);
4967
+ this.initializeFeeItems([]);
4968
+ }
4969
+ });
4970
+ }
4326
4971
  setupPaymentMethodListener() {
4327
4972
  this.paymentForm.get('feepay_payment_method')?.valueChanges
4328
4973
  .pipe(takeUntilDestroyed(this.destroyRef))
4329
4974
  .subscribe(method => {
4330
4975
  this.showChequeDetails.set(method === 'CHEQUE' || method === 'DD');
4331
4976
  this.showBankDetails.set(method === 'BANK_TRANSFER' || method === 'NET_BANKING');
4332
- // Set required validators based on payment method
4333
- if (this.showChequeDetails()) {
4334
- this.paymentForm.get('feepay_cheque_number')?.setValidators([Validators.required]);
4335
- this.paymentForm.get('feepay_cheque_date')?.setValidators([Validators.required]);
4336
- this.paymentForm.get('feepay_bank_name')?.setValidators([Validators.required]);
4337
- }
4338
- else {
4339
- this.paymentForm.get('feepay_cheque_number')?.clearValidators();
4340
- this.paymentForm.get('feepay_cheque_date')?.clearValidators();
4341
- this.paymentForm.get('feepay_bank_name')?.clearValidators();
4342
- }
4343
- if (this.showBankDetails()) {
4344
- this.paymentForm.get('feepay_transaction_reference')?.setValidators([Validators.required]);
4345
- }
4346
- else {
4347
- this.paymentForm.get('feepay_transaction_reference')?.clearValidators();
4348
- }
4977
+ this.paymentForm.get('feepay_cheque_number')?.clearValidators();
4978
+ this.paymentForm.get('feepay_cheque_date')?.clearValidators();
4979
+ this.paymentForm.get('feepay_bank_name')?.clearValidators();
4980
+ this.paymentForm.get('feepay_transaction_reference')?.clearValidators();
4349
4981
  this.paymentForm.updateValueAndValidity();
4350
4982
  });
4351
4983
  }
4352
- onStudentSearch(query) {
4353
- const searchQuery = String(query || '');
4354
- if (searchQuery.length < 3) {
4355
- this.selectedStudent.set(null);
4356
- this.paymentForm.patchValue({ student_id: '' });
4357
- return;
4358
- }
4984
+ onStudentSearch(event) {
4985
+ const query = typeof event === 'object' ? event.query : String(event || '');
4986
+ this.onSearchStudents(query);
4987
+ }
4988
+ onSearchStudents(query) {
4359
4989
  this.loading.set(true);
4360
- // Search for students using user master service
4361
4990
  const payload = {
4362
- query: searchQuery,
4991
+ query,
4363
4992
  pageIndex: 1,
4364
- pageSize: 10,
4365
- pagination: true
4993
+ pageSize: 50,
4994
+ pagination: true,
4995
+ syenm_entity_id_syen: this.appStateService.getActiveEntityValue()?._id || '',
4996
+ syutm_user_type: 'STUDENT'
4366
4997
  };
4367
4998
  this.userMasterService.getUserList(payload)
4368
4999
  .pipe(takeUntilDestroyed(this.destroyRef))
4369
5000
  .subscribe({
4370
5001
  next: (response) => {
4371
5002
  if (response?.success && response?.data) {
4372
- // Filter for students only
4373
- const students = response.data.filter((user) => user.user_type_mapping?.syutm_user_type === 'STUDENT');
4374
- if (students.length === 0) {
4375
- this.notificationService.warning('No students found matching your search.');
4376
- this.selectedStudent.set(null);
4377
- this.paymentForm.patchValue({ student_id: '' });
4378
- this.loading.set(false);
4379
- return;
4380
- }
4381
- // Use first matching student (or could show dropdown for multiple matches)
4382
- const student = students[0];
4383
- const studentData = {
4384
- _id: student._id || '',
4385
- name: student.user_fullname || 'Unknown',
4386
- student_id: student.user_type_mapping?.syutm_type_specific_id || student._id || '',
4387
- class: student.class || 'N/A',
4388
- section: student.section || 'N/A'
4389
- };
4390
- this.selectedStudent.set(studentData);
4391
- this.paymentForm.patchValue({ student_id: studentData._id });
4392
- this.loadOutstandingFees(studentData._id);
5003
+ const options = response.data.map((user) => {
5004
+ const studentName = user.user_fullname || 'Unknown';
5005
+ const specificId = user.user_type_mapping?.syutm_type_specific_id || '';
5006
+ const userId = user._id || '';
5007
+ return {
5008
+ label: `${studentName}${specificId ? ' (' + specificId + ')' : ''}`,
5009
+ value: userId
5010
+ };
5011
+ });
5012
+ this.studentListOptions.set(options);
4393
5013
  }
4394
5014
  else {
4395
- this.notificationService.warning('No students found matching your search.');
4396
- this.selectedStudent.set(null);
4397
- this.paymentForm.patchValue({ student_id: '' });
5015
+ this.studentListOptions.set([]);
4398
5016
  }
4399
5017
  this.loading.set(false);
4400
5018
  },
4401
5019
  error: (err) => {
4402
5020
  console.error('Error searching for students:', err);
4403
- this.notificationService.error('Failed to search for students. Please try again.');
4404
- this.selectedStudent.set(null);
4405
- this.paymentForm.patchValue({ student_id: '' });
5021
+ this.studentListOptions.set([]);
4406
5022
  this.loading.set(false);
4407
5023
  }
4408
5024
  });
4409
5025
  }
5026
+ onStudentSelect(event) {
5027
+ const studentId = typeof event === 'object' ? (event.value || event._id) : event;
5028
+ if (studentId) {
5029
+ this.paymentForm.get('student_id')?.setValue(studentId);
5030
+ }
5031
+ }
5032
+ loadStudentDetails(studentId) {
5033
+ const payload = {
5034
+ _id: studentId,
5035
+ pagination: false,
5036
+ syenm_entity_id_syen: this.appStateService.getActiveEntityValue()?._id || '',
5037
+ syutm_user_type: 'STUDENT'
5038
+ };
5039
+ this.userMasterService.getUserList(payload).subscribe({
5040
+ next: (response) => {
5041
+ if (response?.success && response?.data) {
5042
+ const students = Array.isArray(response.data) ? response.data : [response.data];
5043
+ if (students.length > 0) {
5044
+ const studentData = students[0];
5045
+ this.selectedStudent.set({
5046
+ _id: studentData._id || '',
5047
+ name: (studentData.admap_first_name || studentData.user_fullname || 'Unknown') + ' ' + (studentData.admap_last_name || ''),
5048
+ student_id: studentData.admap_student_id || studentData.user_type_mapping?.syutm_type_specific_id || studentData._id || '',
5049
+ class: studentData.class || 'N/A',
5050
+ section: studentData.section || 'N/A',
5051
+ academic_year_id: studentData.admap_academic_year_id_acayr?._id || studentData.admap_academic_year_id_acayr
5052
+ });
5053
+ this.loadOutstandingFees(studentId);
5054
+ }
5055
+ }
5056
+ },
5057
+ error: (err) => console.error('Error fetching student details:', err)
5058
+ });
5059
+ }
4410
5060
  loadOutstandingFees(studentId) {
4411
5061
  this.loading.set(true);
4412
- // Get outstanding fees from fee assignments
4413
5062
  const payload = {
4414
- feeas_student_id: studentId,
4415
- feeas_status: 'PENDING' // Get only pending or partially paid assignments
5063
+ feeas_student_id_auth: studentId,
5064
+ feeas_entity_id_syen: this.appStateService.getActiveEntityValue()?._id,
5065
+ feeas_academic_year_id_acayr: this.appStateService.getActiveAcademicYearValue()?._id
4416
5066
  };
4417
5067
  this.feeAssignmentService.getFeeAssignmentList(payload).subscribe({
4418
5068
  next: (response) => {
@@ -4420,21 +5070,22 @@ class FeePaymentProcessComponent {
4420
5070
  const today = new Date();
4421
5071
  const outstandingFees = response.data
4422
5072
  .filter((assignment) => {
4423
- // Only include assignments with outstanding amount > 0
4424
- const outstanding = assignment.feeas_amount_remaining ||
4425
- (assignment.feeas_final_amount || 0) - (assignment.feeas_amount_paid || 0);
4426
- return outstanding > 0;
5073
+ const total = assignment.feeas_total_amount || 0;
5074
+ const paid = assignment.feeas_amount_paid || 0;
5075
+ const outstanding = assignment.feeas_outstanding_amount !== undefined ? assignment.feeas_outstanding_amount : (total - paid);
5076
+ return outstanding > 0 && assignment.feeas_status !== 'PAID';
4427
5077
  })
4428
5078
  .map((assignment) => {
4429
- const dueDate = assignment.feeas_due_date ? new Date(assignment.feeas_due_date) : null;
4430
- const outstanding = assignment.feeas_amount_remaining ||
4431
- (assignment.feeas_final_amount || 0) - (assignment.feeas_amount_paid || 0);
5079
+ const total = assignment.feeas_total_amount || 0;
5080
+ const paid = assignment.feeas_amount_paid || 0;
5081
+ const outstanding = assignment.feeas_outstanding_amount !== undefined ? assignment.feeas_outstanding_amount : (total - paid);
4432
5082
  const lateFee = assignment.feeas_late_fee_applied || 0;
5083
+ const dueDate = assignment.feeas_due_date ? new Date(assignment.feeas_due_date) : null;
4433
5084
  return {
4434
5085
  id: assignment._id || '',
4435
5086
  assignment_id: assignment._id || '',
4436
5087
  fee_head: assignment.feeas_fee_name || 'Fee',
4437
- fee_category: assignment.feeas_fee_category_sygms || 'OTHER',
5088
+ fee_category: assignment.feeas_fee_category_sygms?.sygms_title || assignment.feeas_fee_category_sygms || 'OTHER',
4438
5089
  due_date: dueDate || new Date(),
4439
5090
  outstanding_amount: outstanding,
4440
5091
  late_fee: lateFee,
@@ -4444,96 +5095,84 @@ class FeePaymentProcessComponent {
4444
5095
  });
4445
5096
  this.outstandingFees.set(outstandingFees);
4446
5097
  this.initializeFeeItems(outstandingFees);
5098
+ // Try to discover class/section info from assignments if not already present or if we find something better
5099
+ const infoSource = response.data.find((a) => a.feeas_class_program_id_acacpm?.acacpm_alise_title ||
5100
+ a.feeas_section_id_acapts?.acapts_name ||
5101
+ a.class || a.section);
5102
+ if (infoSource && this.selectedStudent()) {
5103
+ const current = this.selectedStudent();
5104
+ const newClass = infoSource.class || infoSource.feeas_class_program_id_acacpm?.acacpm_alise_title;
5105
+ const newSection = infoSource.section || infoSource.feeas_section_id_acapts?.acapts_name;
5106
+ if ((newClass && (current.class === 'N/A' || !current.class)) ||
5107
+ (newSection && (current.section === 'N/A' || !current.section))) {
5108
+ this.selectedStudent.set({
5109
+ ...current,
5110
+ class: newClass || current.class,
5111
+ section: newSection || current.section
5112
+ });
5113
+ }
5114
+ }
4447
5115
  }
4448
- else {
4449
- this.outstandingFees.set([]);
4450
- this.initializeFeeItems([]);
4451
- }
5116
+ this.loading.set(false);
4452
5117
  },
4453
5118
  error: (err) => {
4454
- console.error('Error loading outstanding fees:', err);
4455
- this.notificationService.error('Failed to load outstanding fees');
4456
- this.outstandingFees.set([]);
4457
- this.initializeFeeItems([]);
4458
- },
4459
- complete: () => {
5119
+ console.error('Error loading fees:', err);
4460
5120
  this.loading.set(false);
4461
5121
  }
4462
5122
  });
4463
5123
  }
4464
5124
  initializeFeeItems(fees) {
4465
- // Clear existing items
4466
- while (this.feeItemsArray.length !== 0) {
4467
- this.feeItemsArray.removeAt(0);
4468
- }
4469
- // Add fee items
5125
+ const feeItems = this.paymentForm.get('fee_items');
5126
+ feeItems.clear();
4470
5127
  fees.forEach(fee => {
4471
- const itemGroup = this.fb.group({
5128
+ feeItems.push(this.fb.group({
5129
+ is_selected: [false],
4472
5130
  assignment_id: [fee.assignment_id],
4473
5131
  fee_head: [fee.fee_head],
4474
5132
  fee_category: [fee.fee_category],
5133
+ due_date: [fee.due_date],
4475
5134
  outstanding_amount: [fee.outstanding_amount],
4476
- is_selected: [false],
4477
- amount_paid: [fee.outstanding_amount, [Validators.required, Validators.min(0)]],
4478
5135
  late_fee: [fee.late_fee],
4479
- penalty: [fee.penalty || 0]
4480
- });
4481
- // Set max validator for amount_paid
4482
- itemGroup.get('amount_paid')?.setValidators([
4483
- Validators.required,
4484
- Validators.min(0),
4485
- Validators.max(fee.outstanding_amount)
4486
- ]);
4487
- this.feeItemsArray.push(itemGroup);
5136
+ penalty: [fee.penalty || 0],
5137
+ amount_paid: [0, [Validators.min(0), Validators.max(fee.outstanding_amount + fee.late_fee)]]
5138
+ }));
4488
5139
  });
4489
5140
  }
4490
- togglePayFullOutstanding() {
4491
- const payFull = this.paymentForm.get('pay_full_outstanding')?.value;
4492
- this.feeItemsArray.controls.forEach(control => {
4493
- control.patchValue({ is_selected: payFull });
4494
- if (payFull) {
4495
- const outstanding = control.get('outstanding_amount')?.value || 0;
4496
- control.patchValue({ amount_paid: outstanding });
4497
- }
4498
- });
5141
+ toggleFeeItem(index) {
5142
+ const item = this.feeItemsArray.at(index);
5143
+ const isSelected = item.get('is_selected')?.value;
5144
+ const outstanding = item.get('outstanding_amount')?.value || 0;
5145
+ const lateFee = item.get('late_fee')?.value || 0;
5146
+ const penalty = item.get('penalty')?.value || 0;
5147
+ item.get('amount_paid')?.setValue(isSelected ? (outstanding + lateFee + penalty) : 0);
4499
5148
  }
4500
5149
  selectAllFees() {
4501
- this.feeItemsArray.controls.forEach(control => {
4502
- control.patchValue({ is_selected: true });
4503
- const outstanding = control.get('outstanding_amount')?.value || 0;
4504
- control.patchValue({ amount_paid: outstanding });
5150
+ this.feeItemsArray.controls.forEach((_, i) => {
5151
+ this.feeItemsArray.at(i).get('is_selected')?.setValue(true);
5152
+ this.toggleFeeItem(i);
4505
5153
  });
4506
5154
  }
4507
5155
  clearAllFees() {
4508
- this.feeItemsArray.controls.forEach(control => {
4509
- control.patchValue({ is_selected: false, amount_paid: 0 });
5156
+ this.feeItemsArray.controls.forEach((_, i) => {
5157
+ this.feeItemsArray.at(i).get('is_selected')?.setValue(false);
5158
+ this.toggleFeeItem(i);
4510
5159
  });
4511
- this.paymentForm.patchValue({ pay_full_outstanding: false });
4512
- }
4513
- toggleFeeItem(index) {
4514
- const control = this.feeItemsArray.at(index);
4515
- const isSelected = control.get('is_selected')?.value;
4516
- control.patchValue({ is_selected: !isSelected });
4517
- if (!isSelected) {
4518
- const outstanding = control.get('outstanding_amount')?.value || 0;
4519
- control.patchValue({ amount_paid: outstanding });
4520
- }
4521
- else {
4522
- control.patchValue({ amount_paid: 0 });
4523
- }
4524
5160
  }
4525
5161
  onAmountChange(index, value) {
4526
- const control = this.feeItemsArray.at(index);
4527
- const outstanding = control.get('outstanding_amount')?.value || 0;
4528
- const numValue = parseFloat(String(value || '0')) || 0;
4529
- if (numValue > outstanding) {
4530
- control.patchValue({ amount_paid: outstanding });
4531
- this.notificationService.warning('Amount cannot exceed outstanding amount.');
5162
+ const item = this.feeItemsArray.at(index);
5163
+ const outstanding = item.get('outstanding_amount')?.value || 0;
5164
+ const lateFee = item.get('late_fee')?.value || 0;
5165
+ const penalty = item.get('penalty')?.value || 0;
5166
+ const max = outstanding + lateFee + penalty;
5167
+ const val = parseFloat(String(value || '0')) || 0;
5168
+ if (val > max) {
5169
+ item.get('amount_paid')?.setValue(max);
5170
+ this.notificationService.warning('Amount exceeds total payable');
4532
5171
  }
4533
5172
  }
4534
5173
  onSubmit() {
4535
5174
  if (!this.rightsService.hasRight('CREATE')) {
4536
- this.notificationService.error('You do not have permission to process payments');
5175
+ this.notificationService.error('Insufficient permissions');
4537
5176
  return;
4538
5177
  }
4539
5178
  if (this.paymentForm.invalid || this.submitting()) {
@@ -4542,63 +5181,36 @@ class FeePaymentProcessComponent {
4542
5181
  return;
4543
5182
  }
4544
5183
  if (this.selectedFeeItems().length === 0) {
4545
- this.notificationService.warning('Please select at least one fee item to pay.');
4546
- return;
4547
- }
4548
- if (this.totalPayable() <= 0) {
4549
- this.notificationService.warning('Total payable amount must be greater than zero.');
5184
+ this.notificationService.warning('Select fees to pay');
4550
5185
  return;
4551
5186
  }
4552
5187
  this.submitting.set(true);
4553
- const formValue = this.paymentForm.value;
4554
- const selectedItems = this.feeItemsArray.controls
4555
- .map((control, index) => ({ control, index }))
4556
- .filter(({ control }) => control.get('is_selected')?.value)
4557
- .map(({ control, index }) => ({
4558
- assignment_id: control.get('assignment_id')?.value,
4559
- amount_paid: control.get('amount_paid')?.value,
4560
- late_fee: control.get('late_fee')?.value,
4561
- penalty: control.get('penalty')?.value
4562
- }));
4563
- // Create payload with all fields - using Record to allow all schema fields
4564
- const payloadData = {
4565
- feepay_student_id: formValue.student_id,
4566
- feepay_payment_date: new Date(formValue.feepay_payment_date),
4567
- feepay_payment_mode: formValue.feepay_payment_mode,
4568
- feepay_payment_reference: formValue.feepay_payment_reference ||
4569
- formValue.feepay_cheque_number ||
4570
- formValue.feepay_transaction_reference,
4571
- feepay_bank_name: formValue.feepay_bank_name,
4572
- feepay_bank_branch_name: formValue.feepay_bank_branch_name,
4573
- feepay_bank_ifsc_code: formValue.feepay_bank_ifsc_code,
4574
- feepay_instrument_date: formValue.feepay_instrument_date ? new Date(formValue.feepay_instrument_date) : undefined,
4575
- feepay_cheque_number: formValue.feepay_cheque_number,
4576
- feepay_cheque_date: formValue.feepay_cheque_date ? new Date(formValue.feepay_cheque_date) : undefined,
4577
- feepay_bank_account_number: formValue.feepay_bank_account_number,
4578
- feepay_transaction_reference: formValue.feepay_transaction_reference,
4579
- feepay_discount_percentage: formValue.feepay_discount_percentage || 0,
4580
- feepay_discount_on: formValue.feepay_discount_on,
4581
- feepay_discount_reason: formValue.feepay_discount_reason,
5188
+ const val = this.paymentForm.value;
5189
+ const selectedGM = this.paymentMethodsRaw().find(m => m._id === val.feepay_payment_method);
5190
+ const payload = {
5191
+ feepay_student_id_auth: val.student_id,
5192
+ feepay_academic_year_id_acayr: this.selectedStudent()?.academic_year_id || this.outstandingFees()?.[0]?.id,
5193
+ feepay_entity_id_syen: this.appStateService.getActiveEntityValue()?._id,
5194
+ feepay_payment_date: new Date(val.feepay_payment_date),
5195
+ feepay_payment_mode_id_sygms: val.feepay_payment_method,
5196
+ feepay_payment_reference: val.feepay_payment_reference || val.feepay_cheque_number || val.feepay_transaction_reference,
4582
5197
  feepay_total_amount: this.totalPayable(),
4583
- feepay_late_fee_amount: this.totalLateFee(),
4584
- feepay_status: 'SUCCESS',
4585
- feepay_remarks: formValue.feepay_remarks
5198
+ feepay_status_id_sygms: this.paymentStatusesRaw().find(s => s.sygms_code === 'feepay_status_success')?._id,
5199
+ feepay_remarks: val.feepay_remarks
4586
5200
  };
4587
- const payload = new MFeePaymentInsertUpdatePayload(payloadData);
4588
5201
  this.feePaymentService.saveUpdateFeePayment(payload).subscribe({
4589
- next: (response) => {
4590
- if (response?.success) {
4591
- this.notificationService.success('Payment recorded successfully!');
5202
+ next: (res) => {
5203
+ if (res?.success) {
5204
+ this.notificationService.success('Payment recorded');
4592
5205
  this.router.navigate(['/control-panel/payment']);
4593
5206
  }
4594
5207
  else {
4595
- this.notificationService.error(response?.message || 'Failed to record payment.');
4596
- this.submitting.set(false);
5208
+ this.notificationService.error(res?.message || 'Failed');
4597
5209
  }
5210
+ this.submitting.set(false);
4598
5211
  },
4599
- error: (error) => {
4600
- console.error('Error recording payment:', error);
4601
- this.notificationService.error('Failed to record payment. Please try again.');
5212
+ error: () => {
5213
+ this.notificationService.error('Error occurred');
4602
5214
  this.submitting.set(false);
4603
5215
  }
4604
5216
  });
@@ -4606,31 +5218,36 @@ class FeePaymentProcessComponent {
4606
5218
  onCancel() {
4607
5219
  if (this.paymentForm.dirty) {
4608
5220
  this.confirmationService.ask({
4609
- title: 'Discard Changes?',
5221
+ title: 'Unsaved Changes',
4610
5222
  message: 'You have unsaved changes. Are you sure you want to leave?',
4611
- confirmText: 'Discard',
4612
- cancelText: 'Cancel',
4613
- type: 'warning'
4614
- }).then((confirmed) => {
4615
- if (confirmed) {
4616
- this.router.navigate(['/control-panel/payment']);
4617
- }
4618
- });
5223
+ confirmText: 'Yes, Leave',
5224
+ cancelText: 'Stay'
5225
+ }).then(res => res && this.router.navigate(['/control-panel/payment']));
4619
5226
  }
4620
5227
  else {
4621
5228
  this.router.navigate(['/control-panel/payment']);
4622
5229
  }
4623
5230
  }
4624
5231
  formatCurrency(amount) {
4625
- return `₹${amount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
5232
+ return `₹${(amount || 0).toLocaleString('en-IN', { minimumFractionDigits: 2 })}`;
4626
5233
  }
4627
5234
  isOverdue(date) {
4628
5235
  return new Date(date) < new Date();
4629
5236
  }
4630
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeePaymentProcessComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4631
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: FeePaymentProcessComponent, isStandalone: true, selector: "cide-fee-payment-process", ngImport: i0, template: "<!-- Payment Process Form -->\n<div class=\"tw-w-full tw-h-full\">\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"paymentForm\" \n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n\n <!-- Header Section -->\n <div class=\"tw-table-row tw-w-full tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\n \n <!-- Title -->\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">payment</cide-ele-icon>\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Record Payment</h5>\n </div>\n\n <!-- Actions -->\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\n <!-- Back button or other actions can be added here if needed -->\n </div>\n </div>\n </div>\n </div>\n\n <!-- Form Content -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-6\">\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n <div class=\"tw-space-y-4\">\n\n <!-- Student Information -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 tw-mb-3\">Student Information</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <div>\n <cide-ele-input \n label=\"Search Student\" \n formControlName=\"student_search\"\n placeholder=\"Enter student name or ID...\"\n size=\"sm\"\n leadingIcon=\"search\"\n (ngModelChange)=\"onStudentSearch($event)\">\n </cide-ele-input>\n \n @if (selectedStudent()) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-green-50 tw-border tw-border-green-200 tw-rounded\">\n <div class=\"tw-text-sm tw-font-medium tw-text-green-900\">{{ selectedStudent()?.name }}</div>\n <div class=\"tw-text-xs tw-text-green-700\">ID: {{ selectedStudent()?.student_id }}</div>\n @if (selectedStudent()?.class) {\n <div class=\"tw-text-xs tw-text-green-600\">{{ selectedStudent()?.class }} / {{ selectedStudent()?.section }}</div>\n }\n </div>\n }\n </div>\n\n <cide-ele-input \n label=\"Payment Date\" \n formControlName=\"feepay_payment_date\"\n type=\"date\"\n size=\"sm\"\n leadingIcon=\"calendar_today\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Fee Selection -->\n @if (selectedStudent() && outstandingFees().length > 0) {\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-p-4\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900\">Select Fees to Pay</h6>\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-input \n formControlName=\"pay_full_outstanding\" \n type=\"checkbox\" \n size=\"sm\"\n (change)=\"togglePayFullOutstanding()\">\n </cide-ele-input>\n <span class=\"tw-text-sm tw-text-gray-700\">Pay full outstanding</span>\n </div>\n <button cideEleButton type=\"button\" variant=\"success\" size=\"xs\" (click)=\"selectAllFees()\">\n Select All\n </button>\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"xs\" (click)=\"clearAllFees()\">\n Clear\n </button>\n </div>\n </div>\n\n <div formArrayName=\"fee_items\" class=\"tw-space-y-2 tw-max-h-80 tw-overflow-y-auto tw-border tw-border-gray-200 tw-rounded-lg tw-p-3\">\n @for (item of feeItemsArray.controls; track $index) {\n <div class=\"tw-flex tw-items-center tw-justify-between tw-p-2 tw-bg-gray-50 tw-rounded tw-border tw-border-gray-200\"\n [formGroupName]=\"$index\">\n \n <div class=\"tw-flex tw-items-center tw-gap-2 tw-flex-1\">\n <cide-ele-input \n formControlName=\"is_selected\" \n type=\"checkbox\" \n size=\"sm\"\n (change)=\"toggleFeeItem($index)\">\n </cide-ele-input>\n \n <div class=\"tw-flex-1\">\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900\">\n {{ item.get('fee_head')?.value }}\n </div>\n <div class=\"tw-text-xs tw-text-gray-500\">\n Outstanding: {{ formatCurrency(item.get('outstanding_amount')?.value || 0) }}\n @if (item.get('late_fee')?.value > 0) {\n <span class=\"tw-text-red-600\"> | Late Fee: {{ formatCurrency(item.get('late_fee')?.value) }}</span>\n }\n </div>\n </div>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-input \n formControlName=\"amount_paid\"\n type=\"number\"\n placeholder=\"0.00\"\n size=\"sm\"\n [disabled]=\"!item.get('is_selected')?.value\"\n (ngModelChange)=\"onAmountChange($index, $event)\"\n class=\"tw-w-28\">\n </cide-ele-input>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Payment Details -->\n @if (selectedStudent()) {\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 tw-mb-3\">Payment Details</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select \n label=\"Payment Method\" \n formControlName=\"feepay_payment_method\"\n [options]=\"paymentMethodOptions\"\n size=\"sm\"\n leadingIcon=\"payment\">\n </cide-ele-select>\n\n <cide-ele-select \n label=\"Payment Mode\" \n formControlName=\"feepay_payment_mode\"\n [options]=\"[{value: 'OFFLINE', label: 'Offline'}, {value: 'ONLINE', label: 'Online'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <!-- Cheque/DD Details -->\n @if (showChequeDetails()) {\n <div class=\"tw-mt-4 tw-p-3 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-blue-900 tw-mb-3\">Cheque/DD Details</h6>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input \n label=\"Cheque/DD Number\" \n formControlName=\"feepay_cheque_number\"\n placeholder=\"Enter cheque/DD number\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Cheque/DD Date\" \n formControlName=\"feepay_cheque_date\"\n type=\"date\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-mt-3\">\n <cide-ele-input \n label=\"Bank Name\" \n formControlName=\"feepay_bank_name\"\n placeholder=\"Enter bank name\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Branch Name\" \n formControlName=\"feepay_bank_branch_name\"\n placeholder=\"Enter branch name\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-mt-3\">\n <cide-ele-input \n label=\"IFSC Code\" \n formControlName=\"feepay_bank_ifsc_code\"\n placeholder=\"Enter IFSC code\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-mt-3\">\n <cide-ele-input \n label=\"Instrument Date\" \n formControlName=\"feepay_instrument_date\"\n type=\"date\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Bank Transfer Details -->\n @if (showBankDetails()) {\n <div class=\"tw-mt-4 tw-p-3 tw-bg-green-50 tw-rounded tw-border tw-border-green-200\">\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-green-900 tw-mb-3\">Bank Transfer Details</h6>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input \n label=\"Bank Name\" \n formControlName=\"feepay_bank_name\"\n placeholder=\"Enter bank name\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Branch Name\" \n formControlName=\"feepay_bank_branch_name\"\n placeholder=\"Enter branch name\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-mt-3\">\n <cide-ele-input \n label=\"IFSC Code\" \n formControlName=\"feepay_bank_ifsc_code\"\n placeholder=\"Enter IFSC code\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Account Number\" \n formControlName=\"feepay_bank_account_number\"\n placeholder=\"Enter account number\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-mt-3\">\n <cide-ele-input \n label=\"Transaction Reference\" \n formControlName=\"feepay_transaction_reference\"\n placeholder=\"Enter transaction reference\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Discount Section -->\n <div class=\"tw-mt-4 tw-p-3 tw-bg-purple-50 tw-rounded tw-border tw-border-purple-200\">\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-purple-900 tw-mb-3\">Discount Information</h6>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input \n label=\"Discount (%)\" \n formControlName=\"feepay_discount_percentage\"\n type=\"number\"\n placeholder=\"0\"\n size=\"sm\"\n [min]=\"0\"\n [max]=\"100\">\n </cide-ele-input>\n\n <cide-ele-select \n label=\"Discount On\" \n formControlName=\"feepay_discount_on\"\n [options]=\"[{value: 'SUB_TOTAL', label: 'Sub Total'}, {value: 'FEE_HEAD', label: 'Fee Head'}, {value: 'TOTAL', label: 'Total'}, {value: 'INSTALLMENT', label: 'Installment'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n <div class=\"tw-mt-3\">\n <cide-ele-textarea \n label=\"Discount Reason\" \n formControlName=\"feepay_discount_reason\"\n placeholder=\"Enter reason for discount...\"\n rows=\"2\"\n size=\"sm\">\n </cide-ele-textarea>\n </div>\n </div>\n\n <!-- Payment Reference -->\n <div class=\"tw-mt-4\">\n <cide-ele-input \n label=\"Payment Reference\" \n formControlName=\"feepay_payment_reference\"\n placeholder=\"Enter payment reference number\"\n size=\"sm\"\n leadingIcon=\"receipt\">\n </cide-ele-input>\n </div>\n\n <!-- Remarks -->\n <div class=\"tw-mt-4\">\n <cide-ele-textarea \n label=\"Remarks\" \n formControlName=\"feepay_remarks\"\n placeholder=\"Enter any additional remarks...\"\n rows=\"2\" \n size=\"sm\">\n </cide-ele-textarea>\n </div>\n </div>\n }\n\n <!-- Payment Summary -->\n @if (selectedStudent() && selectedFeeItems().length > 0) {\n <div class=\"tw-bg-gradient-to-r tw-from-green-50 tw-to-emerald-50 tw-rounded-lg tw-border tw-border-green-200 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-green-900 tw-mb-3\">Payment Summary</h6>\n \n <div class=\"tw-space-y-3\">\n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-2 tw-border-b tw-border-green-200\">\n <span class=\"tw-text-gray-700\">Fee Amount:</span>\n <span class=\"tw-font-semibold tw-text-gray-900\">{{ formatCurrency(totalFeeAmount()) }}</span>\n </div>\n \n @if (totalLateFee() > 0) {\n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-2 tw-border-b tw-border-green-200\">\n <span class=\"tw-text-gray-700\">Late Fee Amount:</span>\n <span class=\"tw-font-semibold tw-text-red-600\">{{ formatCurrency(totalLateFee()) }}</span>\n </div>\n }\n \n @if (totalPenalty() > 0) {\n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-2 tw-border-b tw-border-green-200\">\n <span class=\"tw-text-gray-700\">Penalty Amount:</span>\n <span class=\"tw-font-semibold tw-text-red-600\">{{ formatCurrency(totalPenalty()) }}</span>\n </div>\n }\n \n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-3 tw-border-t-2 tw-border-green-300 tw-mt-2\">\n <span class=\"tw-text-lg tw-font-bold tw-text-green-900\">Total Payable:</span>\n <span class=\"tw-text-2xl tw-font-bold tw-text-green-700\">{{ formatCurrency(totalPayable()) }}</span>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Form Validation Errors -->\n <!-- Action Buttons -->\n <div class=\"tw-flex tw-justify-end tw-gap-3 tw-mt-6\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"close\"\n [disabled]=\"loading()\">\n Cancel\n </button>\n\n <button cideEleButton type=\"submit\" variant=\"primary\" size=\"sm\" \n [disabled]=\"submitting() || paymentForm.invalid || selectedFeeItems().length === 0 || loading()\" \n [loading]=\"submitting()\" \n leftIcon=\"save\">\n {{ submitting() ? 'Processing...' : 'Record Payment' }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </form>\n</div>\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideTextareaComponent, selector: "cide-ele-textarea", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "minlength", "maxlength", "rows", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }] });
5237
+ updateBreadcrumbData() {
5238
+ this.breadcrumbData.set([
5239
+ {
5240
+ id: 'process',
5241
+ label: 'Process Payment',
5242
+ icon: 'payment',
5243
+ url: undefined
5244
+ }
5245
+ ]);
5246
+ }
5247
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeePaymentProcessComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5248
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FeePaymentProcessComponent, isStandalone: true, selector: "cide-fee-payment-process", viewQueries: [{ propertyName: "selectTemplate", first: true, predicate: ["selectTemplate"], descendants: true, isSignal: true }, { propertyName: "amountPaidTemplate", first: true, predicate: ["amountPaidTemplate"], descendants: true, isSignal: true }, { propertyName: "outstandingTemplate", first: true, predicate: ["outstandingTemplate"], descendants: true, isSignal: true }, { propertyName: "dateTemplate", first: true, predicate: ["dateTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_payment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n\n <!-- Main Content Grid -->\n <div class=\"tw-p-4 tw-grid tw-grid-cols-1 lg:tw-grid-cols-12 tw-gap-4 tw-h-[calc(100vh-140px)] tw-overflow-hidden\">\n\n <!-- Left: Form Controls (Col 8) -->\n <div class=\"lg:tw-col-span-8 tw-flex tw-flex-col tw-gap-4 tw-overflow-y-auto tw-pr-2\">\n\n <!-- Student Selection Card (Compact) -->\n <div class=\"glass-card tw-rounded-xl tw-p-4 tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">person_search</cide-ele-icon>\n Student Selection\n </h3>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4 tw-items-start\">\n <div [formGroup]=\"paymentForm\">\n <cide-ele-select label=\"Search Student\" placeholder=\"Enter student name or ID...\"\n [options]=\"studentListOptions()\" [loading]=\"loading()\" (searchChange)=\"onStudentSearch($event)\"\n (change)=\"onStudentSelect($event)\" size=\"sm\">\n </cide-ele-select>\n </div>\n\n @if (selectedStudent()) {\n <div\n class=\"premium-gradient tw-p-3 tw-rounded-lg tw-border tw-border-blue-100 tw-flex tw-items-center tw-gap-4\">\n <div\n class=\"tw-h-12 tw-w-12 tw-rounded-full tw-bg-blue-600 tw-flex tw-items-center tw-justify-center tw-text-white tw-font-bold tw-text-xl\">\n {{ selectedStudent()?.name?.[0] || '?' }}\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-sm tw-font-bold tw-text-gray-900\">{{ selectedStudent()?.name }}</div>\n <div class=\"tw-text-xs tw-text-gray-500\">ID: {{ selectedStudent()?.student_id }}</div>\n <div class=\"tw-text-[10px] tw-text-blue-600 tw-font-medium tw-mt-1\">\n {{ selectedStudent()?.class }} | {{ selectedStudent()?.section }}\n </div>\n </div>\n </div>\n } @else {\n <div\n class=\"tw-border tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-p-3 tw-flex tw-items-center tw-justify-center tw-text-gray-400 tw-text-xs\">\n Select a student to view details\n </div>\n }\n </div>\n </div>\n\n <!-- Outstanding Fees Grid (Premium) -->\n <div\n class=\"glass-card tw-rounded-xl tw-flex-1 tw-flex tw-flex-col tw-overflow-hidden tw-border tw-border-gray-200\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-100 tw-flex tw-items-center tw-justify-between tw-bg-gray-50/50\">\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">account_balance_wallet</cide-ele-icon>\n Outstanding Fees\n </h3>\n\n @if (outstandingFees().length > 0) {\n <div class=\"tw-flex tw-gap-2\">\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"selectAllFees()\">Select All</button>\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"clearAllFees()\">Clear</button>\n </div>\n }\n </div>\n\n <div class=\"tw-flex-1 tw-overflow-hidden\">\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n <!-- Payment Method Card (Compact) -->\n <div class=\"glass-card tw-rounded-xl tw-p-4 tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mb-3\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">payments</cide-ele-icon>\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800\">Payment Details</h3>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-2 lg:tw-grid-cols-3 tw-gap-4\" [formGroup]=\"paymentForm\">\n <cide-ele-select formControlName=\"feepay_payment_method\" label=\"Method\" [options]=\"paymentMethodOptions()\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-input formControlName=\"feepay_payment_date\" label=\"Date\" type=\"date\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input formControlName=\"feepay_payment_reference\" label=\"Reference #\" placeholder=\"Ref/Receipt No\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <!-- Dynamic Fields -->\n <div [formGroup]=\"paymentForm\" class=\"tw-mt-4 tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-4\">\n @if (showChequeDetails()) {\n <cide-ele-input formControlName=\"feepay_cheque_number\" label=\"Cheque #\" size=\"sm\"></cide-ele-input>\n <cide-ele-input formControlName=\"feepay_cheque_date\" label=\"Cheque Date\" type=\"date\"\n size=\"sm\"></cide-ele-input>\n <cide-ele-input formControlName=\"feepay_bank_name\" label=\"Bank Name\" size=\"sm\"></cide-ele-input>\n }\n @if (showBankDetails()) {\n <cide-ele-input formControlName=\"feepay_transaction_reference\" label=\"Transaction ID\" size=\"sm\"\n class=\"tw-col-span-2\"></cide-ele-input>\n }\n </div>\n </div>\n </div>\n\n <!-- Right: Summary & Action (Col 4) -->\n <div class=\"lg:tw-col-span-4 tw-h-full\">\n <div\n class=\"glass-card tw-rounded-xl tw-h-full tw-flex tw-flex-col tw-overflow-hidden tw-border tw-border-gray-200\">\n <div class=\"tw-p-4 tw-bg-blue-600 tw-text-white\">\n <h3 class=\"tw-text-lg tw-font-bold\">Payment Summary</h3>\n <p class=\"tw-text-blue-100 tw-text-xs\">Confirm your selection and totals</p>\n </div>\n\n <div class=\"tw-flex-1 tw-p-4 tw-overflow-y-auto tw-space-y-4\">\n <!-- Breakdown -->\n <div class=\"tw-space-y-2\">\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Fees Selected</span>\n <span class=\"tw-font-medium\">{{ selectedFeeItems().length }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Sub-total</span>\n <span class=\"tw-font-medium\">{{ formatCurrency(totalFeeAmount()) }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Late Fee</span>\n <span class=\"tw-text-blue-600 tw-font-medium\">+ {{ formatCurrency(totalLateFee()) }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Penalty</span>\n <span class=\"tw-text-blue-600 tw-font-medium\">+ {{ formatCurrency(totalPenalty()) }}</span>\n </div>\n </div>\n\n <div class=\"tw-border-t tw-border-gray-100 tw-pt-4\">\n <div class=\"tw-flex tw-justify-between tw-items-center\">\n <span class=\"tw-text-base tw-font-bold tw-text-gray-800\">Total Payable</span>\n <span class=\"tw-text-xl tw-font-bold tw-text-blue-600\">{{ formatCurrency(totalPayable()) }}</span>\n </div>\n </div>\n\n <!-- Remarks -->\n <div class=\"tw-mt-6\" [formGroup]=\"paymentForm\">\n <cide-ele-textarea formControlName=\"feepay_remarks\" label=\"Remarks / Notes\"\n placeholder=\"Add payment notes...\" [rows]=\"2\" size=\"sm\">\n </cide-ele-textarea>\n </div>\n </div>\n\n <div class=\"tw-p-4 tw-bg-gray-50 tw-border-t tw-border-gray-100 tw-flex tw-flex-col tw-gap-2\">\n <button cideEleButton variant=\"primary\" class=\"tw-w-full tw-py-3\" [loading]=\"submitting()\"\n [disabled]=\"submitting() || paymentForm.invalid || selectedFeeItems().length === 0 || loading()\"\n (click)=\"onSubmit()\">\n Confirm & Record Payment\n </button>\n <button cideEleButton variant=\"ghost\" class=\"tw-w-full\" (click)=\"onCancel()\" [disabled]=\"submitting()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Grid Templates -->\n<ng-template #selectTemplate let-row=\"row\">\n <div class=\"tw-flex tw-items-center tw-justify-center\" [formGroup]=\"paymentForm\">\n <ng-container formArrayName=\"fee_items\">\n @for (item of feeItemsArray.controls; track $index) {\n @if (item.get('assignment_id')?.value === row.assignment_id) {\n <div [formGroupName]=\"$index\">\n <input type=\"checkbox\" formControlName=\"is_selected\" (change)=\"toggleFeeItem($index)\"\n class=\"tw-rounded tw-border-gray-300\">\n </div>\n }\n }\n </ng-container>\n </div>\n</ng-template>\n\n<ng-template #dateTemplate let-value=\"value\">\n <div class=\"tw-text-xs tw-text-gray-600\">{{ value | date:'dd MMM yyyy' }}</div>\n</ng-template>\n\n<ng-template #outstandingTemplate let-value=\"value\">\n <div class=\"tw-font-semibold tw-text-gray-900\">{{ formatCurrency(value) }}</div>\n</ng-template>\n\n<ng-template #amountPaidTemplate let-row=\"row\">\n <div class=\"tw-flex tw-justify-end\" [formGroup]=\"paymentForm\">\n <ng-container formArrayName=\"fee_items\">\n @for (item of feeItemsArray.controls; track $index) {\n @if (item.get('assignment_id')?.value === row.assignment_id) {\n <div [formGroupName]=\"$index\" class=\"tw-w-24\">\n <cide-ele-input formControlName=\"amount_paid\" size=\"xs\" type=\"number\" [labelHide]=\"true\"\n (onValueChange)=\"onAmountChange($index, $event)\">\n </cide-ele-input>\n </div>\n }\n }\n </ng-container>\n </div>\n</ng-template>", styles: [".glass-card{background:#ffffffe6;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.2);box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.premium-gradient{background:linear-gradient(135deg,#f8fafc,#eff6ff)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideTextareaComponent, selector: "cide-ele-textarea", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "minlength", "maxlength", "rows", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }] });
4632
5249
  }
4633
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeePaymentProcessComponent, decorators: [{
5250
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeePaymentProcessComponent, decorators: [{
4634
5251
  type: Component,
4635
5252
  args: [{ selector: 'cide-fee-payment-process', standalone: true, imports: [
4636
5253
  CommonModule,
@@ -4639,9 +5256,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
4639
5256
  CideTextareaComponent,
4640
5257
  CideEleButtonComponent,
4641
5258
  CideIconComponent,
4642
- CideSelectComponent
4643
- ], template: "<!-- Payment Process Form -->\n<div class=\"tw-w-full tw-h-full\">\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"paymentForm\" \n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n\n <!-- Header Section -->\n <div class=\"tw-table-row tw-w-full tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\n \n <!-- Title -->\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">payment</cide-ele-icon>\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Record Payment</h5>\n </div>\n\n <!-- Actions -->\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\n <!-- Back button or other actions can be added here if needed -->\n </div>\n </div>\n </div>\n </div>\n\n <!-- Form Content -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-6\">\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n <div class=\"tw-space-y-4\">\n\n <!-- Student Information -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 tw-mb-3\">Student Information</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <div>\n <cide-ele-input \n label=\"Search Student\" \n formControlName=\"student_search\"\n placeholder=\"Enter student name or ID...\"\n size=\"sm\"\n leadingIcon=\"search\"\n (ngModelChange)=\"onStudentSearch($event)\">\n </cide-ele-input>\n \n @if (selectedStudent()) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-green-50 tw-border tw-border-green-200 tw-rounded\">\n <div class=\"tw-text-sm tw-font-medium tw-text-green-900\">{{ selectedStudent()?.name }}</div>\n <div class=\"tw-text-xs tw-text-green-700\">ID: {{ selectedStudent()?.student_id }}</div>\n @if (selectedStudent()?.class) {\n <div class=\"tw-text-xs tw-text-green-600\">{{ selectedStudent()?.class }} / {{ selectedStudent()?.section }}</div>\n }\n </div>\n }\n </div>\n\n <cide-ele-input \n label=\"Payment Date\" \n formControlName=\"feepay_payment_date\"\n type=\"date\"\n size=\"sm\"\n leadingIcon=\"calendar_today\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Fee Selection -->\n @if (selectedStudent() && outstandingFees().length > 0) {\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-p-4\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900\">Select Fees to Pay</h6>\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-input \n formControlName=\"pay_full_outstanding\" \n type=\"checkbox\" \n size=\"sm\"\n (change)=\"togglePayFullOutstanding()\">\n </cide-ele-input>\n <span class=\"tw-text-sm tw-text-gray-700\">Pay full outstanding</span>\n </div>\n <button cideEleButton type=\"button\" variant=\"success\" size=\"xs\" (click)=\"selectAllFees()\">\n Select All\n </button>\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"xs\" (click)=\"clearAllFees()\">\n Clear\n </button>\n </div>\n </div>\n\n <div formArrayName=\"fee_items\" class=\"tw-space-y-2 tw-max-h-80 tw-overflow-y-auto tw-border tw-border-gray-200 tw-rounded-lg tw-p-3\">\n @for (item of feeItemsArray.controls; track $index) {\n <div class=\"tw-flex tw-items-center tw-justify-between tw-p-2 tw-bg-gray-50 tw-rounded tw-border tw-border-gray-200\"\n [formGroupName]=\"$index\">\n \n <div class=\"tw-flex tw-items-center tw-gap-2 tw-flex-1\">\n <cide-ele-input \n formControlName=\"is_selected\" \n type=\"checkbox\" \n size=\"sm\"\n (change)=\"toggleFeeItem($index)\">\n </cide-ele-input>\n \n <div class=\"tw-flex-1\">\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900\">\n {{ item.get('fee_head')?.value }}\n </div>\n <div class=\"tw-text-xs tw-text-gray-500\">\n Outstanding: {{ formatCurrency(item.get('outstanding_amount')?.value || 0) }}\n @if (item.get('late_fee')?.value > 0) {\n <span class=\"tw-text-red-600\"> | Late Fee: {{ formatCurrency(item.get('late_fee')?.value) }}</span>\n }\n </div>\n </div>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-input \n formControlName=\"amount_paid\"\n type=\"number\"\n placeholder=\"0.00\"\n size=\"sm\"\n [disabled]=\"!item.get('is_selected')?.value\"\n (ngModelChange)=\"onAmountChange($index, $event)\"\n class=\"tw-w-28\">\n </cide-ele-input>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Payment Details -->\n @if (selectedStudent()) {\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-gray-900 tw-mb-3\">Payment Details</h6>\n \n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\n <cide-ele-select \n label=\"Payment Method\" \n formControlName=\"feepay_payment_method\"\n [options]=\"paymentMethodOptions\"\n size=\"sm\"\n leadingIcon=\"payment\">\n </cide-ele-select>\n\n <cide-ele-select \n label=\"Payment Mode\" \n formControlName=\"feepay_payment_mode\"\n [options]=\"[{value: 'OFFLINE', label: 'Offline'}, {value: 'ONLINE', label: 'Online'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <!-- Cheque/DD Details -->\n @if (showChequeDetails()) {\n <div class=\"tw-mt-4 tw-p-3 tw-bg-blue-50 tw-rounded tw-border tw-border-blue-200\">\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-blue-900 tw-mb-3\">Cheque/DD Details</h6>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input \n label=\"Cheque/DD Number\" \n formControlName=\"feepay_cheque_number\"\n placeholder=\"Enter cheque/DD number\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Cheque/DD Date\" \n formControlName=\"feepay_cheque_date\"\n type=\"date\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-mt-3\">\n <cide-ele-input \n label=\"Bank Name\" \n formControlName=\"feepay_bank_name\"\n placeholder=\"Enter bank name\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Branch Name\" \n formControlName=\"feepay_bank_branch_name\"\n placeholder=\"Enter branch name\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-mt-3\">\n <cide-ele-input \n label=\"IFSC Code\" \n formControlName=\"feepay_bank_ifsc_code\"\n placeholder=\"Enter IFSC code\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-mt-3\">\n <cide-ele-input \n label=\"Instrument Date\" \n formControlName=\"feepay_instrument_date\"\n type=\"date\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Bank Transfer Details -->\n @if (showBankDetails()) {\n <div class=\"tw-mt-4 tw-p-3 tw-bg-green-50 tw-rounded tw-border tw-border-green-200\">\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-green-900 tw-mb-3\">Bank Transfer Details</h6>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input \n label=\"Bank Name\" \n formControlName=\"feepay_bank_name\"\n placeholder=\"Enter bank name\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Branch Name\" \n formControlName=\"feepay_bank_branch_name\"\n placeholder=\"Enter branch name\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-mt-3\">\n <cide-ele-input \n label=\"IFSC Code\" \n formControlName=\"feepay_bank_ifsc_code\"\n placeholder=\"Enter IFSC code\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Account Number\" \n formControlName=\"feepay_bank_account_number\"\n placeholder=\"Enter account number\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n <div class=\"tw-mt-3\">\n <cide-ele-input \n label=\"Transaction Reference\" \n formControlName=\"feepay_transaction_reference\"\n placeholder=\"Enter transaction reference\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Discount Section -->\n <div class=\"tw-mt-4 tw-p-3 tw-bg-purple-50 tw-rounded tw-border tw-border-purple-200\">\n <h6 class=\"tw-text-xs tw-font-semibold tw-text-purple-900 tw-mb-3\">Discount Information</h6>\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input \n label=\"Discount (%)\" \n formControlName=\"feepay_discount_percentage\"\n type=\"number\"\n placeholder=\"0\"\n size=\"sm\"\n [min]=\"0\"\n [max]=\"100\">\n </cide-ele-input>\n\n <cide-ele-select \n label=\"Discount On\" \n formControlName=\"feepay_discount_on\"\n [options]=\"[{value: 'SUB_TOTAL', label: 'Sub Total'}, {value: 'FEE_HEAD', label: 'Fee Head'}, {value: 'TOTAL', label: 'Total'}, {value: 'INSTALLMENT', label: 'Installment'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n <div class=\"tw-mt-3\">\n <cide-ele-textarea \n label=\"Discount Reason\" \n formControlName=\"feepay_discount_reason\"\n placeholder=\"Enter reason for discount...\"\n rows=\"2\"\n size=\"sm\">\n </cide-ele-textarea>\n </div>\n </div>\n\n <!-- Payment Reference -->\n <div class=\"tw-mt-4\">\n <cide-ele-input \n label=\"Payment Reference\" \n formControlName=\"feepay_payment_reference\"\n placeholder=\"Enter payment reference number\"\n size=\"sm\"\n leadingIcon=\"receipt\">\n </cide-ele-input>\n </div>\n\n <!-- Remarks -->\n <div class=\"tw-mt-4\">\n <cide-ele-textarea \n label=\"Remarks\" \n formControlName=\"feepay_remarks\"\n placeholder=\"Enter any additional remarks...\"\n rows=\"2\" \n size=\"sm\">\n </cide-ele-textarea>\n </div>\n </div>\n }\n\n <!-- Payment Summary -->\n @if (selectedStudent() && selectedFeeItems().length > 0) {\n <div class=\"tw-bg-gradient-to-r tw-from-green-50 tw-to-emerald-50 tw-rounded-lg tw-border tw-border-green-200 tw-p-4\">\n <h6 class=\"tw-text-base tw-font-semibold tw-text-green-900 tw-mb-3\">Payment Summary</h6>\n \n <div class=\"tw-space-y-3\">\n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-2 tw-border-b tw-border-green-200\">\n <span class=\"tw-text-gray-700\">Fee Amount:</span>\n <span class=\"tw-font-semibold tw-text-gray-900\">{{ formatCurrency(totalFeeAmount()) }}</span>\n </div>\n \n @if (totalLateFee() > 0) {\n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-2 tw-border-b tw-border-green-200\">\n <span class=\"tw-text-gray-700\">Late Fee Amount:</span>\n <span class=\"tw-font-semibold tw-text-red-600\">{{ formatCurrency(totalLateFee()) }}</span>\n </div>\n }\n \n @if (totalPenalty() > 0) {\n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-2 tw-border-b tw-border-green-200\">\n <span class=\"tw-text-gray-700\">Penalty Amount:</span>\n <span class=\"tw-font-semibold tw-text-red-600\">{{ formatCurrency(totalPenalty()) }}</span>\n </div>\n }\n \n <div class=\"tw-flex tw-justify-between tw-items-center tw-py-3 tw-border-t-2 tw-border-green-300 tw-mt-2\">\n <span class=\"tw-text-lg tw-font-bold tw-text-green-900\">Total Payable:</span>\n <span class=\"tw-text-2xl tw-font-bold tw-text-green-700\">{{ formatCurrency(totalPayable()) }}</span>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Form Validation Errors -->\n <!-- Action Buttons -->\n <div class=\"tw-flex tw-justify-end tw-gap-3 tw-mt-6\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"onCancel()\" leftIcon=\"close\"\n [disabled]=\"loading()\">\n Cancel\n </button>\n\n <button cideEleButton type=\"submit\" variant=\"primary\" size=\"sm\" \n [disabled]=\"submitting() || paymentForm.invalid || selectedFeeItems().length === 0 || loading()\" \n [loading]=\"submitting()\" \n leftIcon=\"save\">\n {{ submitting() ? 'Processing...' : 'Record Payment' }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </form>\n</div>\n\n" }]
4644
- }] });
5259
+ CideSelectComponent,
5260
+ CideLytSharedWrapperComponent,
5261
+ CideEleDataGridComponent
5262
+ ], template: "<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'fee_payment' }\"\n [breadcrumb_data]=\"breadcrumbData()\">\n\n <!-- Main Content Grid -->\n <div class=\"tw-p-4 tw-grid tw-grid-cols-1 lg:tw-grid-cols-12 tw-gap-4 tw-h-[calc(100vh-140px)] tw-overflow-hidden\">\n\n <!-- Left: Form Controls (Col 8) -->\n <div class=\"lg:tw-col-span-8 tw-flex tw-flex-col tw-gap-4 tw-overflow-y-auto tw-pr-2\">\n\n <!-- Student Selection Card (Compact) -->\n <div class=\"glass-card tw-rounded-xl tw-p-4 tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">person_search</cide-ele-icon>\n Student Selection\n </h3>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4 tw-items-start\">\n <div [formGroup]=\"paymentForm\">\n <cide-ele-select label=\"Search Student\" placeholder=\"Enter student name or ID...\"\n [options]=\"studentListOptions()\" [loading]=\"loading()\" (searchChange)=\"onStudentSearch($event)\"\n (change)=\"onStudentSelect($event)\" size=\"sm\">\n </cide-ele-select>\n </div>\n\n @if (selectedStudent()) {\n <div\n class=\"premium-gradient tw-p-3 tw-rounded-lg tw-border tw-border-blue-100 tw-flex tw-items-center tw-gap-4\">\n <div\n class=\"tw-h-12 tw-w-12 tw-rounded-full tw-bg-blue-600 tw-flex tw-items-center tw-justify-center tw-text-white tw-font-bold tw-text-xl\">\n {{ selectedStudent()?.name?.[0] || '?' }}\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-sm tw-font-bold tw-text-gray-900\">{{ selectedStudent()?.name }}</div>\n <div class=\"tw-text-xs tw-text-gray-500\">ID: {{ selectedStudent()?.student_id }}</div>\n <div class=\"tw-text-[10px] tw-text-blue-600 tw-font-medium tw-mt-1\">\n {{ selectedStudent()?.class }} | {{ selectedStudent()?.section }}\n </div>\n </div>\n </div>\n } @else {\n <div\n class=\"tw-border tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-p-3 tw-flex tw-items-center tw-justify-center tw-text-gray-400 tw-text-xs\">\n Select a student to view details\n </div>\n }\n </div>\n </div>\n\n <!-- Outstanding Fees Grid (Premium) -->\n <div\n class=\"glass-card tw-rounded-xl tw-flex-1 tw-flex tw-flex-col tw-overflow-hidden tw-border tw-border-gray-200\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-100 tw-flex tw-items-center tw-justify-between tw-bg-gray-50/50\">\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800 tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">account_balance_wallet</cide-ele-icon>\n Outstanding Fees\n </h3>\n\n @if (outstandingFees().length > 0) {\n <div class=\"tw-flex tw-gap-2\">\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"selectAllFees()\">Select All</button>\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"clearAllFees()\">Clear</button>\n </div>\n }\n </div>\n\n <div class=\"tw-flex-1 tw-overflow-hidden\">\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n <!-- Payment Method Card (Compact) -->\n <div class=\"glass-card tw-rounded-xl tw-p-4 tw-border tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mb-3\">\n <cide-ele-icon size=\"sm\" class=\"tw-text-blue-600\">payments</cide-ele-icon>\n <h3 class=\"tw-text-sm tw-font-bold tw-text-gray-800\">Payment Details</h3>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-2 lg:tw-grid-cols-3 tw-gap-4\" [formGroup]=\"paymentForm\">\n <cide-ele-select formControlName=\"feepay_payment_method\" label=\"Method\" [options]=\"paymentMethodOptions()\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-input formControlName=\"feepay_payment_date\" label=\"Date\" type=\"date\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input formControlName=\"feepay_payment_reference\" label=\"Reference #\" placeholder=\"Ref/Receipt No\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <!-- Dynamic Fields -->\n <div [formGroup]=\"paymentForm\" class=\"tw-mt-4 tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-4\">\n @if (showChequeDetails()) {\n <cide-ele-input formControlName=\"feepay_cheque_number\" label=\"Cheque #\" size=\"sm\"></cide-ele-input>\n <cide-ele-input formControlName=\"feepay_cheque_date\" label=\"Cheque Date\" type=\"date\"\n size=\"sm\"></cide-ele-input>\n <cide-ele-input formControlName=\"feepay_bank_name\" label=\"Bank Name\" size=\"sm\"></cide-ele-input>\n }\n @if (showBankDetails()) {\n <cide-ele-input formControlName=\"feepay_transaction_reference\" label=\"Transaction ID\" size=\"sm\"\n class=\"tw-col-span-2\"></cide-ele-input>\n }\n </div>\n </div>\n </div>\n\n <!-- Right: Summary & Action (Col 4) -->\n <div class=\"lg:tw-col-span-4 tw-h-full\">\n <div\n class=\"glass-card tw-rounded-xl tw-h-full tw-flex tw-flex-col tw-overflow-hidden tw-border tw-border-gray-200\">\n <div class=\"tw-p-4 tw-bg-blue-600 tw-text-white\">\n <h3 class=\"tw-text-lg tw-font-bold\">Payment Summary</h3>\n <p class=\"tw-text-blue-100 tw-text-xs\">Confirm your selection and totals</p>\n </div>\n\n <div class=\"tw-flex-1 tw-p-4 tw-overflow-y-auto tw-space-y-4\">\n <!-- Breakdown -->\n <div class=\"tw-space-y-2\">\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Fees Selected</span>\n <span class=\"tw-font-medium\">{{ selectedFeeItems().length }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Sub-total</span>\n <span class=\"tw-font-medium\">{{ formatCurrency(totalFeeAmount()) }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Late Fee</span>\n <span class=\"tw-text-blue-600 tw-font-medium\">+ {{ formatCurrency(totalLateFee()) }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-500\">Penalty</span>\n <span class=\"tw-text-blue-600 tw-font-medium\">+ {{ formatCurrency(totalPenalty()) }}</span>\n </div>\n </div>\n\n <div class=\"tw-border-t tw-border-gray-100 tw-pt-4\">\n <div class=\"tw-flex tw-justify-between tw-items-center\">\n <span class=\"tw-text-base tw-font-bold tw-text-gray-800\">Total Payable</span>\n <span class=\"tw-text-xl tw-font-bold tw-text-blue-600\">{{ formatCurrency(totalPayable()) }}</span>\n </div>\n </div>\n\n <!-- Remarks -->\n <div class=\"tw-mt-6\" [formGroup]=\"paymentForm\">\n <cide-ele-textarea formControlName=\"feepay_remarks\" label=\"Remarks / Notes\"\n placeholder=\"Add payment notes...\" [rows]=\"2\" size=\"sm\">\n </cide-ele-textarea>\n </div>\n </div>\n\n <div class=\"tw-p-4 tw-bg-gray-50 tw-border-t tw-border-gray-100 tw-flex tw-flex-col tw-gap-2\">\n <button cideEleButton variant=\"primary\" class=\"tw-w-full tw-py-3\" [loading]=\"submitting()\"\n [disabled]=\"submitting() || paymentForm.invalid || selectedFeeItems().length === 0 || loading()\"\n (click)=\"onSubmit()\">\n Confirm & Record Payment\n </button>\n <button cideEleButton variant=\"ghost\" class=\"tw-w-full\" (click)=\"onCancel()\" [disabled]=\"submitting()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Grid Templates -->\n<ng-template #selectTemplate let-row=\"row\">\n <div class=\"tw-flex tw-items-center tw-justify-center\" [formGroup]=\"paymentForm\">\n <ng-container formArrayName=\"fee_items\">\n @for (item of feeItemsArray.controls; track $index) {\n @if (item.get('assignment_id')?.value === row.assignment_id) {\n <div [formGroupName]=\"$index\">\n <input type=\"checkbox\" formControlName=\"is_selected\" (change)=\"toggleFeeItem($index)\"\n class=\"tw-rounded tw-border-gray-300\">\n </div>\n }\n }\n </ng-container>\n </div>\n</ng-template>\n\n<ng-template #dateTemplate let-value=\"value\">\n <div class=\"tw-text-xs tw-text-gray-600\">{{ value | date:'dd MMM yyyy' }}</div>\n</ng-template>\n\n<ng-template #outstandingTemplate let-value=\"value\">\n <div class=\"tw-font-semibold tw-text-gray-900\">{{ formatCurrency(value) }}</div>\n</ng-template>\n\n<ng-template #amountPaidTemplate let-row=\"row\">\n <div class=\"tw-flex tw-justify-end\" [formGroup]=\"paymentForm\">\n <ng-container formArrayName=\"fee_items\">\n @for (item of feeItemsArray.controls; track $index) {\n @if (item.get('assignment_id')?.value === row.assignment_id) {\n <div [formGroupName]=\"$index\" class=\"tw-w-24\">\n <cide-ele-input formControlName=\"amount_paid\" size=\"xs\" type=\"number\" [labelHide]=\"true\"\n (onValueChange)=\"onAmountChange($index, $event)\">\n </cide-ele-input>\n </div>\n }\n }\n </ng-container>\n </div>\n</ng-template>", styles: [".glass-card{background:#ffffffe6;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.2);box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.premium-gradient{background:linear-gradient(135deg,#f8fafc,#eff6ff)}\n"] }]
5263
+ }], propDecorators: { selectTemplate: [{ type: i0.ViewChild, args: ['selectTemplate', { isSignal: true }] }], amountPaidTemplate: [{ type: i0.ViewChild, args: ['amountPaidTemplate', { isSignal: true }] }], outstandingTemplate: [{ type: i0.ViewChild, args: ['outstandingTemplate', { isSignal: true }] }], dateTemplate: [{ type: i0.ViewChild, args: ['dateTemplate', { isSignal: true }] }] } });
4645
5264
 
4646
5265
  var feePaymentProcess_component = /*#__PURE__*/Object.freeze({
4647
5266
  __proto__: null,
@@ -4951,8 +5570,8 @@ class FeePaymentViewComponent {
4951
5570
  goBack() {
4952
5571
  this.router.navigate(['/control-panel/payment']);
4953
5572
  }
4954
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeePaymentViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4955
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: FeePaymentViewComponent, isStandalone: true, selector: "cide-fee-payment-view", ngImport: i0, template: `
5573
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeePaymentViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5574
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FeePaymentViewComponent, isStandalone: true, selector: "cide-fee-payment-view", ngImport: i0, template: `
4956
5575
  <cide-lyt-shared-wrapper [shared_wrapper_setup_param]="shared_wrapper_setup_param">
4957
5576
  @if (loading()) {
4958
5577
  <div class="tw-text-center tw-py-12">
@@ -5146,7 +5765,7 @@ class FeePaymentViewComponent {
5146
5765
  </cide-lyt-shared-wrapper>
5147
5766
  `, isInline: true, styles: [":host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }] });
5148
5767
  }
5149
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeePaymentViewComponent, decorators: [{
5768
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeePaymentViewComponent, decorators: [{
5150
5769
  type: Component,
5151
5770
  args: [{ selector: 'cide-fee-payment-view', standalone: true, imports: [
5152
5771
  CommonModule,
@@ -5413,8 +6032,8 @@ class DiscountRulesComponent {
5413
6032
  console.log('Delete rule:', rule);
5414
6033
  }
5415
6034
  }
5416
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: DiscountRulesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5417
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: DiscountRulesComponent, isStandalone: true, selector: "cide-discount-rules", ngImport: i0, template: `
6035
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiscountRulesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6036
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DiscountRulesComponent, isStandalone: true, selector: "cide-discount-rules", ngImport: i0, template: `
5418
6037
  <div class="discount-rules-container">
5419
6038
  <div class="header">
5420
6039
  <h1>Discount Rules Management</h1>
@@ -5555,7 +6174,7 @@ class DiscountRulesComponent {
5555
6174
  </div>
5556
6175
  `, isInline: true, styles: [".discount-rules-container{padding:20px}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.btn{padding:10px 20px;border:none;border-radius:4px;cursor:pointer;font-size:14px}.btn-primary{background:#007bff;color:#fff}.btn-secondary{background:#6c757d;color:#fff}.tabs{display:flex;gap:10px;margin-bottom:20px;border-bottom:2px solid #e0e0e0}.tab{padding:12px 24px;background:none;border:none;border-bottom:3px solid transparent;cursor:pointer;font-weight:500}.tab.active{border-bottom-color:#007bff;color:#007bff}.table-container{overflow-x:auto;background:#fff;border-radius:8px;border:1px solid #e0e0e0}table{width:100%;border-collapse:collapse}thead{background:#f8f9fa}th{padding:12px;text-align:left;font-weight:600;border-bottom:2px solid #dee2e6}td{padding:12px;border-bottom:1px solid #dee2e6}.badge{padding:4px 12px;border-radius:12px;font-size:12px;background:#e3f2fd;color:#1976d2}.discount-value{font-weight:600;color:#28a745}.priority{display:inline-block;width:30px;height:30px;line-height:30px;text-align:center;background:#ffc107;color:#fff;border-radius:50%;font-weight:700}.status-badge{padding:4px 12px;border-radius:12px;font-size:12px;background:#f8d7da;color:#721c24}.status-badge.active{background:#d4edda;color:#155724}.btn-icon{background:none;border:none;cursor:pointer;font-size:18px;padding:4px}.modal-overlay{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000}.modal-content{background:#fff;border-radius:8px;max-width:800px;width:90%;max-height:90vh;overflow-y:auto}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:20px;border-bottom:1px solid #e0e0e0}.close-btn{background:none;border:none;font-size:28px;cursor:pointer;color:#666}.modal-body{padding:20px}.modal-footer{display:flex;justify-content:flex-end;gap:10px;padding:20px;border-top:1px solid #e0e0e0}.form-row{display:grid;grid-template-columns:1fr 1fr;gap:15px}.form-group{margin-bottom:15px}.form-group label{display:block;margin-bottom:5px;font-weight:500;font-size:14px}.form-group input,.form-group select,.form-group textarea{width:100%;padding:8px;border:1px solid #ddd;border-radius:4px}.form-group small{color:#666;font-size:12px}.checkbox-group{display:flex;flex-direction:column;gap:8px}.checkbox-group label{display:flex;align-items:center;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.SelectMultipleControlValueAccessor, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
5557
6176
  }
5558
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: DiscountRulesComponent, decorators: [{
6177
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiscountRulesComponent, decorators: [{
5559
6178
  type: Component,
5560
6179
  args: [{ selector: 'cide-discount-rules', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: `
5561
6180
  <div class="discount-rules-container">
@@ -5782,10 +6401,10 @@ class ReceiptTemplateService {
5782
6401
  console.log('🔄 Making PATCH request to toggle receipt template status:', { url, payload });
5783
6402
  return this.http.patch(url, payload);
5784
6403
  }
5785
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: ReceiptTemplateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5786
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: ReceiptTemplateService, providedIn: 'root' });
6404
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ReceiptTemplateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6405
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ReceiptTemplateService, providedIn: 'root' });
5787
6406
  }
5788
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: ReceiptTemplateService, decorators: [{
6407
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ReceiptTemplateService, decorators: [{
5789
6408
  type: Injectable,
5790
6409
  args: [{
5791
6410
  providedIn: 'root'
@@ -6621,10 +7240,10 @@ class TemplateDesignerComponent extends CideLytSharedWrapperComponent {
6621
7240
  }
6622
7241
  });
6623
7242
  }
6624
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: TemplateDesignerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6625
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: TemplateDesignerComponent, isStandalone: true, selector: "cide-receipt-template-designer", inputs: { shared_wrapper_setup_param: { classPropertyName: "shared_wrapper_setup_param", publicName: "shared_wrapper_setup_param", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "htmlEditorRef", first: true, predicate: ["htmlEditor"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<!-- Receipt Template Designer -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"shared_wrapper_setup_param()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions class=\"tw-flex tw-items-center tw-gap-2\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"loadTemplates()\" leftIcon=\"folder_open\">\n Load Template\n </button>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"saveTemplate()\" leftIcon=\"save\"\n [disabled]=\"saving() || templateForm.invalid\" [loading]=\"saving()\">\n Save Template\n </button>\n </div>\n\n <!-- Main Content - Three Column Layout -->\n <div class=\"tw-w-full tw-h-full tw-overflow-hidden tw-flex tw-flex-col\" style=\"height: calc(100vh - 120px); max-width: 100vw;\">\n <div class=\"tw-grid tw-grid-cols-12 tw-gap-3 tw-flex-1 tw-min-h-0 tw-p-3\">\n \n <!-- Left Sidebar - Tag Categories & Tags -->\n <div class=\"tw-col-span-12 lg:tw-col-span-3 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden tw-flex tw-flex-col tw-min-w-0 tw-h-full\">\n <!-- Tag Categories Header -->\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2\">Available Tags</h6>\n <form [formGroup]=\"templateForm\">\n <cide-ele-input\n formControlName=\"tag_search\"\n placeholder=\"Search tags...\"\n size=\"sm\"\n leadingIcon=\"search\">\n </cide-ele-input>\n </form>\n </div>\n\n <!-- Category Tabs -->\n <div class=\"tw-flex tw-flex-wrap tw-gap-1 tw-p-2 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-overflow-x-auto\">\n @for (category of tagCategories; track category.id) {\n <button\n type=\"button\"\n class=\"tw-px-2 tw-py-1 tw-text-xs tw-font-medium tw-rounded tw-transition-colors tw-whitespace-nowrap\"\n [class.tw-bg-blue-100]=\"activeCategory() === category.id\"\n [class.tw-text-blue-700]=\"activeCategory() === category.id\"\n [class.tw-bg-gray-100]=\"activeCategory() !== category.id\"\n [class.tw-text-gray-700]=\"activeCategory() !== category.id\"\n (click)=\"onCategoryChange(category.id)\"\n [title]=\"category.name\">\n <cide-ele-icon class=\"tw-w-3 tw-h-3 tw-inline-block tw-mr-1\">{{ category.icon }}</cide-ele-icon>\n <span class=\"tw-hidden sm:tw-inline\">{{ category.name }}</span>\n </button>\n }\n </div>\n\n <!-- Tags List -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-2 tw-min-h-0\">\n @if (filteredTags().length > 0) {\n <div class=\"tw-space-y-1\">\n @for (tag of filteredTags(); track tag.code) {\n <button\n type=\"button\"\n class=\"tw-w-full tw-text-left tw-p-2 tw-rounded tw-border tw-border-gray-200 tw-bg-white hover:tw-bg-blue-50 hover:tw-border-blue-300 tw-transition-colors tw-cursor-pointer tw-group\"\n (click)=\"insertTag(tag)\"\n [title]=\"tag.description\">\n <div class=\"tw-flex tw-items-start tw-justify-between tw-gap-2\">\n <div class=\"tw-flex-1 tw-min-w-0\">\n <code class=\"tw-text-xs tw-font-mono tw-text-blue-600 tw-font-semibold tw-block tw-break-all\">\n {{ tag.code }}\n </code>\n <span class=\"tw-text-xs tw-text-gray-600 tw-block tw-mt-1\">{{ tag.description }}</span>\n @if (tag.example) {\n <span class=\"tw-text-xs tw-text-gray-400 tw-block tw-mt-0.5\">e.g., {{ tag.example }}</span>\n }\n </div>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400 group-hover:tw-text-blue-600 tw-flex-shrink-0 tw-mt-0.5\">add_circle</cide-ele-icon>\n </div>\n </button>\n }\n </div>\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-mx-auto tw-mb-2 tw-text-gray-400\">search_off</cide-ele-icon>\n <p class=\"tw-text-xs\">No tags found</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Middle Column - HTML Editor -->\n <div class=\"tw-col-span-12 lg:tw-col-span-5 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-4\">Template Configuration</h6>\n \n <form [formGroup]=\"templateForm\" class=\"tw-space-y-3\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input\n label=\"Template Name\"\n formControlName=\"template_name\"\n placeholder=\"e.g., Standard Receipt\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input\n label=\"Template Code\"\n formControlName=\"template_code\"\n placeholder=\"e.g., STD_RECEIPT_01\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-select\n label=\"Template Type\"\n formControlName=\"template_type\"\n [options]=\"[{value: 'PAYMENT', label: 'Payment Receipt'}, {value: 'REFUND', label: 'Refund Receipt'}, {value: 'PROVISIONAL', label: 'Provisional Receipt'}]\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-select\n label=\"Template For\"\n formControlName=\"template_for\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}, {value: 'BOTH', label: 'Both'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"is_default\" type=\"checkbox\" size=\"sm\"></cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Set as Default Template</span>\n </div>\n </form>\n </div>\n\n <div class=\"tw-flex-1 tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">HTML Template *</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">Click tags on left to insert or paste HTML here</span>\n </div>\n </div>\n <div class=\"tw-flex-1 tw-p-3 tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <form [formGroup]=\"templateForm\" class=\"tw-h-full\">\n <textarea\n #htmlEditor\n formControlName=\"template_html\"\n placeholder=\"Enter HTML template code here... Use tags from the left sidebar or paste your HTML design.\"\n class=\"template-html-editor tw-w-full tw-h-full tw-p-3 tw-border tw-border-gray-300 tw-rounded-md tw-font-mono tw-text-xs tw-leading-relaxed tw-resize-none focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-blue-500 focus:tw-border-blue-500 tw-bg-white tw-text-gray-900\"\n spellcheck=\"false\"></textarea>\n </form>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Live Preview -->\n <div class=\"tw-col-span-12 lg:tw-col-span-4 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">Live Preview</h6>\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-select\n formControlName=\"preview_type\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}]\"\n size=\"xs\"\n class=\"tw-w-24\">\n </cide-ele-select>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400\" title=\"Auto-refreshes on template change\">sync</cide-ele-icon>\n </div>\n </div>\n </div>\n \n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4 tw-bg-gray-50 tw-min-h-0\">\n <div class=\"tw-bg-white tw-shadow-sm tw-rounded tw-p-4\" [innerHTML]=\"previewHtml()\"></div>\n </div>\n </div>\n\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n", styles: [":host{display:flex;flex-direction:column;height:100%;width:100%;max-width:100vw;overflow:hidden}:host .template-html-editor{height:100%!important;min-height:0;resize:none;font-family:Courier New,Monaco,Consolas,Menlo,monospace;font-size:13px;line-height:1.6;tab-size:2;-moz-tab-size:2;white-space:pre;overflow-wrap:normal;overflow-x:auto;overflow-y:auto;box-sizing:border-box;width:100%;max-width:100%}:host .template-html-editor::placeholder{color:#9ca3af;font-style:italic}:host .template-html-editor:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}:host .tw-grid{height:100%;max-width:100%;overflow:hidden;min-height:0}:host .tw-overflow-hidden{min-height:0;max-width:100%;overflow:hidden}:host .tw-flex-col{min-height:0;max-width:100%;height:100%}:host [class*=tw-col-span]{display:flex;flex-direction:column;min-height:0;min-width:0;max-width:100%;overflow:hidden;height:100%}:host *{max-width:100%;box-sizing:border-box}:host [breadcrumb-actions]{display:flex;align-items:center;gap:.5rem;flex-wrap:nowrap}button[type=button]:hover{transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}button[type=button]:active{transform:translateY(0)}[innerHTML] img{max-width:100%;height:auto}[innerHTML] table{width:100%;border-collapse:collapse}[innerHTML] *{max-width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
7243
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TemplateDesignerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7244
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TemplateDesignerComponent, isStandalone: true, selector: "cide-receipt-template-designer", inputs: { shared_wrapper_setup_param: { classPropertyName: "shared_wrapper_setup_param", publicName: "shared_wrapper_setup_param", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "htmlEditorRef", first: true, predicate: ["htmlEditor"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<!-- Receipt Template Designer -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"shared_wrapper_setup_param()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions class=\"tw-flex tw-items-center tw-gap-2\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"loadTemplates()\" leftIcon=\"folder_open\">\n Load Template\n </button>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"saveTemplate()\" leftIcon=\"save\"\n [disabled]=\"saving() || templateForm.invalid\" [loading]=\"saving()\">\n Save Template\n </button>\n </div>\n\n <!-- Main Content - Three Column Layout -->\n <div class=\"tw-w-full tw-h-full tw-overflow-hidden tw-flex tw-flex-col\" style=\"height: calc(100vh - 120px); max-width: 100vw;\">\n <div class=\"tw-grid tw-grid-cols-12 tw-gap-3 tw-flex-1 tw-min-h-0 tw-p-3\">\n \n <!-- Left Sidebar - Tag Categories & Tags -->\n <div class=\"tw-col-span-12 lg:tw-col-span-3 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden tw-flex tw-flex-col tw-min-w-0 tw-h-full\">\n <!-- Tag Categories Header -->\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2\">Available Tags</h6>\n <form [formGroup]=\"templateForm\">\n <cide-ele-input\n formControlName=\"tag_search\"\n placeholder=\"Search tags...\"\n size=\"sm\"\n leadingIcon=\"search\">\n </cide-ele-input>\n </form>\n </div>\n\n <!-- Category Tabs -->\n <div class=\"tw-flex tw-flex-wrap tw-gap-1 tw-p-2 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-overflow-x-auto\">\n @for (category of tagCategories; track category.id) {\n <button\n type=\"button\"\n class=\"tw-px-2 tw-py-1 tw-text-xs tw-font-medium tw-rounded tw-transition-colors tw-whitespace-nowrap\"\n [class.tw-bg-blue-100]=\"activeCategory() === category.id\"\n [class.tw-text-blue-700]=\"activeCategory() === category.id\"\n [class.tw-bg-gray-100]=\"activeCategory() !== category.id\"\n [class.tw-text-gray-700]=\"activeCategory() !== category.id\"\n (click)=\"onCategoryChange(category.id)\"\n [title]=\"category.name\">\n <cide-ele-icon class=\"tw-w-3 tw-h-3 tw-inline-block tw-mr-1\">{{ category.icon }}</cide-ele-icon>\n <span class=\"tw-hidden sm:tw-inline\">{{ category.name }}</span>\n </button>\n }\n </div>\n\n <!-- Tags List -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-2 tw-min-h-0\">\n @if (filteredTags().length > 0) {\n <div class=\"tw-space-y-1\">\n @for (tag of filteredTags(); track tag.code) {\n <button\n type=\"button\"\n class=\"tw-w-full tw-text-left tw-p-2 tw-rounded tw-border tw-border-gray-200 tw-bg-white hover:tw-bg-blue-50 hover:tw-border-blue-300 tw-transition-colors tw-cursor-pointer tw-group\"\n (click)=\"insertTag(tag)\"\n [title]=\"tag.description\">\n <div class=\"tw-flex tw-items-start tw-justify-between tw-gap-2\">\n <div class=\"tw-flex-1 tw-min-w-0\">\n <code class=\"tw-text-xs tw-font-mono tw-text-blue-600 tw-font-semibold tw-block tw-break-all\">\n {{ tag.code }}\n </code>\n <span class=\"tw-text-xs tw-text-gray-600 tw-block tw-mt-1\">{{ tag.description }}</span>\n @if (tag.example) {\n <span class=\"tw-text-xs tw-text-gray-400 tw-block tw-mt-0.5\">e.g., {{ tag.example }}</span>\n }\n </div>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400 group-hover:tw-text-blue-600 tw-flex-shrink-0 tw-mt-0.5\">add_circle</cide-ele-icon>\n </div>\n </button>\n }\n </div>\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-mx-auto tw-mb-2 tw-text-gray-400\">search_off</cide-ele-icon>\n <p class=\"tw-text-xs\">No tags found</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Middle Column - HTML Editor -->\n <div class=\"tw-col-span-12 lg:tw-col-span-5 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-4\">Template Configuration</h6>\n \n <form [formGroup]=\"templateForm\" class=\"tw-space-y-3\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input\n label=\"Template Name\"\n formControlName=\"template_name\"\n placeholder=\"e.g., Standard Receipt\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input\n label=\"Template Code\"\n formControlName=\"template_code\"\n placeholder=\"e.g., STD_RECEIPT_01\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-select\n label=\"Template Type\"\n formControlName=\"template_type\"\n [options]=\"[{value: 'PAYMENT', label: 'Payment Receipt'}, {value: 'REFUND', label: 'Refund Receipt'}, {value: 'PROVISIONAL', label: 'Provisional Receipt'}]\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-select\n label=\"Template For\"\n formControlName=\"template_for\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}, {value: 'BOTH', label: 'Both'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"is_default\" type=\"checkbox\" size=\"sm\"></cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Set as Default Template</span>\n </div>\n </form>\n </div>\n\n <div class=\"tw-flex-1 tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">HTML Template *</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">Click tags on left to insert or paste HTML here</span>\n </div>\n </div>\n <div class=\"tw-flex-1 tw-p-3 tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <form [formGroup]=\"templateForm\" class=\"tw-h-full\">\n <textarea\n #htmlEditor\n formControlName=\"template_html\"\n placeholder=\"Enter HTML template code here... Use tags from the left sidebar or paste your HTML design.\"\n class=\"template-html-editor tw-w-full tw-h-full tw-p-3 tw-border tw-border-gray-300 tw-rounded-md tw-font-mono tw-text-xs tw-leading-relaxed tw-resize-none focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-blue-500 focus:tw-border-blue-500 tw-bg-white tw-text-gray-900\"\n spellcheck=\"false\"></textarea>\n </form>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Live Preview -->\n <div class=\"tw-col-span-12 lg:tw-col-span-4 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">Live Preview</h6>\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-select\n formControlName=\"preview_type\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}]\"\n size=\"xs\"\n class=\"tw-w-24\">\n </cide-ele-select>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400\" title=\"Auto-refreshes on template change\">sync</cide-ele-icon>\n </div>\n </div>\n </div>\n \n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4 tw-bg-gray-50 tw-min-h-0\">\n <div class=\"tw-bg-white tw-shadow-sm tw-rounded tw-p-4\" [innerHTML]=\"previewHtml()\"></div>\n </div>\n </div>\n\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n", styles: [":host{display:flex;flex-direction:column;height:100%;width:100%;max-width:100vw;overflow:hidden}:host .template-html-editor{height:100%!important;min-height:0;resize:none;font-family:Courier New,Monaco,Consolas,Menlo,monospace;font-size:13px;line-height:1.6;tab-size:2;-moz-tab-size:2;white-space:pre;overflow-wrap:normal;overflow-x:auto;overflow-y:auto;box-sizing:border-box;width:100%;max-width:100%}:host .template-html-editor::placeholder{color:#9ca3af;font-style:italic}:host .template-html-editor:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}:host .tw-grid{height:100%;max-width:100%;overflow:hidden;min-height:0}:host .tw-overflow-hidden{min-height:0;max-width:100%;overflow:hidden}:host .tw-flex-col{min-height:0;max-width:100%;height:100%}:host [class*=tw-col-span]{display:flex;flex-direction:column;min-height:0;min-width:0;max-width:100%;overflow:hidden;height:100%}:host *{max-width:100%;box-sizing:border-box}:host [breadcrumb-actions]{display:flex;align-items:center;gap:.5rem;flex-wrap:nowrap}button[type=button]:hover{transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}button[type=button]:active{transform:translateY(0)}[innerHTML] img{max-width:100%;height:auto}[innerHTML] table{width:100%;border-collapse:collapse}[innerHTML] *{max-width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
6626
7245
  }
6627
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: TemplateDesignerComponent, decorators: [{
7246
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TemplateDesignerComponent, decorators: [{
6628
7247
  type: Component,
6629
7248
  args: [{ selector: 'cide-receipt-template-designer', standalone: true, imports: [
6630
7249
  CommonModule,
@@ -6635,7 +7254,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
6635
7254
  CideSelectComponent,
6636
7255
  CideLytSharedWrapperComponent
6637
7256
  ], template: "<!-- Receipt Template Designer -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"shared_wrapper_setup_param()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions class=\"tw-flex tw-items-center tw-gap-2\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"loadTemplates()\" leftIcon=\"folder_open\">\n Load Template\n </button>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"saveTemplate()\" leftIcon=\"save\"\n [disabled]=\"saving() || templateForm.invalid\" [loading]=\"saving()\">\n Save Template\n </button>\n </div>\n\n <!-- Main Content - Three Column Layout -->\n <div class=\"tw-w-full tw-h-full tw-overflow-hidden tw-flex tw-flex-col\" style=\"height: calc(100vh - 120px); max-width: 100vw;\">\n <div class=\"tw-grid tw-grid-cols-12 tw-gap-3 tw-flex-1 tw-min-h-0 tw-p-3\">\n \n <!-- Left Sidebar - Tag Categories & Tags -->\n <div class=\"tw-col-span-12 lg:tw-col-span-3 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden tw-flex tw-flex-col tw-min-w-0 tw-h-full\">\n <!-- Tag Categories Header -->\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2\">Available Tags</h6>\n <form [formGroup]=\"templateForm\">\n <cide-ele-input\n formControlName=\"tag_search\"\n placeholder=\"Search tags...\"\n size=\"sm\"\n leadingIcon=\"search\">\n </cide-ele-input>\n </form>\n </div>\n\n <!-- Category Tabs -->\n <div class=\"tw-flex tw-flex-wrap tw-gap-1 tw-p-2 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-overflow-x-auto\">\n @for (category of tagCategories; track category.id) {\n <button\n type=\"button\"\n class=\"tw-px-2 tw-py-1 tw-text-xs tw-font-medium tw-rounded tw-transition-colors tw-whitespace-nowrap\"\n [class.tw-bg-blue-100]=\"activeCategory() === category.id\"\n [class.tw-text-blue-700]=\"activeCategory() === category.id\"\n [class.tw-bg-gray-100]=\"activeCategory() !== category.id\"\n [class.tw-text-gray-700]=\"activeCategory() !== category.id\"\n (click)=\"onCategoryChange(category.id)\"\n [title]=\"category.name\">\n <cide-ele-icon class=\"tw-w-3 tw-h-3 tw-inline-block tw-mr-1\">{{ category.icon }}</cide-ele-icon>\n <span class=\"tw-hidden sm:tw-inline\">{{ category.name }}</span>\n </button>\n }\n </div>\n\n <!-- Tags List -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-2 tw-min-h-0\">\n @if (filteredTags().length > 0) {\n <div class=\"tw-space-y-1\">\n @for (tag of filteredTags(); track tag.code) {\n <button\n type=\"button\"\n class=\"tw-w-full tw-text-left tw-p-2 tw-rounded tw-border tw-border-gray-200 tw-bg-white hover:tw-bg-blue-50 hover:tw-border-blue-300 tw-transition-colors tw-cursor-pointer tw-group\"\n (click)=\"insertTag(tag)\"\n [title]=\"tag.description\">\n <div class=\"tw-flex tw-items-start tw-justify-between tw-gap-2\">\n <div class=\"tw-flex-1 tw-min-w-0\">\n <code class=\"tw-text-xs tw-font-mono tw-text-blue-600 tw-font-semibold tw-block tw-break-all\">\n {{ tag.code }}\n </code>\n <span class=\"tw-text-xs tw-text-gray-600 tw-block tw-mt-1\">{{ tag.description }}</span>\n @if (tag.example) {\n <span class=\"tw-text-xs tw-text-gray-400 tw-block tw-mt-0.5\">e.g., {{ tag.example }}</span>\n }\n </div>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400 group-hover:tw-text-blue-600 tw-flex-shrink-0 tw-mt-0.5\">add_circle</cide-ele-icon>\n </div>\n </button>\n }\n </div>\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-mx-auto tw-mb-2 tw-text-gray-400\">search_off</cide-ele-icon>\n <p class=\"tw-text-xs\">No tags found</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Middle Column - HTML Editor -->\n <div class=\"tw-col-span-12 lg:tw-col-span-5 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-4\">Template Configuration</h6>\n \n <form [formGroup]=\"templateForm\" class=\"tw-space-y-3\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input\n label=\"Template Name\"\n formControlName=\"template_name\"\n placeholder=\"e.g., Standard Receipt\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input\n label=\"Template Code\"\n formControlName=\"template_code\"\n placeholder=\"e.g., STD_RECEIPT_01\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-select\n label=\"Template Type\"\n formControlName=\"template_type\"\n [options]=\"[{value: 'PAYMENT', label: 'Payment Receipt'}, {value: 'REFUND', label: 'Refund Receipt'}, {value: 'PROVISIONAL', label: 'Provisional Receipt'}]\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-select\n label=\"Template For\"\n formControlName=\"template_for\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}, {value: 'BOTH', label: 'Both'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"is_default\" type=\"checkbox\" size=\"sm\"></cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Set as Default Template</span>\n </div>\n </form>\n </div>\n\n <div class=\"tw-flex-1 tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">HTML Template *</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">Click tags on left to insert or paste HTML here</span>\n </div>\n </div>\n <div class=\"tw-flex-1 tw-p-3 tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <form [formGroup]=\"templateForm\" class=\"tw-h-full\">\n <textarea\n #htmlEditor\n formControlName=\"template_html\"\n placeholder=\"Enter HTML template code here... Use tags from the left sidebar or paste your HTML design.\"\n class=\"template-html-editor tw-w-full tw-h-full tw-p-3 tw-border tw-border-gray-300 tw-rounded-md tw-font-mono tw-text-xs tw-leading-relaxed tw-resize-none focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-blue-500 focus:tw-border-blue-500 tw-bg-white tw-text-gray-900\"\n spellcheck=\"false\"></textarea>\n </form>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Live Preview -->\n <div class=\"tw-col-span-12 lg:tw-col-span-4 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">Live Preview</h6>\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-select\n formControlName=\"preview_type\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}]\"\n size=\"xs\"\n class=\"tw-w-24\">\n </cide-ele-select>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400\" title=\"Auto-refreshes on template change\">sync</cide-ele-icon>\n </div>\n </div>\n </div>\n \n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4 tw-bg-gray-50 tw-min-h-0\">\n <div class=\"tw-bg-white tw-shadow-sm tw-rounded tw-p-4\" [innerHTML]=\"previewHtml()\"></div>\n </div>\n </div>\n\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n", styles: [":host{display:flex;flex-direction:column;height:100%;width:100%;max-width:100vw;overflow:hidden}:host .template-html-editor{height:100%!important;min-height:0;resize:none;font-family:Courier New,Monaco,Consolas,Menlo,monospace;font-size:13px;line-height:1.6;tab-size:2;-moz-tab-size:2;white-space:pre;overflow-wrap:normal;overflow-x:auto;overflow-y:auto;box-sizing:border-box;width:100%;max-width:100%}:host .template-html-editor::placeholder{color:#9ca3af;font-style:italic}:host .template-html-editor:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}:host .tw-grid{height:100%;max-width:100%;overflow:hidden;min-height:0}:host .tw-overflow-hidden{min-height:0;max-width:100%;overflow:hidden}:host .tw-flex-col{min-height:0;max-width:100%;height:100%}:host [class*=tw-col-span]{display:flex;flex-direction:column;min-height:0;min-width:0;max-width:100%;overflow:hidden;height:100%}:host *{max-width:100%;box-sizing:border-box}:host [breadcrumb-actions]{display:flex;align-items:center;gap:.5rem;flex-wrap:nowrap}button[type=button]:hover{transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}button[type=button]:active{transform:translateY(0)}[innerHTML] img{max-width:100%;height:auto}[innerHTML] table{width:100%;border-collapse:collapse}[innerHTML] *{max-width:100%}\n"] }]
6638
- }], ctorParameters: () => [], propDecorators: { htmlEditorRef: [{
7257
+ }], ctorParameters: () => [], propDecorators: { shared_wrapper_setup_param: [{ type: i0.Input, args: [{ isSignal: true, alias: "shared_wrapper_setup_param", required: false }] }], htmlEditorRef: [{
6639
7258
  type: ViewChild,
6640
7259
  args: ['htmlEditor', { static: false }]
6641
7260
  }] } });
@@ -7001,10 +7620,10 @@ class CollectionReportComponent {
7001
7620
  formatCurrency(amount) {
7002
7621
  return `₹${amount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
7003
7622
  }
7004
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CollectionReportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7005
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.7", type: CollectionReportComponent, isStandalone: true, selector: "cide-collection-report", ngImport: i0, template: "<!-- Collection Report Container -->\r\n<div class=\"tw-w-full tw-h-full\">\r\n <div class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-table-row tw-w-full tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n \r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">assessment</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Fee Collection Report</h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div class=\"tw-flex tw-items-center tw-gap-3\">\r\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"exportToPDF()\" leftIcon=\"picture_as_pdf\">\r\n Export PDF\r\n </button>\r\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"exportToExcel()\" leftIcon=\"table_chart\">\r\n Export Excel\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Filters Section -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <form [formGroup]=\"filterForm\" class=\"tw-space-y-4\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-5 tw-gap-4\">\r\n <cide-ele-input\r\n label=\"Date From\"\r\n formControlName=\"date_from\"\r\n type=\"date\"\r\n size=\"sm\">\r\n </cide-ele-input>\r\n\r\n <cide-ele-input\r\n label=\"Date To\"\r\n formControlName=\"date_to\"\r\n type=\"date\"\r\n size=\"sm\">\r\n </cide-ele-input>\r\n\r\n <cide-ele-select\r\n label=\"Academic Year\"\r\n formControlName=\"academic_year\"\r\n [options]=\"academicYearOptions()\"\r\n size=\"sm\"\r\n placeholder=\"All Years\">\r\n </cide-ele-select>\r\n\r\n <cide-ele-select\r\n label=\"Class/Program\"\r\n formControlName=\"class_program\"\r\n [options]=\"classOptions()\"\r\n size=\"sm\"\r\n placeholder=\"All Classes\">\r\n </cide-ele-select>\r\n\r\n <cide-ele-select\r\n label=\"Payment Mode\"\r\n formControlName=\"payment_mode\"\r\n [options]=\"paymentModeOptions\"\r\n size=\"sm\"\r\n placeholder=\"All Modes\">\r\n </cide-ele-select>\r\n </div>\r\n\r\n <div class=\"tw-flex tw-justify-end\">\r\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"applyFilters()\" leftIcon=\"search\"\r\n [disabled]=\"loading()\" [loading]=\"loading()\">\r\n Generate Report\r\n </button>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n\r\n <!-- Summary Cards -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4\">\r\n <!-- Total Collection Card -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\r\n <div class=\"tw-bg-green-100 tw-rounded-full tw-p-3\">\r\n <cide-ele-icon class=\"tw-text-green-600 tw-w-6 tw-h-6\">account_balance_wallet</cide-ele-icon>\r\n </div>\r\n <div class=\"tw-flex-1\">\r\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Collection</div>\r\n <div class=\"tw-text-xl tw-font-bold tw-text-green-600\">{{ formatCurrency(summary().total_collection) }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Total Receipts Card -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\r\n <div class=\"tw-bg-blue-100 tw-rounded-full tw-p-3\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-6 tw-h-6\">receipt</cide-ele-icon>\r\n </div>\r\n <div class=\"tw-flex-1\">\r\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Receipts</div>\r\n <div class=\"tw-text-xl tw-font-bold tw-text-blue-600\">{{ summary().total_receipts }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Online Payments Card -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\r\n <div class=\"tw-bg-cyan-100 tw-rounded-full tw-p-3\">\r\n <cide-ele-icon class=\"tw-text-cyan-600 tw-w-6 tw-h-6\">language</cide-ele-icon>\r\n </div>\r\n <div class=\"tw-flex-1\">\r\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Online Payments</div>\r\n <div class=\"tw-text-xl tw-font-bold tw-text-cyan-600\">{{ formatCurrency(summary().online_payments) }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Cash Payments Card -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\r\n <div class=\"tw-bg-yellow-100 tw-rounded-full tw-p-3\">\r\n <cide-ele-icon class=\"tw-text-yellow-600 tw-w-6 tw-h-6\">money</cide-ele-icon>\r\n </div>\r\n <div class=\"tw-flex-1\">\r\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Cash Payments</div>\r\n <div class=\"tw-text-xl tw-font-bold tw-text-yellow-600\">{{ formatCurrency(summary().cash_payments) }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Area -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4\">\r\n <div class=\"tw-space-y-6\">\r\n \r\n <!-- Collection by Date Section -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\r\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Collection by Date</h6>\r\n </div>\r\n <div class=\"tw-p-4\">\r\n <cide-ele-data-grid \r\n [config]=\"dateGridConfig()\" \r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n \r\n <!-- Footer Totals -->\r\n <div class=\"tw-mt-4 tw-pt-4 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-grid tw-grid-cols-7 tw-gap-4 tw-text-sm\">\r\n <div class=\"tw-font-semibold tw-text-gray-900\">TOTAL</div>\r\n <div class=\"tw-font-semibold tw-text-center tw-text-gray-900\">{{ totalReceipts() }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-gray-900\">{{ formatCurrency(totalCash()) }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-gray-900\">{{ formatCurrency(totalOnline()) }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-gray-900\">{{ formatCurrency(totalCheque()) }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-gray-900\">{{ formatCurrency(totalOther()) }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-green-600\">{{ formatCurrency(grandTotal()) }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Collection by Class Section -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\r\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Collection by Class/Program</h6>\r\n </div>\r\n <div class=\"tw-p-4\">\r\n <cide-ele-data-grid \r\n [config]=\"classGridConfig()\" \r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n", styles: [":host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }] });
7623
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CollectionReportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7624
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: CollectionReportComponent, isStandalone: true, selector: "cide-collection-report", ngImport: i0, template: "<!-- Collection Report Container -->\r\n<div class=\"tw-w-full tw-h-full\">\r\n <div class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-table-row tw-w-full tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n \r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">assessment</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Fee Collection Report</h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div class=\"tw-flex tw-items-center tw-gap-3\">\r\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"exportToPDF()\" leftIcon=\"picture_as_pdf\">\r\n Export PDF\r\n </button>\r\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"exportToExcel()\" leftIcon=\"table_chart\">\r\n Export Excel\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Filters Section -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <form [formGroup]=\"filterForm\" class=\"tw-space-y-4\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-5 tw-gap-4\">\r\n <cide-ele-input\r\n label=\"Date From\"\r\n formControlName=\"date_from\"\r\n type=\"date\"\r\n size=\"sm\">\r\n </cide-ele-input>\r\n\r\n <cide-ele-input\r\n label=\"Date To\"\r\n formControlName=\"date_to\"\r\n type=\"date\"\r\n size=\"sm\">\r\n </cide-ele-input>\r\n\r\n <cide-ele-select\r\n label=\"Academic Year\"\r\n formControlName=\"academic_year\"\r\n [options]=\"academicYearOptions()\"\r\n size=\"sm\"\r\n placeholder=\"All Years\">\r\n </cide-ele-select>\r\n\r\n <cide-ele-select\r\n label=\"Class/Program\"\r\n formControlName=\"class_program\"\r\n [options]=\"classOptions()\"\r\n size=\"sm\"\r\n placeholder=\"All Classes\">\r\n </cide-ele-select>\r\n\r\n <cide-ele-select\r\n label=\"Payment Mode\"\r\n formControlName=\"payment_mode\"\r\n [options]=\"paymentModeOptions\"\r\n size=\"sm\"\r\n placeholder=\"All Modes\">\r\n </cide-ele-select>\r\n </div>\r\n\r\n <div class=\"tw-flex tw-justify-end\">\r\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"applyFilters()\" leftIcon=\"search\"\r\n [disabled]=\"loading()\" [loading]=\"loading()\">\r\n Generate Report\r\n </button>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n\r\n <!-- Summary Cards -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4\">\r\n <!-- Total Collection Card -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\r\n <div class=\"tw-bg-green-100 tw-rounded-full tw-p-3\">\r\n <cide-ele-icon class=\"tw-text-green-600 tw-w-6 tw-h-6\">account_balance_wallet</cide-ele-icon>\r\n </div>\r\n <div class=\"tw-flex-1\">\r\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Collection</div>\r\n <div class=\"tw-text-xl tw-font-bold tw-text-green-600\">{{ formatCurrency(summary().total_collection) }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Total Receipts Card -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\r\n <div class=\"tw-bg-blue-100 tw-rounded-full tw-p-3\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-6 tw-h-6\">receipt</cide-ele-icon>\r\n </div>\r\n <div class=\"tw-flex-1\">\r\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Receipts</div>\r\n <div class=\"tw-text-xl tw-font-bold tw-text-blue-600\">{{ summary().total_receipts }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Online Payments Card -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\r\n <div class=\"tw-bg-cyan-100 tw-rounded-full tw-p-3\">\r\n <cide-ele-icon class=\"tw-text-cyan-600 tw-w-6 tw-h-6\">language</cide-ele-icon>\r\n </div>\r\n <div class=\"tw-flex-1\">\r\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Online Payments</div>\r\n <div class=\"tw-text-xl tw-font-bold tw-text-cyan-600\">{{ formatCurrency(summary().online_payments) }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Cash Payments Card -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\r\n <div class=\"tw-bg-yellow-100 tw-rounded-full tw-p-3\">\r\n <cide-ele-icon class=\"tw-text-yellow-600 tw-w-6 tw-h-6\">money</cide-ele-icon>\r\n </div>\r\n <div class=\"tw-flex-1\">\r\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Cash Payments</div>\r\n <div class=\"tw-text-xl tw-font-bold tw-text-yellow-600\">{{ formatCurrency(summary().cash_payments) }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Area -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4\">\r\n <div class=\"tw-space-y-6\">\r\n \r\n <!-- Collection by Date Section -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\r\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Collection by Date</h6>\r\n </div>\r\n <div class=\"tw-p-4\">\r\n <cide-ele-data-grid \r\n [config]=\"dateGridConfig()\" \r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n \r\n <!-- Footer Totals -->\r\n <div class=\"tw-mt-4 tw-pt-4 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-grid tw-grid-cols-7 tw-gap-4 tw-text-sm\">\r\n <div class=\"tw-font-semibold tw-text-gray-900\">TOTAL</div>\r\n <div class=\"tw-font-semibold tw-text-center tw-text-gray-900\">{{ totalReceipts() }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-gray-900\">{{ formatCurrency(totalCash()) }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-gray-900\">{{ formatCurrency(totalOnline()) }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-gray-900\">{{ formatCurrency(totalCheque()) }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-gray-900\">{{ formatCurrency(totalOther()) }}</div>\r\n <div class=\"tw-font-semibold tw-text-right tw-text-green-600\">{{ formatCurrency(grandTotal()) }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Collection by Class Section -->\r\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\r\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Collection by Class/Program</h6>\r\n </div>\r\n <div class=\"tw-p-4\">\r\n <cide-ele-data-grid \r\n [config]=\"classGridConfig()\" \r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n", styles: [":host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }] });
7006
7625
  }
7007
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CollectionReportComponent, decorators: [{
7626
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CollectionReportComponent, decorators: [{
7008
7627
  type: Component,
7009
7628
  args: [{ selector: 'cide-collection-report', standalone: true, imports: [
7010
7629
  CommonModule,
@@ -7438,10 +8057,10 @@ class MyFeeStatementComponent {
7438
8057
  onGridEvent(event) {
7439
8058
  console.log('Grid event:', event);
7440
8059
  }
7441
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: MyFeeStatementComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7442
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.1.7", type: MyFeeStatementComponent, isStandalone: true, selector: "cide-my-fee-statement", viewQueries: [{ propertyName: "statusRendererTemplate", first: true, predicate: ["statusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsRendererTemplate", first: true, predicate: ["actionsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "paymentHistoryRendererTemplate", first: true, predicate: ["paymentHistoryRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- My Fee Statement Container with Shared Wrapper -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'my_fee_statement' }\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"makePayment()\" leftIcon=\"payment\"\n [disabled]=\"feeSummary().outstanding === 0 || loading()\">\n Make Payment\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Student Info Section -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gradient-to-r tw-from-blue-50 tw-to-purple-50\">\n <div class=\"tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-w-16 tw-h-16 tw-rounded-full tw-bg-blue-100 tw-flex tw-items-center tw-justify-center tw-border-2 tw-border-white tw-shadow-sm\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-8 tw-h-8\">person</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <h6 class=\"tw-text-lg tw-font-semibold tw-text-gray-900 tw-mb-1\">{{ studentInfo().name }}</h6>\n <div class=\"tw-flex tw-flex-wrap tw-gap-4 tw-text-sm tw-text-gray-600\">\n <span><strong>Student ID:</strong> {{ studentInfo().id }}</span>\n <span><strong>Class:</strong> {{ studentInfo().class }}</span>\n <span><strong>Section:</strong> {{ studentInfo().section }}</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Summary Cards -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4\">\n <!-- Total Fees Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-blue-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-6 tw-h-6\">account_balance_wallet</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Fees</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-blue-600\">{{ formatCurrency(feeSummary().total_fees) }}</div>\n </div>\n </div>\n\n <!-- Paid Amount Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-green-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-green-600 tw-w-6 tw-h-6\">check_circle</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Paid Amount</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-green-600\">{{ formatCurrency(feeSummary().paid_amount) }}</div>\n </div>\n </div>\n\n <!-- Outstanding Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-red-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-red-600 tw-w-6 tw-h-6\">warning</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Outstanding</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-red-600\">{{ formatCurrency(feeSummary().outstanding) }}</div>\n </div>\n </div>\n\n <!-- Discount Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-yellow-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-yellow-600 tw-w-6 tw-h-6\">local_offer</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Discount</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-yellow-600\">{{ formatCurrency(feeSummary().discount) }}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4\">\n <div class=\"tw-space-y-6\">\n \n <!-- Fee Details Section -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Fee Details</h6>\n </div>\n <div class=\"tw-p-4\">\n <cide-ele-data-grid \n [config]=\"feeDetailsGridConfig()\" \n [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n <!-- Payment History Section -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Payment History</h6>\n </div>\n <div class=\"tw-p-4\">\n <cide-ele-data-grid \n [config]=\"paymentHistoryGridConfig()\" \n [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n </div>\n </div>\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #statusRendererTemplate let-row=\"row\">\n <span class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium\"\n [class.tw-bg-green-100]=\"row.status === 'PAID'\"\n [class.tw-text-green-800]=\"row.status === 'PAID'\"\n [class.tw-bg-yellow-100]=\"row.status === 'PENDING' || row.status === 'PARTIALLY_PAID'\"\n [class.tw-text-yellow-800]=\"row.status === 'PENDING' || row.status === 'PARTIALLY_PAID'\"\n [class.tw-bg-red-100]=\"row.status === 'OVERDUE'\"\n [class.tw-text-red-800]=\"row.status === 'OVERDUE'\">\n {{ row.status === 'PARTIALLY_PAID' ? 'PARTIALLY PAID' : row.status }}\n </span>\n</ng-template>\n\n<ng-template #actionsRendererTemplate let-row=\"row\">\n <!-- Actions if needed -->\n</ng-template>\n\n<ng-template #paymentHistoryRendererTemplate let-row=\"row\">\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"downloadReceipt(row)\" leftIcon=\"download\">\n Download\n </button>\n</ng-template>\n\n", styles: [":host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
8060
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MyFeeStatementComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8061
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.15", type: MyFeeStatementComponent, isStandalone: true, selector: "cide-my-fee-statement", viewQueries: [{ propertyName: "statusRendererTemplate", first: true, predicate: ["statusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsRendererTemplate", first: true, predicate: ["actionsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "paymentHistoryRendererTemplate", first: true, predicate: ["paymentHistoryRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- My Fee Statement Container with Shared Wrapper -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'my_fee_statement' }\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"makePayment()\" leftIcon=\"payment\"\n [disabled]=\"feeSummary().outstanding === 0 || loading()\">\n Make Payment\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Student Info Section -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gradient-to-r tw-from-blue-50 tw-to-purple-50\">\n <div class=\"tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-w-16 tw-h-16 tw-rounded-full tw-bg-blue-100 tw-flex tw-items-center tw-justify-center tw-border-2 tw-border-white tw-shadow-sm\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-8 tw-h-8\">person</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <h6 class=\"tw-text-lg tw-font-semibold tw-text-gray-900 tw-mb-1\">{{ studentInfo().name }}</h6>\n <div class=\"tw-flex tw-flex-wrap tw-gap-4 tw-text-sm tw-text-gray-600\">\n <span><strong>Student ID:</strong> {{ studentInfo().id }}</span>\n <span><strong>Class:</strong> {{ studentInfo().class }}</span>\n <span><strong>Section:</strong> {{ studentInfo().section }}</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Summary Cards -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4\">\n <!-- Total Fees Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-blue-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-6 tw-h-6\">account_balance_wallet</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Fees</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-blue-600\">{{ formatCurrency(feeSummary().total_fees) }}</div>\n </div>\n </div>\n\n <!-- Paid Amount Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-green-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-green-600 tw-w-6 tw-h-6\">check_circle</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Paid Amount</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-green-600\">{{ formatCurrency(feeSummary().paid_amount) }}</div>\n </div>\n </div>\n\n <!-- Outstanding Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-red-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-red-600 tw-w-6 tw-h-6\">warning</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Outstanding</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-red-600\">{{ formatCurrency(feeSummary().outstanding) }}</div>\n </div>\n </div>\n\n <!-- Discount Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-yellow-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-yellow-600 tw-w-6 tw-h-6\">local_offer</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Discount</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-yellow-600\">{{ formatCurrency(feeSummary().discount) }}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4\">\n <div class=\"tw-space-y-6\">\n \n <!-- Fee Details Section -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Fee Details</h6>\n </div>\n <div class=\"tw-p-4\">\n <cide-ele-data-grid \n [config]=\"feeDetailsGridConfig()\" \n [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n <!-- Payment History Section -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Payment History</h6>\n </div>\n <div class=\"tw-p-4\">\n <cide-ele-data-grid \n [config]=\"paymentHistoryGridConfig()\" \n [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n </div>\n </div>\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #statusRendererTemplate let-row=\"row\">\n <span class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium\"\n [class.tw-bg-green-100]=\"row.status === 'PAID'\"\n [class.tw-text-green-800]=\"row.status === 'PAID'\"\n [class.tw-bg-yellow-100]=\"row.status === 'PENDING' || row.status === 'PARTIALLY_PAID'\"\n [class.tw-text-yellow-800]=\"row.status === 'PENDING' || row.status === 'PARTIALLY_PAID'\"\n [class.tw-bg-red-100]=\"row.status === 'OVERDUE'\"\n [class.tw-text-red-800]=\"row.status === 'OVERDUE'\">\n {{ row.status === 'PARTIALLY_PAID' ? 'PARTIALLY PAID' : row.status }}\n </span>\n</ng-template>\n\n<ng-template #actionsRendererTemplate let-row=\"row\">\n <!-- Actions if needed -->\n</ng-template>\n\n<ng-template #paymentHistoryRendererTemplate let-row=\"row\">\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"downloadReceipt(row)\" leftIcon=\"download\">\n Download\n </button>\n</ng-template>\n\n", styles: [":host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
7443
8062
  }
7444
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: MyFeeStatementComponent, decorators: [{
8063
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MyFeeStatementComponent, decorators: [{
7445
8064
  type: Component,
7446
8065
  args: [{ selector: 'cide-my-fee-statement', standalone: true, imports: [
7447
8066
  CommonModule,
@@ -7450,7 +8069,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
7450
8069
  CideEleDataGridComponent,
7451
8070
  CideLytSharedWrapperComponent
7452
8071
  ], template: "<!-- My Fee Statement Container with Shared Wrapper -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"{ sypg_page_code: 'my_fee_statement' }\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"makePayment()\" leftIcon=\"payment\"\n [disabled]=\"feeSummary().outstanding === 0 || loading()\">\n Make Payment\n </button>\n </div>\n\n <div class=\"tw-table tw-w-full tw-h-full\">\n\n <!-- Student Info Section -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gradient-to-r tw-from-blue-50 tw-to-purple-50\">\n <div class=\"tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-w-16 tw-h-16 tw-rounded-full tw-bg-blue-100 tw-flex tw-items-center tw-justify-center tw-border-2 tw-border-white tw-shadow-sm\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-8 tw-h-8\">person</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <h6 class=\"tw-text-lg tw-font-semibold tw-text-gray-900 tw-mb-1\">{{ studentInfo().name }}</h6>\n <div class=\"tw-flex tw-flex-wrap tw-gap-4 tw-text-sm tw-text-gray-600\">\n <span><strong>Student ID:</strong> {{ studentInfo().id }}</span>\n <span><strong>Class:</strong> {{ studentInfo().class }}</span>\n <span><strong>Section:</strong> {{ studentInfo().section }}</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Summary Cards -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4 tw-border-b tw-border-gray-200\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4\">\n <!-- Total Fees Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-blue-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-6 tw-h-6\">account_balance_wallet</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Fees</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-blue-600\">{{ formatCurrency(feeSummary().total_fees) }}</div>\n </div>\n </div>\n\n <!-- Paid Amount Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-green-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-green-600 tw-w-6 tw-h-6\">check_circle</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Paid Amount</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-green-600\">{{ formatCurrency(feeSummary().paid_amount) }}</div>\n </div>\n </div>\n\n <!-- Outstanding Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-red-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-red-600 tw-w-6 tw-h-6\">warning</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Outstanding</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-red-600\">{{ formatCurrency(feeSummary().outstanding) }}</div>\n </div>\n </div>\n\n <!-- Discount Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-p-4 tw-flex tw-items-center tw-gap-4\">\n <div class=\"tw-bg-yellow-100 tw-rounded-full tw-p-3\">\n <cide-ele-icon class=\"tw-text-yellow-600 tw-w-6 tw-h-6\">local_offer</cide-ele-icon>\n </div>\n <div class=\"tw-flex-1\">\n <div class=\"tw-text-xs tw-text-gray-600 tw-mb-1\">Total Discount</div>\n <div class=\"tw-text-xl tw-font-bold tw-text-yellow-600\">{{ formatCurrency(feeSummary().discount) }}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4\">\n <div class=\"tw-space-y-6\">\n \n <!-- Fee Details Section -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Fee Details</h6>\n </div>\n <div class=\"tw-p-4\">\n <cide-ele-data-grid \n [config]=\"feeDetailsGridConfig()\" \n [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n <!-- Payment History Section -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Payment History</h6>\n </div>\n <div class=\"tw-p-4\">\n <cide-ele-data-grid \n [config]=\"paymentHistoryGridConfig()\" \n [templateRenderers]=\"templateRenderers()\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n </div>\n </div>\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n<!-- Template Renderers -->\n<ng-template #statusRendererTemplate let-row=\"row\">\n <span class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium\"\n [class.tw-bg-green-100]=\"row.status === 'PAID'\"\n [class.tw-text-green-800]=\"row.status === 'PAID'\"\n [class.tw-bg-yellow-100]=\"row.status === 'PENDING' || row.status === 'PARTIALLY_PAID'\"\n [class.tw-text-yellow-800]=\"row.status === 'PENDING' || row.status === 'PARTIALLY_PAID'\"\n [class.tw-bg-red-100]=\"row.status === 'OVERDUE'\"\n [class.tw-text-red-800]=\"row.status === 'OVERDUE'\">\n {{ row.status === 'PARTIALLY_PAID' ? 'PARTIALLY PAID' : row.status }}\n </span>\n</ng-template>\n\n<ng-template #actionsRendererTemplate let-row=\"row\">\n <!-- Actions if needed -->\n</ng-template>\n\n<ng-template #paymentHistoryRendererTemplate let-row=\"row\">\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"downloadReceipt(row)\" leftIcon=\"download\">\n Download\n </button>\n</ng-template>\n\n", styles: [":host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"] }]
7453
- }] });
8072
+ }], propDecorators: { statusRendererTemplate: [{ type: i0.ViewChild, args: ['statusRendererTemplate', { isSignal: true }] }], actionsRendererTemplate: [{ type: i0.ViewChild, args: ['actionsRendererTemplate', { isSignal: true }] }], paymentHistoryRendererTemplate: [{ type: i0.ViewChild, args: ['paymentHistoryRendererTemplate', { isSignal: true }] }] } });
7454
8073
 
7455
8074
  var myFeeStatement_component = /*#__PURE__*/Object.freeze({
7456
8075
  __proto__: null,
@@ -7820,10 +8439,10 @@ class MyOnlinePaymentComponent {
7820
8439
  formatCurrency(amount) {
7821
8440
  return `₹${amount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
7822
8441
  }
7823
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: MyOnlinePaymentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7824
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: MyOnlinePaymentComponent, isStandalone: true, selector: "cide-my-online-payment", ngImport: i0, template: "<!-- My Online Payment Container -->\n<div class=\"tw-w-full tw-h-full\">\n <div class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\">\n\n <!-- Header Section -->\n <div class=\"tw-table-row tw-w-full tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\n \n <!-- Title -->\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">payment</cide-ele-icon>\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Online Fee Payment</h5>\n </div>\n\n <!-- Actions -->\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"cancel()\" leftIcon=\"arrow_back\">\n Back to Statement\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4\">\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-6\">\n \n <!-- Left Panel - Fee Selection -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden tw-flex tw-flex-col\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Select Fees to Pay</h6>\n </div>\n \n <!-- Quick Actions -->\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex tw-gap-2\">\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"selectAll()\">\n Select All\n </button>\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"selectOverdue()\">\n Select Overdue\n </button>\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"clearSelection()\">\n Clear\n </button>\n </div>\n\n <!-- Fee Items List -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4 tw-space-y-3\">\n @if (outstandingFees().length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-12 tw-h-12 tw-mx-auto tw-mb-2 tw-text-gray-400\">check_circle</cide-ele-icon>\n <p class=\"tw-text-sm\">No outstanding fees</p>\n </div>\n } @else {\n @for (fee of outstandingFees(); track fee.id) {\n <div class=\"tw-p-3 tw-rounded-lg tw-border-2 tw-cursor-pointer tw-transition-colors\"\n [class.tw-border-blue-500]=\"isSelected(fee)\"\n [class.tw-bg-blue-50]=\"isSelected(fee)\"\n [class.tw-border-yellow-400]=\"!isSelected(fee) && isOverdue(fee)\"\n [class.tw-bg-yellow-50]=\"!isSelected(fee) && isOverdue(fee)\"\n [class.tw-border-gray-200]=\"!isSelected(fee) && !isOverdue(fee)\"\n (click)=\"toggleFee(fee)\">\n <div class=\"tw-flex tw-items-start tw-justify-between tw-gap-3\">\n <div class=\"tw-flex tw-items-start tw-gap-3 tw-flex-1\">\n <input \n type=\"checkbox\" \n [checked]=\"isSelected(fee)\"\n (change)=\"toggleFee(fee); $event.stopPropagation()\"\n class=\"tw-mt-1\">\n <div class=\"tw-flex-1\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mb-1\">\n <span class=\"tw-font-medium tw-text-gray-900\">{{ fee.fee_head }}</span>\n @if (isOverdue(fee)) {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-yellow-100 tw-text-yellow-800\">\n Overdue\n </span>\n }\n </div>\n <div class=\"tw-text-xs tw-text-gray-600\">\n Due Date: {{ fee.due_date | date:'dd/MM/yyyy' }}\n </div>\n @if (fee.late_fee > 0) {\n <div class=\"tw-text-xs tw-text-red-600 tw-mt-1\">\n Late Fee: {{ formatCurrency(fee.late_fee) }}\n </div>\n }\n </div>\n </div>\n <div class=\"tw-text-right\">\n <div class=\"tw-font-semibold tw-text-gray-900\">{{ formatCurrency(fee.outstanding) }}</div>\n </div>\n </div>\n </div>\n }\n }\n </div>\n </div>\n\n <!-- Right Panel - Payment Summary & Gateway -->\n <div class=\"tw-space-y-4\">\n \n <!-- Payment Summary Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Payment Summary</h6>\n </div>\n <div class=\"tw-p-4 tw-space-y-3\">\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-600\">Selected Items</span>\n <span class=\"tw-font-medium tw-text-gray-900\">{{ selectedCount() }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-600\">Fee Amount</span>\n <span class=\"tw-font-medium tw-text-gray-900\">{{ formatCurrency(totalFeeAmount()) }}</span>\n </div>\n @if (totalLateFee() > 0) {\n <div class=\"tw-flex tw-justify-between tw-text-sm tw-text-red-600\">\n <span>Late Fee</span>\n <span class=\"tw-font-medium\">{{ formatCurrency(totalLateFee()) }}</span>\n </div>\n }\n <div class=\"tw-flex tw-justify-between tw-text-sm tw-font-semibold tw-pt-2 tw-border-t tw-border-gray-200\">\n <span>Subtotal</span>\n <span>{{ formatCurrency(subtotal()) }}</span>\n </div>\n @if (convenienceFee() > 0) {\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-600\">Convenience Fee (2%)</span>\n <span class=\"tw-font-medium tw-text-gray-900\">{{ formatCurrency(convenienceFee()) }}</span>\n </div>\n }\n <div class=\"tw-flex tw-justify-between tw-text-lg tw-font-bold tw-pt-3 tw-border-t-2 tw-border-gray-300 tw-text-green-600\">\n <span>Total Payable</span>\n <span>{{ formatCurrency(totalPayable()) }}</span>\n </div>\n </div>\n </div>\n\n <!-- Payment Method Selection -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Select Payment Method</h6>\n </div>\n <div class=\"tw-p-4\">\n <form [formGroup]=\"paymentForm\" class=\"tw-space-y-4\">\n \n <!-- Payment Method Cards -->\n <div class=\"tw-grid tw-grid-cols-3 tw-gap-3 tw-mb-4\">\n @for (method of paymentMethodOptions; track method.value) {\n <button\n type=\"button\"\n class=\"tw-p-4 tw-rounded-lg tw-border-2 tw-text-center tw-transition-colors\"\n [class.tw-border-blue-500]=\"selectedPaymentMethod() === method.value\"\n [class.tw-bg-blue-50]=\"selectedPaymentMethod() === method.value\"\n [class.tw-border-gray-200]=\"selectedPaymentMethod() !== method.value\"\n (click)=\"selectPaymentMethod(method.value)\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-mx-auto tw-mb-2\"\n [class.tw-text-blue-600]=\"selectedPaymentMethod() === method.value\"\n [class.tw-text-gray-400]=\"selectedPaymentMethod() !== method.value\">\n @switch (method.value) {\n @case ('UPI') { account_balance_wallet }\n @case ('CARD') { credit_card }\n @case ('NET_BANKING') { account_balance }\n }\n </cide-ele-icon>\n <div class=\"tw-text-xs tw-font-medium\">{{ method.label }}</div>\n </button>\n }\n </div>\n\n <!-- UPI Details -->\n @if (selectedPaymentMethod() === 'UPI') {\n <div class=\"tw-p-3 tw-bg-blue-50 tw-rounded-lg tw-border tw-border-blue-200\">\n <cide-ele-input\n label=\"UPI ID\"\n formControlName=\"upi_id\"\n placeholder=\"username@upi\"\n size=\"sm\"\n [required]=\"true\">\n </cide-ele-input>\n </div>\n }\n\n <!-- Card Details -->\n @if (selectedPaymentMethod() === 'CARD') {\n <div class=\"tw-p-3 tw-bg-blue-50 tw-rounded-lg tw-border tw-border-blue-200 tw-space-y-3\">\n <cide-ele-input\n label=\"Card Number\"\n formControlName=\"card_number\"\n placeholder=\"1234 5678 9012 3456\"\n size=\"sm\"\n maxLength=\"19\"\n [required]=\"true\">\n </cide-ele-input>\n <div class=\"tw-grid tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input\n label=\"Expiry Date\"\n formControlName=\"expiry\"\n placeholder=\"MM/YY\"\n size=\"sm\"\n maxLength=\"5\"\n [required]=\"true\">\n </cide-ele-input>\n <cide-ele-input\n label=\"CVV\"\n formControlName=\"cvv\"\n type=\"password\"\n placeholder=\"***\"\n size=\"sm\"\n maxLength=\"3\"\n [required]=\"true\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Net Banking Details -->\n @if (selectedPaymentMethod() === 'NET_BANKING') {\n <div class=\"tw-p-3 tw-bg-blue-50 tw-rounded-lg tw-border tw-border-blue-200\">\n <cide-ele-select\n label=\"Select Bank\"\n formControlName=\"bank\"\n [options]=\"bankOptions\"\n size=\"sm\"\n placeholder=\"Select Bank\"\n [required]=\"true\">\n </cide-ele-select>\n </div>\n }\n\n <!-- Action Buttons -->\n <div class=\"tw-flex tw-gap-3 tw-pt-4\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"cancel()\" class=\"tw-flex-1\">\n Cancel\n </button>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"proceedToPayment()\"\n [disabled]=\"!canProceed() || submitting()\" [loading]=\"submitting()\" class=\"tw-flex-1\" leftIcon=\"payment\">\n Pay {{ formatCurrency(totalPayable()) }}\n </button>\n </div>\n\n <!-- Security Info -->\n <div class=\"tw-flex tw-items-center tw-justify-center tw-gap-2 tw-pt-2 tw-text-xs tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">lock</cide-ele-icon>\n <span>Secure payment powered by Razorpay</span>\n </div>\n </form>\n </div>\n </div>\n\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n", styles: [":host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }] });
8442
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MyOnlinePaymentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8443
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: MyOnlinePaymentComponent, isStandalone: true, selector: "cide-my-online-payment", ngImport: i0, template: "<!-- My Online Payment Container -->\n<div class=\"tw-w-full tw-h-full\">\n <div class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\">\n\n <!-- Header Section -->\n <div class=\"tw-table-row tw-w-full tw-h-0\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\n \n <!-- Title -->\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">payment</cide-ele-icon>\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Online Fee Payment</h5>\n </div>\n\n <!-- Actions -->\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"cancel()\" leftIcon=\"arrow_back\">\n Back to Statement\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-4\">\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-6\">\n \n <!-- Left Panel - Fee Selection -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden tw-flex tw-flex-col\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Select Fees to Pay</h6>\n </div>\n \n <!-- Quick Actions -->\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex tw-gap-2\">\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"selectAll()\">\n Select All\n </button>\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"selectOverdue()\">\n Select Overdue\n </button>\n <button cideEleButton type=\"button\" variant=\"ghost\" size=\"xs\" (click)=\"clearSelection()\">\n Clear\n </button>\n </div>\n\n <!-- Fee Items List -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4 tw-space-y-3\">\n @if (outstandingFees().length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-12 tw-h-12 tw-mx-auto tw-mb-2 tw-text-gray-400\">check_circle</cide-ele-icon>\n <p class=\"tw-text-sm\">No outstanding fees</p>\n </div>\n } @else {\n @for (fee of outstandingFees(); track fee.id) {\n <div class=\"tw-p-3 tw-rounded-lg tw-border-2 tw-cursor-pointer tw-transition-colors\"\n [class.tw-border-blue-500]=\"isSelected(fee)\"\n [class.tw-bg-blue-50]=\"isSelected(fee)\"\n [class.tw-border-yellow-400]=\"!isSelected(fee) && isOverdue(fee)\"\n [class.tw-bg-yellow-50]=\"!isSelected(fee) && isOverdue(fee)\"\n [class.tw-border-gray-200]=\"!isSelected(fee) && !isOverdue(fee)\"\n (click)=\"toggleFee(fee)\">\n <div class=\"tw-flex tw-items-start tw-justify-between tw-gap-3\">\n <div class=\"tw-flex tw-items-start tw-gap-3 tw-flex-1\">\n <input \n type=\"checkbox\" \n [checked]=\"isSelected(fee)\"\n (change)=\"toggleFee(fee); $event.stopPropagation()\"\n class=\"tw-mt-1\">\n <div class=\"tw-flex-1\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mb-1\">\n <span class=\"tw-font-medium tw-text-gray-900\">{{ fee.fee_head }}</span>\n @if (isOverdue(fee)) {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-yellow-100 tw-text-yellow-800\">\n Overdue\n </span>\n }\n </div>\n <div class=\"tw-text-xs tw-text-gray-600\">\n Due Date: {{ fee.due_date | date:'dd/MM/yyyy' }}\n </div>\n @if (fee.late_fee > 0) {\n <div class=\"tw-text-xs tw-text-red-600 tw-mt-1\">\n Late Fee: {{ formatCurrency(fee.late_fee) }}\n </div>\n }\n </div>\n </div>\n <div class=\"tw-text-right\">\n <div class=\"tw-font-semibold tw-text-gray-900\">{{ formatCurrency(fee.outstanding) }}</div>\n </div>\n </div>\n </div>\n }\n }\n </div>\n </div>\n\n <!-- Right Panel - Payment Summary & Gateway -->\n <div class=\"tw-space-y-4\">\n \n <!-- Payment Summary Card -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Payment Summary</h6>\n </div>\n <div class=\"tw-p-4 tw-space-y-3\">\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-600\">Selected Items</span>\n <span class=\"tw-font-medium tw-text-gray-900\">{{ selectedCount() }}</span>\n </div>\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-600\">Fee Amount</span>\n <span class=\"tw-font-medium tw-text-gray-900\">{{ formatCurrency(totalFeeAmount()) }}</span>\n </div>\n @if (totalLateFee() > 0) {\n <div class=\"tw-flex tw-justify-between tw-text-sm tw-text-red-600\">\n <span>Late Fee</span>\n <span class=\"tw-font-medium\">{{ formatCurrency(totalLateFee()) }}</span>\n </div>\n }\n <div class=\"tw-flex tw-justify-between tw-text-sm tw-font-semibold tw-pt-2 tw-border-t tw-border-gray-200\">\n <span>Subtotal</span>\n <span>{{ formatCurrency(subtotal()) }}</span>\n </div>\n @if (convenienceFee() > 0) {\n <div class=\"tw-flex tw-justify-between tw-text-sm\">\n <span class=\"tw-text-gray-600\">Convenience Fee (2%)</span>\n <span class=\"tw-font-medium tw-text-gray-900\">{{ formatCurrency(convenienceFee()) }}</span>\n </div>\n }\n <div class=\"tw-flex tw-justify-between tw-text-lg tw-font-bold tw-pt-3 tw-border-t-2 tw-border-gray-300 tw-text-green-600\">\n <span>Total Payable</span>\n <span>{{ formatCurrency(totalPayable()) }}</span>\n </div>\n </div>\n </div>\n\n <!-- Payment Method Selection -->\n <div class=\"tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-m-0\">Select Payment Method</h6>\n </div>\n <div class=\"tw-p-4\">\n <form [formGroup]=\"paymentForm\" class=\"tw-space-y-4\">\n \n <!-- Payment Method Cards -->\n <div class=\"tw-grid tw-grid-cols-3 tw-gap-3 tw-mb-4\">\n @for (method of paymentMethodOptions; track method.value) {\n <button\n type=\"button\"\n class=\"tw-p-4 tw-rounded-lg tw-border-2 tw-text-center tw-transition-colors\"\n [class.tw-border-blue-500]=\"selectedPaymentMethod() === method.value\"\n [class.tw-bg-blue-50]=\"selectedPaymentMethod() === method.value\"\n [class.tw-border-gray-200]=\"selectedPaymentMethod() !== method.value\"\n (click)=\"selectPaymentMethod(method.value)\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-mx-auto tw-mb-2\"\n [class.tw-text-blue-600]=\"selectedPaymentMethod() === method.value\"\n [class.tw-text-gray-400]=\"selectedPaymentMethod() !== method.value\">\n @switch (method.value) {\n @case ('UPI') { account_balance_wallet }\n @case ('CARD') { credit_card }\n @case ('NET_BANKING') { account_balance }\n }\n </cide-ele-icon>\n <div class=\"tw-text-xs tw-font-medium\">{{ method.label }}</div>\n </button>\n }\n </div>\n\n <!-- UPI Details -->\n @if (selectedPaymentMethod() === 'UPI') {\n <div class=\"tw-p-3 tw-bg-blue-50 tw-rounded-lg tw-border tw-border-blue-200\">\n <cide-ele-input\n label=\"UPI ID\"\n formControlName=\"upi_id\"\n placeholder=\"username@upi\"\n size=\"sm\"\n [required]=\"true\">\n </cide-ele-input>\n </div>\n }\n\n <!-- Card Details -->\n @if (selectedPaymentMethod() === 'CARD') {\n <div class=\"tw-p-3 tw-bg-blue-50 tw-rounded-lg tw-border tw-border-blue-200 tw-space-y-3\">\n <cide-ele-input\n label=\"Card Number\"\n formControlName=\"card_number\"\n placeholder=\"1234 5678 9012 3456\"\n size=\"sm\"\n maxLength=\"19\"\n [required]=\"true\">\n </cide-ele-input>\n <div class=\"tw-grid tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input\n label=\"Expiry Date\"\n formControlName=\"expiry\"\n placeholder=\"MM/YY\"\n size=\"sm\"\n maxLength=\"5\"\n [required]=\"true\">\n </cide-ele-input>\n <cide-ele-input\n label=\"CVV\"\n formControlName=\"cvv\"\n type=\"password\"\n placeholder=\"***\"\n size=\"sm\"\n maxLength=\"3\"\n [required]=\"true\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Net Banking Details -->\n @if (selectedPaymentMethod() === 'NET_BANKING') {\n <div class=\"tw-p-3 tw-bg-blue-50 tw-rounded-lg tw-border tw-border-blue-200\">\n <cide-ele-select\n label=\"Select Bank\"\n formControlName=\"bank\"\n [options]=\"bankOptions\"\n size=\"sm\"\n placeholder=\"Select Bank\"\n [required]=\"true\">\n </cide-ele-select>\n </div>\n }\n\n <!-- Action Buttons -->\n <div class=\"tw-flex tw-gap-3 tw-pt-4\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"cancel()\" class=\"tw-flex-1\">\n Cancel\n </button>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"proceedToPayment()\"\n [disabled]=\"!canProceed() || submitting()\" [loading]=\"submitting()\" class=\"tw-flex-1\" leftIcon=\"payment\">\n Pay {{ formatCurrency(totalPayable()) }}\n </button>\n </div>\n\n <!-- Security Info -->\n <div class=\"tw-flex tw-items-center tw-justify-center tw-gap-2 tw-pt-2 tw-text-xs tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">lock</cide-ele-icon>\n <span>Secure payment powered by Razorpay</span>\n </div>\n </form>\n </div>\n </div>\n\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n", styles: [":host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }] });
7825
8444
  }
7826
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: MyOnlinePaymentComponent, decorators: [{
8445
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MyOnlinePaymentComponent, decorators: [{
7827
8446
  type: Component,
7828
8447
  args: [{ selector: 'cide-my-online-payment', standalone: true, imports: [
7829
8448
  CommonModule,
@@ -7841,13 +8460,28 @@ var myOnlinePayment_component = /*#__PURE__*/Object.freeze({
7841
8460
  });
7842
8461
 
7843
8462
  class FeeDetailsViewerComponent {
7844
- // Inputs
7845
- isOpen = input(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
7846
- studentId = input(null, ...(ngDevMode ? [{ debugName: "studentId" }] : []));
7847
- feeId = input(null, ...(ngDevMode ? [{ debugName: "feeId" }] : []));
7848
- feeData = input(null, ...(ngDevMode ? [{ debugName: "feeData" }] : [])); // For new applicable fees
7849
- assignmentDate = input(null, ...(ngDevMode ? [{ debugName: "assignmentDate" }] : [])); // Assignment date for due date calculation
7850
- discount = input(0, ...(ngDevMode ? [{ debugName: "discount" }] : [])); // Discount amount to apply
8463
+ // Inputs with backing signals
8464
+ _isOpen = signal(false, ...(ngDevMode ? [{ debugName: "_isOpen" }] : []));
8465
+ set isOpen(value) { this._isOpen.set(value); }
8466
+ get isOpen() { return this._isOpen(); }
8467
+ _studentId = signal(null, ...(ngDevMode ? [{ debugName: "_studentId" }] : []));
8468
+ set studentId(value) { this._studentId.set(value); }
8469
+ get studentId() { return this._studentId(); }
8470
+ _feeId = signal(null, ...(ngDevMode ? [{ debugName: "_feeId" }] : []));
8471
+ set feeId(value) { this._feeId.set(value); }
8472
+ get feeId() { return this._feeId(); }
8473
+ _feeData = signal(null, ...(ngDevMode ? [{ debugName: "_feeData" }] : []));
8474
+ set feeData(value) { this._feeData.set(value); }
8475
+ get feeData() { return this._feeData(); }
8476
+ _assignmentDate = signal(null, ...(ngDevMode ? [{ debugName: "_assignmentDate" }] : []));
8477
+ set assignmentDate(value) { this._assignmentDate.set(value); }
8478
+ get assignmentDate() { return this._assignmentDate(); }
8479
+ _discount = signal(0, ...(ngDevMode ? [{ debugName: "_discount" }] : []));
8480
+ set discount(value) { this._discount.set(value); }
8481
+ get discount() { return this._discount(); }
8482
+ _scholarship = signal(0, ...(ngDevMode ? [{ debugName: "_scholarship" }] : []));
8483
+ set scholarship(value) { this._scholarship.set(value); }
8484
+ get scholarship() { return this._scholarship(); }
7851
8485
  // Outputs
7852
8486
  closed = output();
7853
8487
  // Services
@@ -7860,16 +8494,47 @@ class FeeDetailsViewerComponent {
7860
8494
  loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
7861
8495
  error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
7862
8496
  feeDetails = signal(null, ...(ngDevMode ? [{ debugName: "feeDetails" }] : []));
8497
+ constructor() {
8498
+ // Watch for changes in inputs and reload when they change
8499
+ effect(() => {
8500
+ // Accessing the getters (which read signals) registers dependencies
8501
+ this.isOpen;
8502
+ this.studentId;
8503
+ this.feeId;
8504
+ this.feeData;
8505
+ this.assignmentDate;
8506
+ this.assignmentDate;
8507
+ this.discount;
8508
+ this.scholarship;
8509
+ this.loadFeeDetails();
8510
+ });
8511
+ }
7863
8512
  ngOnInit() {
7864
8513
  // Initialize rights for fee details viewer (view-only)
7865
8514
  this.rightsService.initializeRights('fee_statement');
7866
- // Watch for changes in inputs and reload when they change
7867
- this.loadFeeDetails();
7868
8515
  }
8516
+ /**
8517
+ * Helper to get value from input (handles signals and plain values)
8518
+ * This helper is no longer needed as getters now return unwrapped values.
8519
+ */
8520
+ // private getValue(input: any): any {
8521
+ // if (typeof input === 'function') {
8522
+ // try {
8523
+ // return input();
8524
+ // } catch {
8525
+ // return input;
8526
+ // }
8527
+ // }
8528
+ // // Check if it's a signal object (has a call signature)
8529
+ // if (input && typeof input === 'object' && '_value' in input) {
8530
+ // return (input as any)._value;
8531
+ // }
8532
+ // return input;
8533
+ // }
7869
8534
  loadFeeDetails() {
7870
- // Check if feeData signal input is available and has a value
8535
+ // Check if feeData input is available and has a value
7871
8536
  try {
7872
- const feeDataValue = this.feeData?.();
8537
+ const feeDataValue = this.feeData;
7873
8538
  console.log('🔍 FeeDetailsViewer - loadFeeDetails - feeDataValue:', feeDataValue);
7874
8539
  console.log('🔍 FeeDetailsViewer - loadFeeDetails - _feeItemData:', feeDataValue?._feeItemData);
7875
8540
  if (feeDataValue) {
@@ -7880,11 +8545,11 @@ class FeeDetailsViewerComponent {
7880
8545
  }
7881
8546
  catch (error) {
7882
8547
  // Signal input might not be initialized yet, continue to other checks
7883
- console.warn('FeeData signal not yet initialized:', error);
8548
+ console.warn('FeeData logic error in loadFeeDetails:', error);
7884
8549
  }
7885
8550
  // Fallback to loading from student/fee IDs
7886
- const studentIdValue = this.studentId?.();
7887
- const feeIdValue = this.feeId?.();
8551
+ const studentIdValue = this.studentId;
8552
+ const feeIdValue = this.feeId;
7888
8553
  if (studentIdValue && feeIdValue) {
7889
8554
  // Load existing fee assignment
7890
8555
  this.loadFeeAssignment();
@@ -7900,11 +8565,11 @@ class FeeDetailsViewerComponent {
7900
8565
  // Cleanup handled by takeUntilDestroyed
7901
8566
  }
7902
8567
  loadFeeAssignment() {
7903
- if (!this.feeId() || !this.studentId())
8568
+ if (!this.feeId || !this.studentId)
7904
8569
  return;
7905
8570
  this.loading.set(true);
7906
8571
  this.error.set(null);
7907
- this.feeAssignmentService.getFeeAssignmentById(this.feeId())
8572
+ this.feeAssignmentService.getFeeAssignmentById(this.feeId)
7908
8573
  .pipe(takeUntilDestroyed(this.destroyRef))
7909
8574
  .subscribe({
7910
8575
  next: (response) => {
@@ -7925,7 +8590,7 @@ class FeeDetailsViewerComponent {
7925
8590
  });
7926
8591
  }
7927
8592
  loadFeeStructureItem() {
7928
- if (!this.feeId())
8593
+ if (!this.feeId)
7929
8594
  return;
7930
8595
  this.loading.set(true);
7931
8596
  this.error.set(null);
@@ -7933,7 +8598,7 @@ class FeeDetailsViewerComponent {
7933
8598
  // We need to get the structure first, then find the item
7934
8599
  // For now, let's assume feeId is the structure ID and we need to find the item
7935
8600
  const payload = {
7936
- fees_id: this.feeId()
8601
+ fees_id: this.feeId
7937
8602
  };
7938
8603
  this.feeStructureService.getFeeStructureById(payload)
7939
8604
  .pipe(takeUntilDestroyed(this.destroyRef))
@@ -7975,69 +8640,46 @@ class FeeDetailsViewerComponent {
7975
8640
  }
7976
8641
  processFeeData(fee) {
7977
8642
  console.log('🔍 FeeDetailsViewer - processFeeData - fee:', fee);
7978
- console.log('🔍 FeeDetailsViewer - processFeeData - _feeItemData:', fee._feeItemData);
8643
+ console.log('🔍 FeeDetailsViewer - processFeeData - _feeItemData:', fee?._feeItemData);
7979
8644
  // Ensure we have proper item data structure
7980
- let itemData = fee._feeItemData;
7981
- console.log('🔍 FeeDetailsViewer - processFeeData - itemData before check:', itemData);
7982
- console.log('🔍 FeeDetailsViewer - processFeeData - itemData type:', typeof itemData);
7983
- console.log('🔍 FeeDetailsViewer - processFeeData - itemData keys:', itemData ? Object.keys(itemData) : 'null/undefined');
8645
+ // We use a temporary variable with a broader type to allow fallbacks, then cast to specific type
8646
+ let rawItemData = fee._feeItemData;
7984
8647
  // If _feeItemData doesn't exist or is incomplete, construct it from fee data
7985
- if (!itemData || typeof itemData !== 'object' || Object.keys(itemData).length === 0) {
7986
- console.warn('⚠️ FeeDetailsViewer - _feeItemData is missing or empty, creating fallback');
7987
- // Try to extract from fee object itself if it has the structure
7988
- if (fee && typeof fee === 'object' && 'feesi_item_name' in fee) {
7989
- itemData = fee; // Use fee as itemData if it has feesi_ fields
7990
- }
7991
- else {
7992
- // Last resort: create minimal structure from available fee data
7993
- itemData = {
7994
- feesi_item_name: fee.fees_structure_name || 'N/A',
7995
- feesi_item_code: fee.fees_structure_code || 'N/A',
7996
- feesi_amount: fee.fees_amount || fee.fees_total_amount || 0,
7997
- feesi_description: 'No description available',
7998
- feesi_category_id_sygms: fee.fees_category_name || null,
7999
- feesi_is_mandatory: false,
8000
- feesi_is_refundable: false,
8001
- feesi_is_amount_editable: false,
8002
- feesi_is_installment_allowed: false,
8003
- feesi_installment_count: 1,
8004
- feesi_due_date_offset_days: 0,
8005
- feesi_collection_start_offset_days: 0,
8006
- feesi_collection_end_offset_days: 30,
8007
- feesi_tax_applicable: false,
8008
- feesi_tax_percentage: 0
8009
- };
8010
- }
8648
+ if (!rawItemData || typeof rawItemData !== 'object' || Object.keys(rawItemData).length === 0) {
8649
+ console.warn('⚠️ FeeDetailsViewer - _feeItemData is missing or empty, using fee object as fallback');
8650
+ rawItemData = fee;
8011
8651
  }
8012
- else {
8013
- // Ensure all required fields exist, using fee data as fallback
8014
- // Only use fallback if the field is missing or empty
8015
- if (!itemData.feesi_item_name || itemData.feesi_item_name === 'N/A') {
8016
- itemData.feesi_item_name = fee.fees_structure_name || itemData.feesi_item_name || 'N/A';
8017
- }
8018
- if (!itemData.feesi_item_code || itemData.feesi_item_code === 'N/A') {
8019
- itemData.feesi_item_code = fee.fees_structure_code || itemData.feesi_item_code || 'N/A';
8020
- }
8021
- if (itemData.feesi_amount === undefined || itemData.feesi_amount === null || itemData.feesi_amount === 0) {
8022
- itemData.feesi_amount = fee.fees_amount || fee.fees_total_amount || itemData.feesi_amount || 0;
8023
- }
8024
- if (!itemData.feesi_description || itemData.feesi_description === 'No description available') {
8025
- itemData.feesi_description = itemData.feesi_description || 'No description available';
8652
+ // Ensure we have a valid itemData object to work with
8653
+ const itemData = rawItemData || {};
8654
+ // Robustly fill missing fields in itemData from top-level fee properties
8655
+ // This handles cases where data is flattened or mapped differently
8656
+ if (!itemData.feesi_item_name || itemData.feesi_item_name === 'N/A') {
8657
+ itemData.feesi_item_name = fee.fees_structure_name || fee.feesi_item_name || 'N/A';
8658
+ }
8659
+ if (!itemData.feesi_item_code || itemData.feesi_item_code === 'N/A') {
8660
+ itemData.feesi_item_code = fee.fees_structure_code || fee.feesi_item_code || 'N/A';
8661
+ }
8662
+ if (itemData.feesi_amount === undefined || itemData.feesi_amount === null) {
8663
+ itemData.feesi_amount = fee.fees_amount || fee.fees_total_amount || fee.feesi_amount || 0;
8664
+ }
8665
+ if (!itemData.feesi_description || itemData.feesi_description === 'No description available') {
8666
+ itemData.feesi_description = fee.feesi_description || 'No description available';
8667
+ }
8668
+ // Ensure category is properly set
8669
+ if (!itemData.feesi_category_id_sygms) {
8670
+ // Check if it exists at root
8671
+ if (fee.feesi_category_id_sygms) {
8672
+ itemData.feesi_category_id_sygms = fee.feesi_category_id_sygms;
8026
8673
  }
8027
- // Ensure category is properly set
8028
- if (!itemData.feesi_category_id_sygms || (typeof itemData.feesi_category_id_sygms === 'string' && itemData.feesi_category_id_sygms === 'N/A')) {
8029
- // Try to preserve if it's an object, otherwise use category name from fee
8030
- if (fee.fees_category_name && fee.fees_category_name !== 'N/A') {
8031
- // If we have category name but not the ID object, we'll use the name
8032
- // The category extraction in calculateAndSetFeeDetails will handle this
8033
- }
8674
+ else if (fee.fees_category_name && fee.fees_category_name !== 'N/A') {
8675
+ // We have a name but no ID object, that's fine, logic later handles name only
8034
8676
  }
8035
8677
  }
8036
- const finalAmount = (fee.fees_total_amount || fee.fees_amount || 0) - (this.discount() || fee.discount || 0);
8678
+ const finalAmount = (fee.fees_total_amount || fee.fees_amount || 0) - (this.discount || fee.discount || 0) - (this.scholarship || fee.scholarship || 0);
8037
8679
  // Ensure assignmentDate is a Date object
8038
8680
  let assignmentDate;
8039
8681
  try {
8040
- const dateValue = this.assignmentDate();
8682
+ const dateValue = this.assignmentDate;
8041
8683
  if (dateValue instanceof Date) {
8042
8684
  assignmentDate = dateValue;
8043
8685
  }
@@ -8059,7 +8701,8 @@ class FeeDetailsViewerComponent {
8059
8701
  fees_category_name: fee.fees_category_name || 'N/A',
8060
8702
  fees_amount: fee.fees_amount || fee.fees_total_amount || 0,
8061
8703
  fees_total_amount: fee.fees_total_amount || fee.fees_amount || 0,
8062
- discount: fee.discount || this.discount() || 0,
8704
+ discount: fee.discount || this.discount || 0,
8705
+ scholarship: fee.scholarship || this.scholarship || 0,
8063
8706
  finalAmount: finalAmount,
8064
8707
  _feeItemData: itemData
8065
8708
  };
@@ -8078,7 +8721,7 @@ class FeeDetailsViewerComponent {
8078
8721
  }
8079
8722
  else {
8080
8723
  // Try to get from input signal, otherwise use current date
8081
- const dateValue = this.assignmentDate();
8724
+ const dateValue = this.assignmentDate;
8082
8725
  if (dateValue instanceof Date) {
8083
8726
  assignmentDate = dateValue;
8084
8727
  }
@@ -8121,6 +8764,7 @@ class FeeDetailsViewerComponent {
8121
8764
  fees_amount: assignment.feeas_original_amount || 0,
8122
8765
  fees_total_amount: assignment.feeas_original_amount || 0,
8123
8766
  discount: assignment.feeas_discount_amount || 0,
8767
+ scholarship: assignment.feeas_scholarship_amount || 0,
8124
8768
  finalAmount: finalAmount,
8125
8769
  _feeItemData: itemData,
8126
8770
  _feeAssignmentData: assignment
@@ -8128,11 +8772,11 @@ class FeeDetailsViewerComponent {
8128
8772
  this.calculateAndSetFeeDetails(itemData, feeData, finalAmount, assignmentDate);
8129
8773
  }
8130
8774
  processFeeItemData(item, structure) {
8131
- const finalAmount = (item.feesi_amount || 0) - (this.discount() || 0);
8775
+ const finalAmount = (item.feesi_amount || 0) - (this.discount || 0) - (this.scholarship || 0);
8132
8776
  // Ensure assignmentDate is a Date object
8133
8777
  let assignmentDate;
8134
8778
  try {
8135
- const dateValue = this.assignmentDate();
8779
+ const dateValue = this.assignmentDate;
8136
8780
  if (dateValue instanceof Date) {
8137
8781
  assignmentDate = dateValue;
8138
8782
  }
@@ -8155,7 +8799,8 @@ class FeeDetailsViewerComponent {
8155
8799
  : 'N/A',
8156
8800
  fees_amount: item.feesi_amount || 0,
8157
8801
  fees_total_amount: item.feesi_amount || 0,
8158
- discount: this.discount(),
8802
+ discount: this.discount,
8803
+ scholarship: this.scholarship,
8159
8804
  finalAmount: finalAmount,
8160
8805
  _feeItemData: item
8161
8806
  };
@@ -8247,8 +8892,8 @@ class FeeDetailsViewerComponent {
8247
8892
  }
8248
8893
  else if (itemData.feesi_category_id_sygms) {
8249
8894
  if (typeof itemData.feesi_category_id_sygms === 'object' && itemData.feesi_category_id_sygms !== null) {
8250
- categoryName = itemData.feesi_category_id_sygms?.sygms_title ||
8251
- itemData.feesi_category_id_sygms?.sygms_name ||
8895
+ categoryName = itemData.feesi_category_id_sygms.sygms_title ||
8896
+ itemData.feesi_category_id_sygms.sygms_name ||
8252
8897
  'N/A';
8253
8898
  }
8254
8899
  else if (typeof itemData.feesi_category_id_sygms === 'string') {
@@ -8261,10 +8906,10 @@ class FeeDetailsViewerComponent {
8261
8906
  categoryName = itemData.feesi_item_code;
8262
8907
  }
8263
8908
  // Extract fee name - prioritize item name, then item code, then structure name
8264
- const feeName = itemData.feesi_item_name ||
8265
- itemData.feesi_item_code ||
8266
- feeData.fees_structure_name ||
8267
- 'N/A';
8909
+ const feeName = (itemData.feesi_item_name && itemData.feesi_item_name !== 'N/A') ? itemData.feesi_item_name :
8910
+ (feeData.fees_structure_name && feeData.fees_structure_name !== 'N/A') ? feeData.fees_structure_name :
8911
+ (itemData.feesi_item_code && itemData.feesi_item_code !== 'N/A') ? itemData.feesi_item_code :
8912
+ 'N/A';
8268
8913
  // Extract item code - prioritize item code, then structure code, then structure name
8269
8914
  const itemCode = itemData.feesi_item_code ||
8270
8915
  feeData.fees_structure_code ||
@@ -8282,8 +8927,9 @@ class FeeDetailsViewerComponent {
8282
8927
  name: feeName,
8283
8928
  category: categoryName,
8284
8929
  amount: itemData.feesi_amount || feeData.fees_amount || 0,
8285
- discount: this.discount() || feeData.discount || 0,
8286
- finalAmount: finalAmount > 0 ? finalAmount : (itemData.feesi_amount || feeData.fees_amount || 0),
8930
+ discount: this.discount || feeData.discount || 0,
8931
+ scholarship: this.scholarship || feeData.scholarship || 0,
8932
+ finalAmount: finalAmount,
8287
8933
  structureName: structureName,
8288
8934
  structureCode: feeData.fees_structure_code || 'N/A',
8289
8935
  itemCode: itemCode,
@@ -8308,8 +8954,8 @@ class FeeDetailsViewerComponent {
8308
8954
  onClose() {
8309
8955
  this.closed.emit();
8310
8956
  }
8311
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeDetailsViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8312
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: FeeDetailsViewerComponent, isStandalone: true, selector: "cide-fee-details-viewer", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, studentId: { classPropertyName: "studentId", publicName: "studentId", isSignal: true, isRequired: false, transformFunction: null }, feeId: { classPropertyName: "feeId", publicName: "feeId", isSignal: true, isRequired: false, transformFunction: null }, feeData: { classPropertyName: "feeData", publicName: "feeData", isSignal: true, isRequired: false, transformFunction: null }, assignmentDate: { classPropertyName: "assignmentDate", publicName: "assignmentDate", isSignal: true, isRequired: false, transformFunction: null }, discount: { classPropertyName: "discount", publicName: "discount", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: `
8957
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeDetailsViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8958
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FeeDetailsViewerComponent, isStandalone: true, selector: "cide-fee-details-viewer", inputs: { isOpen: "isOpen", studentId: "studentId", feeId: "feeId", feeData: "feeData", assignmentDate: "assignmentDate", discount: "discount", scholarship: "scholarship" }, outputs: { closed: "closed" }, ngImport: i0, template: `
8313
8959
  <div class="tw-p-4 tw-overflow-y-auto tw-h-full">
8314
8960
  @if (loading()) {
8315
8961
  <div class="tw-text-center tw-py-12">
@@ -8367,6 +9013,12 @@ class FeeDetailsViewerComponent {
8367
9013
  <span class="tw-font-medium tw-text-blue-600">-{{ details.discount | currency }}</span>
8368
9014
  </div>
8369
9015
  }
9016
+ @if (details.scholarship > 0) {
9017
+ <div class="tw-flex tw-justify-between tw-items-center">
9018
+ <span class="tw-text-gray-600">Scholarship Applied:</span>
9019
+ <span class="tw-font-medium tw-text-purple-600">-{{ details.scholarship | currency }}</span>
9020
+ </div>
9021
+ }
8370
9022
  @if (details.taxApplicable && details.taxPercentage > 0) {
8371
9023
  <div class="tw-flex tw-justify-between tw-items-center">
8372
9024
  <span class="tw-text-gray-600">Tax ({{ details.taxPercentage }}%):</span>
@@ -8515,14 +9167,14 @@ class FeeDetailsViewerComponent {
8515
9167
  }
8516
9168
  }
8517
9169
  </div>
8518
- `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }] });
9170
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "pipe", type: CurrencyPipe$1, name: "currency" }] });
8519
9171
  }
8520
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeDetailsViewerComponent, decorators: [{
9172
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FeeDetailsViewerComponent, decorators: [{
8521
9173
  type: Component,
8522
9174
  args: [{ selector: 'cide-fee-details-viewer', standalone: true, imports: [
8523
9175
  CommonModule,
8524
9176
  CideIconComponent,
8525
- CurrencyPipe
9177
+ CurrencyPipe$1
8526
9178
  ], template: `
8527
9179
  <div class="tw-p-4 tw-overflow-y-auto tw-h-full">
8528
9180
  @if (loading()) {
@@ -8581,6 +9233,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
8581
9233
  <span class="tw-font-medium tw-text-blue-600">-{{ details.discount | currency }}</span>
8582
9234
  </div>
8583
9235
  }
9236
+ @if (details.scholarship > 0) {
9237
+ <div class="tw-flex tw-justify-between tw-items-center">
9238
+ <span class="tw-text-gray-600">Scholarship Applied:</span>
9239
+ <span class="tw-font-medium tw-text-purple-600">-{{ details.scholarship | currency }}</span>
9240
+ </div>
9241
+ }
8584
9242
  @if (details.taxApplicable && details.taxPercentage > 0) {
8585
9243
  <div class="tw-flex tw-justify-between tw-items-center">
8586
9244
  <span class="tw-text-gray-600">Tax ({{ details.taxPercentage }}%):</span>
@@ -8730,7 +9388,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
8730
9388
  }
8731
9389
  </div>
8732
9390
  `, styles: [":host{display:block}\n"] }]
8733
- }] });
9391
+ }], ctorParameters: () => [], propDecorators: { isOpen: [{
9392
+ type: Input
9393
+ }], studentId: [{
9394
+ type: Input
9395
+ }], feeId: [{
9396
+ type: Input
9397
+ }], feeData: [{
9398
+ type: Input
9399
+ }], assignmentDate: [{
9400
+ type: Input
9401
+ }], discount: [{
9402
+ type: Input
9403
+ }], scholarship: [{
9404
+ type: Input
9405
+ }], closed: [{ type: i0.Output, args: ["closed"] }] } });
8734
9406
 
8735
9407
  /*
8736
9408
  * Public API Surface of cloud-ide-fees