tin-spa 20.4.1 → 20.4.2

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.
@@ -835,6 +835,14 @@ var InvoiceItemType;
835
835
  InvoiceItemType[InvoiceItemType["Product"] = 1] = "Product";
836
836
  InvoiceItemType[InvoiceItemType["Service"] = 2] = "Service";
837
837
  })(InvoiceItemType || (InvoiceItemType = {}));
838
+ // Fixed asset status enum - mirrors backend AssetStatus
839
+ var AssetStatus;
840
+ (function (AssetStatus) {
841
+ AssetStatus[AssetStatus["Draft"] = 0] = "Draft";
842
+ AssetStatus[AssetStatus["Active"] = 1] = "Active";
843
+ AssetStatus[AssetStatus["FullyDepreciated"] = 2] = "FullyDepreciated";
844
+ AssetStatus[AssetStatus["Disposed"] = 3] = "Disposed";
845
+ })(AssetStatus || (AssetStatus = {}));
838
846
  // Transaction timing enum - separates WHEN payment occurs from HOW
839
847
  var TransactionTiming;
840
848
  (function (TransactionTiming) {
@@ -1660,6 +1668,10 @@ class DataServiceLib {
1660
1668
  this.capDepartments = new CapItem;
1661
1669
  this.capPositions = new CapItem;
1662
1670
  this.capGrades = new CapItem;
1671
+ this.capPayroll = new CapItem; // Changed: Added Payroll module sidebar items
1672
+ this.capSalaryStructures = new CapItem;
1673
+ this.capStatutoryDeductions = new CapItem;
1674
+ this.capPayrollRuns = new CapItem;
1663
1675
  this.capApprovals = new CapItem;
1664
1676
  this.capApprovalsConfig = new CapItem;
1665
1677
  this.capNotifications = new CapItem;
@@ -1670,8 +1682,12 @@ class DataServiceLib {
1670
1682
  this.capAccounting = new CapItem;
1671
1683
  this.capAccounts = new CapItem;
1672
1684
  this.capAggregates = new CapItem; // Added: Capability for aggregates view
1685
+ this.capReports = new CapItem; // Added: Capability for financial reports
1673
1686
  this.capAging = new CapItem; // Added: Capability for aging report
1674
1687
  this.capTaxRates = new CapItem; // Changed: Capability for tax rates management
1688
+ this.capStandingOrders = new CapItem; // Changed: Capability for standing orders management
1689
+ this.capFixedAssets = new CapItem; // Added: Capability for fixed assets management
1690
+ this.capFixedAssetCategories = new CapItem; // Added: Capability for fixed asset categories management
1675
1691
  this.capTransactionTypes = new CapItem;
1676
1692
  this.capTransactions = new CapItem;
1677
1693
  this.capAccountingInvoices = new CapItem;
@@ -1700,6 +1716,7 @@ class DataServiceLib {
1700
1716
  this.capManufacturing = new CapItem; // Changed: Manufacturing module menu group
1701
1717
  this.capSalesModule = new CapItem; // Changed: Sales module menu group
1702
1718
  this.capPurchasingModule = new CapItem; // Changed: Purchasing module menu group
1719
+ this.capSupplierAging = new CapItem; // Changed: AP Aging capability property
1703
1720
  this.tmpProfileuserName = "";
1704
1721
  this.isProcessing = false;
1705
1722
  //--------------------------Departmemts Form-------------------------
@@ -1757,6 +1774,7 @@ class DataServiceLib {
1757
1774
  { name: 'employmentStatus', alias: 'Employment Status', type: 'select', loadAction: { url: 'employees/list/employment-status' } },
1758
1775
  { name: 'activeStatus', alias: 'Active Status', type: 'select', loadAction: { url: 'employees/list/active-status' } },
1759
1776
  { name: 'passportNumber', type: 'text', alias: 'Passport Number' },
1777
+ { name: 'salaryStructureID', alias: 'Salary Structure', type: 'select', loadAction: { url: 'salarystructures/list/x' }, nullable: true }, // Changed: Added for payroll salary structure assignment
1760
1778
  { name: 'userName', type: 'select', alias: 'User', loadAction: { url: 'user/list/x' }, optionDisplay: 'name', optionValue: 'value', nullable: true, infoMessage: 'Related user account' },
1761
1779
  { name: 'address', type: 'text-area', rows: 2, span: true },
1762
1780
  { name: 'phone', type: 'text' },
@@ -1767,6 +1785,8 @@ class DataServiceLib {
1767
1785
  heroField: 'employeeID',
1768
1786
  includeAudit: true,
1769
1787
  };
1788
+ // Changed: Added edit button for employee details dialog
1789
+ this.editEmployeeButton = { name: 'edit', dialog: true, inDialog: true, action: { url: 'employees?action=edit', method: 'post' } };
1770
1790
  this.employeesTableConfig = {
1771
1791
  showFilter: true,
1772
1792
  minColumns: ['name', 'departmentName', 'positionName'],
@@ -1777,13 +1797,70 @@ class DataServiceLib {
1777
1797
  { name: 'genderName', type: 'text', alias: 'Gender' },
1778
1798
  { name: 'departmentName', type: 'text', alias: 'Department' },
1779
1799
  { name: 'positionName', type: 'text', alias: 'Position' },
1800
+ { name: 'salaryStructureName', type: 'text', alias: 'Salary Structure' }, // Changed: Added for payroll display
1780
1801
  { name: 'employmentStatusName', type: 'text', alias: 'Employment Status' },
1781
1802
  { name: 'activeStatusName', type: 'text', alias: 'Active Status' },
1782
1803
  { name: 'isLinked', type: 'checkbox', alias: 'Linked' },
1783
1804
  ],
1784
1805
  buttons: [
1785
1806
  { name: 'create', display: 'Create', dialog: true, action: { url: 'employees?action=create', method: 'post' } },
1786
- { name: 'view', dialog: true },
1807
+ {
1808
+ name: 'view',
1809
+ dialog: true,
1810
+ detailsConfig: {
1811
+ formConfig: this.employeeFormConfig,
1812
+ heroField: 'employeeID',
1813
+ buttons: [this.editEmployeeButton],
1814
+ tableConfigs: [
1815
+ // Changed: Employee salary components child table
1816
+ {
1817
+ tabTitle: 'Salary Components',
1818
+ showFilter: false,
1819
+ elevation: 'none',
1820
+ flatButtons: true,
1821
+ columns: [
1822
+ { name: 'componentName', type: 'text', alias: 'Component' },
1823
+ { name: 'componentType', type: 'text', alias: 'Type' },
1824
+ { name: 'calculationMethod', type: 'text', alias: 'Calculation' },
1825
+ { name: 'value', type: 'money', alias: 'Value' },
1826
+ ],
1827
+ buttons: [
1828
+ { name: 'create', display: 'Create', dialog: true, action: { url: 'employeesalarycomponents?action=create', method: 'post' } },
1829
+ { name: 'edit', dialog: true, action: { url: 'employeesalarycomponents?action=edit', method: 'post' } },
1830
+ { name: 'delete', dialog: true, action: { url: 'employeesalarycomponents?action=delete', method: 'post' } },
1831
+ ],
1832
+ loadAction: { url: 'employeesalarycomponents/x/x' }, loadCriteria: 'employee', loadIDField: 'employeeID',
1833
+ formConfig: {
1834
+ title: 'Salary Component',
1835
+ fixedTitle: true,
1836
+ fields: [
1837
+ { name: 'salaryComponentID', alias: 'Component', type: 'select', loadAction: { url: 'salarycomponents/list/x' }, required: true },
1838
+ { name: 'value', type: 'money', alias: 'Value', required: true },
1839
+ ],
1840
+ loadAction: { url: 'employeesalarycomponents/id' },
1841
+ heroField: 'employeeSalaryComponentID',
1842
+ },
1843
+ },
1844
+ // Changed: Employee payslip history child table
1845
+ {
1846
+ tabTitle: 'Payslip History',
1847
+ showFilter: false,
1848
+ elevation: 'none',
1849
+ flatButtons: true,
1850
+ columns: [
1851
+ { name: 'grossPay', type: 'money', alias: 'Gross Pay' },
1852
+ { name: 'totalDeductions', type: 'money', alias: 'Deductions' },
1853
+ { name: 'netPay', type: 'money', alias: 'Net Pay' },
1854
+ { name: 'statusName', type: 'text', alias: 'Status' },
1855
+ ],
1856
+ buttons: [
1857
+ { name: 'view', dialog: true },
1858
+ ],
1859
+ loadAction: { url: 'payslips/x/x' }, loadCriteria: 'employee', loadIDField: 'employeeID',
1860
+ },
1861
+ ],
1862
+ }
1863
+ },
1787
1864
  { name: 'edit', dialog: true, action: { url: 'employees?action=edit', method: 'post' } },
1788
1865
  { name: 'delete', dialog: true, action: { url: 'employees?action=delete', method: 'post' } },
1789
1866
  ],
@@ -2350,6 +2427,23 @@ class DataServiceLib {
2350
2427
  this.capPositions.display = "Positions";
2351
2428
  this.capPositions.link = "home/admin/positions";
2352
2429
  this.capPositions.icon = "picture_in_picture_medium";
2430
+ // Changed: Added Payroll module sidebar section
2431
+ this.capPayroll.name = "cap110";
2432
+ this.capPayroll.display = "Payroll";
2433
+ this.capPayroll.icon = "payments";
2434
+ this.capPayroll.capSubItems = [this.capSalaryStructures, this.capStatutoryDeductions, this.capPayrollRuns];
2435
+ this.capSalaryStructures.name = "cap111";
2436
+ this.capSalaryStructures.display = "Salary Structures";
2437
+ this.capSalaryStructures.link = "home/admin/payroll-salary-structures";
2438
+ this.capSalaryStructures.icon = "account_tree";
2439
+ this.capStatutoryDeductions.name = "cap112";
2440
+ this.capStatutoryDeductions.display = "Statutory Deductions";
2441
+ this.capStatutoryDeductions.link = "home/admin/payroll-statutory-deductions";
2442
+ this.capStatutoryDeductions.icon = "gavel";
2443
+ this.capPayrollRuns.name = "cap113";
2444
+ this.capPayrollRuns.display = "Payroll Runs";
2445
+ this.capPayrollRuns.link = "home/admin/payroll-runs";
2446
+ this.capPayrollRuns.icon = "play_circle";
2353
2447
  this.capApprovals.name = "cap21";
2354
2448
  this.capApprovals.display = "Approvals";
2355
2449
  this.capApprovals.link = "home/admin/approvals";
@@ -2376,7 +2470,7 @@ class DataServiceLib {
2376
2470
  this.capAccounting.name = "cap27";
2377
2471
  this.capAccounting.display = "Accounting";
2378
2472
  this.capAccounting.icon = "account_balance";
2379
- this.capAccounting.capSubItems = [this.capAccounts, this.capTransactions, this.capAggregates, this.capTransactionTypes, this.capTaxRates,]; // Changed: Added Tax Rates to Accounting submenu
2473
+ this.capAccounting.capSubItems = [this.capAccounts, this.capTransactions, this.capAggregates, this.capReports, this.capTransactionTypes, this.capTaxRates, this.capStandingOrders, this.capFixedAssets, this.capFixedAssetCategories]; // Changed: Added Fixed Assets to Accounting submenu
2380
2474
  this.capAccounts.name = "cap52"; // Changed: Fixed conflict with capBrands (was cap14)
2381
2475
  this.capAccounts.display = "Accounts";
2382
2476
  this.capAccounts.link = "home/admin/accounting-accounts";
@@ -2385,10 +2479,26 @@ class DataServiceLib {
2385
2479
  this.capAggregates.display = "Aggregates";
2386
2480
  this.capAggregates.link = "home/admin/accounting-aggregates";
2387
2481
  this.capAggregates.icon = "bar_chart";
2482
+ this.capReports.name = "cap61"; // Added: Financial reports capability
2483
+ this.capReports.display = "Reports";
2484
+ this.capReports.link = "home/admin/accounting-reports";
2485
+ this.capReports.icon = "assessment";
2388
2486
  this.capTaxRates.name = "cap60"; // Changed: Tax rates capability
2389
2487
  this.capTaxRates.display = "Tax Rates";
2390
2488
  this.capTaxRates.link = "home/admin/accounting-tax-rates";
2391
2489
  this.capTaxRates.icon = "percent";
2490
+ this.capStandingOrders.name = "cap64"; // Changed: Standing orders capability
2491
+ this.capStandingOrders.display = "Standing Orders";
2492
+ this.capStandingOrders.link = "home/admin/accounting-standing-orders";
2493
+ this.capStandingOrders.icon = "schedule";
2494
+ this.capFixedAssets.name = "cap70"; // Added: Fixed assets capability
2495
+ this.capFixedAssets.display = "Fixed Assets";
2496
+ this.capFixedAssets.link = "home/admin/accounting-fixed-assets";
2497
+ this.capFixedAssets.icon = "precision_manufacturing";
2498
+ this.capFixedAssetCategories.name = "cap71"; // Added: Fixed asset categories capability
2499
+ this.capFixedAssetCategories.display = "Asset Categories";
2500
+ this.capFixedAssetCategories.link = "home/admin/accounting-fixed-asset-categories";
2501
+ this.capFixedAssetCategories.icon = "category";
2392
2502
  this.capTransactionTypes.name = "cap28";
2393
2503
  this.capTransactionTypes.display = "Transaction Types";
2394
2504
  this.capTransactionTypes.link = "home/admin/accounting-transaction-types";
@@ -2438,7 +2548,7 @@ class DataServiceLib {
2438
2548
  this.capPurchasingModule.name = "cap62";
2439
2549
  this.capPurchasingModule.display = "Purchasing";
2440
2550
  this.capPurchasingModule.icon = "shopping_cart";
2441
- this.capPurchasingModule.capSubItems = [this.capInventoryReceipts, this.capPurchaseOrders]; // Changed: Moved from capInventory
2551
+ this.capPurchasingModule.capSubItems = [this.capInventoryReceipts, this.capPurchaseOrders, this.capSupplierAging]; // Changed: Added AP Aging to Purchasing menu
2442
2552
  this.capInventory.name = "cap34";
2443
2553
  this.capInventory.display = "Inventory";
2444
2554
  this.capInventory.icon = "inventory";
@@ -2485,6 +2595,10 @@ class DataServiceLib {
2485
2595
  this.capInventoryReceipts.display = "Receipts";
2486
2596
  this.capInventoryReceipts.link = "home/admin/inventory-receipts";
2487
2597
  this.capInventoryReceipts.icon = "receipt_long";
2598
+ this.capSupplierAging.name = "cap63"; // Changed: AP Aging capability
2599
+ this.capSupplierAging.display = "AP Aging";
2600
+ this.capSupplierAging.link = "home/admin/accounting-supplier-aging";
2601
+ this.capSupplierAging.icon = "schedule";
2488
2602
  this.capSalesOrders.name = "cap39";
2489
2603
  this.capSalesOrders.display = "Sales Orders";
2490
2604
  this.capSalesOrders.link = "home/admin/inventory-sales-orders";
@@ -3626,6 +3740,99 @@ class AccountingService {
3626
3740
  loadAction: { url: 'transactiontemplates/account/x' }, loadCriteria: 'account', loadIDField: 'accountID',
3627
3741
  formConfig: this.transactionTemplateFormConfig
3628
3742
  };
3743
+ //--------------------------Standing Orders-------------------------
3744
+ // Standing order form configuration — schedule recurring transactions linked to templates
3745
+ this.standingOrderFormConfig = {
3746
+ security: { allow: [this.dataService.capAccounting] },
3747
+ title: 'Standing Order',
3748
+ includeAudit: true,
3749
+ fields: [
3750
+ { name: 'name', type: 'text', required: true, span: true, alias: 'Name' },
3751
+ { name: 'transactionTemplateID', type: 'select', required: true, alias: 'Transaction Template', loadAction: { url: 'transactiontemplates/list/x' } },
3752
+ { name: 'frequency', type: 'select', required: true, alias: 'Frequency',
3753
+ options: [
3754
+ { name: 'Daily', value: 1 },
3755
+ { name: 'Weekly', value: 2 },
3756
+ { name: 'Monthly', value: 3 }
3757
+ ]
3758
+ },
3759
+ { name: 'dayOfMonth', type: 'number', alias: 'Day of Month (1-28)', min: 1, max: 28, nullable: true,
3760
+ hiddenCondition: (x) => x.frequency !== 3 },
3761
+ { name: 'dayOfWeek', type: 'select', alias: 'Day of Week', nullable: true,
3762
+ hiddenCondition: (x) => x.frequency !== 2,
3763
+ options: [
3764
+ { name: 'Sunday', value: 0 }, { name: 'Monday', value: 1 },
3765
+ { name: 'Tuesday', value: 2 }, { name: 'Wednesday', value: 3 },
3766
+ { name: 'Thursday', value: 4 }, { name: 'Friday', value: 5 },
3767
+ { name: 'Saturday', value: 6 }
3768
+ ] },
3769
+ { name: 'startDate', type: 'date', required: true, alias: 'Start Date' },
3770
+ { name: 'endDate', type: 'date', alias: 'End Date', nullable: true },
3771
+ { name: 'amount', type: 'money', alias: 'Amount (leave blank to use template default)', nullable: true },
3772
+ { name: 'isActive', type: 'checkbox', alias: 'Active', defaultValue: true }
3773
+ ],
3774
+ loadAction: { url: 'standingorders/id' },
3775
+ heroField: 'standingOrderID'
3776
+ };
3777
+ // Execution history child table — shows all execution attempts for a standing order
3778
+ this.standingOrderExecutionsTableConfig = {
3779
+ tabTitle: 'Execution History',
3780
+ showFilter: false,
3781
+ elevation: 'none',
3782
+ flatButtons: true,
3783
+ minColumns: ['executionDate', 'success', 'message'],
3784
+ columns: [
3785
+ { name: 'executionDate', type: 'date', alias: 'Date' },
3786
+ { name: 'executedAt', type: 'datetime', alias: 'Executed At' },
3787
+ { name: 'success', type: 'checkbox', alias: 'Success' },
3788
+ { name: 'isManual', type: 'checkbox', alias: 'Manual' },
3789
+ { name: 'message', type: 'text', alias: 'Result' },
3790
+ { name: 'transactionID', type: 'number', alias: 'Transaction ID' }
3791
+ ],
3792
+ buttons: [],
3793
+ loadAction: { url: 'standingorderexecutions/order/x' }, loadCriteria: 'order', loadIDField: 'standingOrderID'
3794
+ };
3795
+ // Standing order action buttons
3796
+ this.standingOrderCreateButton = { name: 'create', display: 'Create Standing Order', dialog: true, action: { url: 'standingorders?action=create', method: 'post' } };
3797
+ this.standingOrderEditButton = { name: 'edit', dialog: true, action: { url: 'standingorders?action=edit', method: 'post' } };
3798
+ this.standingOrderDeleteButton = { name: 'delete', inDialog: true, icon: { name: 'delete', color: 'red' }, action: { url: 'standingorders?action=delete', method: 'post', successMessage: 'Standing order deleted' }, confirm: { message: 'Delete this standing order?' } };
3799
+ this.standingOrderExecuteButton = { name: 'execute', display: 'Run Now', icon: { name: 'play_arrow', color: 'green' }, inDialog: true, action: { url: 'standingorders?action=execute', method: 'post', successMessage: 'Standing order executed' }, confirm: { message: 'Manually trigger this standing order now?' }, visible: (x) => x.isActive };
3800
+ this.standingOrderPauseButton = { name: 'toggle', display: 'Pause', inDialog: true, icon: { name: 'pause', color: 'orange' }, action: { url: 'standingorders?action=toggle', method: 'post', successMessage: 'Standing order paused' }, visible: (x) => x.isActive };
3801
+ this.standingOrderResumeButton = { name: 'toggle', display: 'Resume', inDialog: true, icon: { name: 'play_arrow', color: 'green' }, action: { url: 'standingorders?action=toggle', method: 'post', successMessage: 'Standing order activated' }, visible: (x) => !x.isActive };
3802
+ // Details config for standing order — includes execution history child table
3803
+ this.standingOrderDetailsConfig = {
3804
+ formConfig: this.standingOrderFormConfig,
3805
+ heroField: 'standingOrderID',
3806
+ tableConfigs: [this.standingOrderExecutionsTableConfig],
3807
+ buttons: [this.standingOrderCreateButton, this.standingOrderEditButton, this.standingOrderExecuteButton, this.standingOrderDeleteButton]
3808
+ };
3809
+ // Standing orders management table — main page
3810
+ this.standingOrdersTableConfig = {
3811
+ showFilter: true,
3812
+ minColumns: ['name', 'templateName', 'scheduleDisplay'],
3813
+ flatButtons: true,
3814
+ columns: [
3815
+ { name: 'name', type: 'button', detailsConfig: this.standingOrderDetailsConfig },
3816
+ { name: 'templateName', type: 'text', alias: 'Template' },
3817
+ { name: 'scheduleDisplay', type: 'text', alias: 'Schedule' },
3818
+ { name: 'amountDisplay', type: 'text', alias: 'Amount' },
3819
+ { name: 'startDate', type: 'date', alias: 'Start Date' },
3820
+ { name: 'endDate', type: 'date', alias: 'End Date' },
3821
+ { name: 'lastRunDisplay', type: 'text', alias: 'Last Run' },
3822
+ { name: 'isActive', type: 'checkbox', alias: 'Active' }
3823
+ ],
3824
+ buttons: [
3825
+ this.standingOrderCreateButton,
3826
+ { name: 'view', dialog: true, detailsConfig: this.standingOrderDetailsConfig },
3827
+ this.standingOrderEditButton,
3828
+ this.standingOrderPauseButton,
3829
+ this.standingOrderResumeButton,
3830
+ this.standingOrderExecuteButton,
3831
+ this.standingOrderDeleteButton
3832
+ ],
3833
+ loadAction: { url: 'standingorders/all/x' },
3834
+ formConfig: this.standingOrderFormConfig
3835
+ };
3629
3836
  //--------------------------Accounts-------------------------
3630
3837
  this.accountDetailsConfig = {
3631
3838
  ...this.accountBaseDetailsConfig,
@@ -3659,6 +3866,63 @@ class AccountingService {
3659
3866
  loadAction: { url: 'accounts/all/x' },
3660
3867
  formConfig: this.accountFormConfig
3661
3868
  };
3869
+ //--------------------------Financial Reports-------------------------
3870
+ // Trial Balance table config — shows all accounts with debit/credit totals
3871
+ this.trialBalanceTableConfig = {
3872
+ showFilter: true,
3873
+ pageSizes: [25, 50, 100],
3874
+ minColumns: ['accountName', 'totalDebits', 'totalCredits'],
3875
+ flatButtons: true,
3876
+ columns: [
3877
+ { name: 'accountName', type: 'text', alias: 'Account' },
3878
+ { name: 'accountType', type: 'text', alias: 'Type' },
3879
+ { name: 'totalDebits', type: 'money', alias: 'Debits' },
3880
+ { name: 'totalCredits', type: 'money', alias: 'Credits' },
3881
+ { name: 'closingBalance', type: 'money', alias: 'Balance',
3882
+ colors: [
3883
+ { name: 'green', condition: (x) => x.closingBalance > 0 },
3884
+ { name: 'red', condition: (x) => x.closingBalance < 0 }
3885
+ ]
3886
+ }
3887
+ ],
3888
+ loadAction: { url: 'accounts/reports/trialbalance' }
3889
+ };
3890
+ // Profit & Loss table config — shows revenue and expense accounts with section
3891
+ this.pnlTableConfig = {
3892
+ showFilter: true,
3893
+ pageSizes: [25, 50, 100],
3894
+ minColumns: ['accountName', 'section', 'amount'],
3895
+ flatButtons: true,
3896
+ columns: [
3897
+ { name: 'accountName', type: 'text', alias: 'Account' },
3898
+ { name: 'section', type: 'text', alias: 'Section' },
3899
+ { name: 'amount', type: 'money', alias: 'Amount',
3900
+ colors: [
3901
+ { name: 'green', condition: (x) => x.amount > 0 },
3902
+ { name: 'red', condition: (x) => x.amount < 0 }
3903
+ ]
3904
+ }
3905
+ ],
3906
+ loadAction: { url: 'accounts/reports/pnl' }
3907
+ };
3908
+ // Balance Sheet report table config — shows asset, liability, equity accounts with section
3909
+ this.balanceSheetReportTableConfig = {
3910
+ showFilter: true,
3911
+ pageSizes: [25, 50, 100],
3912
+ minColumns: ['accountName', 'section', 'balance'],
3913
+ flatButtons: true,
3914
+ columns: [
3915
+ { name: 'accountName', type: 'text', alias: 'Account' },
3916
+ { name: 'section', type: 'text', alias: 'Section' },
3917
+ { name: 'balance', type: 'money', alias: 'Balance',
3918
+ colors: [
3919
+ { name: 'green', condition: (x) => x.balance > 0 },
3920
+ { name: 'red', condition: (x) => x.balance < 0 }
3921
+ ]
3922
+ }
3923
+ ],
3924
+ loadAction: { url: 'accounts/reports/balancesheet' }
3925
+ };
3662
3926
  //--------------------------Aggregates-------------------------
3663
3927
  // Monthly aggregates table showing Assets, Liabilities, Income, Expenses, Profit, and Equity by month
3664
3928
  this.aggregatesTableConfig = {
@@ -3725,6 +3989,297 @@ class AccountingService {
3725
3989
  ],
3726
3990
  loadAction: { url: 'accounts/aggregates/balancesheet' }
3727
3991
  };
3992
+ //--------------------------Fixed Asset Categories-------------------------
3993
+ // Category form config for create/edit dialog
3994
+ this.categoryFormConfig = {
3995
+ title: 'Asset Category',
3996
+ includeAudit: true,
3997
+ heroField: 'fixedAssetCategoryID',
3998
+ fields: [
3999
+ { name: 'name', type: 'text', required: true },
4000
+ { name: 'description', type: 'text' },
4001
+ { name: 'defaultDepreciationMethod', alias: 'Depreciation Method', type: 'select', required: true, loadAction: { url: 'fixedassetcategories/list/depreciation-methods' }, defaultValue: 0 },
4002
+ { name: 'defaultUsefulLifeMonths', alias: 'Useful Life (Months)', type: 'number', required: true, defaultValue: 60 },
4003
+ { name: 'defaultResidualValuePercent', alias: 'Residual Value %', type: 'number', required: true, defaultValue: 10 },
4004
+ ],
4005
+ };
4006
+ this.categoryCreateButton = { name: 'create', display: 'Create Category', dialog: true, action: { url: 'fixedassetcategories?action=create', method: 'post' } };
4007
+ this.categoryEditButton = { name: 'edit', display: 'Edit', icon: { name: 'edit' }, dialog: true, action: { url: 'fixedassetcategories?action=edit', method: 'post' } };
4008
+ this.categoryDetailsConfig = {
4009
+ formConfig: this.categoryFormConfig,
4010
+ tableConfigs: [],
4011
+ heroField: 'fixedAssetCategoryID',
4012
+ buttons: [this.categoryCreateButton, this.categoryEditButton]
4013
+ };
4014
+ // Category table for listing all asset categories
4015
+ this.categoryTableConfig = {
4016
+ showFilter: true,
4017
+ minColumns: ['name', 'defaultDepreciationMethodName', 'assetCount'],
4018
+ columns: [
4019
+ { name: 'name', type: 'button', detailsConfig: this.categoryDetailsConfig },
4020
+ { name: 'defaultDepreciationMethodName', alias: 'Method', type: 'text' },
4021
+ { name: 'defaultUsefulLifeMonths', alias: 'Useful Life (Mo)', type: 'number' },
4022
+ { name: 'defaultResidualValuePercent', alias: 'Residual %', type: 'number' },
4023
+ { name: 'assetCount', alias: 'Assets', type: 'number' },
4024
+ { name: 'updatedByDetails', alias: 'Last Updated', type: 'text' },
4025
+ ],
4026
+ buttons: [
4027
+ { name: 'create', dialog: true, detailsConfig: this.categoryDetailsConfig, action: { url: 'fixedassetcategories?action=create', method: 'post' } },
4028
+ { name: 'delete', display: 'Delete', icon: { name: 'delete', color: 'red' }, action: { url: 'fixedassetcategories?action=delete', method: 'post' }, confirm: { message: 'Delete this category?' } },
4029
+ ],
4030
+ loadAction: { url: 'fixedassetcategories/all/x' },
4031
+ };
4032
+ //--------------------------Fixed Assets-------------------------
4033
+ // Fixed asset form config for create/edit dialog
4034
+ this.assetFormConfig = {
4035
+ title: 'Fixed Asset',
4036
+ includeAudit: true,
4037
+ heroField: 'fixedAssetID',
4038
+ fields: [
4039
+ { name: 'assetNumber', alias: 'Asset #', type: 'label', readonly: true, hideOnCreate: true },
4040
+ { name: 'name', type: 'text', required: true },
4041
+ { name: 'description', type: 'text' },
4042
+ { name: 'fixedAssetCategoryID', alias: 'Category', type: 'select', required: true, loadAction: { url: 'fixedassetcategories/list/x' } },
4043
+ { name: 'acquisitionDate', alias: 'Acquisition Date', type: 'date', required: true },
4044
+ { name: 'acquisitionCost', alias: 'Cost', type: 'money', required: true },
4045
+ { name: 'residualValue', alias: 'Residual Value', type: 'money', required: true, defaultValue: 0 },
4046
+ { name: 'usefulLifeMonths', alias: 'Useful Life (Months)', type: 'number', required: true },
4047
+ { name: 'depreciationMethod', alias: 'Depreciation Method', type: 'select', required: true, loadAction: { url: 'fixedassets/list/depreciation-methods' }, defaultValue: 0 },
4048
+ { name: 'location', type: 'text' },
4049
+ { name: 'serialNumber', alias: 'Serial Number', type: 'text' },
4050
+ { name: 'assetTag', alias: 'Asset Tag', type: 'text' },
4051
+ { name: 'statusName', alias: 'Status', type: 'label', readonly: true, hideOnCreate: true },
4052
+ { name: 'netBookValueDisplay', alias: 'Net Book Value', type: 'label', readonly: true, hideOnCreate: true },
4053
+ { name: 'accumulatedDepreciation', alias: 'Accum. Depreciation', type: 'label', readonly: true, hideOnCreate: true },
4054
+ ],
4055
+ loadAction: { url: 'fixedassets/id' },
4056
+ };
4057
+ // Depreciation entries nested table for asset details dialog
4058
+ this.depreciationEntriesTableConfig = {
4059
+ tabTitle: 'Depreciation History',
4060
+ showFilter: false,
4061
+ columns: [
4062
+ { name: 'periodDate', alias: 'Period', type: 'date' },
4063
+ { name: 'amountDisplay', alias: 'Amount', type: 'text' },
4064
+ { name: 'accumulatedAmountDisplay', alias: 'Accumulated', type: 'text' },
4065
+ { name: 'netBookValueDisplay', alias: 'NBV', type: 'text' },
4066
+ { name: 'entryDate', alias: 'Posted', type: 'date' },
4067
+ ],
4068
+ buttons: [],
4069
+ loadAction: { url: 'depreciationentries/{fixedAssetID}/x' }, loadCriteria: 'asset', loadIDField: 'fixedAssetID',
4070
+ };
4071
+ // Asset action buttons
4072
+ this.assetCreateButton = { name: 'create', display: 'Create Asset', dialog: true, action: { url: 'fixedassets?action=create', method: 'post' } };
4073
+ this.assetEditButton = { name: 'edit', display: 'Edit', icon: { name: 'edit' }, dialog: true, action: { url: 'fixedassets?action=edit', method: 'post' }, visible: x => x.status == AssetStatus.Draft };
4074
+ this.assetActivateButton = { name: 'activate', display: 'Activate', icon: { name: 'check_circle', color: 'green' }, action: { url: 'fixedassets?action=activate', method: 'post' }, confirm: { message: 'Activate this asset? This will post the acquisition journal entry.' }, visible: x => x.status == AssetStatus.Draft };
4075
+ this.assetDepreciateButton = { name: 'depreciate', display: 'Depreciate', icon: { name: 'trending_down', color: 'orange' }, action: { url: 'fixedassets?action=depreciate', method: 'post' }, confirm: { message: 'Post depreciation for current period?' }, visible: x => x.status == AssetStatus.Active };
4076
+ // Dispose form for the dispose dialog
4077
+ this.disposeFormConfig = {
4078
+ title: 'Dispose Asset',
4079
+ fixedTitle: true,
4080
+ fields: [
4081
+ { name: 'disposalType', alias: 'Disposal Type', type: 'select', required: true, loadAction: { url: 'fixedassets/list/disposal-types' }, defaultValue: 0 },
4082
+ { name: 'disposalAmount', alias: 'Sale Amount', type: 'money', defaultValue: 0, hiddenCondition: x => x.disposalType !== 0 },
4083
+ ]
4084
+ };
4085
+ this.assetDisposeButton = { name: 'dispose', display: 'Dispose', icon: { name: 'delete_forever', color: 'red' }, dialog: true, detailsConfig: { formConfig: this.disposeFormConfig, heroField: 'fixedAssetID', mode: 'edit', buttons: [{ name: 'dispose', display: 'Dispose Asset', inDialog: true, action: { url: 'fixedassets?action=dispose', method: 'post', successMessage: 'Asset disposed' } }] }, visible: x => x.status == AssetStatus.Active || x.status == AssetStatus.FullyDepreciated };
4086
+ // Asset details dialog with depreciation history and action buttons
4087
+ this.assetDetailsConfig = {
4088
+ formConfig: this.assetFormConfig,
4089
+ tableConfigs: [this.depreciationEntriesTableConfig],
4090
+ heroField: 'fixedAssetID',
4091
+ buttons: [this.assetCreateButton, this.assetEditButton, this.assetActivateButton, this.assetDepreciateButton, this.assetDisposeButton]
4092
+ };
4093
+ // Asset summary tiles
4094
+ this.assetTileConfig = {
4095
+ clickable: true,
4096
+ tiles: [
4097
+ { name: 'draft', alias: 'Draft', color: '#FFC107', action: { url: 'fixedassets/draft/x' } },
4098
+ { name: 'active', alias: 'Active', color: '#4CAF50', action: { url: 'fixedassets/active/x' } },
4099
+ { name: 'fullyDepreciated', alias: 'Fully Depreciated', color: '#2196F3' },
4100
+ { name: 'disposed', alias: 'Disposed', color: '#9E9E9E' },
4101
+ ],
4102
+ loadAction: { url: 'fixedassets/summary/x' }
4103
+ };
4104
+ // Main fixed assets table
4105
+ this.assetsTableConfig = {
4106
+ showFilter: true,
4107
+ minColumns: ['assetNumber', 'name', 'statusName'],
4108
+ columns: [
4109
+ { name: 'assetNumber', alias: 'Asset #', type: 'button', detailsConfig: this.assetDetailsConfig },
4110
+ { name: 'name', type: 'text' },
4111
+ { name: 'categoryName', alias: 'Category', type: 'text' },
4112
+ { name: 'acquisitionDate', alias: 'Acquired', type: 'date' },
4113
+ { name: 'acquisitionCostDisplay', alias: 'Cost', type: 'text' },
4114
+ { name: 'netBookValueDisplay', alias: 'NBV', type: 'text' },
4115
+ { name: 'depreciationMethodName', alias: 'Method', type: 'text' },
4116
+ { name: 'statusName', alias: 'Status', type: 'chip',
4117
+ colors: [
4118
+ { name: '#FFCC80', condition: x => x.status == AssetStatus.Draft },
4119
+ { name: '#A5D6A7', condition: x => x.status == AssetStatus.Active },
4120
+ { name: '#90CAF9', condition: x => x.status == AssetStatus.FullyDepreciated },
4121
+ { name: '#BDBDBD', condition: x => x.status == AssetStatus.Disposed },
4122
+ ]
4123
+ },
4124
+ { name: 'updatedByDetails', alias: 'Last Updated', type: 'text' },
4125
+ ],
4126
+ buttons: [
4127
+ { name: 'create', dialog: true, detailsConfig: this.assetDetailsConfig, action: { url: 'fixedassets?action=create', method: 'post' } },
4128
+ this.assetActivateButton,
4129
+ this.assetDepreciateButton,
4130
+ { name: 'delete', display: 'Delete', icon: { name: 'delete', color: 'red' }, action: { url: 'fixedassets?action=delete', method: 'post' }, confirm: { message: 'Delete this asset?' }, visible: x => x.status == AssetStatus.Draft },
4131
+ ],
4132
+ loadAction: { url: 'fixedassets/all/x' },
4133
+ tileConfig: this.assetTileConfig
4134
+ };
4135
+ //--------------------------Budgets-------------------------
4136
+ // Budget form configuration
4137
+ this.budgetFormConfig = {
4138
+ title: 'Budget',
4139
+ includeAudit: true,
4140
+ fields: [
4141
+ { name: 'name', type: 'text', required: true, alias: 'Budget Name' },
4142
+ { name: 'fiscalYear', type: 'number', required: true, alias: 'Fiscal Year', defaultValue: new Date().getFullYear() },
4143
+ { name: 'description', type: 'text', span: true },
4144
+ { name: 'statusName', type: 'label', alias: 'Status', readonly: true, hideOnCreate: true },
4145
+ { name: 'isActive', type: 'checkbox', alias: 'Active', readonly: true, hideOnCreate: true },
4146
+ { name: 'totalBudgetedDisplay', type: 'label', alias: 'Total Budgeted', readonly: true, hideOnCreate: true }
4147
+ ],
4148
+ loadAction: { url: 'budgets/id' },
4149
+ heroField: 'budgetID'
4150
+ };
4151
+ // Budget line form configuration
4152
+ this.budgetLineFormConfig = {
4153
+ title: 'Budget Line',
4154
+ fields: [
4155
+ { name: 'budgetID', type: 'number', hidden: true },
4156
+ { name: 'accountID', type: 'select', alias: 'Account', required: true, loadAction: { url: 'accounts/list/x' } },
4157
+ { name: 'departmentID', type: 'select', alias: 'Department', nullable: true, loadAction: { url: 'departments/list/x' } },
4158
+ { name: 'period', type: 'date', required: true, alias: 'Period (1st of Month)' },
4159
+ { name: 'budgetedAmount', type: 'money', required: true, alias: 'Budgeted Amount' }
4160
+ ],
4161
+ loadAction: { url: 'budgetlines/id' },
4162
+ heroField: 'budgetLineID'
4163
+ };
4164
+ // Budget lines child table
4165
+ this.budgetLinesTableConfig = {
4166
+ tabTitle: 'Budget Lines',
4167
+ showFilter: true,
4168
+ minColumns: ['periodLabel', 'accountName', 'budgetedAmountDisplay'],
4169
+ columns: [
4170
+ { name: 'periodLabel', type: 'text', alias: 'Period' },
4171
+ { name: 'accountName', type: 'text', alias: 'Account' },
4172
+ { name: 'accountTypeName', type: 'text', alias: 'Type' },
4173
+ { name: 'departmentName', type: 'text', alias: 'Department' },
4174
+ { name: 'budgetedAmount', type: 'money', alias: 'Amount' }
4175
+ ],
4176
+ buttons: [
4177
+ { name: 'create', display: 'Add Line', dialog: true, action: { url: 'budgetlines?action=create', method: 'post' }, disabled: (x) => x.status == 2 },
4178
+ { name: 'edit', dialog: true, action: { url: 'budgetlines?action=edit', method: 'post' }, disabled: (x) => x.budgetStatus == 2 },
4179
+ { name: 'delete', inDialog: true, icon: { name: 'delete', color: 'red' }, action: { url: 'budgetlines?action=delete', method: 'post', successMessage: 'Line deleted' }, confirm: { message: 'Delete this budget line?' }, disabled: (x) => x.budgetStatus == 2 }
4180
+ ],
4181
+ loadAction: { url: 'budgetlines/x/x' }, loadCriteria: 'budget', loadIDField: 'budgetID',
4182
+ formConfig: this.budgetLineFormConfig
4183
+ };
4184
+ // Budget action buttons
4185
+ this.budgetPublishButton = { name: 'publish', display: 'Publish', inDialog: true, icon: { name: 'publish', color: 'green' }, action: { url: 'budgets?action=publish', method: 'post', successMessage: 'Budget published' }, confirm: { message: 'Publish this budget? Lines will be locked for editing.' }, visible: (x) => x.status == 1 };
4186
+ this.budgetSetActiveButton = { name: 'setactive', display: 'Set Active', inDialog: true, icon: { name: 'star', color: 'blue' }, action: { url: 'budgets?action=setactive', method: 'post', successMessage: 'Budget set as active' }, confirm: { message: 'Set this budget as the active budget for its fiscal year?' }, visible: (x) => x.status == 2 && !x.isActive };
4187
+ this.budgetCopyButton = { name: 'copy', display: 'Copy to Next Year', inDialog: true, icon: { name: 'content_copy', color: 'purple' }, action: { url: 'budgets?action=copy', method: 'post', successMessage: 'Budget copied' }, confirm: { message: 'Copy this budget to the next fiscal year?' } };
4188
+ this.budgetEditButton = { name: 'edit', dialog: true, action: { url: 'budgets?action=edit', method: 'post' }, visible: (x) => x.status == 1 };
4189
+ // Budget details dialog with lines table and action buttons
4190
+ this.budgetDetailsConfig = {
4191
+ formConfig: this.budgetFormConfig,
4192
+ tableConfigs: [this.budgetLinesTableConfig],
4193
+ heroField: 'budgetID',
4194
+ buttons: [
4195
+ this.budgetPublishButton,
4196
+ this.budgetSetActiveButton,
4197
+ this.budgetCopyButton,
4198
+ this.budgetEditButton
4199
+ ]
4200
+ };
4201
+ // Main budgets table configuration
4202
+ this.budgetsTableConfig = {
4203
+ showFilter: true,
4204
+ minColumns: ['name', 'fiscalYear', 'statusName'],
4205
+ flatButtons: true,
4206
+ columns: [
4207
+ { name: 'name', type: 'button', detailsConfig: this.budgetDetailsConfig },
4208
+ { name: 'fiscalYear', type: 'number', alias: 'Fiscal Year' },
4209
+ { name: 'statusName', type: 'chip', alias: 'Status',
4210
+ colors: [
4211
+ { name: '#FFCC80', condition: (x) => x.status == 1 },
4212
+ { name: '#A5D6A7', condition: (x) => x.status == 2 }
4213
+ ]
4214
+ },
4215
+ { name: 'isActive', type: 'checkbox', alias: 'Active' },
4216
+ { name: 'lineCount', type: 'number', alias: 'Lines' },
4217
+ { name: 'totalBudgetedDisplay', type: 'text', alias: 'Total Budgeted' }
4218
+ ],
4219
+ buttons: [
4220
+ { name: 'create', display: 'Create Budget', dialog: true, action: { url: 'budgets?action=create', method: 'post' } },
4221
+ this.budgetPublishButton,
4222
+ this.budgetSetActiveButton,
4223
+ this.budgetCopyButton,
4224
+ { name: 'delete', inDialog: true, icon: { name: 'delete', color: 'red' }, action: { url: 'budgets?action=delete', method: 'post', successMessage: 'Budget deleted' }, confirm: { message: 'Delete this budget?' }, visible: (x) => x.status == 1 }
4225
+ ],
4226
+ loadAction: { url: 'budgets/all/x' },
4227
+ formConfig: this.budgetFormConfig
4228
+ };
4229
+ //--------------------------Budget vs Actual Report-------------------------
4230
+ // Budget vs Actual - By Period detail table
4231
+ this.budgetVsActualByPeriodTableConfig = {
4232
+ tabTitle: 'By Period',
4233
+ showFilter: true,
4234
+ pageSizes: [25, 50, 100],
4235
+ minColumns: ['periodLabel', 'accountName', 'budgetedDisplay'],
4236
+ flatButtons: true,
4237
+ columns: [
4238
+ { name: 'periodLabel', type: 'text', alias: 'Period' },
4239
+ { name: 'accountName', type: 'text', alias: 'Account' },
4240
+ { name: 'accountType', type: 'text', alias: 'Type' },
4241
+ { name: 'departmentName', type: 'text', alias: 'Department' },
4242
+ { name: 'budgetedDisplay', type: 'text', alias: 'Budgeted' },
4243
+ { name: 'actualDisplay', type: 'text', alias: 'Actual' },
4244
+ { name: 'varianceDisplay', type: 'text', alias: 'Variance',
4245
+ colors: [
4246
+ { name: 'green', condition: (x) => !x.isOverBudget },
4247
+ { name: 'red', condition: (x) => x.isOverBudget }
4248
+ ]
4249
+ },
4250
+ { name: 'variancePercent', type: 'number', alias: 'Variance %' }
4251
+ ]
4252
+ };
4253
+ // Budget vs Actual - By Account summary table
4254
+ this.budgetVsActualByAccountTableConfig = {
4255
+ tabTitle: 'By Account',
4256
+ showFilter: true,
4257
+ pageSizes: [25, 50, 100],
4258
+ minColumns: ['accountName', 'totalBudgetedDisplay', 'totalActualDisplay'],
4259
+ flatButtons: true,
4260
+ columns: [
4261
+ { name: 'accountName', type: 'text', alias: 'Account' },
4262
+ { name: 'accountType', type: 'text', alias: 'Type' },
4263
+ { name: 'totalBudgetedDisplay', type: 'text', alias: 'Total Budgeted' },
4264
+ { name: 'totalActualDisplay', type: 'text', alias: 'Total Actual' },
4265
+ { name: 'varianceDisplay', type: 'text', alias: 'Variance',
4266
+ colors: [
4267
+ { name: 'green', condition: (x) => !x.isOverBudget },
4268
+ { name: 'red', condition: (x) => x.isOverBudget }
4269
+ ]
4270
+ },
4271
+ { name: 'variancePercent', type: 'number', alias: 'Variance %' }
4272
+ ]
4273
+ };
4274
+ // Budget summary tiles for report page
4275
+ this.budgetSummaryTileConfig = {
4276
+ tiles: [
4277
+ { name: 'totalBudgeted', alias: 'Total Budgeted', color: '#2196F3', info: 'Sum of all budget line amounts' },
4278
+ { name: 'totalActual', alias: 'Total Actual', color: '#4CAF50', info: 'Sum of actual amounts from ledger' },
4279
+ { name: 'totalVariance', alias: 'Total Variance', color: '#FF9800', info: 'Difference between budgeted and actual' },
4280
+ { name: 'overBudgetLines', alias: 'Over Budget', color: '#F44336', info: 'Number of lines over budget' }
4281
+ ]
4282
+ };
3728
4283
  }
3729
4284
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AccountingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3730
4285
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AccountingService, providedIn: 'root' }); }
@@ -7458,13 +8013,16 @@ class TilesComponent {
7458
8013
  this.loadData(this.config?.loadAction, "");
7459
8014
  }
7460
8015
  }
7461
- this.reload.subscribe(v => {
7462
- if (v == true) {
7463
- if (this.config?.loadAction) {
7464
- this.loadData(this.config?.loadAction, "");
8016
+ // Changed: Added null guard — reload is undefined when parent doesn't pass [reload] input
8017
+ if (this.reload) {
8018
+ this.reload.subscribe(v => {
8019
+ if (v == true) {
8020
+ if (this.config?.loadAction) {
8021
+ this.loadData(this.config?.loadAction, "");
8022
+ }
7465
8023
  }
7466
- }
7467
- });
8024
+ });
8025
+ }
7468
8026
  }
7469
8027
  ngOnChanges() {
7470
8028
  }
@@ -14507,7 +15065,8 @@ class TinSpaModule {
14507
15065
  TenantsComponent, MembershipComponent, PlansComponent, CustomersComponent,
14508
15066
  SuppliersComponent, DepartmentsComponent, EmployeesComponent, PositionsComponent,
14509
15067
  AppModelsComponent, LoanProductsComponent, LoansComponent, LoanPaymentsComponent, WelcomeComponent, // Tin-SPA modules welcome
14510
- TermsDialogComponent, PrivacyDialogComponent // Changed: Added terms and privacy dialogs to exports
15068
+ TermsDialogComponent, PrivacyDialogComponent, // Changed: Added terms and privacy dialogs to exports
15069
+ SelectLiteComponent // Changed: Exported so pages outside TinSpaModule can use spa-select-lite
14511
15070
  ] }); }
14512
15071
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TinSpaModule, providers: [
14513
15072
  { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptor, multi: true },
@@ -14592,7 +15151,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
14592
15151
  TenantsComponent, MembershipComponent, PlansComponent, CustomersComponent,
14593
15152
  SuppliersComponent, DepartmentsComponent, EmployeesComponent, PositionsComponent,
14594
15153
  AppModelsComponent, LoanProductsComponent, LoansComponent, LoanPaymentsComponent, WelcomeComponent, // Tin-SPA modules welcome
14595
- TermsDialogComponent, PrivacyDialogComponent // Changed: Added terms and privacy dialogs to exports
15154
+ TermsDialogComponent, PrivacyDialogComponent, // Changed: Added terms and privacy dialogs to exports
15155
+ SelectLiteComponent // Changed: Exported so pages outside TinSpaModule can use spa-select-lite
14596
15156
  ],
14597
15157
  providers: [
14598
15158
  { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptor, multi: true },
@@ -16117,213 +16677,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
16117
16677
  }]
16118
16678
  }], ctorParameters: () => [{ type: DataServiceLib }] });
16119
16679
 
16120
- class TransactionTypesComponent {
16680
+ // Changed: Purchasing service extracted from inventory.service.ts for Purchasing module
16681
+ class PurchasingService {
16682
+ // Changed: Add supplier payments tab and record payment button to receipt details after all properties initialized
16121
16683
  constructor() {
16122
- this.accountingService = inject(AccountingService);
16123
- this.pageConfig = {
16124
- title: 'Transaction Types',
16125
- tableConfig: this.accountingService.transactionTypesTableConfig
16684
+ this.dataService = inject(DataServiceLib);
16685
+ this.inventoryService = inject(InventoryService); // Changed: Reference for product detailsConfig
16686
+ //--------------------------Purchase Orders-------------------------
16687
+ // Payment type options (used across forms)
16688
+ this.paymentTypeOptions = [
16689
+ { value: 0, name: 'Cash' },
16690
+ { value: 1, name: 'Bank' }
16691
+ ];
16692
+ // PO Item form configuration
16693
+ this.purchaseOrderItemFormConfig = {
16694
+ title: 'PO Item',
16695
+ fixedTitle: true,
16696
+ fields: [
16697
+ { name: 'productID', type: 'select', alias: 'Product', required: true, loadAction: { url: 'products/list/x' }, detailsConfig: this.inventoryService.productDetailsConfig },
16698
+ { name: 'orderedQuantity', type: 'number', alias: 'Quantity', required: true },
16699
+ { name: 'estimatedUnitCost', type: 'money', alias: 'Est. Unit Cost', required: true },
16700
+ { name: 'lineTotal', type: 'money', alias: 'Line Total', readonly: true, hideOnCreate: true }
16701
+ ],
16702
+ loadAction: { url: 'purchaseorderitems/id' }
16126
16703
  };
16127
- }
16128
- ngOnInit() {
16129
- }
16130
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TransactionTypesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16131
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TransactionTypesComponent, isStandalone: false, selector: "spa-transaction-types", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
16132
- }
16133
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TransactionTypesComponent, decorators: [{
16134
- type: Component,
16135
- args: [{
16136
- selector: 'spa-transaction-types',
16137
- template: '<spa-page [config]="pageConfig"></spa-page>',
16138
- standalone: false
16139
- }]
16140
- }] });
16141
-
16142
- class TransactionsComponent {
16143
- constructor() {
16144
- this.accountingService = inject(AccountingService);
16145
- this.pageConfig = {
16146
- title: 'Transactions',
16147
- tableConfig: this.accountingService.transactionsTableConfig
16148
- };
16149
- }
16150
- ngOnInit() {
16151
- }
16152
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TransactionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16153
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TransactionsComponent, isStandalone: false, selector: "spa-transactions", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
16154
- }
16155
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TransactionsComponent, decorators: [{
16156
- type: Component,
16157
- args: [{
16158
- selector: 'spa-transactions',
16159
- template: '<spa-page [config]="pageConfig"></spa-page>',
16160
- standalone: false
16161
- }]
16162
- }] });
16163
-
16164
- // Invoice management component for tin-spa library
16165
- class InvoicesComponent {
16166
- constructor() {
16167
- this.accountingService = inject(AccountingService);
16168
- this.httpService = inject(HttpService);
16169
- this.http = inject(HttpClient);
16170
- this.messageService = inject(MessageService);
16171
- this.pageConfig = {
16172
- title: 'Invoices',
16173
- tableConfig: this.accountingService.invoicesTableConfig
16174
- };
16175
- }
16176
- ngOnInit() {
16177
- }
16178
- // Handle action click events from the table
16179
- actionClicked(event) {
16180
- if (event.name === 'pdf') {
16181
- this.messageService.confirm(`Download Invoice ?`).subscribe((result) => {
16182
- if (result == "yes") {
16183
- this.download(event.data);
16184
- }
16185
- });
16186
- }
16187
- }
16188
- // Download invoice as PDF
16189
- download(invoice) {
16190
- this.http.post(`${this.httpService.apiUrl}invoices/pdf?action=x`, invoice, { responseType: 'blob' })
16191
- .subscribe((response) => {
16192
- const blob = new Blob([response], { type: 'application/pdf' });
16193
- const url = window.URL.createObjectURL(blob);
16194
- const link = document.createElement('a');
16195
- link.href = url;
16196
- link.download = `Invoice_${invoice.invoiceID}.pdf`;
16197
- link.click();
16198
- window.URL.revokeObjectURL(url);
16199
- });
16200
- }
16201
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: InvoicesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16202
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: InvoicesComponent, isStandalone: false, selector: "spa-invoices", ngImport: i0, template: '<spa-page [config]="pageConfig" (actionClick)="actionClicked($event)"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
16203
- }
16204
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: InvoicesComponent, decorators: [{
16205
- type: Component,
16206
- args: [{
16207
- selector: 'spa-invoices',
16208
- template: '<spa-page [config]="pageConfig" (actionClick)="actionClicked($event)"></spa-page>',
16209
- standalone: false
16210
- }]
16211
- }] });
16212
-
16213
- // Outstanding invoices component for tin-spa library
16214
- class OutstandingInvoicesComponent {
16215
- constructor() {
16216
- this.accountingService = inject(AccountingService);
16217
- this.pageConfig = {
16218
- title: 'Outstanding Invoices',
16219
- tableConfig: this.accountingService.outstandingInvoicesTableConfig
16220
- };
16221
- }
16222
- ngOnInit() {
16223
- }
16224
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: OutstandingInvoicesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16225
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: OutstandingInvoicesComponent, isStandalone: false, selector: "spa-outstanding-invoices", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
16226
- }
16227
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: OutstandingInvoicesComponent, decorators: [{
16228
- type: Component,
16229
- args: [{
16230
- selector: 'spa-outstanding-invoices',
16231
- template: '<spa-page [config]="pageConfig"></spa-page>',
16232
- standalone: false
16233
- }]
16234
- }] });
16235
-
16236
- // Component now uses centralized inventory service for configurations
16237
- class ProductsComponent {
16238
- constructor() {
16239
- this.inventoryService = inject(InventoryService);
16240
- this.pageConfig = {
16241
- title: 'Products',
16242
- tableConfig: this.inventoryService.productsTableConfig
16243
- };
16244
- }
16245
- ngOnInit() { }
16246
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ProductsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16247
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: ProductsComponent, isStandalone: false, selector: "spa-products", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
16248
- }
16249
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ProductsComponent, decorators: [{
16250
- type: Component,
16251
- args: [{
16252
- selector: 'spa-products',
16253
- standalone: false,
16254
- template: '<spa-page [config]="pageConfig"></spa-page>'
16255
- }]
16256
- }] });
16257
-
16258
- // Component now uses centralized inventory service for configurations
16259
- class InventoryItemsComponent {
16260
- constructor() {
16261
- this.inventoryService = inject(InventoryService);
16262
- this.pageConfig = {
16263
- title: 'Inventory Items',
16264
- tableConfig: this.inventoryService.inventoryItemsTableConfig
16265
- };
16266
- }
16267
- ngOnInit() { }
16268
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: InventoryItemsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16269
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: InventoryItemsComponent, isStandalone: false, selector: "spa-inventory-items", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
16270
- }
16271
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: InventoryItemsComponent, decorators: [{
16272
- type: Component,
16273
- args: [{
16274
- selector: 'spa-inventory-items',
16275
- template: '<spa-page [config]="pageConfig"></spa-page>',
16276
- standalone: false
16277
- }]
16278
- }] });
16279
-
16280
- // Changed: Purchasing service extracted from inventory.service.ts for Purchasing module
16281
- class PurchasingService {
16282
- constructor() {
16283
- this.dataService = inject(DataServiceLib);
16284
- this.inventoryService = inject(InventoryService); // Changed: Reference for product detailsConfig
16285
- //--------------------------Purchase Orders-------------------------
16286
- // Payment type options (used across forms)
16287
- this.paymentTypeOptions = [
16288
- { value: 0, name: 'Cash' },
16289
- { value: 1, name: 'Bank' }
16290
- ];
16291
- // PO Item form configuration
16292
- this.purchaseOrderItemFormConfig = {
16293
- title: 'PO Item',
16294
- fixedTitle: true,
16295
- fields: [
16296
- { name: 'productID', type: 'select', alias: 'Product', required: true, loadAction: { url: 'products/list/x' }, detailsConfig: this.inventoryService.productDetailsConfig },
16297
- { name: 'orderedQuantity', type: 'number', alias: 'Quantity', required: true },
16298
- { name: 'estimatedUnitCost', type: 'money', alias: 'Est. Unit Cost', required: true },
16299
- { name: 'lineTotal', type: 'money', alias: 'Line Total', readonly: true, hideOnCreate: true }
16300
- ],
16301
- loadAction: { url: 'purchaseorderitems/id' }
16302
- };
16303
- // PO Items table - shows ordered vs received quantities
16304
- this.purchaseOrderItemsTableConfig = {
16305
- tabTitle: 'Items',
16306
- showFilter: false,
16307
- elevation: 'none',
16308
- flatButtons: true,
16309
- columns: [
16310
- { name: 'productName', type: 'text', alias: 'Product' },
16311
- { name: 'orderedQuantity', type: 'number', alias: 'Ordered' },
16312
- { name: 'receivedQuantity', type: 'number', alias: 'Received' },
16313
- { name: 'remainingQuantity', type: 'number', alias: 'Remaining' },
16314
- { name: 'estimatedUnitCost', type: 'money', alias: 'Est. Cost' },
16315
- { name: 'lineTotal', type: 'money', alias: 'Line Total' },
16316
- { name: 'isFullyReceived', type: 'checkbox', alias: 'Complete', icon: { name: 'check_circle', color: 'green' } }
16317
- ],
16318
- buttons: [
16319
- { name: 'create', display: 'Add Item', dialog: true, action: { url: 'purchaseorderitems?action=create', method: 'post' } },
16320
- { name: 'edit', dialog: true, action: { url: 'purchaseorderitems?action=edit', method: 'post' } },
16321
- { name: 'delete', dialog: true, action: { url: 'purchaseorderitems?action=delete', method: 'post' } }
16322
- ],
16323
- loadAction: { url: 'purchaseorderitems/x/x' },
16324
- loadCriteria: 'po',
16325
- loadIDField: 'purchaseOrderID',
16326
- formConfig: this.purchaseOrderItemFormConfig
16704
+ // PO Items table - shows ordered vs received quantities
16705
+ this.purchaseOrderItemsTableConfig = {
16706
+ tabTitle: 'Items',
16707
+ showFilter: false,
16708
+ elevation: 'none',
16709
+ flatButtons: true,
16710
+ columns: [
16711
+ { name: 'productName', type: 'text', alias: 'Product' },
16712
+ { name: 'orderedQuantity', type: 'number', alias: 'Ordered' },
16713
+ { name: 'receivedQuantity', type: 'number', alias: 'Received' },
16714
+ { name: 'remainingQuantity', type: 'number', alias: 'Remaining' },
16715
+ { name: 'estimatedUnitCost', type: 'money', alias: 'Est. Cost' },
16716
+ { name: 'lineTotal', type: 'money', alias: 'Line Total' },
16717
+ { name: 'isFullyReceived', type: 'checkbox', alias: 'Complete', icon: { name: 'check_circle', color: 'green' } }
16718
+ ],
16719
+ buttons: [
16720
+ { name: 'create', display: 'Add Item', dialog: true, action: { url: 'purchaseorderitems?action=create', method: 'post' } },
16721
+ { name: 'edit', dialog: true, action: { url: 'purchaseorderitems?action=edit', method: 'post' } },
16722
+ { name: 'delete', dialog: true, action: { url: 'purchaseorderitems?action=delete', method: 'post' } }
16723
+ ],
16724
+ loadAction: { url: 'purchaseorderitems/x/x' },
16725
+ loadCriteria: 'po',
16726
+ loadIDField: 'purchaseOrderID',
16727
+ formConfig: this.purchaseOrderItemFormConfig
16327
16728
  };
16328
16729
  // PO form configuration
16329
16730
  this.purchaseOrderFormConfig = {
@@ -16503,6 +16904,8 @@ class PurchasingService {
16503
16904
  },
16504
16905
  { name: 'totals', type: 'section', alias: 'Totals', hideOnCreate: true, collapsed: true },
16505
16906
  { name: 'totalAmount', type: 'money', alias: 'Total Amount', readonly: true, section: 'totals', infoMessage: 'Total value of all items' },
16907
+ { name: 'dueDate', type: 'date', alias: 'Due Date', readonly: true, section: 'totals', hiddenCondition: (x) => x.timing !== 1, infoMessage: 'Payment due date (auto-set to receipt date + 30 days)' }, // Changed: DueDate for Deferred receipts
16908
+ { name: 'outstandingAmount', type: 'money', alias: 'Outstanding', readonly: true, section: 'totals', hiddenCondition: (x) => x.timing !== 1, infoMessage: 'Amount still owed to supplier' }, // Changed: Outstanding for Deferred receipts
16506
16909
  { name: 'additionalInfo', type: 'section', alias: 'Additional Information', collapsed: true },
16507
16910
  { name: 'notes', type: 'text', alias: 'Notes', span: true, section: 'additionalInfo', infoMessage: 'Additional notes about this receipt' },
16508
16911
  { name: 'supplierInvoiceNumber', type: 'text', alias: 'Supplier Invoice #', section: 'additionalInfo', infoMessage: 'Invoice number from supplier' },
@@ -16554,7 +16957,8 @@ class PurchasingService {
16554
16957
  { name: 'check_circle', color: '#4CAF50', condition: (x) => x.status === InventoryReceiptStatus.Completed, tip: 'Completed' }
16555
16958
  ]
16556
16959
  },
16557
- { name: 'totalAmount', type: 'money', alias: 'Total Value' }
16960
+ { name: 'totalAmount', type: 'money', alias: 'Total Value' },
16961
+ { name: 'outstandingAmount', type: 'money', alias: 'Outstanding', hiddenCondition: (x) => x?.timing !== 1 } // Changed: Show outstanding for Deferred receipts, guard against undefined
16558
16962
  ],
16559
16963
  buttons: [
16560
16964
  { name: 'view', icon: { name: 'launch' }, dialog: true, detailsConfig: this.inventoryReceiptDetailsConfig },
@@ -16564,6 +16968,87 @@ class PurchasingService {
16564
16968
  loadAction: { url: 'inventoryreceipts/all/x' },
16565
16969
  formConfig: this.inventoryReceiptFormConfig
16566
16970
  };
16971
+ //--------------------------Supplier Payments-------------------------
16972
+ // Changed: Supplier payment form for recording payments against credit purchase receipts
16973
+ this.supplierPaymentFormConfig = {
16974
+ security: { allow: [this.dataService.capInventoryReceipts] },
16975
+ title: 'Record Payment',
16976
+ fixedTitle: true,
16977
+ fields: [
16978
+ { name: 'inventoryReceiptID', type: 'number', hidden: true },
16979
+ { name: 'paymentDate', type: 'date', alias: 'Payment Date', required: true },
16980
+ { name: 'method', type: 'select', alias: 'Payment Method', required: true, defaultValue: 2, loadAction: { url: 'supplierpayments/list/methods' } },
16981
+ { name: 'outstandingAmount', type: 'label', alias: 'Outstanding', readonly: true },
16982
+ { name: 'amount', type: 'money', alias: 'Amount', required: true, span: true },
16983
+ { name: 'reference', type: 'text', alias: 'Reference', span: true }
16984
+ ],
16985
+ };
16986
+ // Changed: Supplier payment create button — uses edit mode to pre-fill from receipt data
16987
+ this.supplierPaymentCreateButton = { name: 'edit', action: { url: 'supplierpayments?action=create', method: 'post', successMessage: 'Payment Recorded' } };
16988
+ // Changed: Supplier payment create dialog — opens from receipt details
16989
+ this.supplierPaymentCreateDetailsConfig = {
16990
+ formConfig: this.supplierPaymentFormConfig,
16991
+ heroField: 'inventoryReceiptID',
16992
+ mode: 'edit',
16993
+ buttons: [this.supplierPaymentCreateButton]
16994
+ };
16995
+ // Changed: Record payment button for receipt aging tables
16996
+ this.supplierRecordPaymentButton = { name: 'record-payment', display: 'Record Payment', dialog: true, icon: { name: 'payment', color: 'blue' },
16997
+ detailsConfig: this.supplierPaymentCreateDetailsConfig,
16998
+ visible: (x) => x.timing === 1 && x.status === InventoryReceiptStatus.Completed && x.outstandingAmount > 0
16999
+ };
17000
+ // Changed: Supplier payments table for receipt details dialog
17001
+ this.supplierPaymentsTableConfig = {
17002
+ tabTitle: 'Payments',
17003
+ showFilter: false,
17004
+ elevation: 'none',
17005
+ flatButtons: true,
17006
+ columns: [
17007
+ { name: 'paymentDate', type: 'date', alias: 'Date' },
17008
+ { name: 'amount', type: 'money', alias: 'Amount' },
17009
+ { name: 'methodName', type: 'text', alias: 'Method' },
17010
+ { name: 'reference', type: 'text', alias: 'Reference' }
17011
+ ],
17012
+ buttons: [
17013
+ { name: 'delete', dialog: true, icon: { name: 'delete', color: 'red' }, action: { url: 'supplierpayments?action=delete', method: 'post' }, confirm: { message: 'Void this payment? The accounting transaction will be reversed.' } }
17014
+ ],
17015
+ loadAction: { url: 'supplierpayments/x/x' }, loadCriteria: 'receipt', loadIDField: 'inventoryReceiptID',
17016
+ formConfig: this.supplierPaymentFormConfig
17017
+ };
17018
+ //--------------------------AP Aging Report-------------------------
17019
+ // Changed: AP aging summary tiles — mirrors AR aging pattern
17020
+ this.apAgingTileConfig = {
17021
+ tiles: [
17022
+ { name: 'current', alias: 'Current', color: '#4CAF50', info: 'Not yet due' },
17023
+ { name: 'days30', alias: '1-30 Days', color: '#FFC107', info: '1-30 days overdue' },
17024
+ { name: 'days60', alias: '31-60 Days', color: '#FF9800', info: '31-60 days overdue' },
17025
+ { name: 'days90', alias: '61-90 Days', color: '#F44336', info: '61-90 days overdue' },
17026
+ { name: 'days90Plus', alias: '90+ Days', color: '#B71C1C', info: 'Over 90 days overdue' },
17027
+ { name: 'total', alias: 'Total Outstanding', color: '#9E9E9E', info: 'Total outstanding amount' }
17028
+ ],
17029
+ };
17030
+ // Changed: AP aging base table config — common columns for all aging tabs
17031
+ this.apAgingBaseTableConfig = {
17032
+ showFilter: true,
17033
+ flatButtons: true,
17034
+ minColumns: ['receiptNumber', 'supplierName', 'outstandingAmount'],
17035
+ columns: [
17036
+ { name: 'receiptNumber', type: 'text', alias: 'Receipt #', detailsConfig: this.inventoryReceiptDetailsConfig },
17037
+ { name: 'supplierName', type: 'text', alias: 'Supplier' },
17038
+ { name: 'receiptDate', type: 'date', alias: 'Receipt Date' },
17039
+ { name: 'dueDate', type: 'date', alias: 'Due Date' },
17040
+ { name: 'daysOverdue', type: 'number', alias: 'Days Overdue' },
17041
+ { name: 'totalAmount', type: 'money', alias: 'Total' },
17042
+ { name: 'paidAmount', type: 'money', alias: 'Paid' },
17043
+ { name: 'outstandingAmount', type: 'money', alias: 'Outstanding' }
17044
+ ],
17045
+ buttons: [
17046
+ { name: 'view', dialog: true, detailsConfig: this.inventoryReceiptDetailsConfig },
17047
+ this.supplierRecordPaymentButton,
17048
+ ]
17049
+ };
17050
+ this.inventoryReceiptDetailsConfig.tableConfigs.push(this.supplierPaymentsTableConfig);
17051
+ this.inventoryReceiptDetailsConfig.buttons.push(this.supplierRecordPaymentButton);
16567
17052
  }
16568
17053
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PurchasingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
16569
17054
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PurchasingService, providedIn: 'root' }); }
@@ -16573,30 +17058,268 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
16573
17058
  args: [{
16574
17059
  providedIn: 'root'
16575
17060
  }]
16576
- }] });
17061
+ }], ctorParameters: () => [] });
16577
17062
 
16578
- class PurchaseOrdersComponent {
16579
- constructor() {
16580
- this.purchasingService = inject(PurchasingService); // Changed: Inject PurchasingService
16581
- this.pageConfig = {
16582
- title: 'Purchase Orders',
16583
- tableConfig: this.purchasingService.purchaseOrdersTableConfig // Changed: Use PurchasingService config
16584
- };
17063
+ // AP Aging report component for accounts payable tracking — mirrors AR AgingComponent pattern
17064
+ class SupplierAgingComponent {
17065
+ ngOnInit() {
17066
+ this.loadSummaryData();
16585
17067
  }
16586
- ngOnInit() { }
16587
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PurchaseOrdersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16588
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: PurchaseOrdersComponent, isStandalone: false, selector: "spa-purchase-orders", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
17068
+ loadSummaryData() {
17069
+ this.dataServiceLib.CallApi({ url: 'inventoryreceipts/aging-summary/x' }, '').subscribe((apiResponse) => {
17070
+ if (apiResponse.success) {
17071
+ this.summaryData = apiResponse.data;
17072
+ }
17073
+ });
17074
+ }
17075
+ constructor(dataServiceLib) {
17076
+ this.dataServiceLib = dataServiceLib;
17077
+ this.purchasingService = inject(PurchasingService);
17078
+ this.tileConfig = this.purchasingService.apAgingTileConfig;
17079
+ // Changed: Build 5-tab aging table layout using AP aging base config from PurchasingService
17080
+ this.agingTableConfigs = [
17081
+ {
17082
+ ...this.purchasingService.apAgingBaseTableConfig,
17083
+ tabTitle: 'Current',
17084
+ loadAction: { url: 'inventoryreceipts/aging-current/x' },
17085
+ countAction: { url: 'inventoryreceipts/count/aging-current' }
17086
+ },
17087
+ {
17088
+ ...this.purchasingService.apAgingBaseTableConfig,
17089
+ tabTitle: '1-30 Days',
17090
+ loadAction: { url: 'inventoryreceipts/aging-30/x' },
17091
+ countAction: { url: 'inventoryreceipts/count/aging-30' }
17092
+ },
17093
+ {
17094
+ ...this.purchasingService.apAgingBaseTableConfig,
17095
+ tabTitle: '31-60 Days',
17096
+ loadAction: { url: 'inventoryreceipts/aging-60/x' },
17097
+ countAction: { url: 'inventoryreceipts/count/aging-60' }
17098
+ },
17099
+ {
17100
+ ...this.purchasingService.apAgingBaseTableConfig,
17101
+ tabTitle: '61-90 Days',
17102
+ loadAction: { url: 'inventoryreceipts/aging-90/x' },
17103
+ countAction: { url: 'inventoryreceipts/count/aging-90' }
17104
+ },
17105
+ {
17106
+ ...this.purchasingService.apAgingBaseTableConfig,
17107
+ tabTitle: '90+ Days',
17108
+ loadAction: { url: 'inventoryreceipts/aging-90plus/x' },
17109
+ countAction: { url: 'inventoryreceipts/count/aging-90plus' }
17110
+ }
17111
+ ];
17112
+ }
17113
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: SupplierAgingComponent, deps: [{ token: DataServiceLib }], target: i0.ɵɵFactoryTarget.Component }); }
17114
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: SupplierAgingComponent, isStandalone: false, selector: "spa-supplier-aging", ngImport: i0, template: `
17115
+ <h4>Accounts Payable Aging</h4>
17116
+ <hr>
17117
+ <div *ngIf="summaryData" class="mt-3 mb-3">
17118
+ <spa-tiles [config]="tileConfig" [data]="summaryData"></spa-tiles>
17119
+ </div>
17120
+
17121
+ <spa-tabs [tableConfigs]="agingTableConfigs"></spa-tabs>
17122
+ `, isInline: true, dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: TilesComponent, selector: "spa-tiles", inputs: ["config", "lastSearch", "data", "reload"], outputs: ["tileActionSelected", "tileClick", "tileUnClick"] }, { kind: "component", type: TabsComponent, selector: "spa-tabs", inputs: ["tableConfigs", "reload", "parentDetails"], outputs: ["formRefresh"] }] }); }
16589
17123
  }
16590
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PurchaseOrdersComponent, decorators: [{
17124
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: SupplierAgingComponent, decorators: [{
16591
17125
  type: Component,
16592
17126
  args: [{
16593
- selector: 'spa-purchase-orders',
16594
- template: '<spa-page [config]="pageConfig"></spa-page>',
16595
- standalone: false
16596
- }]
16597
- }] });
16598
-
16599
- // Changed: Component moved from inventory module to purchasing module
17127
+ selector: 'spa-supplier-aging',
17128
+ template: `
17129
+ <h4>Accounts Payable Aging</h4>
17130
+ <hr>
17131
+ <div *ngIf="summaryData" class="mt-3 mb-3">
17132
+ <spa-tiles [config]="tileConfig" [data]="summaryData"></spa-tiles>
17133
+ </div>
17134
+
17135
+ <spa-tabs [tableConfigs]="agingTableConfigs"></spa-tabs>
17136
+ `,
17137
+ standalone: false
17138
+ }]
17139
+ }], ctorParameters: () => [{ type: DataServiceLib }] });
17140
+
17141
+ class TransactionTypesComponent {
17142
+ constructor() {
17143
+ this.accountingService = inject(AccountingService);
17144
+ this.pageConfig = {
17145
+ title: 'Transaction Types',
17146
+ tableConfig: this.accountingService.transactionTypesTableConfig
17147
+ };
17148
+ }
17149
+ ngOnInit() {
17150
+ }
17151
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TransactionTypesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
17152
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TransactionTypesComponent, isStandalone: false, selector: "spa-transaction-types", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
17153
+ }
17154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TransactionTypesComponent, decorators: [{
17155
+ type: Component,
17156
+ args: [{
17157
+ selector: 'spa-transaction-types',
17158
+ template: '<spa-page [config]="pageConfig"></spa-page>',
17159
+ standalone: false
17160
+ }]
17161
+ }] });
17162
+
17163
+ class TransactionsComponent {
17164
+ constructor() {
17165
+ this.accountingService = inject(AccountingService);
17166
+ this.pageConfig = {
17167
+ title: 'Transactions',
17168
+ tableConfig: this.accountingService.transactionsTableConfig
17169
+ };
17170
+ }
17171
+ ngOnInit() {
17172
+ }
17173
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TransactionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
17174
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TransactionsComponent, isStandalone: false, selector: "spa-transactions", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
17175
+ }
17176
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TransactionsComponent, decorators: [{
17177
+ type: Component,
17178
+ args: [{
17179
+ selector: 'spa-transactions',
17180
+ template: '<spa-page [config]="pageConfig"></spa-page>',
17181
+ standalone: false
17182
+ }]
17183
+ }] });
17184
+
17185
+ // Invoice management component for tin-spa library
17186
+ class InvoicesComponent {
17187
+ constructor() {
17188
+ this.accountingService = inject(AccountingService);
17189
+ this.httpService = inject(HttpService);
17190
+ this.http = inject(HttpClient);
17191
+ this.messageService = inject(MessageService);
17192
+ this.pageConfig = {
17193
+ title: 'Invoices',
17194
+ tableConfig: this.accountingService.invoicesTableConfig
17195
+ };
17196
+ }
17197
+ ngOnInit() {
17198
+ }
17199
+ // Handle action click events from the table
17200
+ actionClicked(event) {
17201
+ if (event.name === 'pdf') {
17202
+ this.messageService.confirm(`Download Invoice ?`).subscribe((result) => {
17203
+ if (result == "yes") {
17204
+ this.download(event.data);
17205
+ }
17206
+ });
17207
+ }
17208
+ }
17209
+ // Download invoice as PDF
17210
+ download(invoice) {
17211
+ this.http.post(`${this.httpService.apiUrl}invoices/pdf?action=x`, invoice, { responseType: 'blob' })
17212
+ .subscribe((response) => {
17213
+ const blob = new Blob([response], { type: 'application/pdf' });
17214
+ const url = window.URL.createObjectURL(blob);
17215
+ const link = document.createElement('a');
17216
+ link.href = url;
17217
+ link.download = `Invoice_${invoice.invoiceID}.pdf`;
17218
+ link.click();
17219
+ window.URL.revokeObjectURL(url);
17220
+ });
17221
+ }
17222
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: InvoicesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
17223
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: InvoicesComponent, isStandalone: false, selector: "spa-invoices", ngImport: i0, template: '<spa-page [config]="pageConfig" (actionClick)="actionClicked($event)"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
17224
+ }
17225
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: InvoicesComponent, decorators: [{
17226
+ type: Component,
17227
+ args: [{
17228
+ selector: 'spa-invoices',
17229
+ template: '<spa-page [config]="pageConfig" (actionClick)="actionClicked($event)"></spa-page>',
17230
+ standalone: false
17231
+ }]
17232
+ }] });
17233
+
17234
+ // Outstanding invoices component for tin-spa library
17235
+ class OutstandingInvoicesComponent {
17236
+ constructor() {
17237
+ this.accountingService = inject(AccountingService);
17238
+ this.pageConfig = {
17239
+ title: 'Outstanding Invoices',
17240
+ tableConfig: this.accountingService.outstandingInvoicesTableConfig
17241
+ };
17242
+ }
17243
+ ngOnInit() {
17244
+ }
17245
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: OutstandingInvoicesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
17246
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: OutstandingInvoicesComponent, isStandalone: false, selector: "spa-outstanding-invoices", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
17247
+ }
17248
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: OutstandingInvoicesComponent, decorators: [{
17249
+ type: Component,
17250
+ args: [{
17251
+ selector: 'spa-outstanding-invoices',
17252
+ template: '<spa-page [config]="pageConfig"></spa-page>',
17253
+ standalone: false
17254
+ }]
17255
+ }] });
17256
+
17257
+ // Component now uses centralized inventory service for configurations
17258
+ class ProductsComponent {
17259
+ constructor() {
17260
+ this.inventoryService = inject(InventoryService);
17261
+ this.pageConfig = {
17262
+ title: 'Products',
17263
+ tableConfig: this.inventoryService.productsTableConfig
17264
+ };
17265
+ }
17266
+ ngOnInit() { }
17267
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ProductsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
17268
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: ProductsComponent, isStandalone: false, selector: "spa-products", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
17269
+ }
17270
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ProductsComponent, decorators: [{
17271
+ type: Component,
17272
+ args: [{
17273
+ selector: 'spa-products',
17274
+ standalone: false,
17275
+ template: '<spa-page [config]="pageConfig"></spa-page>'
17276
+ }]
17277
+ }] });
17278
+
17279
+ // Component now uses centralized inventory service for configurations
17280
+ class InventoryItemsComponent {
17281
+ constructor() {
17282
+ this.inventoryService = inject(InventoryService);
17283
+ this.pageConfig = {
17284
+ title: 'Inventory Items',
17285
+ tableConfig: this.inventoryService.inventoryItemsTableConfig
17286
+ };
17287
+ }
17288
+ ngOnInit() { }
17289
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: InventoryItemsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
17290
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: InventoryItemsComponent, isStandalone: false, selector: "spa-inventory-items", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
17291
+ }
17292
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: InventoryItemsComponent, decorators: [{
17293
+ type: Component,
17294
+ args: [{
17295
+ selector: 'spa-inventory-items',
17296
+ template: '<spa-page [config]="pageConfig"></spa-page>',
17297
+ standalone: false
17298
+ }]
17299
+ }] });
17300
+
17301
+ class PurchaseOrdersComponent {
17302
+ constructor() {
17303
+ this.purchasingService = inject(PurchasingService); // Changed: Inject PurchasingService
17304
+ this.pageConfig = {
17305
+ title: 'Purchase Orders',
17306
+ tableConfig: this.purchasingService.purchaseOrdersTableConfig // Changed: Use PurchasingService config
17307
+ };
17308
+ }
17309
+ ngOnInit() { }
17310
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PurchaseOrdersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
17311
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: PurchaseOrdersComponent, isStandalone: false, selector: "spa-purchase-orders", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
17312
+ }
17313
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PurchaseOrdersComponent, decorators: [{
17314
+ type: Component,
17315
+ args: [{
17316
+ selector: 'spa-purchase-orders',
17317
+ template: '<spa-page [config]="pageConfig"></spa-page>',
17318
+ standalone: false
17319
+ }]
17320
+ }] });
17321
+
17322
+ // Changed: Component moved from inventory module to purchasing module
16600
17323
  class InventoryReceiptsComponent {
16601
17324
  constructor() {
16602
17325
  this.purchasingService = inject(PurchasingService); // Changed: Inject PurchasingService
@@ -17394,6 +18117,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
17394
18117
  }]
17395
18118
  }] });
17396
18119
 
18120
+ // Financial Reports component with Trial Balance, P&L, Balance Sheet tabs
18121
+ class ReportsComponent {
18122
+ constructor(dataServiceLib, accountingService) {
18123
+ this.dataServiceLib = dataServiceLib;
18124
+ this.accountingService = accountingService;
18125
+ this.reportTabConfigs = [
18126
+ {
18127
+ ...this.accountingService.trialBalanceTableConfig,
18128
+ tabTitle: 'Trial Balance',
18129
+ loadAction: { url: 'accounts/reports/trialbalance' },
18130
+ },
18131
+ {
18132
+ ...this.accountingService.pnlTableConfig,
18133
+ tabTitle: 'Profit & Loss',
18134
+ loadAction: { url: 'accounts/reports/pnl' },
18135
+ },
18136
+ {
18137
+ ...this.accountingService.balanceSheetReportTableConfig,
18138
+ tabTitle: 'Balance Sheet',
18139
+ loadAction: { url: 'accounts/reports/balancesheet' },
18140
+ }
18141
+ ];
18142
+ }
18143
+ ngOnInit() {
18144
+ }
18145
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ReportsComponent, deps: [{ token: DataServiceLib }, { token: AccountingService }], target: i0.ɵɵFactoryTarget.Component }); }
18146
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: ReportsComponent, isStandalone: false, selector: "spa-reports", ngImport: i0, template: `
18147
+ <h4>Financial Reports</h4>
18148
+ <hr>
18149
+
18150
+ <spa-tabs [tableConfigs]="reportTabConfigs"></spa-tabs>
18151
+ `, isInline: true, dependencies: [{ kind: "component", type: TabsComponent, selector: "spa-tabs", inputs: ["tableConfigs", "reload", "parentDetails"], outputs: ["formRefresh"] }] }); }
18152
+ }
18153
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ReportsComponent, decorators: [{
18154
+ type: Component,
18155
+ args: [{
18156
+ selector: 'spa-reports',
18157
+ template: `
18158
+ <h4>Financial Reports</h4>
18159
+ <hr>
18160
+
18161
+ <spa-tabs [tableConfigs]="reportTabConfigs"></spa-tabs>
18162
+ `,
18163
+ standalone: false
18164
+ }]
18165
+ }], ctorParameters: () => [{ type: DataServiceLib }, { type: AccountingService }] });
18166
+
17397
18167
  // Tax Rates management page - CRUD for VAT tax rates
17398
18168
  class TaxRatesComponent {
17399
18169
  constructor() {
@@ -17416,6 +18186,72 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
17416
18186
  }]
17417
18187
  }] });
17418
18188
 
18189
+ // Standing Orders management page — CRUD for recurring scheduled transactions
18190
+ class StandingOrdersComponent {
18191
+ constructor() {
18192
+ this.accountingService = inject(AccountingService);
18193
+ this.pageConfig = {
18194
+ title: 'Standing Orders',
18195
+ tableConfig: this.accountingService.standingOrdersTableConfig
18196
+ };
18197
+ }
18198
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: StandingOrdersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18199
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: StandingOrdersComponent, isStandalone: true, selector: "spa-standing-orders", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "ngmodule", type: TinSpaModule }, { kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
18200
+ }
18201
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: StandingOrdersComponent, decorators: [{
18202
+ type: Component,
18203
+ args: [{
18204
+ selector: 'spa-standing-orders',
18205
+ standalone: true,
18206
+ imports: [TinSpaModule],
18207
+ template: '<spa-page [config]="pageConfig"></spa-page>'
18208
+ }]
18209
+ }] });
18210
+
18211
+ // Fixed Asset Categories management page — CRUD for asset categories with depreciation defaults
18212
+ class FixedAssetCategoriesComponent {
18213
+ constructor() {
18214
+ this.accountingService = inject(AccountingService);
18215
+ this.pageConfig = {
18216
+ title: 'Asset Categories',
18217
+ tableConfig: this.accountingService.categoryTableConfig
18218
+ };
18219
+ }
18220
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: FixedAssetCategoriesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18221
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: FixedAssetCategoriesComponent, isStandalone: true, selector: "spa-fixed-asset-categories", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "ngmodule", type: TinSpaModule }, { kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
18222
+ }
18223
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: FixedAssetCategoriesComponent, decorators: [{
18224
+ type: Component,
18225
+ args: [{
18226
+ selector: 'spa-fixed-asset-categories',
18227
+ standalone: true,
18228
+ imports: [TinSpaModule],
18229
+ template: '<spa-page [config]="pageConfig"></spa-page>'
18230
+ }]
18231
+ }] });
18232
+
18233
+ // Fixed Assets management page — full lifecycle with tiles, CRUD, activation, depreciation, and disposal
18234
+ class FixedAssetsComponent {
18235
+ constructor() {
18236
+ this.accountingService = inject(AccountingService);
18237
+ this.pageConfig = {
18238
+ title: 'Fixed Assets',
18239
+ tableConfig: this.accountingService.assetsTableConfig
18240
+ };
18241
+ }
18242
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: FixedAssetsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18243
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: FixedAssetsComponent, isStandalone: true, selector: "spa-fixed-assets", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "ngmodule", type: TinSpaModule }, { kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
18244
+ }
18245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: FixedAssetsComponent, decorators: [{
18246
+ type: Component,
18247
+ args: [{
18248
+ selector: 'spa-fixed-assets',
18249
+ standalone: true,
18250
+ imports: [TinSpaModule],
18251
+ template: '<spa-page [config]="pageConfig"></spa-page>'
18252
+ }]
18253
+ }] });
18254
+
17419
18255
  class GptCachesComponent {
17420
18256
  constructor() {
17421
18257
  this.dataService = inject(DataServiceLib);
@@ -17496,6 +18332,498 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
17496
18332
  args: [{ selector: 'spa-preferences', standalone: false, template: "<h4>Preferences</h4>\r\n<hr>\r\n\r\n<mat-card>\r\n <mat-card-content>\r\n <form (ngSubmit)=\"onSubmit()\">\r\n\r\n <div class=\"tin-col mt-3\">\r\n\r\n <div class=\"header-title\">General</div>\r\n <hr class=\"header-line\">\r\n <div class=\"ml-4 header\">\r\n <spa-select display=\"Default Currency\" [(value)]=\"preference.defaultCurrency\" optionDisplay=\"name\" optionValue=\"value\" [options]=\"currencyOptions\"></spa-select>\r\n </div>\r\n\r\n <div class=\"header-title\">Accounting</div>\r\n <hr class=\"header-line\">\r\n <div class=\"ml-4 header\">\r\n <spa-select display=\"First Month of Year\" [(value)]=\"preference.firstMonthOfYear\" optionDisplay=\"name\" optionValue=\"value\" [options]=\"monthOptions\"></spa-select>\r\n <spa-select display=\"First Day of Month\" [(value)]=\"preference.firstDayOfMonth\" optionDisplay=\"name\" optionValue=\"value\" [options]=\"dayOptions\"></spa-select>\r\n </div>\r\n\r\n </div>\r\n\r\n <mat-card-actions>\r\n <button mat-raised-button color=\"primary\" type=\"submit\">Save Preferences</button>\r\n </mat-card-actions>\r\n </form>\r\n </mat-card-content>\r\n</mat-card>\r\n", styles: [".header-title{font-size:24px;font-weight:300}.header-line{margin-top:5px;margin-bottom:5px}.header{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:16px;margin-bottom:30px}\n"] }]
17497
18333
  }], ctorParameters: () => [{ type: DataServiceLib }, { type: MessageService }] });
17498
18334
 
18335
+ class PayrollService {
18336
+ constructor() {
18337
+ this.dataService = inject(DataServiceLib);
18338
+ //--------------------------Salary Components (child of SalaryStructure)-------------------------
18339
+ this.salaryComponentFormConfig = {
18340
+ title: 'Salary Component',
18341
+ fixedTitle: true,
18342
+ fields: [
18343
+ { name: 'name', type: 'text', required: true },
18344
+ { name: 'componentType', alias: 'Type', type: 'select', loadAction: { url: 'salarycomponents/list/component-type' }, required: true },
18345
+ { name: 'calculationMethod', alias: 'Calculation', type: 'select', loadAction: { url: 'salarycomponents/list/calculation-method' }, required: true },
18346
+ { name: 'sortOrder', alias: 'Sort Order', type: 'number', defaultValue: 0 },
18347
+ { name: 'isActive', type: 'checkbox', alias: 'Active', defaultValue: true },
18348
+ ],
18349
+ loadAction: { url: 'salarycomponents/id' },
18350
+ heroField: 'salaryComponentID',
18351
+ };
18352
+ this.salaryComponentsTableConfig = {
18353
+ tabTitle: 'Components',
18354
+ showFilter: false,
18355
+ elevation: 'none',
18356
+ flatButtons: true,
18357
+ columns: [
18358
+ { name: 'name', type: 'text' },
18359
+ { name: 'componentTypeName', type: 'text', alias: 'Type' },
18360
+ { name: 'calculationMethodName', type: 'text', alias: 'Calculation' },
18361
+ { name: 'sortOrder', type: 'text', alias: 'Order' },
18362
+ { name: 'isActive', type: 'checkbox', alias: 'Active' },
18363
+ ],
18364
+ buttons: [
18365
+ { name: 'create', display: 'Create', dialog: true, action: { url: 'salarycomponents?action=create', method: 'post' } },
18366
+ { name: 'edit', dialog: true, action: { url: 'salarycomponents?action=edit', method: 'post' } },
18367
+ { name: 'delete', dialog: true, action: { url: 'salarycomponents?action=delete', method: 'post' } },
18368
+ ],
18369
+ loadAction: { url: 'salarycomponents/x/x' }, loadCriteria: 'structure', loadIDField: 'salaryStructureID',
18370
+ formConfig: this.salaryComponentFormConfig,
18371
+ };
18372
+ //--------------------------Salary Structures-------------------------
18373
+ this.editSalaryStructureButton = { name: 'edit', dialog: true, inDialog: true, action: { url: 'salarystructures?action=edit', method: 'post' } };
18374
+ this.salaryStructureFormConfig = {
18375
+ title: 'Salary Structure',
18376
+ fields: [
18377
+ { name: 'name', type: 'text', required: true },
18378
+ { name: 'description', type: 'text-area', rows: 2, span: true },
18379
+ { name: 'isActive', type: 'checkbox', alias: 'Active', defaultValue: true },
18380
+ ],
18381
+ loadAction: { url: 'salarystructures/id' },
18382
+ heroField: 'salaryStructureID',
18383
+ includeAudit: true,
18384
+ };
18385
+ this.salaryStructuresTableConfig = {
18386
+ showFilter: true,
18387
+ flatButtons: true,
18388
+ minColumns: ['name', 'componentCount', 'employeeCount'],
18389
+ columns: [
18390
+ { name: 'name', type: 'text' },
18391
+ { name: 'description', type: 'text' },
18392
+ { name: 'componentCount', type: 'text', alias: 'Components' },
18393
+ { name: 'employeeCount', type: 'text', alias: 'Employees' },
18394
+ { name: 'isActive', type: 'checkbox', alias: 'Active' },
18395
+ ],
18396
+ buttons: [
18397
+ { name: 'create', display: 'Create', dialog: true, action: { url: 'salarystructures?action=create', method: 'post' } },
18398
+ {
18399
+ name: 'view',
18400
+ dialog: true,
18401
+ detailsConfig: {
18402
+ formConfig: this.salaryStructureFormConfig,
18403
+ heroField: 'salaryStructureID',
18404
+ buttons: [this.editSalaryStructureButton],
18405
+ tableConfigs: [this.salaryComponentsTableConfig],
18406
+ }
18407
+ },
18408
+ { name: 'edit', dialog: true, action: { url: 'salarystructures?action=edit', method: 'post' } },
18409
+ { name: 'delete', dialog: true, action: { url: 'salarystructures?action=delete', method: 'post' } },
18410
+ ],
18411
+ loadAction: { url: 'salarystructures/all/x' },
18412
+ formConfig: this.salaryStructureFormConfig,
18413
+ };
18414
+ //--------------------------Statutory Deduction Bands (child of StatutoryDeductionType)-------------------------
18415
+ this.statutoryDeductionBandFormConfig = {
18416
+ title: 'Tax Band',
18417
+ fixedTitle: true,
18418
+ fields: [
18419
+ { name: 'validFrom', type: 'date', alias: 'Valid From', required: true },
18420
+ { name: 'bandMin', type: 'money', alias: 'Minimum', required: true },
18421
+ { name: 'bandMax', type: 'money', alias: 'Maximum' },
18422
+ { name: 'rate', type: 'number', alias: 'Rate %', required: true },
18423
+ { name: 'fixedAmount', type: 'money', alias: 'Fixed Amount' },
18424
+ ],
18425
+ loadAction: { url: 'statutorydeductionbands/id' },
18426
+ heroField: 'statutoryDeductionBandID',
18427
+ };
18428
+ this.statutoryDeductionBandsTableConfig = {
18429
+ tabTitle: 'Tax Bands',
18430
+ showFilter: false,
18431
+ elevation: 'none',
18432
+ flatButtons: true,
18433
+ columns: [
18434
+ { name: 'validFrom', type: 'date', alias: 'Valid From' },
18435
+ { name: 'bandMin', type: 'money', alias: 'Min' },
18436
+ { name: 'bandMax', type: 'money', alias: 'Max' },
18437
+ { name: 'rate', type: 'text', alias: 'Rate %' },
18438
+ { name: 'fixedAmount', type: 'money', alias: 'Fixed Amount' },
18439
+ ],
18440
+ buttons: [
18441
+ { name: 'create', display: 'Create', dialog: true, action: { url: 'statutorydeductionbands?action=create', method: 'post' } },
18442
+ { name: 'edit', dialog: true, action: { url: 'statutorydeductionbands?action=edit', method: 'post' } },
18443
+ { name: 'delete', dialog: true, action: { url: 'statutorydeductionbands?action=delete', method: 'post' } },
18444
+ ],
18445
+ loadAction: { url: 'statutorydeductionbands/x/x' }, loadCriteria: 'type', loadIDField: 'statutoryDeductionTypeID',
18446
+ formConfig: this.statutoryDeductionBandFormConfig,
18447
+ };
18448
+ //--------------------------Statutory Deduction Types-------------------------
18449
+ this.editStatutoryDeductionTypeButton = { name: 'edit', dialog: true, inDialog: true, action: { url: 'statutorydeductiontypes?action=edit', method: 'post' } };
18450
+ this.statutoryDeductionTypeFormConfig = {
18451
+ title: 'Statutory Deduction Type',
18452
+ fields: [
18453
+ { name: 'name', type: 'text', required: true },
18454
+ { name: 'category', type: 'select', loadAction: { url: 'statutorydeductiontypes/list/deduction-category' }, required: true },
18455
+ { name: 'referencedDeductionTypeID', alias: 'Referenced Deduction', type: 'select', loadAction: { url: 'statutorydeductiontypes/list/x' }, nullable: true, infoMessage: 'For levies calculated as % of another deduction' },
18456
+ { name: 'isActive', type: 'checkbox', alias: 'Active', defaultValue: true },
18457
+ ],
18458
+ loadAction: { url: 'statutorydeductiontypes/id' },
18459
+ heroField: 'statutoryDeductionTypeID',
18460
+ includeAudit: true,
18461
+ };
18462
+ this.statutoryDeductionTypesTableConfig = {
18463
+ showFilter: true,
18464
+ flatButtons: true,
18465
+ minColumns: ['name', 'categoryName', 'bandCount'],
18466
+ columns: [
18467
+ { name: 'name', type: 'text' },
18468
+ { name: 'categoryName', type: 'text', alias: 'Category' },
18469
+ { name: 'referencedDeductionTypeName', type: 'text', alias: 'Referenced Deduction' },
18470
+ { name: 'bandCount', type: 'text', alias: 'Bands' },
18471
+ { name: 'isActive', type: 'checkbox', alias: 'Active' },
18472
+ ],
18473
+ buttons: [
18474
+ { name: 'create', display: 'Create', dialog: true, action: { url: 'statutorydeductiontypes?action=create', method: 'post' } },
18475
+ {
18476
+ name: 'view',
18477
+ dialog: true,
18478
+ detailsConfig: {
18479
+ formConfig: this.statutoryDeductionTypeFormConfig,
18480
+ heroField: 'statutoryDeductionTypeID',
18481
+ buttons: [this.editStatutoryDeductionTypeButton],
18482
+ tableConfigs: [this.statutoryDeductionBandsTableConfig],
18483
+ }
18484
+ },
18485
+ { name: 'edit', dialog: true, action: { url: 'statutorydeductiontypes?action=edit', method: 'post' } },
18486
+ { name: 'delete', dialog: true, action: { url: 'statutorydeductiontypes?action=delete', method: 'post' } },
18487
+ ],
18488
+ loadAction: { url: 'statutorydeductiontypes/all/x' },
18489
+ formConfig: this.statutoryDeductionTypeFormConfig,
18490
+ };
18491
+ //--------------------------Payslip Lines (child of Payslip)-------------------------
18492
+ this.payslipLineFormConfig = {
18493
+ title: 'Payslip Line',
18494
+ fixedTitle: true,
18495
+ fields: [
18496
+ { name: 'componentName', type: 'text', alias: 'Component', required: true },
18497
+ { name: 'componentType', alias: 'Type', type: 'select', loadAction: { url: 'salarycomponents/list/component-type' }, required: true },
18498
+ { name: 'amount', type: 'money', alias: 'Amount', required: true },
18499
+ { name: 'isStatutory', type: 'checkbox', alias: 'Statutory' },
18500
+ { name: 'sortOrder', alias: 'Sort Order', type: 'number', defaultValue: 0 },
18501
+ ],
18502
+ loadAction: { url: 'paysliplines/id' },
18503
+ heroField: 'payslipLineID',
18504
+ };
18505
+ this.payslipLinesTableConfig = {
18506
+ tabTitle: 'Payslip Lines',
18507
+ showFilter: false,
18508
+ elevation: 'none',
18509
+ flatButtons: true,
18510
+ columns: [
18511
+ { name: 'componentName', type: 'text', alias: 'Component' },
18512
+ { name: 'componentTypeName', type: 'text', alias: 'Type' },
18513
+ { name: 'isStatutory', type: 'checkbox', alias: 'Statutory' },
18514
+ { name: 'amount', type: 'money', alias: 'Amount' },
18515
+ { name: 'sortOrder', type: 'text', alias: 'Order' },
18516
+ ],
18517
+ buttons: [
18518
+ { name: 'create', display: 'Add Line', dialog: true, action: { url: 'paysliplines?action=create', method: 'post' } },
18519
+ { name: 'edit', dialog: true, action: { url: 'paysliplines?action=edit', method: 'post' } },
18520
+ { name: 'delete', dialog: true, action: { url: 'paysliplines?action=delete', method: 'post' } },
18521
+ ],
18522
+ loadAction: { url: 'paysliplines/x/x' }, loadCriteria: 'payslip', loadIDField: 'payslipID',
18523
+ formConfig: this.payslipLineFormConfig,
18524
+ };
18525
+ //--------------------------Payslips (child of PayrollRun, also used in employee details)-------------------------
18526
+ this.payslipFormConfig = {
18527
+ title: 'Payslip',
18528
+ fixedTitle: true,
18529
+ fields: [
18530
+ { name: 'employeeName', alias: 'Employee', type: 'text', readonly: true },
18531
+ { name: 'grossPay', alias: 'Gross Pay', type: 'money', readonly: true },
18532
+ { name: 'totalDeductions', alias: 'Deductions', type: 'money', readonly: true },
18533
+ { name: 'netPay', alias: 'Net Pay', type: 'money', readonly: true },
18534
+ { name: 'statusName', alias: 'Status', type: 'text', readonly: true },
18535
+ ],
18536
+ loadAction: { url: 'payslips/id' },
18537
+ heroField: 'payslipID',
18538
+ };
18539
+ this.payslipsChildTableConfig = {
18540
+ tabTitle: 'Payslips',
18541
+ showFilter: false,
18542
+ elevation: 'none',
18543
+ flatButtons: true,
18544
+ columns: [
18545
+ { name: 'employeeName', type: 'text', alias: 'Employee' },
18546
+ { name: 'grossPay', type: 'money', alias: 'Gross Pay' },
18547
+ { name: 'totalDeductions', type: 'money', alias: 'Deductions' },
18548
+ { name: 'netPay', type: 'money', alias: 'Net Pay' },
18549
+ { name: 'statusName', type: 'text', alias: 'Status' },
18550
+ ],
18551
+ buttons: [
18552
+ {
18553
+ name: 'view',
18554
+ dialog: true,
18555
+ detailsConfig: {
18556
+ formConfig: this.payslipFormConfig,
18557
+ heroField: 'payslipID',
18558
+ tableConfigs: [this.payslipLinesTableConfig],
18559
+ }
18560
+ },
18561
+ ],
18562
+ loadAction: { url: 'payslips/x/x' }, loadCriteria: 'run', loadIDField: 'payrollRunID',
18563
+ formConfig: this.payslipFormConfig,
18564
+ };
18565
+ // Employee Payslip History (child table in Employee details)
18566
+ this.employeePayslipHistoryTableConfig = {
18567
+ tabTitle: 'Payslip History',
18568
+ showFilter: false,
18569
+ elevation: 'none',
18570
+ flatButtons: true,
18571
+ columns: [
18572
+ { name: 'grossPay', type: 'money', alias: 'Gross Pay' },
18573
+ { name: 'totalDeductions', type: 'money', alias: 'Deductions' },
18574
+ { name: 'netPay', type: 'money', alias: 'Net Pay' },
18575
+ { name: 'statusName', type: 'text', alias: 'Status' },
18576
+ ],
18577
+ buttons: [
18578
+ {
18579
+ name: 'view',
18580
+ dialog: true,
18581
+ detailsConfig: {
18582
+ formConfig: this.payslipFormConfig,
18583
+ heroField: 'payslipID',
18584
+ tableConfigs: [this.payslipLinesTableConfig],
18585
+ }
18586
+ },
18587
+ ],
18588
+ loadAction: { url: 'payslips/x/x' }, loadCriteria: 'employee', loadIDField: 'employeeID',
18589
+ formConfig: this.payslipFormConfig,
18590
+ };
18591
+ //--------------------------Employee Salary Components (child of Employee)-------------------------
18592
+ this.employeeSalaryComponentFormConfig = {
18593
+ title: 'Salary Component',
18594
+ fixedTitle: true,
18595
+ fields: [
18596
+ { name: 'salaryComponentID', alias: 'Component', type: 'select', loadAction: { url: 'salarycomponents/list/x' }, required: true },
18597
+ { name: 'value', type: 'money', alias: 'Value', required: true },
18598
+ ],
18599
+ loadAction: { url: 'employeesalarycomponents/id' },
18600
+ heroField: 'employeeSalaryComponentID',
18601
+ };
18602
+ this.employeeSalaryComponentsTableConfig = {
18603
+ tabTitle: 'Salary Components',
18604
+ showFilter: false,
18605
+ elevation: 'none',
18606
+ flatButtons: true,
18607
+ columns: [
18608
+ { name: 'componentName', type: 'text', alias: 'Component' },
18609
+ { name: 'componentType', type: 'text', alias: 'Type' },
18610
+ { name: 'calculationMethod', type: 'text', alias: 'Calculation' },
18611
+ { name: 'value', type: 'money', alias: 'Value' },
18612
+ ],
18613
+ buttons: [
18614
+ { name: 'create', display: 'Create', dialog: true, action: { url: 'employeesalarycomponents?action=create', method: 'post' } },
18615
+ { name: 'edit', dialog: true, action: { url: 'employeesalarycomponents?action=edit', method: 'post' } },
18616
+ { name: 'delete', dialog: true, action: { url: 'employeesalarycomponents?action=delete', method: 'post' } },
18617
+ ],
18618
+ loadAction: { url: 'employeesalarycomponents/x/x' }, loadCriteria: 'employee', loadIDField: 'employeeID',
18619
+ formConfig: this.employeeSalaryComponentFormConfig,
18620
+ };
18621
+ //--------------------------Payroll Runs-------------------------
18622
+ // Action buttons with status-based visibility
18623
+ this.submitPayrollButton = { name: 'submit', display: 'Submit', inDialog: true, action: { url: 'payrollruns?action=submit', method: 'post' }, visible: (row) => row?.status === 1 }; // Changed: null-check row to prevent TypeError when dialog renders before row data loads
18624
+ this.postPayrollButton = { name: 'post', display: 'Post', inDialog: true, action: { url: 'payrollruns?action=post', method: 'post' }, visible: (row) => row?.status === 2 }; // Changed: null-check row
18625
+ this.markPaidButton = { name: 'paid', display: 'Mark Paid', inDialog: true, action: { url: 'payrollruns?action=paid', method: 'post' }, visible: (row) => row?.status === 3 }; // Changed: null-check row
18626
+ this.payrollRunFormConfig = {
18627
+ title: 'Payroll Run',
18628
+ fields: [
18629
+ { name: 'periodYear', alias: 'Year', type: 'number', required: true },
18630
+ { name: 'periodMonth', alias: 'Month', type: 'number', required: true },
18631
+ { name: 'payDate', alias: 'Pay Date', type: 'date', required: true },
18632
+ { name: 'description', type: 'text-area', rows: 2, span: true },
18633
+ ],
18634
+ loadAction: { url: 'payrollruns/id' },
18635
+ heroField: 'payrollRunID',
18636
+ includeAudit: true,
18637
+ };
18638
+ this.payrollRunsTableConfig = {
18639
+ showFilter: true,
18640
+ flatButtons: true,
18641
+ minColumns: ['periodYear', 'totalGrossPay', 'statusName'],
18642
+ columns: [
18643
+ { name: 'periodYear', type: 'text', alias: 'Year' },
18644
+ { name: 'periodMonth', type: 'text', alias: 'Month' },
18645
+ { name: 'payDate', type: 'date', alias: 'Pay Date' },
18646
+ { name: 'payslipCount', type: 'text', alias: 'Payslips' },
18647
+ { name: 'totalGrossPay', type: 'money', alias: 'Gross Pay' },
18648
+ { name: 'totalNetPay', type: 'money', alias: 'Net Pay' },
18649
+ { name: 'statusName', type: 'text', alias: 'Status' },
18650
+ ],
18651
+ buttons: [
18652
+ { name: 'create', display: 'Create', dialog: true, action: { url: 'payrollruns?action=create', method: 'post' } },
18653
+ {
18654
+ name: 'view',
18655
+ dialog: true,
18656
+ detailsConfig: {
18657
+ formConfig: this.payrollRunFormConfig,
18658
+ heroField: 'payrollRunID',
18659
+ buttons: [this.submitPayrollButton, this.postPayrollButton, this.markPaidButton],
18660
+ tableConfigs: [this.payslipsChildTableConfig],
18661
+ }
18662
+ },
18663
+ { name: 'edit', dialog: true, action: { url: 'payrollruns?action=edit', method: 'post' }, visible: (row) => row?.status === 1 }, // Changed: null-check row
18664
+ { name: 'delete', dialog: true, action: { url: 'payrollruns?action=delete', method: 'post' }, visible: (row) => row?.status === 1 }, // Changed: null-check row
18665
+ ],
18666
+ loadAction: { url: 'payrollruns/all/x' },
18667
+ formConfig: this.payrollRunFormConfig,
18668
+ };
18669
+ }
18670
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PayrollService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
18671
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PayrollService, providedIn: 'root' }); }
18672
+ }
18673
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PayrollService, decorators: [{
18674
+ type: Injectable,
18675
+ args: [{
18676
+ providedIn: 'root'
18677
+ }]
18678
+ }] });
18679
+
18680
+ class SalaryStructuresComponent {
18681
+ constructor() {
18682
+ this.payrollService = inject(PayrollService);
18683
+ this.pageConfig = {
18684
+ title: 'Salary Structures',
18685
+ tableConfig: this.payrollService.salaryStructuresTableConfig
18686
+ };
18687
+ }
18688
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: SalaryStructuresComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18689
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: SalaryStructuresComponent, isStandalone: false, selector: "spa-salary-structures", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
18690
+ }
18691
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: SalaryStructuresComponent, decorators: [{
18692
+ type: Component,
18693
+ args: [{
18694
+ selector: 'spa-salary-structures',
18695
+ standalone: false,
18696
+ template: '<spa-page [config]="pageConfig"></spa-page>'
18697
+ }]
18698
+ }] });
18699
+
18700
+ class StatutoryDeductionsComponent {
18701
+ constructor() {
18702
+ this.payrollService = inject(PayrollService);
18703
+ this.pageConfig = {
18704
+ title: 'Statutory Deductions',
18705
+ tableConfig: this.payrollService.statutoryDeductionTypesTableConfig
18706
+ };
18707
+ }
18708
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: StatutoryDeductionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18709
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: StatutoryDeductionsComponent, isStandalone: false, selector: "spa-statutory-deductions", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
18710
+ }
18711
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: StatutoryDeductionsComponent, decorators: [{
18712
+ type: Component,
18713
+ args: [{
18714
+ selector: 'spa-statutory-deductions',
18715
+ standalone: false,
18716
+ template: '<spa-page [config]="pageConfig"></spa-page>'
18717
+ }]
18718
+ }] });
18719
+
18720
+ class PayrollRunsComponent {
18721
+ constructor() {
18722
+ this.payrollService = inject(PayrollService);
18723
+ this.pageConfig = {
18724
+ title: 'Payroll Runs',
18725
+ tableConfig: this.payrollService.payrollRunsTableConfig
18726
+ };
18727
+ }
18728
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PayrollRunsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18729
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: PayrollRunsComponent, isStandalone: false, selector: "spa-payroll-runs", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
18730
+ }
18731
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PayrollRunsComponent, decorators: [{
18732
+ type: Component,
18733
+ args: [{
18734
+ selector: 'spa-payroll-runs',
18735
+ standalone: false,
18736
+ template: '<spa-page [config]="pageConfig"></spa-page>'
18737
+ }]
18738
+ }] });
18739
+
18740
+ // Budget management component for CRUD operations
18741
+ class BudgetsComponent {
18742
+ constructor() {
18743
+ this.accountingService = inject(AccountingService);
18744
+ this.pageConfig = {
18745
+ title: 'Budgets',
18746
+ tableConfig: this.accountingService.budgetsTableConfig
18747
+ };
18748
+ }
18749
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: BudgetsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18750
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: BudgetsComponent, isStandalone: false, selector: "spa-budgets", ngImport: i0, template: '<spa-page [config]="pageConfig"></spa-page>', isInline: true, dependencies: [{ kind: "component", type: PageComponent, selector: "spa-page", inputs: ["config"], outputs: ["searchModeActivated", "searchModeDeactivated", "refreshClick", "actionClick", "actionResponse", "inputChange", "createClick", "searchClick", "dataLoad", "titleActionChange"] }] }); }
18751
+ }
18752
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: BudgetsComponent, decorators: [{
18753
+ type: Component,
18754
+ args: [{
18755
+ selector: 'spa-budgets',
18756
+ template: '<spa-page [config]="pageConfig"></spa-page>',
18757
+ standalone: false
18758
+ }]
18759
+ }] });
18760
+
18761
+ // Budget vs Actual report component with budget selector, tiles, and tabbed tables
18762
+ class BudgetVsActualComponent {
18763
+ constructor() {
18764
+ this.accountingService = inject(AccountingService);
18765
+ this.httpService = inject(HttpService);
18766
+ this.selectedBudgetID = null;
18767
+ this.reportTabConfigs = [];
18768
+ this.summaryTileConfig = { ...this.accountingService.budgetSummaryTileConfig };
18769
+ }
18770
+ // Load report data when a budget is selected
18771
+ onBudgetSelected() {
18772
+ if (!this.selectedBudgetID) {
18773
+ this.reportTabConfigs = [];
18774
+ return;
18775
+ }
18776
+ // Update tile config to load summary for selected budget
18777
+ this.summaryTileConfig = {
18778
+ ...this.accountingService.budgetSummaryTileConfig,
18779
+ loadAction: { url: `budgetreport/summary/${this.selectedBudgetID}` }
18780
+ };
18781
+ // Build tab configs with dynamic URLs for selected budget
18782
+ this.reportTabConfigs = [
18783
+ {
18784
+ ...this.accountingService.budgetVsActualByPeriodTableConfig,
18785
+ loadAction: { url: `budgetreport/vsactual/${this.selectedBudgetID}` }
18786
+ },
18787
+ {
18788
+ ...this.accountingService.budgetVsActualByAccountTableConfig,
18789
+ loadAction: { url: `budgetreport/summary/${this.selectedBudgetID}` }
18790
+ }
18791
+ ];
18792
+ }
18793
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: BudgetVsActualComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18794
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: BudgetVsActualComponent, isStandalone: false, selector: "spa-budget-vs-actual", ngImport: i0, template: `
18795
+ <h4>Budget vs Actual</h4>
18796
+ <hr>
18797
+
18798
+ <div style="max-width: 300px; margin-bottom: 16px;">
18799
+ <spa-select-lite display="Select Budget" [loadAction]="{ url: 'budgets/list/x' }" [(value)]="selectedBudgetID" (valueChange)="onBudgetSelected()"></spa-select-lite>
18800
+ </div>
18801
+
18802
+ <spa-tiles *ngIf="summaryTileConfig.loadAction" [config]="summaryTileConfig"></spa-tiles>
18803
+
18804
+ <spa-tabs *ngIf="reportTabConfigs.length > 0" [tableConfigs]="reportTabConfigs"></spa-tabs>
18805
+ `, isInline: true, dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: TilesComponent, selector: "spa-tiles", inputs: ["config", "lastSearch", "data", "reload"], outputs: ["tileActionSelected", "tileClick", "tileUnClick"] }, { kind: "component", type: TabsComponent, selector: "spa-tabs", inputs: ["tableConfigs", "reload", "parentDetails"], outputs: ["formRefresh"] }, { kind: "component", type: SelectLiteComponent, selector: "spa-select-lite" }] }); }
18806
+ }
18807
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: BudgetVsActualComponent, decorators: [{
18808
+ type: Component,
18809
+ args: [{
18810
+ selector: 'spa-budget-vs-actual',
18811
+ template: `
18812
+ <h4>Budget vs Actual</h4>
18813
+ <hr>
18814
+
18815
+ <div style="max-width: 300px; margin-bottom: 16px;">
18816
+ <spa-select-lite display="Select Budget" [loadAction]="{ url: 'budgets/list/x' }" [(value)]="selectedBudgetID" (valueChange)="onBudgetSelected()"></spa-select-lite>
18817
+ </div>
18818
+
18819
+ <spa-tiles *ngIf="summaryTileConfig.loadAction" [config]="summaryTileConfig"></spa-tiles>
18820
+
18821
+ <spa-tabs *ngIf="reportTabConfigs.length > 0" [tableConfigs]="reportTabConfigs"></spa-tabs>
18822
+ `,
18823
+ standalone: false
18824
+ }]
18825
+ }] });
18826
+
17499
18827
  const routes$1 = [
17500
18828
  { path: "users", component: UsersComponent },
17501
18829
  { path: "roles", component: RolesComponent },
@@ -17530,8 +18858,13 @@ const routes$1 = [
17530
18858
  { path: "accounting-transactions", component: TransactionsComponent },
17531
18859
  { path: "accounting-invoices", component: InvoicesComponent },
17532
18860
  { path: "accounting-aging", component: AgingComponent }, // Added: Aging route
18861
+ { path: "accounting-supplier-aging", component: SupplierAgingComponent }, // Changed: AP Aging route
17533
18862
  { path: "accounting-outstanding-invoices", component: OutstandingInvoicesComponent },
18863
+ { path: "accounting-reports", component: ReportsComponent }, // Added: Financial reports route
17534
18864
  { path: "accounting-tax-rates", component: TaxRatesComponent }, // Changed: Tax rates management route
18865
+ { path: "accounting-standing-orders", component: StandingOrdersComponent }, // Changed: Standing orders management route
18866
+ { path: "accounting-fixed-assets", component: FixedAssetsComponent }, // Added: Fixed assets management route
18867
+ { path: "accounting-fixed-asset-categories", component: FixedAssetCategoriesComponent }, // Added: Fixed asset categories management route
17535
18868
  { path: "loans-products", component: LoanProductsComponent },
17536
18869
  { path: "loans", component: LoansComponent },
17537
18870
  { path: "loans-payments", component: LoanPaymentsComponent },
@@ -17551,7 +18884,12 @@ const routes$1 = [
17551
18884
  { path: "bundle-products", component: BundleProductsComponent }, // Added: Bundle products route
17552
18885
  { path: "production-recipes", component: ProductionRecipesComponent },
17553
18886
  { path: "production-orders", component: ProductionOrdersComponent },
17554
- { path: "preferences", component: PreferencesComponent } // Changed: Added Preferences route
18887
+ { path: "preferences", component: PreferencesComponent }, // Changed: Added Preferences route
18888
+ { path: "payroll-salary-structures", component: SalaryStructuresComponent }, // Changed: Added for Payroll module
18889
+ { path: "payroll-statutory-deductions", component: StatutoryDeductionsComponent }, // Changed: Added for Payroll module
18890
+ { path: "payroll-runs", component: PayrollRunsComponent }, // Changed: Added for Payroll module
18891
+ { path: "accounting-budgets", component: BudgetsComponent }, // Changed: Added for Budget module
18892
+ { path: "accounting-budget-vs-actual", component: BudgetVsActualComponent } // Changed: Added for Budget module
17555
18893
  ];
17556
18894
  class AdminRoutingModule {
17557
18895
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AdminRoutingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
@@ -17573,10 +18911,12 @@ class AdminModule {
17573
18911
  AccountsComponent,
17574
18912
  AggregatesComponent, // Added: Aggregates component declaration
17575
18913
  AgingComponent, // Added: Aging component declaration
18914
+ SupplierAgingComponent, // Changed: AP Aging component declaration
17576
18915
  TransactionTypesComponent,
17577
18916
  TransactionsComponent,
17578
18917
  InvoicesComponent,
17579
18918
  OutstandingInvoicesComponent,
18919
+ ReportsComponent, // Added: Financial Reports component declaration
17580
18920
  // Inventory components
17581
18921
  ProductsComponent,
17582
18922
  InventoryItemsComponent,
@@ -17594,7 +18934,12 @@ class AdminModule {
17594
18934
  ProductionOrdersComponent,
17595
18935
  BundleProductsComponent, // Added: Bundle products component
17596
18936
  ServiceItemsComponent, // Added: Service items component
17597
- PreferencesComponent // Changed: Added Preferences component
18937
+ PreferencesComponent, // Changed: Added Preferences component
18938
+ SalaryStructuresComponent, // Changed: Added for Payroll module
18939
+ StatutoryDeductionsComponent, // Changed: Added for Payroll module
18940
+ PayrollRunsComponent, // Changed: Added for Payroll module
18941
+ BudgetsComponent, // Changed: Added for Budget module
18942
+ BudgetVsActualComponent // Changed: Added for Budget module
17598
18943
  ], imports: [CommonModule,
17599
18944
  AdminRoutingModule,
17600
18945
  SpaAdminModule] }); }
@@ -17610,10 +18955,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
17610
18955
  AccountsComponent,
17611
18956
  AggregatesComponent, // Added: Aggregates component declaration
17612
18957
  AgingComponent, // Added: Aging component declaration
18958
+ SupplierAgingComponent, // Changed: AP Aging component declaration
17613
18959
  TransactionTypesComponent,
17614
18960
  TransactionsComponent,
17615
18961
  InvoicesComponent,
17616
18962
  OutstandingInvoicesComponent,
18963
+ ReportsComponent, // Added: Financial Reports component declaration
17617
18964
  // Inventory components
17618
18965
  ProductsComponent,
17619
18966
  InventoryItemsComponent,
@@ -17631,7 +18978,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
17631
18978
  ProductionOrdersComponent,
17632
18979
  BundleProductsComponent, // Added: Bundle products component
17633
18980
  ServiceItemsComponent, // Added: Service items component
17634
- PreferencesComponent // Changed: Added Preferences component
18981
+ PreferencesComponent, // Changed: Added Preferences component
18982
+ SalaryStructuresComponent, // Changed: Added for Payroll module
18983
+ StatutoryDeductionsComponent, // Changed: Added for Payroll module
18984
+ PayrollRunsComponent, // Changed: Added for Payroll module
18985
+ BudgetsComponent, // Changed: Added for Budget module
18986
+ BudgetVsActualComponent // Changed: Added for Budget module
17635
18987
  ],
17636
18988
  imports: [
17637
18989
  CommonModule,
@@ -17688,5 +19040,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
17688
19040
  * Generated bundle index. Do not edit.
17689
19041
  */
17690
19042
 
17691
- export { Account, AccountsComponent as AccountingAccountsComponent, AggregatesComponent as AccountingAggregatesComponent, AgingComponent as AccountingAgingComponent, InvoicesComponent as AccountingInvoicesComponent, OutstandingInvoicesComponent as AccountingOutstandingInvoicesComponent, AccountingService, TransactionTypesComponent as AccountingTransactionTypesComponent, TransactionsComponent as AccountingTransactionsComponent, Action, ActivityComponent, AdminModule, AlertComponent, AlertConfig, AlertMessage, ApiResponse, AppConfig, AppModelsComponent, AttachComponent, AuthService, BrandsComponent, CacheConfig, CapItem, CapsulesComponent, CategoriesComponent, ChangePasswordComponent, ChangeUserPassword, CheckComponent, ChipsComponent, Constants, Core, CreateAccountComponent, CustomersComponent, DataServiceLib, DateComponent, DatetimeComponent, DepartmentsComponent, DetailsDialog, DetailsDialogConfig, DetailsDialogProcessor, DetailsSource, DialogService, EmailComponent, EmployeesComponent, ExportService, FilterComponent, FormComponent, FormConfig, GeneralService, GradesComponent, GroupsComponent, HtmlComponent, HttpService, IndexModule, InventoryReceiptStatus, InventoryService, InvoiceItemType, InvoiceStatus, LabelComponent, ListDialogComponent, ListDialogConfig, LoaderComponent, LoaderService, LoanPaymentsComponent, LoanProductsComponent, LoansComponent, LoansService, LogLevel, LogService, LoginComponent, LogsComponent, MembershipComponent, MessageService, MoneyComponent, MovementType, NavMenuComponent, NotesComponent, NotesConfig, NumberComponent, OnboardingComponent, OptionComponent, PageComponent, PageConfig, PlansComponent, PositionsComponent, PreferencesComponent, PrivacyDialogComponent, Profile, ProfileComponent, RecoverAccountComponent, Register, Role, RoleAccess, RolesComponent, SearchComponent, SearchConfig, SecurityConfig, SelectBitwiseComponent, SelectComponent, SelectMultiComponent, SettingsComponent, SignupComponent, SignupData, SpaAdminModule, SpaIndexModule, SpaMatModule, SpaUserModule, StatusesComponent, Step, StepConfig, StepsComponent, StorageService, SubCategoriesComponent, SuppliersComponent, TabService, TableComponent, TableConfig, TabsComponent, TabsInternalComponent, TabsLiteComponent, TasksComponent, TenantsComponent, TermsDialogComponent, TextAreaComponent, TextComponent, TextMaskComponent, TextMultiComponent, TextSingleComponent, TileConfig, TilesComponent, TinSpaComponent, TinSpaModule, TinSpaService, TitleActionsComponent, TransactionTiming, UnitOfMeasure, User, UserModule, UsersComponent, ViewerComponent, WelcomeComponent, authGuard, dialogOptions, loginConfig, messageDialog, viewerDialog };
19043
+ export { Account, AccountsComponent as AccountingAccountsComponent, AggregatesComponent as AccountingAggregatesComponent, AgingComponent as AccountingAgingComponent, InvoicesComponent as AccountingInvoicesComponent, OutstandingInvoicesComponent as AccountingOutstandingInvoicesComponent, ReportsComponent as AccountingReportsComponent, AccountingService, TransactionTypesComponent as AccountingTransactionTypesComponent, TransactionsComponent as AccountingTransactionsComponent, Action, ActivityComponent, AdminModule, AlertComponent, AlertConfig, AlertMessage, ApiResponse, AppConfig, AppModelsComponent, AssetStatus, AttachComponent, AuthService, BrandsComponent, CacheConfig, CapItem, CapsulesComponent, CategoriesComponent, ChangePasswordComponent, ChangeUserPassword, CheckComponent, ChipsComponent, Constants, Core, CreateAccountComponent, CustomersComponent, DataServiceLib, DateComponent, DatetimeComponent, DepartmentsComponent, DetailsDialog, DetailsDialogConfig, DetailsDialogProcessor, DetailsSource, DialogService, EmailComponent, EmployeesComponent, ExportService, FilterComponent, FormComponent, FormConfig, GeneralService, GradesComponent, GroupsComponent, HtmlComponent, HttpService, IndexModule, InventoryReceiptStatus, InventoryService, InvoiceItemType, InvoiceStatus, LabelComponent, ListDialogComponent, ListDialogConfig, LoaderComponent, LoaderService, LoanPaymentsComponent, LoanProductsComponent, LoansComponent, LoansService, LogLevel, LogService, LoginComponent, LogsComponent, MembershipComponent, MessageService, MoneyComponent, MovementType, NavMenuComponent, NotesComponent, NotesConfig, NumberComponent, OnboardingComponent, OptionComponent, PageComponent, PageConfig, PlansComponent, PositionsComponent, PreferencesComponent, PrivacyDialogComponent, Profile, ProfileComponent, RecoverAccountComponent, Register, Role, RoleAccess, RolesComponent, SearchComponent, SearchConfig, SecurityConfig, SelectBitwiseComponent, SelectComponent, SelectLiteComponent, SelectMultiComponent, SettingsComponent, SignupComponent, SignupData, SpaAdminModule, SpaIndexModule, SpaMatModule, SpaUserModule, StatusesComponent, Step, StepConfig, StepsComponent, StorageService, SubCategoriesComponent, SuppliersComponent, TabService, TableComponent, TableConfig, TabsComponent, TabsInternalComponent, TabsLiteComponent, TasksComponent, TenantsComponent, TermsDialogComponent, TextAreaComponent, TextComponent, TextMaskComponent, TextMultiComponent, TextSingleComponent, TileConfig, TilesComponent, TinSpaComponent, TinSpaModule, TinSpaService, TitleActionsComponent, TransactionTiming, UnitOfMeasure, User, UserModule, UsersComponent, ViewerComponent, WelcomeComponent, authGuard, dialogOptions, loginConfig, messageDialog, viewerDialog };
17692
19044
  //# sourceMappingURL=tin-spa.mjs.map