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.
- package/fesm2022/cloud-ide-fees-fee-discount-form.component-R_yZNKM-.mjs +383 -0
- package/fesm2022/cloud-ide-fees-fee-discount-form.component-R_yZNKM-.mjs.map +1 -0
- package/fesm2022/cloud-ide-fees-fee-scholarship-form.component-C2eJrtQT.mjs +418 -0
- package/fesm2022/cloud-ide-fees-fee-scholarship-form.component-C2eJrtQT.mjs.map +1 -0
- package/fesm2022/cloud-ide-fees.mjs +1434 -762
- package/fesm2022/cloud-ide-fees.mjs.map +1 -1
- package/index.d.ts +201 -114
- package/package.json +1 -1
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, inject, Injectable, DestroyRef, viewChild, signal, computed, input, ChangeDetectorRef, ViewChild,
|
|
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,
|
|
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,
|
|
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.
|
|
21
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.
|
|
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.
|
|
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.
|
|
237
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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.
|
|
811
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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
|
-
//
|
|
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
|
|
2117
|
-
|
|
2118
|
-
this.
|
|
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
|
|
2329
|
+
* Get academic year name from app state
|
|
2339
2330
|
*/
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
2488
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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: '
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2714
|
-
student_name: item.student_name ||
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
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
|
-
|
|
2970
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
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.
|
|
3756
|
+
return this.feeSource() === 'CUSTOM';
|
|
3043
3757
|
}, ...(ngDevMode ? [{ debugName: "showCustomFeeFields" }] : []));
|
|
3044
3758
|
showFeeStructureField = computed(() => {
|
|
3045
|
-
return this.
|
|
3759
|
+
return this.feeSource() === 'STRUCTURE';
|
|
3046
3760
|
}, ...(ngDevMode ? [{ debugName: "showFeeStructureField" }] : []));
|
|
3047
3761
|
totalAmount = computed(() => {
|
|
3048
|
-
const original =
|
|
3049
|
-
const discount =
|
|
3050
|
-
const scholarship =
|
|
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
|
-
//
|
|
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
|
-
|
|
3115
|
-
|
|
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(
|
|
3122
|
-
this.
|
|
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
|
-
|
|
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.
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
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
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
this.
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
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
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
3363
|
-
if
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
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.
|
|
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
|
|
3453
|
-
this.
|
|
3454
|
-
this.
|
|
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
|
-
*
|
|
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
|
-
|
|
3493
|
-
|
|
4081
|
+
onProgramSectionValuesChange(values) {
|
|
4082
|
+
// No-op: Signals handle reactivity now
|
|
3494
4083
|
}
|
|
3495
|
-
|
|
3496
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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.
|
|
3555
|
-
const discount =
|
|
3556
|
-
const scholarship =
|
|
3557
|
-
const originalAmount =
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
4295
|
+
CideLytSharedWrapperComponent,
|
|
3749
4296
|
CideLytSharedWrapperComponent,
|
|
3750
4297
|
ProgramSectionSelectorWrapperComponent,
|
|
3751
|
-
|
|
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.
|
|
3824
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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.
|
|
4211
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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
|
-
|
|
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: ['
|
|
4245
|
-
feepay_payment_method: ['
|
|
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
|
-
//
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
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
|
|
4282
|
-
|
|
4283
|
-
|
|
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
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
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
|
-
|
|
4889
|
+
return acc;
|
|
4890
|
+
}, 0);
|
|
4295
4891
|
}, ...(ngDevMode ? [{ debugName: "totalFeeAmount" }] : []));
|
|
4296
4892
|
totalLateFee = computed(() => {
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
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
|
-
|
|
4899
|
+
return acc;
|
|
4900
|
+
}, 0);
|
|
4304
4901
|
}, ...(ngDevMode ? [{ debugName: "totalLateFee" }] : []));
|
|
4305
4902
|
totalPenalty = computed(() => {
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4323
|
-
this.
|
|
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
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
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(
|
|
4353
|
-
const
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
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
|
|
4991
|
+
query,
|
|
4363
4992
|
pageIndex: 1,
|
|
4364
|
-
pageSize:
|
|
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
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
}
|
|
4381
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
4415
|
-
|
|
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
|
-
|
|
4424
|
-
const
|
|
4425
|
-
|
|
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
|
|
4430
|
-
const
|
|
4431
|
-
|
|
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
|
-
|
|
4449
|
-
this.outstandingFees.set([]);
|
|
4450
|
-
this.initializeFeeItems([]);
|
|
4451
|
-
}
|
|
5116
|
+
this.loading.set(false);
|
|
4452
5117
|
},
|
|
4453
5118
|
error: (err) => {
|
|
4454
|
-
console.error('Error loading
|
|
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
|
-
|
|
4466
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4491
|
-
const
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
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(
|
|
4502
|
-
|
|
4503
|
-
|
|
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(
|
|
4509
|
-
|
|
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
|
|
4527
|
-
const outstanding =
|
|
4528
|
-
const
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
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('
|
|
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('
|
|
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
|
|
4554
|
-
const
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
.
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
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
|
-
|
|
4584
|
-
|
|
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: (
|
|
4590
|
-
if (
|
|
4591
|
-
this.notificationService.success('Payment recorded
|
|
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(
|
|
4596
|
-
this.submitting.set(false);
|
|
5208
|
+
this.notificationService.error(res?.message || 'Failed');
|
|
4597
5209
|
}
|
|
5210
|
+
this.submitting.set(false);
|
|
4598
5211
|
},
|
|
4599
|
-
error: (
|
|
4600
|
-
|
|
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: '
|
|
5221
|
+
title: 'Unsaved Changes',
|
|
4610
5222
|
message: 'You have unsaved changes. Are you sure you want to leave?',
|
|
4611
|
-
confirmText: '
|
|
4612
|
-
cancelText: '
|
|
4613
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
4955
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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.
|
|
5417
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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.
|
|
5786
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
7442
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
8643
|
+
console.log('🔍 FeeDetailsViewer - processFeeData - _feeItemData:', fee?._feeItemData);
|
|
7979
8644
|
// Ensure we have proper item data structure
|
|
7980
|
-
|
|
7981
|
-
|
|
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 (!
|
|
7986
|
-
console.warn('⚠️ FeeDetailsViewer - _feeItemData is missing or empty,
|
|
7987
|
-
|
|
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
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
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
|
-
|
|
8028
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
8251
|
-
itemData.feesi_category_id_sygms
|
|
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
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
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
|
|
8286
|
-
|
|
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.
|
|
8312
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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
|