@mbc-cqrs-serverless/sequence 1.0.15 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +200 -122
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
# @mbc-cqrs-serverless/sequence
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@mbc-cqrs-serverless/sequence)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
Robust sequence number generation for the MBC CQRS Serverless framework. Generate unique, formatted sequence numbers with automatic rotation support for invoices, orders, tickets, and more.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Atomic Counter**: DynamoDB-based atomic operations ensure no duplicates
|
|
13
|
+
- **Flexible Rotation**: Reset sequences by fiscal year, year, month, or day
|
|
14
|
+
- **Custom Formatting**: Configure prefixes, padding, and format patterns
|
|
15
|
+
- **Multi-tenant**: Isolated sequences per tenant
|
|
16
|
+
- **Hierarchical Codes**: Support up to 5 levels of code hierarchy
|
|
14
17
|
|
|
15
18
|
## Installation
|
|
16
19
|
|
|
@@ -18,173 +21,248 @@ The Sequence package provides robust sequence number generation functionality fo
|
|
|
18
21
|
npm install @mbc-cqrs-serverless/sequence
|
|
19
22
|
```
|
|
20
23
|
|
|
21
|
-
##
|
|
24
|
+
## Quick Start
|
|
22
25
|
|
|
23
|
-
###
|
|
26
|
+
### 1. Register the Module
|
|
24
27
|
|
|
25
|
-
1. Import and configure the sequence module:
|
|
26
28
|
```typescript
|
|
27
|
-
import { SequenceModule } from '@mbc-cqrs-serverless/sequence';
|
|
28
29
|
import { Module } from '@nestjs/common';
|
|
30
|
+
import { SequencesModule } from '@mbc-cqrs-serverless/sequence';
|
|
29
31
|
|
|
30
32
|
@Module({
|
|
31
33
|
imports: [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
region: 'ap-northeast-1',
|
|
34
|
+
SequencesModule.register({
|
|
35
|
+
enableController: true, // Optional: enable REST endpoints
|
|
35
36
|
}),
|
|
36
37
|
],
|
|
37
38
|
})
|
|
38
39
|
export class AppModule {}
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
###
|
|
42
|
-
|
|
43
|
-
1. Define a sequence configuration:
|
|
44
|
-
```typescript
|
|
45
|
-
import {
|
|
46
|
-
SequenceConfig,
|
|
47
|
-
RotateByEnum
|
|
48
|
-
} from '@mbc-cqrs-serverless/sequence';
|
|
49
|
-
|
|
50
|
-
const invoiceSequence: SequenceConfig = {
|
|
51
|
-
name: 'INVOICE',
|
|
52
|
-
prefix: 'INV',
|
|
53
|
-
padding: 6,
|
|
54
|
-
rotateBy: RotateByEnum.FISCAL_YEAR,
|
|
55
|
-
startNumber: 1,
|
|
56
|
-
};
|
|
57
|
-
```
|
|
42
|
+
### 2. Generate Sequence Numbers
|
|
58
43
|
|
|
59
|
-
2. Use the sequence service:
|
|
60
44
|
```typescript
|
|
61
|
-
import {
|
|
45
|
+
import { Injectable } from '@nestjs/common';
|
|
46
|
+
import { SequencesService, RotateByEnum } from '@mbc-cqrs-serverless/sequence';
|
|
47
|
+
import { getUserContext, IInvoke } from '@mbc-cqrs-serverless/core';
|
|
62
48
|
|
|
63
49
|
@Injectable()
|
|
64
50
|
export class InvoiceService {
|
|
65
|
-
constructor(
|
|
66
|
-
|
|
67
|
-
) {
|
|
51
|
+
constructor(private readonly sequencesService: SequencesService) {}
|
|
52
|
+
|
|
53
|
+
async createInvoice(opts: { invokeContext: IInvoke }) {
|
|
54
|
+
const { tenantCode } = getUserContext(opts.invokeContext);
|
|
55
|
+
|
|
56
|
+
const seq = await this.sequencesService.generateSequenceItem(
|
|
57
|
+
{
|
|
58
|
+
tenantCode,
|
|
59
|
+
typeCode: 'INVOICE',
|
|
60
|
+
rotateBy: RotateByEnum.FISCAL_YEARLY,
|
|
61
|
+
},
|
|
62
|
+
opts,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
console.log(seq.no); // 1
|
|
66
|
+
console.log(seq.formattedNo); // "INV-0001" (based on master data format)
|
|
67
|
+
console.log(seq.issuedAt); // Date object
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
const sequence = await this.sequencesService.next('INVOICE');
|
|
71
|
-
return sequence.formattedNo; // Returns: "INV000001"
|
|
69
|
+
return seq;
|
|
72
70
|
}
|
|
73
71
|
}
|
|
74
72
|
```
|
|
75
73
|
|
|
76
|
-
|
|
74
|
+
## API Reference
|
|
75
|
+
|
|
76
|
+
### SequencesService
|
|
77
|
+
|
|
78
|
+
| Method | Description |
|
|
79
|
+
|--------|-------------|
|
|
80
|
+
| `generateSequenceItem(dto, options)` | Generate sequence using master data configuration |
|
|
81
|
+
| `generateSequenceItemWithProvideSetting(dto, options)` | Generate sequence with inline settings |
|
|
82
|
+
|
|
83
|
+
### GenerateFormattedSequenceDto
|
|
84
|
+
|
|
85
|
+
| Property | Type | Required | Description |
|
|
86
|
+
|----------|------|----------|-------------|
|
|
87
|
+
| `tenantCode` | string | Yes | Tenant identifier |
|
|
88
|
+
| `typeCode` | string | Yes | Sequence type (e.g., 'INVOICE', 'ORDER') |
|
|
89
|
+
| `rotateBy` | RotateByEnum | No | Rotation strategy |
|
|
90
|
+
| `date` | Date | No | Date for sequence (default: now) |
|
|
91
|
+
| `prefix` | string | No | Prefix to add before formatted number |
|
|
92
|
+
| `postfix` | string | No | Postfix to add after formatted number |
|
|
93
|
+
| `params` | object | No | Additional parameters (code1-code5) |
|
|
94
|
+
|
|
95
|
+
### RotateByEnum
|
|
96
|
+
|
|
97
|
+
| Value | Description | Example Reset |
|
|
98
|
+
|-------|-------------|---------------|
|
|
99
|
+
| `FISCAL_YEARLY` | Reset on fiscal year start (April 1st in Japan) | Apr 1, 2024 |
|
|
100
|
+
| `YEARLY` | Reset on calendar year | Jan 1, 2024 |
|
|
101
|
+
| `MONTHLY` | Reset each month | First of each month |
|
|
102
|
+
| `DAILY` | Reset each day | Every day |
|
|
103
|
+
| `NONE` | Never reset, continuous increment | Never |
|
|
104
|
+
|
|
105
|
+
### SequenceEntity (Return Type)
|
|
77
106
|
|
|
78
|
-
1. Yearly rotation:
|
|
79
107
|
```typescript
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
108
|
+
{
|
|
109
|
+
id: string; // Unique identifier
|
|
110
|
+
no: number; // Raw sequence number
|
|
111
|
+
formattedNo: string; // Formatted sequence string
|
|
112
|
+
issuedAt: Date; // Timestamp of generation
|
|
113
|
+
}
|
|
86
114
|
```
|
|
87
115
|
|
|
88
|
-
|
|
116
|
+
## Usage Examples
|
|
117
|
+
|
|
118
|
+
### Fiscal Year Rotation (Japan)
|
|
119
|
+
|
|
120
|
+
Sequences reset on April 1st:
|
|
121
|
+
|
|
89
122
|
```typescript
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
123
|
+
const seq = await this.sequencesService.generateSequenceItem(
|
|
124
|
+
{
|
|
125
|
+
tenantCode: 'MBC',
|
|
126
|
+
typeCode: 'INVOICE',
|
|
127
|
+
rotateBy: RotateByEnum.FISCAL_YEARLY,
|
|
128
|
+
},
|
|
129
|
+
opts,
|
|
130
|
+
);
|
|
131
|
+
// FY2024: INV-0001, INV-0002, ...
|
|
132
|
+
// FY2025 (after Apr 1): INV-0001, INV-0002, ...
|
|
96
133
|
```
|
|
97
134
|
|
|
98
|
-
|
|
135
|
+
### Monthly Rotation
|
|
136
|
+
|
|
137
|
+
Sequences reset on the first of each month:
|
|
138
|
+
|
|
99
139
|
```typescript
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
140
|
+
const seq = await this.sequencesService.generateSequenceItem(
|
|
141
|
+
{
|
|
142
|
+
tenantCode: 'MBC',
|
|
143
|
+
typeCode: 'ORDER',
|
|
144
|
+
rotateBy: RotateByEnum.MONTHLY,
|
|
145
|
+
},
|
|
146
|
+
opts,
|
|
147
|
+
);
|
|
148
|
+
// January: ORD-202401-0001, ORD-202401-0002
|
|
149
|
+
// February: ORD-202402-0001, ORD-202402-0002
|
|
106
150
|
```
|
|
107
151
|
|
|
108
|
-
###
|
|
152
|
+
### Daily Rotation
|
|
153
|
+
|
|
154
|
+
Sequences reset every day:
|
|
109
155
|
|
|
110
|
-
1. Define custom format patterns:
|
|
111
156
|
```typescript
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
157
|
+
const seq = await this.sequencesService.generateSequenceItem(
|
|
158
|
+
{
|
|
159
|
+
tenantCode: 'MBC',
|
|
160
|
+
typeCode: 'TICKET',
|
|
161
|
+
rotateBy: RotateByEnum.DAILY,
|
|
162
|
+
},
|
|
163
|
+
opts,
|
|
164
|
+
);
|
|
165
|
+
// Day 1: TKT-20240115-001, TKT-20240115-002
|
|
166
|
+
// Day 2: TKT-20240116-001, TKT-20240116-002
|
|
118
167
|
```
|
|
119
168
|
|
|
120
|
-
|
|
169
|
+
### Hierarchical Sequences
|
|
170
|
+
|
|
171
|
+
Use code1-code5 for hierarchical sequence numbers:
|
|
172
|
+
|
|
121
173
|
```typescript
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return sequence.formattedNo; // Returns: "DOC/2024/TENANT1/0001"
|
|
136
|
-
}
|
|
137
|
-
}
|
|
174
|
+
const seq = await this.sequencesService.generateSequenceItem(
|
|
175
|
+
{
|
|
176
|
+
tenantCode: 'MBC',
|
|
177
|
+
typeCode: 'PRODUCT',
|
|
178
|
+
params: {
|
|
179
|
+
code1: 'ELECTRONICS',
|
|
180
|
+
code2: 'PHONES',
|
|
181
|
+
},
|
|
182
|
+
rotateBy: RotateByEnum.YEARLY,
|
|
183
|
+
},
|
|
184
|
+
opts,
|
|
185
|
+
);
|
|
186
|
+
// Each category has its own sequence: ELECTRONICS-PHONES-0001
|
|
138
187
|
```
|
|
139
188
|
|
|
140
|
-
###
|
|
189
|
+
### Custom Settings (No Master Data)
|
|
141
190
|
|
|
142
|
-
|
|
191
|
+
Provide format settings directly without master data lookup:
|
|
143
192
|
|
|
144
193
|
```typescript
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
)
|
|
157
|
-
);
|
|
158
|
-
return numbers.map(seq => seq.formattedNo);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
194
|
+
const seq = await this.sequencesService.generateSequenceItemWithProvideSetting(
|
|
195
|
+
{
|
|
196
|
+
tenantCode: 'MBC',
|
|
197
|
+
typeCode: 'CUSTOM',
|
|
198
|
+
format: '%%year%%-%%month#:0>2%%-%%no#:0>4%%',
|
|
199
|
+
rotateBy: RotateByEnum.MONTHLY,
|
|
200
|
+
prefix: 'DOC-',
|
|
201
|
+
},
|
|
202
|
+
opts,
|
|
203
|
+
);
|
|
204
|
+
// Result: DOC-2024-01-0001
|
|
161
205
|
```
|
|
162
206
|
|
|
163
|
-
###
|
|
207
|
+
### Format Patterns
|
|
164
208
|
|
|
165
|
-
|
|
166
|
-
import { SequenceError } from '@mbc-cqrs-serverless/sequence';
|
|
209
|
+
Format strings use `%%key%%` syntax with optional padding:
|
|
167
210
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
211
|
+
| Pattern | Output | Description |
|
|
212
|
+
|---------|--------|-------------|
|
|
213
|
+
| `%%no%%` | `1` | Raw number |
|
|
214
|
+
| `%%no#:0>4%%` | `0001` | Zero-padded to 4 digits |
|
|
215
|
+
| `%%year%%` | `2024` | Current year |
|
|
216
|
+
| `%%month%%` | `1` | Current month (1-12) |
|
|
217
|
+
| `%%month#:0>2%%` | `01` | Zero-padded month |
|
|
218
|
+
| `%%day%%` | `15` | Current day |
|
|
219
|
+
| `%%fiscal_year%%` | `71` | Fiscal year number |
|
|
220
|
+
| `%%code1%%` | `DEPT` | Hierarchical code 1 |
|
|
221
|
+
|
|
222
|
+
## Master Data Configuration
|
|
223
|
+
|
|
224
|
+
The `generateSequenceItem` method reads format configuration from master data:
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"pk": "MASTER#MBC",
|
|
229
|
+
"sk": "MASTER_DATA#INVOICE",
|
|
230
|
+
"format": "%%year%%-%%no#:0>4%%",
|
|
231
|
+
"startMonth": 4,
|
|
232
|
+
"registerDate": "2024-04-01"
|
|
174
233
|
}
|
|
175
234
|
```
|
|
176
235
|
|
|
236
|
+
## Concurrent Access Safety
|
|
237
|
+
|
|
238
|
+
All sequence operations use DynamoDB atomic counters, ensuring thread-safe generation:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
// Safe for concurrent requests
|
|
242
|
+
const results = await Promise.all([
|
|
243
|
+
sequencesService.generateSequenceItem({ tenantCode, typeCode: 'ORDER' }, opts),
|
|
244
|
+
sequencesService.generateSequenceItem({ tenantCode, typeCode: 'ORDER' }, opts),
|
|
245
|
+
sequencesService.generateSequenceItem({ tenantCode, typeCode: 'ORDER' }, opts),
|
|
246
|
+
]);
|
|
247
|
+
// Results: [{ no: 1 }, { no: 2 }, { no: 3 }] - guaranteed unique
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Related Packages
|
|
251
|
+
|
|
252
|
+
| Package | Description |
|
|
253
|
+
|---------|-------------|
|
|
254
|
+
| [@mbc-cqrs-serverless/core](https://www.npmjs.com/package/@mbc-cqrs-serverless/core) | Core CQRS framework |
|
|
255
|
+
| [@mbc-cqrs-serverless/master](https://www.npmjs.com/package/@mbc-cqrs-serverless/master) | Master data for sequence formats |
|
|
256
|
+
|
|
177
257
|
## Documentation
|
|
178
258
|
|
|
259
|
+
Full documentation available at [https://mbc-cqrs-serverless.mbc-net.com/](https://mbc-cqrs-serverless.mbc-net.com/)
|
|
179
260
|
|
|
180
|
-
|
|
181
|
-
-
|
|
182
|
-
- Rotation strategies
|
|
183
|
-
- Format customization
|
|
184
|
-
- Usage examples
|
|
185
|
-
- API reference
|
|
261
|
+
- [Sequence Service Guide](https://mbc-cqrs-serverless.mbc-net.com/docs/sequence-service)
|
|
262
|
+
- [Build a Todo App Tutorial](https://mbc-cqrs-serverless.mbc-net.com/docs/build-todo-app)
|
|
186
263
|
|
|
187
264
|
## License
|
|
188
265
|
|
|
189
|
-
Copyright
|
|
190
|
-
|
|
266
|
+
Copyright © 2024-2025, Murakami Business Consulting, Inc. [https://www.mbc-net.com/](https://www.mbc-net.com/)
|
|
267
|
+
|
|
268
|
+
This project is under the [MIT License](../../LICENSE.txt).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mbc-cqrs-serverless/sequence",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.17",
|
|
4
4
|
"description": "Generate increment sequence with time-rotation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mbc",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@mbc-cqrs-serverless/core": "1.0.
|
|
44
|
+
"@mbc-cqrs-serverless/core": "1.0.17"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "1870821803cfb045c9c4d6bc18d513fa2558de1c"
|
|
47
47
|
}
|