|
| 1 | +--- |
| 2 | +title: "AutoNumber Field" |
| 3 | +description: "Read-only auto-generated sequence number" |
| 4 | +--- |
| 5 | + |
| 6 | +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; |
| 7 | + |
| 8 | +The AutoNumber Field component displays auto-generated sequence numbers. This is a read-only field where the value is automatically generated by the backend when records are created. |
| 9 | + |
| 10 | +## Basic Usage |
| 11 | + |
| 12 | +<ComponentDemo |
| 13 | + schema={{ |
| 14 | + type: 'auto_number', |
| 15 | + name: 'order_number', |
| 16 | + label: 'Order Number', |
| 17 | + readonly: true, |
| 18 | + value: 'ORD-0001' |
| 19 | + }} |
| 20 | + title="Basic AutoNumber" |
| 21 | +/> |
| 22 | + |
| 23 | +## Custom Format |
| 24 | + |
| 25 | +<ComponentDemo |
| 26 | + schema={{ |
| 27 | + type: 'auto_number', |
| 28 | + name: 'invoice_id', |
| 29 | + label: 'Invoice ID', |
| 30 | + format: 'INV-{0000}', |
| 31 | + readonly: true, |
| 32 | + value: 'INV-1234' |
| 33 | + }} |
| 34 | + title="Invoice Number Format" |
| 35 | +/> |
| 36 | + |
| 37 | +## Date-Based Format |
| 38 | + |
| 39 | +<ComponentDemo |
| 40 | + schema={{ |
| 41 | + type: 'auto_number', |
| 42 | + name: 'ticket_id', |
| 43 | + label: 'Ticket ID', |
| 44 | + format: 'TKT-{YYYY}{MM}-{0000}', |
| 45 | + readonly: true, |
| 46 | + value: 'TKT-202403-0567' |
| 47 | + }} |
| 48 | + title="Date-Based Ticket ID" |
| 49 | +/> |
| 50 | + |
| 51 | +## Field Schema |
| 52 | + |
| 53 | +```typescript |
| 54 | +interface AutoNumberFieldSchema { |
| 55 | + type: 'auto_number'; |
| 56 | + name: string; // Field name/ID |
| 57 | + label?: string; // Field label |
| 58 | + value?: string | number; // Generated value (read-only) |
| 59 | + readonly: true; // Always read-only |
| 60 | + className?: string; // Additional CSS classes |
| 61 | + |
| 62 | + // AutoNumber Configuration |
| 63 | + format?: string; // Number format template |
| 64 | + starting_number?: number; // Starting sequence number |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +## Format Templates |
| 69 | + |
| 70 | +Common format patterns: |
| 71 | + |
| 72 | +### Simple Sequential |
| 73 | + |
| 74 | +```typescript |
| 75 | +format: '{0000}' // 0001, 0002, 0003... |
| 76 | +format: '{00000}' // 00001, 00002, 00003... |
| 77 | +``` |
| 78 | + |
| 79 | +### With Prefix |
| 80 | + |
| 81 | +```typescript |
| 82 | +format: 'ORD-{0000}' // ORD-0001, ORD-0002... |
| 83 | +format: 'INV-{00000}' // INV-00001, INV-00002... |
| 84 | +format: 'CUST-{000}' // CUST-001, CUST-002... |
| 85 | +``` |
| 86 | + |
| 87 | +### Date-Based |
| 88 | + |
| 89 | +```typescript |
| 90 | +format: '{YYYY}-{0000}' // 2024-0001, 2024-0002... |
| 91 | +format: '{YY}{MM}-{000}' // 2403-001, 2403-002... |
| 92 | +format: 'ORD-{YYYYMMDD}-{00}' // ORD-20240315-01... |
| 93 | +``` |
| 94 | + |
| 95 | +### Mixed Format |
| 96 | + |
| 97 | +```typescript |
| 98 | +format: 'PO-{YYYY}-{MM}-{0000}' // PO-2024-03-0001 |
| 99 | +format: '{YY}Q{Q}-{000}' // 24Q1-001, 24Q1-002... |
| 100 | +``` |
| 101 | + |
| 102 | +## Format Placeholders |
| 103 | + |
| 104 | +- `{0}`, `{00}`, `{000}`, etc. - Sequential number with padding |
| 105 | +- `{YYYY}` - Four-digit year (2024) |
| 106 | +- `{YY}` - Two-digit year (24) |
| 107 | +- `{MM}` - Two-digit month (03) |
| 108 | +- `{DD}` - Two-digit day (15) |
| 109 | +- `{Q}` - Quarter (1-4) |
| 110 | + |
| 111 | +## Backend Implementation |
| 112 | + |
| 113 | +AutoNumber values are generated on record creation: |
| 114 | + |
| 115 | +```typescript |
| 116 | +const generateAutoNumber = (format: string, sequence: number) => { |
| 117 | + const now = new Date(); |
| 118 | + |
| 119 | + return format |
| 120 | + .replace('{YYYY}', now.getFullYear().toString()) |
| 121 | + .replace('{YY}', now.getFullYear().toString().slice(-2)) |
| 122 | + .replace('{MM}', (now.getMonth() + 1).toString().padStart(2, '0')) |
| 123 | + .replace('{DD}', now.getDate().toString().padStart(2, '0')) |
| 124 | + .replace('{Q}', Math.ceil((now.getMonth() + 1) / 3).toString()) |
| 125 | + .replace(/\{0+\}/, (match) => { |
| 126 | + const padding = match.length - 2; |
| 127 | + return sequence.toString().padStart(padding, '0'); |
| 128 | + }); |
| 129 | +}; |
| 130 | + |
| 131 | +// Example usage |
| 132 | +generateAutoNumber('ORD-{YYYY}-{0000}', 42); |
| 133 | +// Returns: "ORD-2024-0042" |
| 134 | +``` |
| 135 | + |
| 136 | +## Sequence Management |
| 137 | + |
| 138 | +The backend maintains sequence counters: |
| 139 | + |
| 140 | +```typescript |
| 141 | +interface SequenceCounter { |
| 142 | + object: string; // Object name |
| 143 | + field: string; // Field name |
| 144 | + current_value: number; // Current sequence number |
| 145 | + prefix?: string; // Optional prefix for partitioning |
| 146 | +} |
| 147 | + |
| 148 | +// Increment sequence atomically |
| 149 | +const getNextSequence = async (object: string, field: string) => { |
| 150 | + return await db.transaction(async (tx) => { |
| 151 | + const counter = await tx.findOne('sequences', { object, field }); |
| 152 | + const nextValue = (counter?.current_value || 0) + 1; |
| 153 | + await tx.upsert('sequences', { object, field }, { current_value: nextValue }); |
| 154 | + return nextValue; |
| 155 | + }); |
| 156 | +}; |
| 157 | +``` |
| 158 | + |
| 159 | +## Use Cases |
| 160 | + |
| 161 | +- **Order Management**: Order numbers, PO numbers |
| 162 | +- **Invoicing**: Invoice IDs, receipt numbers |
| 163 | +- **Ticketing**: Support ticket IDs, case numbers |
| 164 | +- **Customer Management**: Customer IDs, account numbers |
| 165 | +- **Inventory**: SKU numbers, serial numbers |
| 166 | +- **Document Management**: Document IDs, revision numbers |
| 167 | + |
| 168 | +## Best Practices |
| 169 | + |
| 170 | +1. **Choose appropriate padding**: Use enough digits for expected volume |
| 171 | +2. **Include year for long-running systems**: Helps with archival and partitioning |
| 172 | +3. **Use meaningful prefixes**: Makes numbers self-documenting |
| 173 | +4. **Don't expose internal IDs**: Use auto-numbers for user-facing identifiers |
| 174 | +5. **Consider reset policies**: Decide if/when sequences reset (yearly, monthly, etc.) |
0 commit comments