~openerp-commiter/openobject-addons/stable-sja-branch

« back to all changes in this revision

Viewing changes to huissier/barcode/usps.py

  • Committer: sja-axelor
  • Date: 2009-10-13 09:52:57 UTC
  • Revision ID: suniljagyasi@gmail.com-20091013095257-8u26ww0r20z9y6ey
add

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
 
3
# All rights reserved.
 
4
#
 
5
# Redistribution and use in source and binary forms, with or without
 
6
# modification, are permitted provided that the following conditions
 
7
# are met:
 
8
# 1. Redistributions of source code must retain the above copyright
 
9
#    notice, this list of conditions and the following disclaimer.
 
10
# 2. Redistributions in binary form must reproduce the above copyright
 
11
#    notice, this list of conditions and the following disclaimer in the
 
12
#    documentation and/or other materials provided with the distribution.
 
13
# 3. All advertising materials mentioning features or use of this software
 
14
#    must display the following acknowledgement:
 
15
#      This product includes software developed by Tyler C. Sarna.
 
16
# 4. Neither the name of the author nor the names of contributors
 
17
#    may be used to endorse or promote products derived from this software
 
18
#    without specific prior written permission.
 
19
#
 
20
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 
21
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
22
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
23
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 
24
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
25
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
26
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
27
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
28
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
29
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
30
# POSSIBILITY OF SUCH DAMAGE.
 
31
#
 
32
 
 
33
from reportlab.lib.units import inch
 
34
from common import Barcode
 
35
import string
 
36
 
 
37
_fim_patterns = {
 
38
    'A' : "||  |  ||",
 
39
    'B' : "| || || |",
 
40
    'C' : "|| | | ||",
 
41
    'D' : "||| | |||",
 
42
    # XXX There is an E.
 
43
    # The below has been seen, but dunno if it is E or not:
 
44
    # 'E' : '|||| ||||'
 
45
}
 
46
 
 
47
_postnet_patterns = {
 
48
    '1' : "...||",    '2' : "..|.|",    '3' : "..||.",    '4' : ".|..|",
 
49
    '5' : ".|.|.",    '6' : ".||..",    '7' : "|...|",    '8' : "|..|.",
 
50
    '9' : "|.|..",    '0' : "||...",    'S' : "|",        
 
51
}
 
52
 
 
53
 
 
54
class FIM(Barcode):
 
55
    """"
 
56
    FIM (Facing ID Marks) encode only one letter.
 
57
    There are currently four defined:
 
58
 
 
59
    A   Courtesy reply mail with pre-printed POSTNET
 
60
    B   Business reply mail without pre-printed POSTNET
 
61
    C   Business reply mail with pre-printed POSTNET
 
62
    D   OCR Readable mail without pre-printed POSTNET
 
63
 
 
64
    Interleaved 2 of 5 is a numeric-only barcode.  It encodes an even
 
65
    number of digits; if an odd number is given, a 0 is prepended.
 
66
 
 
67
    Options that may be passed to constructor:
 
68
 
 
69
        value (single character string from the set A - D. required.):
 
70
            The value to encode.
 
71
   
 
72
        quiet (bool, default 1):
 
73
            Wether to include quiet zones in the symbol.
 
74
            
 
75
    The following may also be passed, but doing so will generate nonstandard
 
76
    symbols which should not be used. This is mainly documented here to
 
77
    show the defaults:
 
78
    
 
79
        height (float, default 5/8 inch):
 
80
            Height of the code. This might legitimately be overriden to make
 
81
            a taller symbol that will 'bleed' off the edge of the paper,
 
82
            leaving 5/8 inch remaining.
 
83
            
 
84
        lquiet (float, default 1/4 inch):
 
85
            Quiet zone size to left of code, if quiet is true.
 
86
            Default is the greater of .25 inch, or .15 times the symbol's
 
87
            length.
 
88
            
 
89
        rquiet (float, default 15/32 inch):
 
90
            Quiet zone size to right left of code, if quiet is true.
 
91
 
 
92
    Sources of information on FIM:
 
93
    
 
94
    USPS Publication 25, A Guide to Business Mail Preparation
 
95
    http://new.usps.com/cpim/ftp/pubs/pub25.pdf
 
96
    """
 
97
    
 
98
    def __init__(self, value='', **args):
 
99
        self.barwidth = inch * (1.0/32.0)
 
100
        self.barspace = inch * (1.0/16.0)
 
101
        self.height = inch * (5.0/8.0)
 
102
        self.rquiet = inch * (0.25)
 
103
        self.lquiet = inch * (15.0/32.0)
 
104
        self.quiet = 0
 
105
 
 
106
        for (k, v) in args.items():
 
107
            setattr(self, k, v)
 
108
 
 
109
        Barcode.__init__(self, value)
 
110
 
 
111
    def validate(self):
 
112
        self.valid = 1
 
113
        self.validated = ''
 
114
        for c in self.value:
 
115
            if c in string.whitespace:
 
116
                continue
 
117
            elif c in "abcdABCD":
 
118
                self.validated = self.validated + string.upper(c)
 
119
            else:
 
120
                self.valid = 0
 
121
 
 
122
        if len(self.validated) != 1:
 
123
            raise ValueError, "Input must be exactly one character"
 
124
 
 
125
        return self.validated
 
126
 
 
127
    def decompose(self):
 
128
        self.decomposed = ''
 
129
        for c in self.encoded:
 
130
            self.decomposed = self.decomposed + _fim_patterns[c]
 
131
 
 
132
        return self.decomposed
 
133
 
 
134
    def computeSize(self):
 
135
        self.width = (len(self.decomposed) - 1) * self.barspace + self.barwidth
 
136
        if self.quiet:
 
137
            self.xo = self.lquiet
 
138
            self.width = self.lquiet + self.width + self.rquiet
 
139
        else:
 
140
            self.xo = 0.0
 
141
 
 
142
    def draw(self):
 
143
        left = self.xo
 
144
        for c in self.decomposed:
 
145
            if c == '|':
 
146
                self.rect(left, 0.0, self.barwidth, self.height)
 
147
            left = left + self.barspace
 
148
 
 
149
 
 
150
class POSTNET(Barcode):
 
151
    """"
 
152
    POSTNET is used in the US to encode "zip codes" (postal codes) on
 
153
    mail. It can encode 5, 9, or 11 digit codes. I've read that it's
 
154
    pointless to do 5 digits, since USPS will just have to re-print
 
155
    them with 9 or 11 digits.
 
156
    
 
157
    Sources of information on POSTNET:
 
158
    
 
159
    USPS Publication 25, A Guide to Business Mail Preparation
 
160
    http://new.usps.com/cpim/ftp/pubs/pub25.pdf
 
161
    """
 
162
    
 
163
    def __init__(self, value='', **args):
 
164
        self.sbarheight = inch * 0.050
 
165
        self.fbarheight = inch * 0.125
 
166
        self.barwide = inch * 0.018
 
167
        self.spacewide = inch * 0.0275
 
168
       
 
169
        for (k, v) in args.items():
 
170
            setattr(self, k, v)
 
171
 
 
172
        Barcode.__init__(self, value)
 
173
 
 
174
    def validate(self):
 
175
        self.validated = ''
 
176
        self.valid = 1
 
177
        count = 0
 
178
        for c in self.value:
 
179
            if c in (string.whitespace + '-'):
 
180
                pass
 
181
            elif c in string.digits:
 
182
                count = count + 1
 
183
                if count == 6:
 
184
                    self.validated = self.validated + '-'
 
185
                self.validated = self.validated + c
 
186
            else:
 
187
                self.valid = 0
 
188
 
 
189
        if len(self.validated) not in [5, 10, 12]:
 
190
            self.valid = 0
 
191
 
 
192
        return self.validated
 
193
 
 
194
    def encode(self):
 
195
        self.encoded = "S"
 
196
        check = 0
 
197
        for c in self.validated:
 
198
            if c in string.digits:
 
199
                self.encoded = self.encoded + c
 
200
                check = check + string.atoi(c)
 
201
            elif c == '-':
 
202
                pass
 
203
            else:
 
204
                raise ValueError, "Invalid character in input"
 
205
        check = (10 - (check % 10)) % 10
 
206
        self.encoded = self.encoded + `check` + 'S'
 
207
        return self.encoded
 
208
        
 
209
    def decompose(self):
 
210
        self.decomposed = ''
 
211
        for c in self.encoded:
 
212
            self.decomposed = self.decomposed + _postnet_patterns[c]
 
213
        return self.decomposed
 
214
 
 
215
    def computeSize(self):
 
216
        self.width = len(self.decomposed) * self.barwide 
 
217
        self.width = self.width + (len(self.decomposed) - 1) * self.spacewide
 
218
        self.height = self.fbarheight
 
219
        self.xo = 0.0
 
220
 
 
221
    def draw(self):
 
222
        sdown = self.fbarheight - self.sbarheight
 
223
        left = self.xo
 
224
        
 
225
        for c in self.decomposed:
 
226
            if c == '.':
 
227
                h = self.sbarheight
 
228
            else:
 
229
                h = self.fbarheight
 
230
            self.rect(left, 0.0, self.barwide, h)
 
231
            left = left + self.barwide + self.spacewide