forked from chilts/node-coupon-code
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcoupon-code.js
More file actions
147 lines (123 loc) · 4.1 KB
/
coupon-code.js
File metadata and controls
147 lines (123 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// --------------------------------------------------------------------------------------------------------------------
//
// coupon-code.js : An implementation of Perl's Algorithm::CouponCode for NodeJS.
//
// Author : Andrew Chilton
// Web : http://www.chilts.org/blog/
// Email : <chilts@appsattic.com>
//
// Copyright (c) : 2011 AppsAttic Ltd
// Web : http://www.appsattic.com/
// License : http://opensource.org/licenses/MIT
//
// --------------------------------------------------------------------------------------------------------------------
// constants
var symbolsStr = '0123456789ABCDEFGHJKLMNPQRTUVWXY';
var symbolsArr = symbolsStr.split('');
var symbolsObj = {};
var i = 0;
symbolsStr.split('').forEach(function(c) {
symbolsObj[c] = i;
i++;
});
// --------------------------------------------------------------------------------------------------------------------
// exports
module.exports.generate = function(opts) {
var parts;
if ( !opts ) {
opts = {};
}
opts.parts = opts.parts || 3;
opts.partLen = opts.partLen || 4; //includes checkdigit
// if we have a plaintext, generate a code from that
if ( opts.plaintext ) {
// not yet implemented
return '';
}
else {
// default to a random code
parts = [];
var data;
var part;
for( var i = 0; i < opts.parts; i++ ) {
data = '';
for (var j=0;j<opts.partLen-1;j++) {
data += randomSymbol();
}
//data = randomSymbol() + randomSymbol() + randomSymbol() + randomSymbol();
part = data + checkDigitAlg1(data, i+1);
parts.push(part);
}
}
return parts.join('-');
};
module.exports.validate = function(opts) {
if ( !opts ) {
return '';
}
// turn the string into a set of options
if ( typeof opts === 'string' ) {
opts = { code : opts, parts : 3 };
}
// default parts to 3
opts.parts = opts.parts || 3;
// if we have been given no code, this is not valid
if ( !opts.code ) {
return '';
}
opts.partLen = opts.partLen || 4;
var partLen = opts.partLen;
var code = opts.code;
// uppercase the code, take out any random chars and replace OIZS with 0125
code = code.toUpperCase();
code = code.replace(/[^0-9A-Z]+/g, '');
code = code.replace(/O/g, '0');
code = code.replace(/I/g, '1');
code = code.replace(/Z/g, '2');
code = code.replace(/S/g, '5');
// split in the different parts
var parts = [];
var tmp = code;
while( tmp.length > 0 ) {
parts.push( tmp.substr(0, partLen) );
tmp = tmp.substr(partLen);
}
console.log(parts);
// make sure we have been given the same number of parts as we are expecting
if ( parts.length !== opts.parts ) {
return '';
}
// validate each part
var part, str, check;
for ( var i = 0; i < parts.length; i++ ) {
part = parts[i];
// check this part has X chars
if ( part.length !== partLen ) {
return '';
}
// split out the data and the check
data = part.substr(0, partLen-1);
check = part.substr(partLen-1, 1);
if ( check !== checkDigitAlg1(data, i+1) ) {
return '';
}
}
// everything looked ok with this code
return parts.join('-');
};
// --------------------------------------------------------------------------------------------------------------------
// internal helpers
function randomSymbol() {
return symbolsArr[parseInt(Math.random() * symbolsArr.length,10)];
}
// returns the checksum character for this (data/part) combination
function checkDigitAlg1(data, check) {
// check's initial value is the part number (e.g. 3 or above)
// loop through the data chars
data.split('').forEach(function(v) {
var k = symbolsObj[v];
check = check * 19 + k;
});
return symbolsArr[ check % 31 ];
}
// --------------------------------------------------------------------------------------------------------------------