Project

General

Profile

Download (3.85 KB) Statistics
| Branch: | Tag: | Revision:

calebasse / calebasse / facturation / noemie.py @ 99a62b84

1
import os
2
from datetime import datetime
3
import time
4
import email
5
from glob import glob
6
from gzip import GzipFile
7
from StringIO import StringIO
8

    
9
from noemie_format import NOEMIE
10
from b2 import b2_transmission_settings
11

    
12
DEFAULT_NOEMIE_DIRECTORY = '/var/lib/calebasse/B2/NOEMIE'
13

    
14
NOEMIE_DIRECTORY = b2_transmission_settings.get('noemie_directory', DEFAULT_NOEMIE_DIRECTORY)
15

    
16
def noemie_output_directory():
17
    if not os.path.isdir(NOEMIE_DIRECTORY):
18
        raise IOError('NOEMIE output directory (%s) is not a directory' % NOEMIE_DIRECTORY)
19
    if not os.access(NOEMIE_DIRECTORY, os.R_OK + os.X_OK):
20
        raise IOError('NOEMIE output directory (%s) is not readable (r-x)' % NOEMIE_DIRECTORY)
21
    return NOEMIE_DIRECTORY
22

    
23

    
24
def noemie_try_gunzip(data):
25
    "gunzip data if it is a gzip stream"
26
    sio = StringIO(data)
27
    gz = GzipFile(fileobj=sio, mode='rb')
28
    try:
29
        data = gz.read()
30
    except IOError:
31
        pass
32
    return data
33

    
34
def noemie_decode(data):
35
    lines = []
36
    entity = ''
37
    while data and entity != '999':
38
        entity = data[:3]
39
        analyzer = NOEMIE.get(entity)
40
        if analyzer is None:
41
            split = data.split('@',1)
42
            if len(split) < 2:
43
                raw, data = data, ''
44
            else:
45
                raw, data = split
46
            lines.append({
47
                'description': 'Error: unknown entity %s' % entity,
48
                'segments': [],
49
                'raw': raw,
50
            })
51
            continue
52
        line = { 'description': analyzer['description'] }
53
        segments = []
54
        index = 0
55
        for anaseg in analyzer.get('segments',[]):
56
            seg = {
57
                'name': anaseg['name'],
58
                }
59
            value = data[index : index+anaseg['size']]
60
            if anaseg.get('values'):
61
                seg['raw'] = value
62
                value = anaseg['values'].get(value)
63
            seg['value'] = value
64
            index += anaseg['size']
65
            segments.append(seg)
66
        line['segments'] = segments
67
        line['raw'] = data[:index]
68
        data = data[index:]
69
        lines.append(line)
70
    return lines
71

    
72

    
73
def noemie_from_mail(name, with_data=True):
74
    filename = os.path.join(noemie_output_directory(), name)
75
    fp = open(filename, 'rb')
76
    try:
77
        mail = email.message_from_file(fp)
78
    except:
79
        fp.close()
80
        return None
81
    fp.close()
82

    
83
    noemie = [part for part in mail.walk() \
84
        if part.get_content_type().lower() == 'application/edi-consent']
85
    if not noemie:
86
        return None
87
    noemie = noemie[0] # only one NOEMIE part per email
88

    
89
    subject = mail.get('Subject')
90
    from_addr = mail.get('From')
91
    to_addr = mail.get('To')
92
    nature = noemie.get('Content-Description')
93
    if with_data:
94
        data = noemie.get_payload()
95
        if 'base64' == noemie.get('Content-Transfer-Encoding').lower():
96
            data = data.decode('base64')
97
        data = noemie_try_gunzip(data)
98
        data = noemie_decode(data)
99

    
100
    filedate = datetime.fromtimestamp(os.stat(filename).st_mtime)
101
    try:
102
        date = email.Utils.parsedate(mail.get('Date', mail.get('Delivery-date')))
103
        if isinstance(date, tuple):
104
            date = datetime.fromtimestamp(time.mktime(date))
105
        else:
106
            date = filedate
107
    except:
108
        date = filedate
109

    
110
    # TODO: try to get HealthCenter from from_addr
111
    result = {
112
            'name': name,
113
            'date': date,
114
            'from': from_addr,
115
            'to': to_addr,
116
            'subject': subject,
117
            'nature': nature,
118
            }
119
    if with_data:
120
        result['data'] = data
121
    return result
122

    
123
def noemie_mails():
124
    mails = []
125
    for filename in glob(os.path.join(noemie_output_directory(), '*')):
126
        mail = noemie_from_mail(os.path.basename(filename), with_data=False)
127
        if mail:
128
            mails.append(mail)
129
    mails.sort(key=lambda x: x['date'], reverse=True)
130
    return mails
(10-10/16)