tin-spa 20.2.8 → 20.3.0

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.
@@ -789,6 +789,7 @@ var InvoiceStatus;
789
789
  InvoiceStatus[InvoiceStatus["Submitted"] = 1] = "Submitted";
790
790
  InvoiceStatus[InvoiceStatus["Paid"] = 2] = "Paid";
791
791
  InvoiceStatus[InvoiceStatus["Discarded"] = 3] = "Discarded";
792
+ InvoiceStatus[InvoiceStatus["Paying"] = 4] = "Paying"; // Changed: Added Paying status for partially paid invoices
792
793
  })(InvoiceStatus || (InvoiceStatus = {}));
793
794
  // Inventory receipt status tracking enum - mirrors backend
794
795
  var InventoryReceiptStatus;
@@ -1467,6 +1468,7 @@ class DataServiceLib {
1467
1468
  this.capCategories = new CapItem;
1468
1469
  this.capSubCategories = new CapItem;
1469
1470
  this.capBrands = new CapItem;
1471
+ this.capGPTCaches = new CapItem; // Added: GPT Cache capability property
1470
1472
  this.capSuppliers = new CapItem;
1471
1473
  this.capTasks = new CapItem;
1472
1474
  this.capHR = new CapItem;
@@ -1484,6 +1486,7 @@ class DataServiceLib {
1484
1486
  this.capAccounting = new CapItem;
1485
1487
  this.capAccounts = new CapItem;
1486
1488
  this.capAggregates = new CapItem; // Added: Capability for aggregates view
1489
+ this.capAging = new CapItem; // Added: Capability for aging report
1487
1490
  this.capTransactionTypes = new CapItem;
1488
1491
  this.capTransactions = new CapItem;
1489
1492
  this.capAccountingInvoices = new CapItem;
@@ -1495,6 +1498,7 @@ class DataServiceLib {
1495
1498
  this.capInventoryDashboard = new CapItem;
1496
1499
  this.capInventoryStock = new CapItem; // Changed: Added new cap item for inventory stock view
1497
1500
  this.capProducts = new CapItem;
1501
+ this.capBundleProducts = new CapItem; // Added: Capability for bundle products
1498
1502
  this.capInventoryItems = new CapItem;
1499
1503
  this.capPurchaseOrders = new CapItem;
1500
1504
  this.capInventoryReceipts = new CapItem;
@@ -1824,6 +1828,45 @@ class DataServiceLib {
1824
1828
  loadAction: { url: 'suppliers/all/x' },
1825
1829
  formConfig: this.supplierFormConfig
1826
1830
  };
1831
+ //--------------------------GPT Caches-------------------------
1832
+ this.gptCachesFormConfig = {
1833
+ security: { allow: [this.capGPTCaches] },
1834
+ title: 'GPT Cache',
1835
+ fields: [
1836
+ { name: 'gptCacheID', type: 'number', readonly: true, alias: 'ID' },
1837
+ { name: 'methodName', type: 'text', required: true, alias: 'Method Name', span: true },
1838
+ { name: 'requestHash', type: 'text', readonly: true, alias: 'Request Hash', span: true },
1839
+ { name: 'requestText', type: 'text-area', required: true, alias: 'Request Text', span: true, rows: 4 },
1840
+ { name: 'responseJson', type: 'text-area', required: true, alias: 'Response JSON', span: true, rows: 4 },
1841
+ { name: 'matchCount', type: 'number', alias: 'Match Count' },
1842
+ { name: 'hitCount', type: 'number', alias: 'Hit Count' },
1843
+ { name: 'createdDate', type: 'datetime', readonly: true, alias: 'Created' },
1844
+ { name: 'updatedDate', type: 'datetime', readonly: true, alias: 'Updated' }
1845
+ ],
1846
+ loadAction: { url: 'gptcaches/id' },
1847
+ heroField: 'gptCacheID',
1848
+ };
1849
+ this.gptCachesTableConfig = {
1850
+ showFilter: true,
1851
+ minColumns: ['methodName', 'requestText', 'hitCount'],
1852
+ columns: [
1853
+ { name: 'methodName', alias: 'Method' },
1854
+ { name: 'requestText', alias: 'Request', maxLength: 100 },
1855
+ { name: 'responseJson', alias: 'Response', maxLength: 100 },
1856
+ { name: 'requestHash', alias: 'Hash', maxLength: 20 },
1857
+ { name: 'matchCount', type: 'number', alias: 'Matches', icon: { name: 'verified', color: 'green', condition: (x) => x.matchCount > 3 } },
1858
+ { name: 'hitCount', type: 'number', alias: 'Hits', icon: { name: 'trending_up', color: 'blue', condition: (x) => x.hitCount > 10 } },
1859
+ { name: 'createdDate', type: 'datetime', alias: 'Created' },
1860
+ { name: 'updatedDate', type: 'datetime', alias: 'Updated' }
1861
+ ],
1862
+ buttons: [
1863
+ { name: 'view', dialog: true, tip: 'View Cache Details' },
1864
+ { name: 'edit', dialog: true, action: { url: 'gptcaches?action=edit', method: 'post' }, tip: 'Edit Cache' },
1865
+ { name: 'delete', confirm: { message: 'Are you sure you want to delete this cache entry?' }, action: { url: 'gptcaches?action=delete', method: 'post' }, tip: 'Delete Cache' }
1866
+ ],
1867
+ loadAction: { url: 'gptcaches/all/x' },
1868
+ formConfig: this.gptCachesFormConfig
1869
+ };
1827
1870
  //--------------------------Notifications-------------------------
1828
1871
  this.notificationOptions = [
1829
1872
  { name: 'UI Only', value: 1 },
@@ -2030,7 +2073,7 @@ class DataServiceLib {
2030
2073
  this.capAdmin.name = "cap2";
2031
2074
  this.capAdmin.display = "Admin";
2032
2075
  this.capAdmin.icon = "security";
2033
- this.capAdmin.capSubItems = [this.capUsers, this.capRoles, this.capLogs, this.capSettings];
2076
+ this.capAdmin.capSubItems = [this.capUsers, this.capRoles, this.capLogs, this.capGPTCaches, this.capSettings]; // Added: GPT Cache to admin menu
2034
2077
  this.capUsers.name = "cap3";
2035
2078
  this.capUsers.display = "Users";
2036
2079
  this.capUsers.link = "home/admin/users";
@@ -2079,7 +2122,11 @@ class DataServiceLib {
2079
2122
  this.capBrands.display = "Brands";
2080
2123
  this.capBrands.link = "home/admin/brands";
2081
2124
  this.capBrands.icon = "loyalty";
2082
- //cap104 available
2125
+ // Added: GPT Cache capability
2126
+ this.capGPTCaches.name = "cap104";
2127
+ this.capGPTCaches.display = "GPT Cache";
2128
+ this.capGPTCaches.link = "home/admin/gpt-caches";
2129
+ this.capGPTCaches.icon = "memory";
2083
2130
  //cap105 available
2084
2131
  this.capSuppliers.name = "cap15";
2085
2132
  this.capSuppliers.display = "Suppliers";
@@ -2133,7 +2180,7 @@ class DataServiceLib {
2133
2180
  this.capAccounting.display = "Accounting";
2134
2181
  this.capAccounting.icon = "account_balance";
2135
2182
  this.capAccounting.capSubItems = [this.capAccounts, this.capTransactions, this.capAggregates, this.capTransactionTypes, this.capAccountingInvoices,
2136
- this.capAccountingOutstandingInvoices];
2183
+ this.capAging, this.capAccountingOutstandingInvoices]; // Added: capAging to submenu
2137
2184
  this.capAccounts.name = "cap52"; // Changed: Fixed conflict with capBrands (was cap14)
2138
2185
  this.capAccounts.display = "Accounts";
2139
2186
  this.capAccounts.link = "home/admin/accounting-accounts";
@@ -2142,6 +2189,10 @@ class DataServiceLib {
2142
2189
  this.capAggregates.display = "Aggregates";
2143
2190
  this.capAggregates.link = "home/admin/accounting-aggregates";
2144
2191
  this.capAggregates.icon = "bar_chart";
2192
+ this.capAging.name = "cap58"; // Added: Aging capability
2193
+ this.capAging.display = "Aging Report";
2194
+ this.capAging.link = "home/admin/accounting-aging";
2195
+ this.capAging.icon = "schedule";
2145
2196
  this.capTransactionTypes.name = "cap28";
2146
2197
  this.capTransactionTypes.display = "Transaction Types";
2147
2198
  this.capTransactionTypes.link = "home/admin/accounting-transaction-types";
@@ -2177,7 +2228,7 @@ class DataServiceLib {
2177
2228
  this.capInventory.name = "cap34";
2178
2229
  this.capInventory.display = "Inventory";
2179
2230
  this.capInventory.icon = "inventory";
2180
- this.capInventory.capSubItems = [this.capSales, this.capInventoryReceipts, this.capProducts, this.capInventoryStock, this.capInventoryTransactions, this.capInventoryItems,
2231
+ this.capInventory.capSubItems = [this.capSales, this.capInventoryReceipts, this.capProducts, this.capBundleProducts, this.capInventoryStock, this.capInventoryTransactions, this.capInventoryItems,
2181
2232
  this.capPurchaseOrders, this.capSalesOrders, this.capRequisitions, this.capInventoryAdjustments,
2182
2233
  this.capInventoryReturns, this.capRequisitionReturns, this.capProductionRecipes, this.capProductionOrders, this.capInventoryDashboard];
2183
2234
  this.capInventoryDashboard.name = "cap35";
@@ -2192,6 +2243,10 @@ class DataServiceLib {
2192
2243
  this.capProducts.display = "Products";
2193
2244
  this.capProducts.link = "home/admin/inventory-products";
2194
2245
  this.capProducts.icon = "category";
2246
+ this.capBundleProducts.name = "cap57"; // Added: Bundle products capability
2247
+ this.capBundleProducts.display = "Bundle Products";
2248
+ this.capBundleProducts.link = "home/admin/bundle-products";
2249
+ this.capBundleProducts.icon = "inventory_2";
2195
2250
  this.capInventoryItems.name = "cap37";
2196
2251
  this.capInventoryItems.display = "Inventory Items";
2197
2252
  this.capInventoryItems.link = "home/admin/inventory-items";
@@ -2624,17 +2679,65 @@ class AccountingService {
2624
2679
  buttons: [this.accountCreateButton, this.finAccounEditButton]
2625
2680
  };
2626
2681
  //--------------------------Invoices-------------------------
2682
+ // Added: Invoice payment form configuration
2683
+ this.invoicePaymentFormConfig = {
2684
+ security: { allow: [this.dataService.capAccountingInvoices] },
2685
+ title: 'Record Payment',
2686
+ fixedTitle: true,
2687
+ fields: [
2688
+ { name: 'invoiceID', type: 'number', hidden: true },
2689
+ { name: 'paymentDate', type: 'date', alias: 'Payment Date', required: true },
2690
+ { name: 'method', type: 'select', alias: 'Payment Method', required: true, defaultValue: 1, loadAction: { url: 'invoicepayments/list/methods' } },
2691
+ { name: 'outstandingAmount', type: 'label', alias: 'Outstanding', readonly: true },
2692
+ { name: 'amount', type: 'money', alias: 'Amount', required: true, span: true },
2693
+ { name: 'reference', type: 'text', alias: 'Reference', span: true }
2694
+ ],
2695
+ };
2696
+ this.invoicePaymentCreateButton = { name: 'edit', action: { url: 'invoicepayments?action=create', method: 'post', successMessage: 'Payment Recorded' } };
2697
+ this.invoicePaymentsCreateDetailsDialogConfig = {
2698
+ formConfig: this.invoicePaymentFormConfig,
2699
+ heroField: 'invoiceID',
2700
+ mode: 'edit',
2701
+ buttons: [
2702
+ this.invoicePaymentCreateButton
2703
+ ]
2704
+ };
2705
+ // Added: Invoice payments table for history tracking
2706
+ this.invoicePaymentsTableConfig = {
2707
+ tabTitle: 'Payment History',
2708
+ showFilter: false,
2709
+ minColumns: ['paymentDate', 'amount', 'methodName'],
2710
+ columns: [
2711
+ { name: 'invoicePaymentID', type: 'number', alias: 'ID', hiddenCondition: () => true },
2712
+ { name: 'paymentDate', type: 'date', alias: 'Date' },
2713
+ { name: 'amount', type: 'money', alias: 'Amount' },
2714
+ { name: 'methodName', type: 'text', alias: 'Method' },
2715
+ { name: 'reference', type: 'text', alias: 'Reference' }
2716
+ ],
2717
+ buttons: [
2718
+ { name: 'migrate-payments', display: 'Migrate Legacy Payments', inHeader: true, icon: { name: 'sync', color: 'green' },
2719
+ action: { url: 'invoicepayments/migrate', method: 'post',
2720
+ successMessage: 'Migration completed successfully' },
2721
+ confirm: { message: 'This will migrate existing invoice payments from the legacy PaidAmount field to the new InvoicePayments table. Continue?' }
2722
+ }
2723
+ ],
2724
+ loadAction: { url: 'invoicepayments/x/x' }, loadCriteria: 'invoice', loadIDField: 'invoiceID'
2725
+ };
2627
2726
  // Invoice form configuration with customer and status fields
2628
2727
  this.invoiceFormConfig = {
2629
2728
  security: { allow: [this.dataService.capAccountingInvoices] },
2630
2729
  title: 'Invoice',
2631
2730
  includeAudit: true,
2632
2731
  fields: [
2633
- { name: 'invoiceDate', type: 'date' },
2634
- { name: 'invoiceID', type: 'number', readonly: true, hideOnCreate: true },
2635
- { name: 'customerID', alias: 'Customer', type: 'select', loadAction: { url: 'customers/list/x' }, detailsConfig: this.dataService.customerDetailsConfig },
2732
+ { name: 'invoiceDate', type: 'date', required: true },
2733
+ { name: 'invoiceNumber', type: 'text', alias: 'Invoice #' }, // Changed: Made editable on create for optional manual numbering
2734
+ { name: 'customerID', alias: 'Customer', type: 'select', required: true, loadAction: { url: 'customers/list/x' }, detailsConfig: this.dataService.customerDetailsConfig },
2735
+ { name: 'paymentTerms', type: 'select', alias: 'Payment Terms', required: true, defaultValue: 30, loadAction: { url: 'invoices/list/payment-terms' } },
2736
+ { name: 'dueDate', type: 'date', alias: 'Due Date', readonly: true, hideOnCreate: true },
2636
2737
  { name: 'status', type: 'select', hideOnCreate: true, readonly: true, loadAction: { url: 'invoices/list/statuses' } },
2637
2738
  { name: 'totalDisplay', type: 'label', alias: 'Total', format: 'text', readonly: true, hideOnCreate: true },
2739
+ { name: 'paidAmount', type: 'label', alias: 'Paid', readonly: true, hideOnCreate: true },
2740
+ { name: 'outstandingAmount', type: 'label', alias: 'Outstanding', readonly: true, hideOnCreate: true }
2638
2741
  ],
2639
2742
  loadAction: { url: 'invoices/id' },
2640
2743
  heroField: 'invoiceID',
@@ -2644,6 +2747,7 @@ class AccountingService {
2644
2747
  tabTitle: 'Invoice Items',
2645
2748
  showFilter: false,
2646
2749
  minColumns: ['description', 'quantity', 'amount'],
2750
+ causeFormRefresh: true,
2647
2751
  columns: [
2648
2752
  { name: 'invoiceItemID', type: 'number', alias: 'ID', hiddenCondition: () => true },
2649
2753
  { name: 'description', type: 'text', alias: 'Description' },
@@ -2652,7 +2756,9 @@ class AccountingService {
2652
2756
  { name: 'amount', type: 'money', alias: 'Amount' }
2653
2757
  ],
2654
2758
  buttons: [
2655
- { name: 'create', display: 'Add Item', dialog: true, action: { url: 'invoiceitems?action=create', method: 'post' }, disabled: x => x.status != InvoiceStatus.Draft },
2759
+ { name: 'create', display: 'Add Item', dialog: true, action: { url: 'invoiceitems?action=create', method: 'post' },
2760
+ disabled: x => x.status != InvoiceStatus.Draft
2761
+ },
2656
2762
  { name: 'edit', dialog: true, action: { url: 'invoiceitems?action=edit', method: 'post' }, disabled: x => x.status != InvoiceStatus.Draft },
2657
2763
  { name: 'delete', inDialog: true, icon: { name: 'delete', color: 'red' }, action: { url: 'invoiceitems?action=delete', method: 'post', successMessage: 'Deleted' }, confirm: { message: 'Delete this item?' }, disabled: x => x.status != InvoiceStatus.Draft }
2658
2764
  ],
@@ -2660,8 +2766,8 @@ class AccountingService {
2660
2766
  formConfig: {
2661
2767
  title: 'Invoice Item',
2662
2768
  fields: [
2663
- { name: 'description', type: 'text', required: true },
2664
- { name: 'quantity', type: 'number', required: true },
2769
+ { name: 'description', type: 'text', required: true, span: true },
2770
+ { name: 'quantity', type: 'number', required: true, defaultValue: 1 },
2665
2771
  { name: 'unitPrice', type: 'number', alias: 'Unit Price', required: true },
2666
2772
  { name: 'amount', type: 'number', readonly: true, hideOnCreate: true }
2667
2773
  ],
@@ -2669,18 +2775,32 @@ class AccountingService {
2669
2775
  }
2670
2776
  };
2671
2777
  // Invoice action buttons
2672
- this.invoicePayButton = { name: 'pay', inDialog: true, display: 'Pay', icon: { name: 'attach_money', color: 'green' }, action: { url: 'invoices?action=pay', method: 'post', successMessage: 'Paid' }, confirm: { message: 'All loads on invoice have been Paid ?' }, visible: x => x.status == InvoiceStatus.Submitted };
2673
- this.invoiceDiscardButton = { name: 'discard', inDialog: true, display: 'Discard', icon: { name: 'close', color: 'red' }, action: { url: 'invoices?action=discard', method: 'post', successMessage: 'Discarded' }, confirm: { message: 'Invoice will be marked as cancelled and all related loads removed ?' }, visible: x => x.status == InvoiceStatus.Draft };
2674
- this.invoiceSubmitButton = { name: 'submit', inDialog: true, display: 'Submit', icon: { name: 'send', }, action: { url: 'invoices?action=submit', method: 'post', successMessage: 'Submitted' }, confirm: { message: 'Submit ?' }, visible: x => x.status == InvoiceStatus.Draft, disabled: x => x.totalAmount == 0 };
2675
- this.invoiceEditButton = { name: 'edit', dialog: true, action: { url: 'invoices?action=edit', method: 'post', }, confirm: { message: 'Proceed ?' }, disabled: x => x.status == InvoiceStatus.Paid };
2778
+ this.invoiceRecordPaymentButton = { name: 'record-payment', display: 'Record Payment', dialog: true, icon: { name: 'payment', color: 'blue' },
2779
+ detailsConfig: this.invoicePaymentsCreateDetailsDialogConfig,
2780
+ visible: x => (x.status == InvoiceStatus.Submitted || x.status == InvoiceStatus.Paying) && x.outstandingAmount > 0 // Changed: Allow on both Submitted and Paying
2781
+ }; // Changed: Use detailsConfig to open payment form dialog
2782
+ this.invoiceDiscardButton = { name: 'discard', inDialog: true, display: 'Discard', icon: { name: 'close', color: 'red' },
2783
+ action: { url: 'invoices?action=discard', method: 'post', successMessage: 'Discarded' }, confirm: { message: 'Invoice will be marked as cancelled?' },
2784
+ visible: x => x.status == InvoiceStatus.Draft || x.status == InvoiceStatus.Submitted // Changed: Only allow on Draft and Submitted
2785
+ };
2786
+ this.invoiceSubmitButton = { name: 'submit', inDialog: true, display: 'Submit', icon: { name: 'send', },
2787
+ action: { url: 'invoices?action=submit', method: 'post', successMessage: 'Submitted' },
2788
+ confirm: { message: 'Submit invoice? This will record revenue and create an accounts receivable entry.' },
2789
+ visible: x => x.status == InvoiceStatus.Draft,
2790
+ disabled: x => x.totalAmount == 0
2791
+ };
2792
+ this.invoiceEditButton = { name: 'edit', dialog: true, action: { url: 'invoices?action=edit', method: 'post', }, confirm: { message: 'Proceed ?' },
2793
+ visible: x => x.status == InvoiceStatus.Draft || x.status == InvoiceStatus.Submitted // Changed: Disable on Paying and Paid
2794
+ };
2676
2795
  this.invoiceDownloadButton = { name: 'pdf', display: 'Download PDF', inDialog: true, icon: { name: 'picture_as_pdf', color: 'red' } };
2677
- // Invoice details dialog with items and action buttons
2796
+ // Invoice details dialog with items, payments history, and action buttons
2678
2797
  this.invoiceDetailsDialogConfig = {
2679
2798
  formConfig: this.invoiceFormConfig,
2680
- tableConfigs: [this.invoiceItemsTableConfig],
2799
+ tableConfigs: [this.invoiceItemsTableConfig, this.invoicePaymentsTableConfig],
2681
2800
  heroField: 'invoiceID',
2682
- buttons: [this.invoiceSubmitButton, this.invoicePayButton, this.invoiceDiscardButton, this.invoiceEditButton]
2801
+ buttons: [this.invoiceSubmitButton, this.invoiceRecordPaymentButton, this.invoiceDiscardButton, this.invoiceEditButton]
2683
2802
  };
2803
+ this.invoiceViewButton = { name: 'view', dialog: true, detailsConfig: this.invoiceDetailsDialogConfig };
2684
2804
  // Invoice summary tiles
2685
2805
  this.invoicesTileConfig = {
2686
2806
  clickable: true,
@@ -2694,34 +2814,75 @@ class AccountingService {
2694
2814
  // Main invoices table configuration
2695
2815
  this.invoicesTableConfig = {
2696
2816
  showFilter: true,
2697
- minColumns: ['invoiceID', 'customerName', 'statusName'],
2817
+ minColumns: ['invoiceNumber', 'customerName', 'statusName'],
2698
2818
  minButtons: ['view', 'pdf'],
2699
2819
  flatButtons: true,
2700
2820
  collapseButtons: true,
2701
2821
  greyOut: x => x.status == InvoiceStatus.Paid,
2702
2822
  columns: [
2703
- { name: 'invoiceID', type: 'number', alias: 'ID' },
2823
+ { name: 'invoiceNumber', type: 'text', alias: 'Invoice #' },
2704
2824
  { name: 'customerName', type: 'text', alias: 'Customer' },
2705
2825
  { name: 'invoiceDate', type: 'date' },
2706
- { name: 'statusName', type: 'chip', alias: 'Status', colors: [{ name: '#FFCC80', condition: x => x.status == InvoiceStatus.Draft }, { name: '#90CAF9', condition: x => x.status == InvoiceStatus.Submitted }, { name: '#A5D6A7', condition: x => x.status == InvoiceStatus.Paid }, { name: '#EF9A9A', condition: x => x.status == InvoiceStatus.Discarded }] },
2826
+ { name: 'dueDate', type: 'date', alias: 'Due Date' },
2827
+ { name: 'daysOverdue', type: 'number', alias: 'Days Overdue', },
2828
+ { name: 'statusName', type: 'chip', alias: 'Status', detailsConfig: this.invoiceDetailsDialogConfig,
2829
+ colors: [
2830
+ { name: '#FFCC80', condition: x => x.status == InvoiceStatus.Draft },
2831
+ { name: '#90CAF9', condition: x => x.status == InvoiceStatus.Submitted },
2832
+ { name: '#FFD54F', condition: x => x.status == InvoiceStatus.Paying }, // Changed: Added Paying status color (amber/yellow)
2833
+ { name: '#A5D6A7', condition: x => x.status == InvoiceStatus.Paid },
2834
+ { name: '#EF9A9A', condition: x => x.status == InvoiceStatus.Discarded }
2835
+ ]
2836
+ },
2707
2837
  { name: 'itemCount', type: 'number', alias: 'Items' },
2708
2838
  { name: 'totalAmount', type: 'money', alias: 'Total' },
2709
2839
  { name: 'paidAmount', type: 'money', alias: 'Paid' },
2710
2840
  { name: 'outstandingAmount', type: 'money', alias: 'Outstanding' }
2711
2841
  ],
2712
2842
  buttons: [
2713
- { name: 'create', display: 'Create', dialog: true, action: { url: 'invoices?action=create', method: 'post' } },
2843
+ { name: 'create', display: 'Create', dialog: true, action: { url: 'invoices?action=create', method: 'post' }, onSuccessButton: this.invoiceViewButton },
2714
2844
  { name: 'view', dialog: true, detailsConfig: this.invoiceDetailsDialogConfig },
2715
- this.invoiceDownloadButton,
2845
+ this.invoiceRecordPaymentButton,
2716
2846
  this.invoiceSubmitButton,
2717
- this.invoicePayButton,
2847
+ // this.invoicePayButton,
2718
2848
  this.invoiceDiscardButton,
2719
- this.invoiceEditButton
2849
+ this.invoiceEditButton,
2850
+ this.invoiceDownloadButton,
2720
2851
  ],
2721
2852
  loadAction: { url: 'invoices/all/x' },
2722
2853
  formConfig: this.invoiceFormConfig,
2723
2854
  tileConfig: this.invoicesTileConfig
2724
2855
  };
2856
+ //--------------------------Aging Report-------------------------
2857
+ // Added: Aging report summary tiles
2858
+ this.agingTileConfig = {
2859
+ // clickable: true,
2860
+ tiles: [
2861
+ { name: 'current', alias: 'Current', color: '#4CAF50', info: 'Not yet due', },
2862
+ { name: 'days30', alias: '1-30 Days', color: '#FFC107', info: '1-30 days overdue', },
2863
+ { name: 'days60', alias: '31-60 Days', color: '#FF9800', info: '31-60 days overdue', },
2864
+ { name: 'days90', alias: '61-90 Days', color: '#F44336', info: '61-90 days overdue', },
2865
+ { name: 'days90Plus', alias: '90+ Days', color: '#B71C1C', info: 'Over 90 days overdue', },
2866
+ { name: 'total', alias: 'Total Outstanding', color: '#9E9E9E', info: 'Total outstanding amount' }
2867
+ ],
2868
+ // loadAction: { url: 'invoices/aging-summary/x' }
2869
+ };
2870
+ // Added: Base aging table configuration with common properties
2871
+ this.agingBaseTableConfig = {
2872
+ showFilter: true,
2873
+ minColumns: ['invoiceNumber', 'customerName', 'outstandingAmount'],
2874
+ columns: [
2875
+ { name: 'invoiceNumber', type: 'text', alias: 'Invoice #' },
2876
+ { name: 'customerName', type: 'text', alias: 'Customer' },
2877
+ { name: 'invoiceDate', type: 'date', alias: 'Invoice Date' },
2878
+ { name: 'dueDate', type: 'date', alias: 'Due Date' },
2879
+ { name: 'daysOverdue', type: 'number', alias: 'Days Overdue' },
2880
+ { name: 'totalAmount', type: 'money', alias: 'Total' },
2881
+ { name: 'paidAmount', type: 'money', alias: 'Paid' },
2882
+ { name: 'outstandingAmount', type: 'money', alias: 'Outstanding' }
2883
+ ],
2884
+ buttons: [{ name: 'view', dialog: true, detailsConfig: this.invoiceDetailsDialogConfig }]
2885
+ };
2725
2886
  //--------------------------Customer Invoices-------------------------
2726
2887
  // Customer invoice form without customerID field
2727
2888
  this.customerInvoiceFormConfig = {
@@ -2735,19 +2896,24 @@ class AccountingService {
2735
2896
  loadCriteria: 'customer-invoice',
2736
2897
  buttons: []
2737
2898
  };
2899
+ // Added: Customer invoice payments table (read-only)
2900
+ this.customerInvoicePaymentsTableConfig = {
2901
+ ...this.invoicePaymentsTableConfig,
2902
+ loadCriteria: 'customer-invoice'
2903
+ };
2738
2904
  // Customer invoice details dialog (read-only)
2739
2905
  this.customerInvoiceDetailsDialogConfig = {
2740
2906
  formConfig: this.customerInvoiceFormConfig,
2741
- tableConfigs: [this.customerInvoiceItemsTableConfig],
2907
+ tableConfigs: [this.customerInvoiceItemsTableConfig, this.customerInvoicePaymentsTableConfig],
2742
2908
  heroField: 'invoiceID',
2743
2909
  buttons: []
2744
2910
  };
2745
2911
  // Customer invoices table configuration
2746
2912
  this.customerInvoicesTableConfig = {
2747
2913
  ...this.invoicesTableConfig,
2748
- minColumns: ['invoiceID', 'totalDisplay'],
2914
+ minColumns: ['invoiceNumber', 'totalDisplay'],
2749
2915
  minButtons: ['view', 'pdf'],
2750
- columns: [...this.invoicesTableConfig.columns.filter(x => ['invoiceID', 'invoiceDate', 'statusName', 'itemCount', 'totalAmount'].includes(x.name))],
2916
+ columns: [...this.invoicesTableConfig.columns.filter(x => ['invoiceNumber', 'invoiceDate', 'dueDate', 'statusName', 'itemCount', 'totalAmount', 'paidAmount', 'outstandingAmount'].includes(x.name))],
2751
2917
  buttons: [{ name: 'view', dialog: true, detailsConfig: this.customerInvoiceDetailsDialogConfig }, this.invoiceDownloadButton],
2752
2918
  loadAction: { url: 'invoices/customer-all/x' }
2753
2919
  };
@@ -2835,6 +3001,7 @@ class AccountingService {
2835
3001
  ],
2836
3002
  buttons: [
2837
3003
  this.transactionTypeCreateButton,
3004
+ { name: 'seed', display: 'Seed Financial Data', inHeader: true, icon: { name: 'add_circle' }, action: { url: 'transactiontypes/seed/x' }, confirm: { message: 'Seed generic financial accounts and transaction types?' } }, // Changed: Use GET endpoint via criteria
2838
3005
  { name: 'view', dialog: true },
2839
3006
  this.transactionTypeEditButton,
2840
3007
  { name: 'delete', dialog: true, action: { url: 'transactiontypes?action=delete', method: 'post' } },
@@ -3412,12 +3579,13 @@ class InventoryService {
3412
3579
  { name: 'name', type: 'text', required: true, alias: 'Product Name', section: 'productInfo', infoMessage: 'The unique name of the product' },
3413
3580
  { name: 'sku', type: 'text', alias: 'SKU (optional)', section: 'productInfo', infoMessage: 'Stock Keeping Unit for inventory tracking (optional)' }, // Changed: Removed required flag
3414
3581
  { name: 'description', type: 'text', alias: 'Description', span: true, section: 'productInfo', infoMessage: 'Detailed description of the product' },
3582
+ { name: 'isBundle', type: 'checkbox', alias: 'Bundle Product', span: true, section: 'productInfo', infoMessage: 'Check if this is a bundle/combo product made up of other products' }, // Added: Bundle product flag
3415
3583
  { name: 'pricingInfo', type: 'section', alias: 'Pricing' },
3416
3584
  { name: 'sellingPrice', type: 'money', required: true, alias: 'Selling Price', section: 'pricingInfo', infoMessage: 'Default selling price per unit' },
3417
3585
  { name: 'inventoryInfo', type: 'section', alias: 'Inventory Settings', collapsedCondition: x => x.productID },
3418
- { name: 'isSerialized', type: 'checkbox', alias: 'Serialized Product', span: true, section: 'inventoryInfo', infoMessage: 'Track individual items by serial number' }, // Changed: Added span to cross two columns
3586
+ { name: 'isSerialized', type: 'checkbox', alias: 'Serialized Product', span: true, section: 'inventoryInfo', infoMessage: 'Track individual items by serial number', hiddenCondition: x => x.isBundle }, // Changed: Hide for bundles
3419
3587
  { name: 'baseUnit', type: 'select', required: true, alias: 'Base Unit', section: 'inventoryInfo', loadAction: { url: 'products/list/base-unit' }, defaultFirstValue: true, infoMessage: 'Unit of measure for inventory tracking' }, // Changed: Added defaultFirstValue flag
3420
- { name: 'minimumInventoryLevel', type: 'number', required: true, alias: 'Minimum Inventory Level', section: 'inventoryInfo', infoMessage: 'Alert threshold for low stock' },
3588
+ { name: 'minimumInventoryLevel', type: 'number', required: true, alias: 'Minimum Inventory Level', section: 'inventoryInfo', infoMessage: 'Alert threshold for low stock', hiddenCondition: x => x.isBundle }, // Changed: Hide for bundles
3421
3589
  { name: 'categoryInfo', type: 'section', alias: 'Categorization', collapsed: true },
3422
3590
  { name: 'categoryID', type: 'select', alias: 'Category', nullable: true, section: 'categoryInfo', loadAction: { url: 'categories/list/x' }, detailsConfig: this.generalService.categoryDetailsConfig, infoMessage: 'The main product category' }, // Changed: Added nullable flag
3423
3591
  { name: 'subCategoryID', type: 'select', alias: 'Sub Category', section: 'categoryInfo', loadAction: { url: 'subcategories/list/x' }, detailsConfig: this.generalService.subCategoryDetailsConfig, infoMessage: 'More specific product classification' },
@@ -3452,6 +3620,102 @@ class InventoryService {
3452
3620
  loadAction: { url: 'products/all/x' },
3453
3621
  formConfig: this.productFormConfig
3454
3622
  };
3623
+ //--------------------------Product Components (Bundle Configuration)-------------------------
3624
+ // Product component form for adding/editing bundle components
3625
+ this.productComponentFormConfig = {
3626
+ title: 'Bundle Component',
3627
+ fixedTitle: true,
3628
+ fields: [
3629
+ { name: 'productComponentID', type: 'number', alias: 'ID', hidden: true },
3630
+ { name: 'productID', type: 'number', alias: 'Bundle Product ID', hidden: true },
3631
+ { name: 'componentProductID', type: 'select', alias: 'Component Product', required: true, detailsConfig: this.productDetailsConfig,
3632
+ loadAction: { url: 'products/list/components' },
3633
+ infoMessage: 'Select a non-bundle product to include in this bundle'
3634
+ },
3635
+ { name: 'quantity', type: 'number', alias: 'Quantity', required: true, defaultValue: 1, infoMessage: 'Number of units required per bundle' }
3636
+ ],
3637
+ loadAction: { url: 'productcomponents/id' },
3638
+ heroField: 'productComponentID'
3639
+ };
3640
+ // Product components table for bundle details
3641
+ this.productComponentsTableConfig = {
3642
+ tabTitle: 'Components',
3643
+ showFilter: false,
3644
+ elevation: 'none',
3645
+ flatButtons: true,
3646
+ causeFormRefresh: true,
3647
+ minColumns: ['componentProductName', 'quantity', 'estimatedCost'],
3648
+ columns: [
3649
+ { name: 'componentProductName', type: 'text', alias: 'Component' },
3650
+ { name: 'quantity', type: 'number', alias: 'Quantity per Bundle' },
3651
+ { name: 'componentCurrentStock', type: 'number', alias: 'Available Stock' },
3652
+ { name: 'estimatedCost', type: 'money', alias: 'Est. Cost' }
3653
+ ],
3654
+ buttons: [
3655
+ { name: 'create', display: 'Add Component', dialog: true, action: { url: 'productcomponents?action=create', method: 'post' } },
3656
+ { name: 'edit', dialog: true, action: { url: 'productcomponents?action=edit', method: 'post' } },
3657
+ { name: 'delete', dialog: true, action: { url: 'productcomponents?action=delete', method: 'post' } }
3658
+ ],
3659
+ loadAction: { url: 'productcomponents/x/x' }, loadCriteria: 'bundle', loadIDField: 'productID',
3660
+ formConfig: this.productComponentFormConfig
3661
+ };
3662
+ // Bundle product form configuration
3663
+ this.bundleProductFormConfig = {
3664
+ security: { allow: [this.dataService.capProducts] },
3665
+ title: 'Bundle Product',
3666
+ fixedTitle: true,
3667
+ multiColumn: true,
3668
+ includeAudit: true,
3669
+ fields: [
3670
+ { name: 'productInfo', type: 'section', alias: 'Bundle Information' },
3671
+ { name: 'name', type: 'text', required: true, alias: 'Bundle Name', section: 'productInfo', infoMessage: 'Name for this product bundle' },
3672
+ { name: 'sku', type: 'text', alias: 'SKU (optional)', section: 'productInfo', infoMessage: 'Stock Keeping Unit for bundle tracking' },
3673
+ { name: 'description', type: 'text', alias: 'Description', span: true, section: 'productInfo', infoMessage: 'Description of what is included in this bundle' },
3674
+ { name: 'isBundle', type: 'checkbox', alias: 'Is Bundle', hidden: true, defaultValue: true },
3675
+ { name: 'pricingInfo', type: 'section', alias: 'Pricing' },
3676
+ { name: 'sellingPrice', type: 'money', required: true, alias: 'Bundle Price', section: 'pricingInfo', infoMessage: 'Selling price for the complete bundle' },
3677
+ { name: 'bundleEstimatedCost', type: 'money', alias: 'Estimated Cost', section: 'pricingInfo', readonly: true, hideOnCreate: true, infoMessage: 'Total estimated cost based on component costs' },
3678
+ { name: 'inventoryInfo', type: 'section', alias: 'Inventory Settings', collapsedCondition: x => x.productID },
3679
+ { name: 'baseUnit', type: 'select', required: true, alias: 'Base Unit', section: 'inventoryInfo', loadAction: { url: 'products/list/base-unit' }, defaultFirstValue: true, infoMessage: 'Unit of measure for bundle' },
3680
+ { name: 'bundleAvailableQuantity', type: 'number', alias: 'Available to Sell', section: 'inventoryInfo', readonly: true, hideOnCreate: true, infoMessage: 'Number of bundles that can be assembled from current component stock' },
3681
+ ],
3682
+ loadAction: { url: 'products/id' },
3683
+ heroField: 'productID'
3684
+ };
3685
+ this.bundleProductDetailsConfig = {
3686
+ formConfig: this.bundleProductFormConfig,
3687
+ tableConfigs: [this.productComponentsTableConfig],
3688
+ heroField: 'productID',
3689
+ buttons: [
3690
+ { name: 'create', display: 'Create Bundle', dialog: true, action: { url: 'products?action=create', method: 'post' } },
3691
+ { name: 'edit', dialog: true, action: { url: 'products?action=edit', method: 'post' } },
3692
+ { name: 'delete', dialog: true, action: { url: 'products?action=delete', method: 'post' } }
3693
+ ]
3694
+ };
3695
+ this.bundleProductViewButton = { name: 'view', dialog: true, detailsConfig: this.bundleProductDetailsConfig };
3696
+ this.bundleProductCreateButton = { name: 'create', display: 'Create Bundle', dialog: true, action: { url: 'products?action=create', method: 'post' } };
3697
+ // Table configuration for bundle products
3698
+ this.bundleProductsTableConfig = {
3699
+ showFilter: true,
3700
+ flatButtons: true,
3701
+ minColumns: ['name', 'sku', 'bundleAvailableQuantity'],
3702
+ columns: [
3703
+ { name: 'name', type: 'text', alias: 'Bundle Name' },
3704
+ { name: 'sku', type: 'text', alias: 'SKU' },
3705
+ { name: 'bundleAvailableQuantity', type: 'number', alias: 'Available', icon: { name: 'info', color: '#2196F3', condition: (x) => x.bundleAvailableQuantity > 0 } }, // Changed: Removed infoMessage as it's not valid for columns
3706
+ { name: 'bundleEstimatedCost', type: 'money', alias: 'Est. Cost' },
3707
+ { name: 'sellingPrice', type: 'money', alias: 'Selling Price' },
3708
+ { name: 'categoryName', type: 'text', alias: 'Category' }
3709
+ ],
3710
+ buttons: [
3711
+ this.bundleProductCreateButton,
3712
+ this.bundleProductViewButton,
3713
+ { name: 'edit', dialog: true, action: { url: 'products?action=edit', method: 'post' } },
3714
+ { name: 'delete', dialog: true, action: { url: 'products?action=delete', method: 'post' } }
3715
+ ],
3716
+ loadAction: { url: 'products/bundles/x' },
3717
+ formConfig: this.bundleProductFormConfig
3718
+ };
3455
3719
  //--------------------------Requisitions-------------------------
3456
3720
  this.requisitionItemFormConfig = {
3457
3721
  title: 'Requisition Item',
@@ -3821,7 +4085,7 @@ class InventoryService {
3821
4085
  title: 'Sales Order Item',
3822
4086
  fixedTitle: true, // Changed: Use fixedTitle to avoid duplication with 'Add Item' button
3823
4087
  fields: [
3824
- { name: 'productID', type: 'select', alias: 'Product', required: true, loadAction: { url: 'products/list/x' }, detailsConfig: this.productDetailsConfig },
4088
+ { name: 'productID', type: 'select', alias: 'Product', required: true, loadAction: { url: 'products/list/x' }, detailsConfig: this.productDetailsConfig }, // Changed: Show all products including bundles
3825
4089
  { name: 'quantity', type: 'number', alias: 'Quantity', required: true },
3826
4090
  { name: 'unitPrice', type: 'money', alias: 'Unit Price', required: true },
3827
4091
  { name: 'discount', type: 'money', alias: 'Discount' },
@@ -3867,7 +4131,7 @@ class InventoryService {
3867
4131
  { name: 'quickDelivery', type: 'checkbox', alias: 'Quick Delivery (Skip to Delivered)', section: 'quickProcess' },
3868
4132
  { name: 'deliveredDate', type: 'date', alias: 'Delivery Date', section: 'quickProcess' },
3869
4133
  { name: 'paymentInfo', type: 'section', alias: 'Payment (For Delivery)' },
3870
- { name: 'paymentMethod', type: 'select', alias: 'Payment Method', section: 'paymentInfo', options: [{ name: 'Cash', value: 0 }, { name: 'Bank Transfer', value: 1 }, { name: 'Mobile Money', value: 2 }, { name: 'Card', value: 3 }, { name: 'Credit', value: 4 }] },
4134
+ { name: 'paymentMethod', type: 'select', alias: 'Payment Method', section: 'paymentInfo', options: [{ name: 'Cash', value: 0 }, { name: 'Bank Transfer', value: 1 }, { name: 'Mobile Money', value: 2 }, { name: 'Card', value: 3 }, { name: 'Credit', value: 4 }, { name: 'Complementary', value: 5 }] },
3871
4135
  { name: 'paymentReference', type: 'text', alias: 'Payment Reference', section: 'paymentInfo' },
3872
4136
  { name: 'status', type: 'select', alias: 'Status', readonly: true, loadAction: { url: 'salesorders/list/status' } },
3873
4137
  { name: 'totals', type: 'section', alias: 'Totals' },
@@ -4044,7 +4308,7 @@ class InventoryService {
4044
4308
  fixedTitle: true,
4045
4309
  fields: [
4046
4310
  {
4047
- name: 'productID', type: 'select', required: true, alias: 'Product', span: true, loadAction: { url: 'products/list/x' },
4311
+ name: 'productID', type: 'select', required: true, alias: 'Product', span: true, loadAction: { url: 'products/list/x' }, // Changed: Show all products including bundles
4048
4312
  onSelectChange: (selectedProductId, formData, option) => {
4049
4313
  if (option && option.sellingPrice) {
4050
4314
  formData.unitPrice = option.sellingPrice; // Changed: Auto-populate unitPrice with product's sellingPrice
@@ -4102,7 +4366,7 @@ class InventoryService {
4102
4366
  { name: 'multipleProducts', type: 'checkbox', alias: 'Multiple Products', defaultValue: false, hideOnExists: true, infoMessage: 'Check this box if you want to add multiple products to this sale' }, // Changed: Added checkbox for multiple products mode
4103
4367
  { name: 'saleType', type: 'select', required: true, alias: 'Sale Type', section: 'saleInfo', options: [{ name: 'Quick Sale', value: 0 }, { name: 'From Order', value: 1 }], defaultFirstValue: true, hideOnCreate: true, infoMessage: 'Select if this is a quick sale or created from an order' },
4104
4368
  { name: 'quickSaleItem', type: 'section', alias: 'Quick Sale Item', hiddenCondition: x => x.multipleProducts === true || x.saleID }, // Changed: Section for single product entry
4105
- { name: 'productID', type: 'select', required: true, alias: 'Product', section: 'quickSaleItem', span: true, loadAction: { url: 'products/list/x' }, hiddenCondition: x => x.multipleProducts === true, // Changed: Product selection for quick sale
4369
+ { name: 'productID', type: 'select', required: true, alias: 'Product', section: 'quickSaleItem', span: true, loadAction: { url: 'products/list/x' }, hiddenCondition: x => x.multipleProducts === true, // Changed: Show all products including bundles
4106
4370
  onSelectChange: (selectedProductId, formData, option) => {
4107
4371
  if (option && option.sellingPrice) {
4108
4372
  formData.unitPrice = option.sellingPrice; // Changed: Auto-populate unitPrice with product's sellingPrice
@@ -4112,7 +4376,7 @@ class InventoryService {
4112
4376
  { name: 'quantity', type: 'number', required: true, alias: 'Quantity', section: 'quickSaleItem', defaultValue: 1, hiddenCondition: x => x.multipleProducts === true, infoMessage: 'Quantity of the product' }, // Changed: Quantity field for quick sale
4113
4377
  { name: 'unitPrice', type: 'money', required: true, alias: 'Unit Price', section: 'quickSaleItem', hiddenCondition: x => x.multipleProducts === true, infoMessage: 'Price per unit' }, // Changed: Unit price field for quick sale
4114
4378
  { name: 'paymentInfo', type: 'section', alias: 'Payment Information', collapsedCondition: x => x.saleID },
4115
- { name: 'paymentMethod', type: 'select', required: true, alias: 'Payment Method', section: 'paymentInfo', options: [{ name: 'Cash', value: 0 }, { name: 'Bank Transfer', value: 1 }, { name: 'Mobile Money', value: 2 }, { name: 'Card', value: 3 }, { name: 'Credit', value: 4 }], defaultFirstValue: true, infoMessage: 'Method of payment used for this sale' },
4379
+ { name: 'paymentMethod', type: 'select', required: true, alias: 'Payment Method', section: 'paymentInfo', options: [{ name: 'Cash', value: 0 }, { name: 'Bank Transfer', value: 1 }, { name: 'Mobile Money', value: 2 }, { name: 'Card', value: 3 }, { name: 'Credit', value: 4 }, { name: 'Complementary', value: 5 }], defaultFirstValue: true, infoMessage: 'Method of payment used for this sale' },
4116
4380
  { name: 'paymentReference', type: 'text', alias: 'Payment Reference', section: 'paymentInfo', infoMessage: 'Transaction reference number or payment receipt' },
4117
4381
  { name: 'paymentStatus', type: 'select', alias: 'Payment Status', readonly: true, section: 'paymentInfo', loadAction: { url: 'sales/list/payment-status' }, hideOnCreate: true, infoMessage: 'Current payment status of the sale' },
4118
4382
  { name: 'totals', type: 'section', alias: 'Totals', collapsed: true, hideOnCreate: true },
@@ -4241,6 +4505,7 @@ class InventoryService {
4241
4505
  };
4242
4506
  this.productDetailsConfig = {
4243
4507
  formConfig: this.productFormConfig,
4508
+ tableConfigs: [this.productComponentsTableConfig], // Added: Show components for bundle products
4244
4509
  heroField: 'productID',
4245
4510
  buttons: [this.productCreateButton, this.productEditButton, this.productDeleteButton]
4246
4511
  };
@@ -14054,11 +14319,11 @@ class ChangePasswordComponent {
14054
14319
  }
14055
14320
  }
14056
14321
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ChangePasswordComponent, deps: [{ token: i1$2.Router }, { token: i2.Location }, { token: HttpService }, { token: MessageService }, { token: DataServiceLib }, { token: AuthService }, { token: i1$2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); }
14057
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: ChangePasswordComponent, isStandalone: false, selector: "spa-change-password", ngImport: i0, template: "<h4>Change Password</h4>\r\n<hr>\r\n\r\n\r\n<div class=\"container tin-grid\" style=\"font-size:14px;\">\r\n\r\n <div class=\"fill\">\r\n\r\n <spa-text id=\"txtuserName\" display=\"Username\" [(value)]=\"changePassword.userName\" [readonly]=\"true\"></spa-text>\r\n <spa-text id=\"txtPassword\" display=\"Current Password\" [(value)]=\"changePassword.currentPassword\" type=\"password\"></spa-text>\r\n <spa-text id=\"txtNewPassword\" display=\"New Password\" [(value)]=\"changePassword.newPassword\" type=\"password\"></spa-text>\r\n <spa-text id=\"txtConfirmPassword\" display=\"Confirm Password\" [(value)]=\"changePassword.confirmPassword\" type=\"password\"></spa-text>\r\n <button id=\"btnChange\" mat-raised-button color=\"primary\" (click)=\"change()\" cdkFocusInitial>Change</button>\r\n\r\n </div>\r\n\r\n <div class=\"alert alert-info\" style=\"font-size: 14px;\" role=\"alert\">\r\n <b>*Please consider these requirements for your new password.</b> <br><br>\r\n\r\n At least 8 characters<br>\r\n At least 1 uppercase letter (A-Z)<br>\r\n At least 2 lowercase letters (a-z)<br>\r\n At least 1 digit (0-9)<br>\r\n At least 1 special character (~`! \u2026)<br>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n\r\n<!-- <div class=\"container\">\r\n\r\n <div class=\"d-flex justify-content-center row align-items-center\" >\r\n\r\n <div class=\"col\">\r\n\r\n <div class=\"tin-input \" style=\"font-size:14px;\">\r\n\r\n <div class=\"col\" *ngIf=\"changePassword.userName!=''\">\r\n <spa-text id=\"txtuserName\" display=\"Username\" [(value)]=\"changePassword.userName\" width=\"300px\" [readonly]=\"true\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\" *ngIf=\"!myRole[dataService.capUsers.name]\">\r\n <spa-text id=\"txtPassword\" display=\"Current Password\" [(value)]=\"changePassword.currentPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\">\r\n <spa-text id=\"txtNewPassword\" display=\"New Password\" [(value)]=\"changePassword.newPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\">\r\n <spa-text id=\"txtConfirmPassword\" display=\"Confirm Password\" [(value)]=\"changePassword.confirmPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col mt-3\">\r\n <button id=\"btnChange\" mat-raised-button color=\"primary\" (click)=\"change()\" cdkFocusInitial>Change</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n <div class=\"col\">\r\n\r\n <div class=\"alert alert-info\" style=\"font-size: 14px;\" role=\"alert\">\r\n <b>*Please consider these requirements for your new password.</b> <br><br>\r\n\r\n At least 8 characters<br>\r\n At least 1 uppercase letter (A-Z)<br>\r\n At least 2 lowercase letters (a-z)<br>\r\n At least 1 digit (0-9)<br>\r\n At least 1 special character (~`! \u2026)<br>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n\r\n\r\n\r\n </div>\r\n</div> -->\r\n\r\n", styles: [""], dependencies: [{ kind: "component", type: i5$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: TextComponent, selector: "spa-text", inputs: ["appearance", "readonly", "hint", "display", "placeholder", "value", "format", "type", "width", "copyContent", "clearContent", "required", "min", "max", "regex", "suffix", "infoMessage"], outputs: ["valueChange", "leave", "enterPress"] }] }); }
14322
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: ChangePasswordComponent, isStandalone: false, selector: "spa-change-password", ngImport: i0, template: "<h4>Change Password</h4>\r\n<hr>\r\n\r\n\r\n<div class=\"container tin-grid\" style=\"font-size:14px;\">\r\n\r\n <div class=\"fill\">\r\n\r\n <spa-text id=\"txtuserName\" display=\"Username\" [(value)]=\"changePassword.userName\" [readonly]=\"true\"></spa-text>\r\n <spa-text-mask id=\"txtPassword\" display=\"Current Password\" [(value)]=\"changePassword.currentPassword\" type=\"password\"></spa-text-mask>\r\n <spa-text-mask id=\"txtNewPassword\" display=\"New Password\" [(value)]=\"changePassword.newPassword\" type=\"password\"></spa-text-mask>\r\n <spa-text-mask id=\"txtConfirmPassword\" display=\"Confirm Password\" [(value)]=\"changePassword.confirmPassword\" type=\"password\"></spa-text-mask>\r\n <button id=\"btnChange\" mat-raised-button color=\"primary\" (click)=\"change()\" cdkFocusInitial>Change</button>\r\n\r\n </div>\r\n\r\n <div class=\"alert alert-info\" style=\"font-size: 14px;\" role=\"alert\">\r\n <b>*Please consider these requirements for your new password.</b> <br><br>\r\n\r\n At least 8 characters<br>\r\n At least 1 uppercase letter (A-Z)<br>\r\n At least 2 lowercase letters (a-z)<br>\r\n At least 1 digit (0-9)<br>\r\n At least 1 special character (~`! \u2026)<br>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n\r\n<!-- <div class=\"container\">\r\n\r\n <div class=\"d-flex justify-content-center row align-items-center\" >\r\n\r\n <div class=\"col\">\r\n\r\n <div class=\"tin-input \" style=\"font-size:14px;\">\r\n\r\n <div class=\"col\" *ngIf=\"changePassword.userName!=''\">\r\n <spa-text id=\"txtuserName\" display=\"Username\" [(value)]=\"changePassword.userName\" width=\"300px\" [readonly]=\"true\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\" *ngIf=\"!myRole[dataService.capUsers.name]\">\r\n <spa-text id=\"txtPassword\" display=\"Current Password\" [(value)]=\"changePassword.currentPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\">\r\n <spa-text id=\"txtNewPassword\" display=\"New Password\" [(value)]=\"changePassword.newPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\">\r\n <spa-text id=\"txtConfirmPassword\" display=\"Confirm Password\" [(value)]=\"changePassword.confirmPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col mt-3\">\r\n <button id=\"btnChange\" mat-raised-button color=\"primary\" (click)=\"change()\" cdkFocusInitial>Change</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n <div class=\"col\">\r\n\r\n <div class=\"alert alert-info\" style=\"font-size: 14px;\" role=\"alert\">\r\n <b>*Please consider these requirements for your new password.</b> <br><br>\r\n\r\n At least 8 characters<br>\r\n At least 1 uppercase letter (A-Z)<br>\r\n At least 2 lowercase letters (a-z)<br>\r\n At least 1 digit (0-9)<br>\r\n At least 1 special character (~`! \u2026)<br>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n\r\n\r\n\r\n </div>\r\n</div> -->\r\n\r\n", styles: [""], dependencies: [{ kind: "component", type: i5$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: TextComponent, selector: "spa-text", inputs: ["appearance", "readonly", "hint", "display", "placeholder", "value", "format", "type", "width", "copyContent", "clearContent", "required", "min", "max", "regex", "suffix", "infoMessage"], outputs: ["valueChange", "leave", "enterPress"] }, { kind: "component", type: TextMaskComponent, selector: "spa-text-mask", inputs: ["appearance", "readonly", "hint", "display", "placeholder", "value", "width", "required", "min", "max", "regex", "infoMessage"], outputs: ["valueChange", "leave", "enterPress"] }] }); }
14058
14323
  }
14059
14324
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ChangePasswordComponent, decorators: [{
14060
14325
  type: Component,
14061
- args: [{ selector: 'spa-change-password', standalone: false, template: "<h4>Change Password</h4>\r\n<hr>\r\n\r\n\r\n<div class=\"container tin-grid\" style=\"font-size:14px;\">\r\n\r\n <div class=\"fill\">\r\n\r\n <spa-text id=\"txtuserName\" display=\"Username\" [(value)]=\"changePassword.userName\" [readonly]=\"true\"></spa-text>\r\n <spa-text id=\"txtPassword\" display=\"Current Password\" [(value)]=\"changePassword.currentPassword\" type=\"password\"></spa-text>\r\n <spa-text id=\"txtNewPassword\" display=\"New Password\" [(value)]=\"changePassword.newPassword\" type=\"password\"></spa-text>\r\n <spa-text id=\"txtConfirmPassword\" display=\"Confirm Password\" [(value)]=\"changePassword.confirmPassword\" type=\"password\"></spa-text>\r\n <button id=\"btnChange\" mat-raised-button color=\"primary\" (click)=\"change()\" cdkFocusInitial>Change</button>\r\n\r\n </div>\r\n\r\n <div class=\"alert alert-info\" style=\"font-size: 14px;\" role=\"alert\">\r\n <b>*Please consider these requirements for your new password.</b> <br><br>\r\n\r\n At least 8 characters<br>\r\n At least 1 uppercase letter (A-Z)<br>\r\n At least 2 lowercase letters (a-z)<br>\r\n At least 1 digit (0-9)<br>\r\n At least 1 special character (~`! \u2026)<br>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n\r\n<!-- <div class=\"container\">\r\n\r\n <div class=\"d-flex justify-content-center row align-items-center\" >\r\n\r\n <div class=\"col\">\r\n\r\n <div class=\"tin-input \" style=\"font-size:14px;\">\r\n\r\n <div class=\"col\" *ngIf=\"changePassword.userName!=''\">\r\n <spa-text id=\"txtuserName\" display=\"Username\" [(value)]=\"changePassword.userName\" width=\"300px\" [readonly]=\"true\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\" *ngIf=\"!myRole[dataService.capUsers.name]\">\r\n <spa-text id=\"txtPassword\" display=\"Current Password\" [(value)]=\"changePassword.currentPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\">\r\n <spa-text id=\"txtNewPassword\" display=\"New Password\" [(value)]=\"changePassword.newPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\">\r\n <spa-text id=\"txtConfirmPassword\" display=\"Confirm Password\" [(value)]=\"changePassword.confirmPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col mt-3\">\r\n <button id=\"btnChange\" mat-raised-button color=\"primary\" (click)=\"change()\" cdkFocusInitial>Change</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n <div class=\"col\">\r\n\r\n <div class=\"alert alert-info\" style=\"font-size: 14px;\" role=\"alert\">\r\n <b>*Please consider these requirements for your new password.</b> <br><br>\r\n\r\n At least 8 characters<br>\r\n At least 1 uppercase letter (A-Z)<br>\r\n At least 2 lowercase letters (a-z)<br>\r\n At least 1 digit (0-9)<br>\r\n At least 1 special character (~`! \u2026)<br>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n\r\n\r\n\r\n </div>\r\n</div> -->\r\n\r\n" }]
14326
+ args: [{ selector: 'spa-change-password', standalone: false, template: "<h4>Change Password</h4>\r\n<hr>\r\n\r\n\r\n<div class=\"container tin-grid\" style=\"font-size:14px;\">\r\n\r\n <div class=\"fill\">\r\n\r\n <spa-text id=\"txtuserName\" display=\"Username\" [(value)]=\"changePassword.userName\" [readonly]=\"true\"></spa-text>\r\n <spa-text-mask id=\"txtPassword\" display=\"Current Password\" [(value)]=\"changePassword.currentPassword\" type=\"password\"></spa-text-mask>\r\n <spa-text-mask id=\"txtNewPassword\" display=\"New Password\" [(value)]=\"changePassword.newPassword\" type=\"password\"></spa-text-mask>\r\n <spa-text-mask id=\"txtConfirmPassword\" display=\"Confirm Password\" [(value)]=\"changePassword.confirmPassword\" type=\"password\"></spa-text-mask>\r\n <button id=\"btnChange\" mat-raised-button color=\"primary\" (click)=\"change()\" cdkFocusInitial>Change</button>\r\n\r\n </div>\r\n\r\n <div class=\"alert alert-info\" style=\"font-size: 14px;\" role=\"alert\">\r\n <b>*Please consider these requirements for your new password.</b> <br><br>\r\n\r\n At least 8 characters<br>\r\n At least 1 uppercase letter (A-Z)<br>\r\n At least 2 lowercase letters (a-z)<br>\r\n At least 1 digit (0-9)<br>\r\n At least 1 special character (~`! \u2026)<br>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n\r\n<!-- <div class=\"container\">\r\n\r\n <div class=\"d-flex justify-content-center row align-items-center\" >\r\n\r\n <div class=\"col\">\r\n\r\n <div class=\"tin-input \" style=\"font-size:14px;\">\r\n\r\n <div class=\"col\" *ngIf=\"changePassword.userName!=''\">\r\n <spa-text id=\"txtuserName\" display=\"Username\" [(value)]=\"changePassword.userName\" width=\"300px\" [readonly]=\"true\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\" *ngIf=\"!myRole[dataService.capUsers.name]\">\r\n <spa-text id=\"txtPassword\" display=\"Current Password\" [(value)]=\"changePassword.currentPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\">\r\n <spa-text id=\"txtNewPassword\" display=\"New Password\" [(value)]=\"changePassword.newPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col\">\r\n <spa-text id=\"txtConfirmPassword\" display=\"Confirm Password\" [(value)]=\"changePassword.confirmPassword\" width=\"300px\" type=\"password\"></spa-text>\r\n </div>\r\n\r\n <div class=\"col mt-3\">\r\n <button id=\"btnChange\" mat-raised-button color=\"primary\" (click)=\"change()\" cdkFocusInitial>Change</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n <div class=\"col\">\r\n\r\n <div class=\"alert alert-info\" style=\"font-size: 14px;\" role=\"alert\">\r\n <b>*Please consider these requirements for your new password.</b> <br><br>\r\n\r\n At least 8 characters<br>\r\n At least 1 uppercase letter (A-Z)<br>\r\n At least 2 lowercase letters (a-z)<br>\r\n At least 1 digit (0-9)<br>\r\n At least 1 special character (~`! \u2026)<br>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n\r\n\r\n\r\n </div>\r\n</div> -->\r\n\r\n" }]
14062
14327
  }], ctorParameters: () => [{ type: i1$2.Router }, { type: i2.Location }, { type: HttpService }, { type: MessageService }, { type: DataServiceLib }, { type: AuthService }, { type: i1$2.ActivatedRoute }] });
14063
14328
 
14064
14329
  class ProfileComponent {
@@ -14131,11 +14396,11 @@ class ProfileComponent {
14131
14396
  });
14132
14397
  }
14133
14398
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ProfileComponent, deps: [{ token: DataServiceLib }, { token: MessageService }, { token: HttpService }, { token: i1$2.Router }, { token: AuthService }], target: i0.ɵɵFactoryTarget.Component }); }
14134
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: ProfileComponent, isStandalone: false, selector: "spa-profile", inputs: { appConfig: "appConfig" }, ngImport: i0, template: "\r\n<h4>Profile</h4>\r\n<hr>\r\n\r\n<div class=\"container tin-grid-auto\" style=\"font-size:14px;\">\r\n\r\n <div class=\"tin-center centa\">\r\n <div class=\"profileImage\">{{initials}}</div>\r\n <mat-label id=\"lbluserName\" >{{profile?.userName}}</mat-label>\r\n </div>\r\n\r\n <div>\r\n\r\n <spa-text id=\"txtFirstName\" display=\"First Name\" [(value)]=\"profile.firstName\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtLastName\" display=\"Last Name\" [(value)]=\"profile.lastName\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtAuth\" display=\"Authentication\" [(value)]=\"profile.authType\" [readonly]=\"true\"></spa-text>\r\n <spa-text id=\"txtEmail\" display=\"Email\" [(value)]=\"profile.email\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-select id=\"cboRole\" display=\"Role\" [options]=\"roles\" optionDisplay=\"roleName\" optionValue=\"roleID\" [(value)]=\"profile.roleID\" [readonly]=\"selfProfile\"></spa-select>\r\n <spa-label *ngIf=\"dataService.appConfig.multitenant\" display=\"Code\" [value]=\"profile.code\" ></spa-label>\r\n\r\n <button id=\"btnUpdate\" class=\"w-100\" mat-raised-button color=\"primary\" *ngIf=\"!selfProfile\" [disabled]=\"isProcessing\" (click)=\"updateProfile()\">Update Profile</button>\r\n </div>\r\n\r\n\r\n <div class=\"tin-center centa\">\r\n <a mat-button id=\"lnkUserManager\" style=\"margin-left: 1em\" *ngIf=\"!selfProfile\" (click)=\"gotoUsers()\">User Manager</a>\r\n <a mat-button id=\"lnkChangePassword\" style=\"margin-left: 1em\" *ngIf=\"(selfProfile || myRole[dataService.capUsers.name]) && profile.authType=='local'\" (click)=\"changePassword()\">Change Password</a>\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n", styles: [".centa{display:flex;flex-direction:column}.profileImage{width:150px;height:150px;border-radius:50%;background:#512da8;font-size:50px;color:#fff;text-align:center;line-height:150px;margin:20px 0 0}#lbluserName{font-size:20px;font-style:italic}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "component", type: TextComponent, selector: "spa-text", inputs: ["appearance", "readonly", "hint", "display", "placeholder", "value", "format", "type", "width", "copyContent", "clearContent", "required", "min", "max", "regex", "suffix", "infoMessage"], outputs: ["valueChange", "leave", "enterPress"] }, { kind: "component", type: SelectComponent, selector: "spa-select", inputs: ["detailsConfig"] }, { kind: "component", type: LabelComponent, selector: "spa-label", inputs: ["display", "value", "format", "suffix", "size"] }] }); }
14399
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: ProfileComponent, isStandalone: false, selector: "spa-profile", inputs: { appConfig: "appConfig" }, ngImport: i0, template: "\r\n<h4>Profile</h4>\r\n<hr>\r\n\r\n<div class=\"container tin-grid-auto\" style=\"font-size:14px;\">\r\n\r\n <div class=\"tin-center centa\">\r\n <div class=\"profileImage\">{{initials}}</div>\r\n <mat-label id=\"lbluserName\" >{{profile?.userName}}</mat-label>\r\n </div>\r\n\r\n <div>\r\n\r\n <spa-text id=\"txtFirstName\" display=\"First Name\" [(value)]=\"profile.firstName\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtLastName\" display=\"Last Name\" [(value)]=\"profile.lastName\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtAuth\" display=\"Authentication\" [(value)]=\"profile.authType\" [readonly]=\"true\"></spa-text>\r\n <spa-text id=\"txtEmail\" display=\"Email\" [(value)]=\"profile.email\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtRole\" display=\"Role\" [(value)]=\"profile.role.roleName\" [readonly]=\"selfProfile\"></spa-text>\r\n <!-- <spa-select id=\"cboRole\" display=\"Role\" [options]=\"roles\" optionDisplay=\"roleName\" optionValue=\"roleID\" [(value)]=\"profile.roleID\" [readonly]=\"selfProfile\"></spa-select> -->\r\n <spa-label *ngIf=\"dataService.appConfig.multitenant\" display=\"Code\" [value]=\"profile.code\" ></spa-label>\r\n\r\n <button id=\"btnUpdate\" class=\"w-100\" mat-raised-button color=\"primary\" *ngIf=\"!selfProfile\" [disabled]=\"isProcessing\" (click)=\"updateProfile()\">Update Profile</button>\r\n </div>\r\n\r\n\r\n <div class=\"tin-center centa\">\r\n <a mat-button id=\"lnkUserManager\" style=\"margin-left: 1em\" *ngIf=\"!selfProfile\" (click)=\"gotoUsers()\">User Manager</a>\r\n <a mat-button id=\"lnkChangePassword\" style=\"margin-left: 1em\" *ngIf=\"(selfProfile || myRole[dataService.capUsers.name]) && profile.authType=='local'\" (click)=\"changePassword()\">Change Password</a>\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n", styles: [".centa{display:flex;flex-direction:column}.profileImage{width:150px;height:150px;border-radius:50%;background:#512da8;font-size:50px;color:#fff;text-align:center;line-height:150px;margin:20px 0 0}#lbluserName{font-size:20px;font-style:italic}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "component", type: TextComponent, selector: "spa-text", inputs: ["appearance", "readonly", "hint", "display", "placeholder", "value", "format", "type", "width", "copyContent", "clearContent", "required", "min", "max", "regex", "suffix", "infoMessage"], outputs: ["valueChange", "leave", "enterPress"] }, { kind: "component", type: LabelComponent, selector: "spa-label", inputs: ["display", "value", "format", "suffix", "size"] }] }); }
14135
14400
  }
14136
14401
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ProfileComponent, decorators: [{
14137
14402
  type: Component,
14138
- args: [{ selector: 'spa-profile', standalone: false, template: "\r\n<h4>Profile</h4>\r\n<hr>\r\n\r\n<div class=\"container tin-grid-auto\" style=\"font-size:14px;\">\r\n\r\n <div class=\"tin-center centa\">\r\n <div class=\"profileImage\">{{initials}}</div>\r\n <mat-label id=\"lbluserName\" >{{profile?.userName}}</mat-label>\r\n </div>\r\n\r\n <div>\r\n\r\n <spa-text id=\"txtFirstName\" display=\"First Name\" [(value)]=\"profile.firstName\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtLastName\" display=\"Last Name\" [(value)]=\"profile.lastName\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtAuth\" display=\"Authentication\" [(value)]=\"profile.authType\" [readonly]=\"true\"></spa-text>\r\n <spa-text id=\"txtEmail\" display=\"Email\" [(value)]=\"profile.email\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-select id=\"cboRole\" display=\"Role\" [options]=\"roles\" optionDisplay=\"roleName\" optionValue=\"roleID\" [(value)]=\"profile.roleID\" [readonly]=\"selfProfile\"></spa-select>\r\n <spa-label *ngIf=\"dataService.appConfig.multitenant\" display=\"Code\" [value]=\"profile.code\" ></spa-label>\r\n\r\n <button id=\"btnUpdate\" class=\"w-100\" mat-raised-button color=\"primary\" *ngIf=\"!selfProfile\" [disabled]=\"isProcessing\" (click)=\"updateProfile()\">Update Profile</button>\r\n </div>\r\n\r\n\r\n <div class=\"tin-center centa\">\r\n <a mat-button id=\"lnkUserManager\" style=\"margin-left: 1em\" *ngIf=\"!selfProfile\" (click)=\"gotoUsers()\">User Manager</a>\r\n <a mat-button id=\"lnkChangePassword\" style=\"margin-left: 1em\" *ngIf=\"(selfProfile || myRole[dataService.capUsers.name]) && profile.authType=='local'\" (click)=\"changePassword()\">Change Password</a>\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n", styles: [".centa{display:flex;flex-direction:column}.profileImage{width:150px;height:150px;border-radius:50%;background:#512da8;font-size:50px;color:#fff;text-align:center;line-height:150px;margin:20px 0 0}#lbluserName{font-size:20px;font-style:italic}\n"] }]
14403
+ args: [{ selector: 'spa-profile', standalone: false, template: "\r\n<h4>Profile</h4>\r\n<hr>\r\n\r\n<div class=\"container tin-grid-auto\" style=\"font-size:14px;\">\r\n\r\n <div class=\"tin-center centa\">\r\n <div class=\"profileImage\">{{initials}}</div>\r\n <mat-label id=\"lbluserName\" >{{profile?.userName}}</mat-label>\r\n </div>\r\n\r\n <div>\r\n\r\n <spa-text id=\"txtFirstName\" display=\"First Name\" [(value)]=\"profile.firstName\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtLastName\" display=\"Last Name\" [(value)]=\"profile.lastName\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtAuth\" display=\"Authentication\" [(value)]=\"profile.authType\" [readonly]=\"true\"></spa-text>\r\n <spa-text id=\"txtEmail\" display=\"Email\" [(value)]=\"profile.email\" [readonly]=\"selfProfile\"></spa-text>\r\n <spa-text id=\"txtRole\" display=\"Role\" [(value)]=\"profile.role.roleName\" [readonly]=\"selfProfile\"></spa-text>\r\n <!-- <spa-select id=\"cboRole\" display=\"Role\" [options]=\"roles\" optionDisplay=\"roleName\" optionValue=\"roleID\" [(value)]=\"profile.roleID\" [readonly]=\"selfProfile\"></spa-select> -->\r\n <spa-label *ngIf=\"dataService.appConfig.multitenant\" display=\"Code\" [value]=\"profile.code\" ></spa-label>\r\n\r\n <button id=\"btnUpdate\" class=\"w-100\" mat-raised-button color=\"primary\" *ngIf=\"!selfProfile\" [disabled]=\"isProcessing\" (click)=\"updateProfile()\">Update Profile</button>\r\n </div>\r\n\r\n\r\n <div class=\"tin-center centa\">\r\n <a mat-button id=\"lnkUserManager\" style=\"margin-left: 1em\" *ngIf=\"!selfProfile\" (click)=\"gotoUsers()\">User Manager</a>\r\n <a mat-button id=\"lnkChangePassword\" style=\"margin-left: 1em\" *ngIf=\"(selfProfile || myRole[dataService.capUsers.name]) && profile.authType=='local'\" (click)=\"changePassword()\">Change Password</a>\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n", styles: [".centa{display:flex;flex-direction:column}.profileImage{width:150px;height:150px;border-radius:50%;background:#512da8;font-size:50px;color:#fff;text-align:center;line-height:150px;margin:20px 0 0}#lbluserName{font-size:20px;font-style:italic}\n"] }]
14139
14404
  }], ctorParameters: () => [{ type: DataServiceLib }, { type: MessageService }, { type: HttpService }, { type: i1$2.Router }, { type: AuthService }], propDecorators: { appConfig: [{
14140
14405
  type: Input
14141
14406
  }] } });
@@ -14984,6 +15249,84 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
14984
15249
  }]
14985
15250
  }], ctorParameters: () => [{ type: DataServiceLib }, { type: AccountingService }] });
14986
15251
 
15252
+ // Aging report component for accounts receivable tracking
15253
+ class AgingComponent {
15254
+ ngOnInit() {
15255
+ this.loadSummaryData();
15256
+ }
15257
+ loadSummaryData() {
15258
+ this.dataServiceLib.CallApi({ url: 'invoices/aging-summary/x' }, '').subscribe((apiResponse) => {
15259
+ if (apiResponse.success) {
15260
+ this.summaryData = apiResponse.data;
15261
+ }
15262
+ });
15263
+ }
15264
+ constructor(dataServiceLib) {
15265
+ this.dataServiceLib = dataServiceLib;
15266
+ this.accountingService = inject(AccountingService);
15267
+ this.tileConfig = this.accountingService.agingTileConfig;
15268
+ // this.tileConfig = this.accountingService.agingTileConfig;
15269
+ this.agingTableConfigs = [
15270
+ {
15271
+ ...this.accountingService.agingBaseTableConfig,
15272
+ tabTitle: 'Current',
15273
+ loadAction: { url: 'invoices/aging-current/x' },
15274
+ countAction: { url: 'invoices/count/aging-current' }
15275
+ },
15276
+ {
15277
+ ...this.accountingService.agingBaseTableConfig,
15278
+ tabTitle: '1-30 Days',
15279
+ loadAction: { url: 'invoices/aging-30/x' },
15280
+ countAction: { url: 'invoices/count/aging-30' }
15281
+ },
15282
+ {
15283
+ ...this.accountingService.agingBaseTableConfig,
15284
+ tabTitle: '31-60 Days',
15285
+ loadAction: { url: 'invoices/aging-60/x' },
15286
+ countAction: { url: 'invoices/count/aging-60' }
15287
+ },
15288
+ {
15289
+ ...this.accountingService.agingBaseTableConfig,
15290
+ tabTitle: '61-90 Days',
15291
+ loadAction: { url: 'invoices/aging-90/x' },
15292
+ countAction: { url: 'invoices/count/aging-90' }
15293
+ },
15294
+ {
15295
+ ...this.accountingService.agingBaseTableConfig,
15296
+ tabTitle: '90+ Days',
15297
+ loadAction: { url: 'invoices/aging-90plus/x' },
15298
+ countAction: { url: 'invoices/count/aging-90plus' }
15299
+ }
15300
+ ];
15301
+ }
15302
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AgingComponent, deps: [{ token: DataServiceLib }], target: i0.ɵɵFactoryTarget.Component }); }
15303
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: AgingComponent, isStandalone: false, selector: "spa-aging", ngImport: i0, template: `
15304
+ <h4>Accounts Receivable Aging</h4>
15305
+ <hr>
15306
+ <div *ngIf="summaryData" class="mt-3 mb-3">
15307
+ <spa-tiles [config]="tileConfig" [data]="summaryData"></spa-tiles>
15308
+ </div>
15309
+
15310
+ <spa-tabs [tableConfigs]="agingTableConfigs"></spa-tabs>
15311
+ `, 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"] }] }); }
15312
+ }
15313
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AgingComponent, decorators: [{
15314
+ type: Component,
15315
+ args: [{
15316
+ selector: 'spa-aging',
15317
+ template: `
15318
+ <h4>Accounts Receivable Aging</h4>
15319
+ <hr>
15320
+ <div *ngIf="summaryData" class="mt-3 mb-3">
15321
+ <spa-tiles [config]="tileConfig" [data]="summaryData"></spa-tiles>
15322
+ </div>
15323
+
15324
+ <spa-tabs [tableConfigs]="agingTableConfigs"></spa-tabs>
15325
+ `,
15326
+ standalone: false
15327
+ }]
15328
+ }], ctorParameters: () => [{ type: DataServiceLib }] });
15329
+
14987
15330
  class TransactionTypesComponent {
14988
15331
  constructor() {
14989
15332
  this.accountingService = inject(AccountingService);
@@ -15674,11 +16017,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
15674
16017
  }]
15675
16018
  }] });
15676
16019
 
16020
+ // Component for managing bundle/combo products
16021
+ class BundleProductsComponent {
16022
+ constructor() {
16023
+ this.inventoryService = inject(InventoryService);
16024
+ this.pageConfig = {
16025
+ title: 'Bundle Products',
16026
+ tableConfig: this.inventoryService.bundleProductsTableConfig
16027
+ };
16028
+ }
16029
+ ngOnInit() { }
16030
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: BundleProductsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16031
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: BundleProductsComponent, isStandalone: false, selector: "spa-bundle-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"] }] }); }
16032
+ }
16033
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: BundleProductsComponent, decorators: [{
16034
+ type: Component,
16035
+ args: [{
16036
+ selector: 'spa-bundle-products',
16037
+ standalone: false,
16038
+ template: '<spa-page [config]="pageConfig"></spa-page>'
16039
+ }]
16040
+ }] });
16041
+
16042
+ class GptCachesComponent {
16043
+ constructor() {
16044
+ this.dataService = inject(DataServiceLib);
16045
+ this.pageConfig = {
16046
+ title: 'GPT Cache',
16047
+ tableConfig: this.dataService.gptCachesTableConfig
16048
+ };
16049
+ }
16050
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: GptCachesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16051
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: GptCachesComponent, isStandalone: true, selector: "spa-gpt-caches", 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"] }] }); }
16052
+ }
16053
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: GptCachesComponent, decorators: [{
16054
+ type: Component,
16055
+ args: [{
16056
+ selector: 'spa-gpt-caches',
16057
+ standalone: true,
16058
+ imports: [TinSpaModule],
16059
+ template: '<spa-page [config]="pageConfig"></spa-page>'
16060
+ }]
16061
+ }] });
16062
+
15677
16063
  const routes$1 = [
15678
16064
  { path: "users", component: UsersComponent },
15679
16065
  { path: "roles", component: RolesComponent },
15680
16066
  { path: "create-account", component: CreateAccountComponent },
15681
16067
  { path: "logs", component: LogsComponent },
16068
+ { path: "gpt-caches", component: GptCachesComponent }, // Added: GPT Cache route
15682
16069
  { path: "settings", component: SettingsComponent },
15683
16070
  { path: "tenant-settings", component: TenantSettingsComponent },
15684
16071
  { path: "tenants", component: TenantsComponent },
@@ -15706,6 +16093,7 @@ const routes$1 = [
15706
16093
  { path: "accounting-transaction-types", component: TransactionTypesComponent },
15707
16094
  { path: "accounting-transactions", component: TransactionsComponent },
15708
16095
  { path: "accounting-invoices", component: InvoicesComponent },
16096
+ { path: "accounting-aging", component: AgingComponent }, // Added: Aging route
15709
16097
  { path: "accounting-outstanding-invoices", component: OutstandingInvoicesComponent },
15710
16098
  { path: "loans-products", component: LoanProductsComponent },
15711
16099
  { path: "loans", component: LoansComponent },
@@ -15723,6 +16111,7 @@ const routes$1 = [
15723
16111
  { path: "inventory-transactions", component: InventoryTransactionsComponent },
15724
16112
  { path: "inventory-dashboard", component: InventoryDashboardComponent },
15725
16113
  { path: "inventory-stock", component: InventoryStockComponent }, // Changed: Added inventory stock route
16114
+ { path: "bundle-products", component: BundleProductsComponent }, // Added: Bundle products route
15726
16115
  { path: "production-recipes", component: ProductionRecipesComponent },
15727
16116
  { path: "production-orders", component: ProductionOrdersComponent }
15728
16117
  ];
@@ -15745,6 +16134,7 @@ class AdminModule {
15745
16134
  // Accounting components
15746
16135
  AccountsComponent,
15747
16136
  AggregatesComponent, // Added: Aggregates component declaration
16137
+ AgingComponent, // Added: Aging component declaration
15748
16138
  TransactionTypesComponent,
15749
16139
  TransactionsComponent,
15750
16140
  InvoicesComponent,
@@ -15764,7 +16154,9 @@ class AdminModule {
15764
16154
  InventoryDashboardComponent,
15765
16155
  InventoryStockComponent,
15766
16156
  ProductionRecipesComponent,
15767
- ProductionOrdersComponent], imports: [CommonModule,
16157
+ ProductionOrdersComponent,
16158
+ BundleProductsComponent // Added: Bundle products component
16159
+ ], imports: [CommonModule,
15768
16160
  AdminRoutingModule,
15769
16161
  SpaAdminModule] }); }
15770
16162
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AdminModule, imports: [CommonModule,
@@ -15778,6 +16170,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
15778
16170
  // Accounting components
15779
16171
  AccountsComponent,
15780
16172
  AggregatesComponent, // Added: Aggregates component declaration
16173
+ AgingComponent, // Added: Aging component declaration
15781
16174
  TransactionTypesComponent,
15782
16175
  TransactionsComponent,
15783
16176
  InvoicesComponent,
@@ -15797,7 +16190,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
15797
16190
  InventoryDashboardComponent,
15798
16191
  InventoryStockComponent,
15799
16192
  ProductionRecipesComponent,
15800
- ProductionOrdersComponent
16193
+ ProductionOrdersComponent,
16194
+ BundleProductsComponent // Added: Bundle products component
15801
16195
  ],
15802
16196
  imports: [
15803
16197
  CommonModule,
@@ -15854,5 +16248,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
15854
16248
  * Generated bundle index. Do not edit.
15855
16249
  */
15856
16250
 
15857
- export { Account, AccountsComponent as AccountingAccountsComponent, AggregatesComponent as AccountingAggregatesComponent, 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, 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, Profile, ProfileComponent, RecoverAccountComponent, Register, Role, RoleAccess, RolesComponent, SearchComponent, SearchConfig, SecurityConfig, SelectBitwiseComponent, SelectComponent, SelectMultiComponent, SettingsComponent, SignupComponent, SpaAdminModule, SpaIndexModule, SpaMatModule, SpaUserModule, StatusesComponent, Step, StepConfig, StepsComponent, StorageService, SubCategoriesComponent, SuppliersComponent, TabService, TableComponent, TableConfig, TabsComponent, TabsInternalComponent, TabsLiteComponent, TasksComponent, TenantsComponent, TextAreaComponent, TextComponent, TextMaskComponent, TextMultiComponent, TextSingleComponent, TileConfig, TilesComponent, TinSpaComponent, TinSpaModule, TinSpaService, TitleActionsComponent, UnitOfMeasure, User, UserModule, UsersComponent, ViewerComponent, WelcomeComponent, authGuard, dialogOptions, loginConfig, messageDialog, viewerDialog };
16251
+ 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, 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, Profile, ProfileComponent, RecoverAccountComponent, Register, Role, RoleAccess, RolesComponent, SearchComponent, SearchConfig, SecurityConfig, SelectBitwiseComponent, SelectComponent, SelectMultiComponent, SettingsComponent, SignupComponent, SpaAdminModule, SpaIndexModule, SpaMatModule, SpaUserModule, StatusesComponent, Step, StepConfig, StepsComponent, StorageService, SubCategoriesComponent, SuppliersComponent, TabService, TableComponent, TableConfig, TabsComponent, TabsInternalComponent, TabsLiteComponent, TasksComponent, TenantsComponent, TextAreaComponent, TextComponent, TextMaskComponent, TextMultiComponent, TextSingleComponent, TileConfig, TilesComponent, TinSpaComponent, TinSpaModule, TinSpaService, TitleActionsComponent, UnitOfMeasure, User, UserModule, UsersComponent, ViewerComponent, WelcomeComponent, authGuard, dialogOptions, loginConfig, messageDialog, viewerDialog };
15858
16252
  //# sourceMappingURL=tin-spa.mjs.map