Passed
Push — master ( c101ad...59898a )
by Guangyu
01:57 queued 12s
created

excelexporters.tenantbill   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 331
Duplicated Lines 11.78 %

Importance

Changes 0
Metric Value
eloc 253
dl 39
loc 331
rs 8.96
c 0
b 0
f 0
wmc 43

2 Functions

Rating   Name   Duplication   Size   Complexity  
F generate_excel() 0 265 38
B export() 39 39 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like excelexporters.tenantbill often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import base64
2
import uuid
3
import os
4
import datetime
5
from openpyxl.chart import (
6
    PieChart,
7
    BarChart,
8
    Reference,
9
)
10
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
11
from decimal import Decimal
12
from openpyxl.drawing.image import Image
13
from openpyxl import Workbook
14
from openpyxl.chart.label import DataLabelList
15
16
17
####################################################################################################################
18
# PROCEDURES
19
# Step 1: Validate the report data
20
# Step 2: Generate excel file
21
# Step 3: Encode the excel file bytes to Base64
22
####################################################################################################################
23
24
25 View Code Duplication
def export(report,
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
26
           name,
27
           reporting_start_datetime_local,
28
           reporting_end_datetime_local,
29
           period_type):
30
    ####################################################################################################################
31
    # Step 1: Validate the report data
32
    ####################################################################################################################
33
    if report is None:
34
        return None
35
    print(report)
36
37
    ####################################################################################################################
38
    # Step 2: Generate excel file from the report data
39
    ####################################################################################################################
40
    filename = generate_excel(report,
41
                              name,
42
                              reporting_start_datetime_local,
43
                              reporting_end_datetime_local,
44
                              period_type)
45
    ####################################################################################################################
46
    # Step 3: Encode the excel file to Base64
47
    ####################################################################################################################
48
    try:
49
        with open(filename, 'rb') as binary_file:
50
            binary_file_data = binary_file.read()
51
    except IOError as ex:
52
        pass
53
54
    # Base64 encode the bytes
55
    base64_encoded_data = base64.b64encode(binary_file_data)
0 ignored issues
show
introduced by
The variable binary_file_data does not seem to be defined for all execution paths.
Loading history...
56
    # get the Base64 encoded data using human-readable characters.
57
    base64_message = base64_encoded_data.decode('utf-8')
58
    # delete the file from server
59
    try:
60
        os.remove(filename)
61
    except NotImplementedError as ex:
62
        pass
63
    return base64_message
64
65
66
def generate_excel(report,
67
                   name,
68
                   reporting_start_datetime_local,
69
                   reporting_end_datetime_local,
70
                   period_type):
71
    wb = Workbook()
72
    ws = wb.active
73
74
    # Row height
75
    for i in range(1, 11 + 1):
76
        ws.row_dimensions[i].height = 0.1
77
    ws.row_dimensions[12].height = 45.0
78
    ws.row_dimensions[13].height = 10.0
79
    ws.merge_cells('B13:I13')
80
    for i in range(14, 23 + 1):
81
        ws.row_dimensions[i].height = 0.1
82
    ws.row_dimensions[24].height = 30.0
83
    ws.row_dimensions[25].height = 10.0
84
    ws.merge_cells('B25:I25')
85
    for i in range(26, 35 + 1):
86
        ws.row_dimensions[i].height = 0.1
87
    for i in range(36, 41 + 1):
88
        ws.row_dimensions[i].height = 30.0
89
    ws.row_dimensions[42].height = 10.0
90
    ws.merge_cells('B42:I42')
91
    for i in range(43, 52 + 1):
92
        ws.row_dimensions[i].height = 0.1
93
94
    # Col width
95
    ws.column_dimensions['A'].width = 1.5
96
    for i in range(ord('B'), ord('J')):
97
        ws.column_dimensions[chr(i)].width = 17
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable chr does not seem to be defined.
Loading history...
98
    ws.column_dimensions['J'].width = 1.5
99
    ws.column_dimensions['E'].width = 14
100
    ws.column_dimensions['F'].width = 14
101
102
    # merge cell
103
    ws.merge_cells('C12:H12')
104
105
    ws.merge_cells('C24:I24')
106
107
    for i in range(36, 41 + 1):
108
        ws.merge_cells('C{}:D{}'.format(i, i))
109
        ws.merge_cells('E{}:F{}'.format(i, i))
110
        ws.merge_cells('H{}:I{}'.format(i, i))
111
112
    # Font
113
    notice_font = Font(name='宋体', size=25, bold=True)
114
    name_font = Font(name='Constantia', size=14, bold=True)
115
    title_font = Font(name='宋体', size=14, bold=True)
116
    data_font = Font(name='Franklin Gothic Book', size=11)
117
118
    table_fill = PatternFill(fill_type='solid', fgColor='1F497D')
119
    f_border = Border(left=Side(border_style='medium', color='00000000'),
120
                      right=Side(border_style='medium', color='00000000'),
121
                      bottom=Side(border_style='medium', color='00000000'),
122
                      top=Side(border_style='medium', color='00000000')
123
                      )
124
    b_border = Border(
125
        bottom=Side(border_style='medium', color='00000000'),
126
    )
127
128
    b_c_alignment = Alignment(vertical='bottom',
129
                              horizontal='center',
130
                              text_rotation=0,
131
                              wrap_text=False,
132
                              shrink_to_fit=False,
133
                              indent=0)
134
    c_c_alignment = Alignment(vertical='center',
135
                              horizontal='center',
136
                              text_rotation=0,
137
                              wrap_text=False,
138
                              shrink_to_fit=False,
139
                              indent=0)
140
    b_r_alignment = Alignment(vertical='bottom',
141
                              horizontal='right',
142
                              text_rotation=0,
143
                              wrap_text=False,
144
                              shrink_to_fit=False,
145
                              indent=0)
146
    c_r_alignment = Alignment(vertical='bottom',
147
                              horizontal='center',
148
                              text_rotation=0,
149
                              wrap_text=False,
150
                              shrink_to_fit=False,
151
                              indent=0)
152
    b_l_alignment = Alignment(vertical='bottom',
153
                              horizontal='left',
154
                              text_rotation=0,
155
                              wrap_text=False,
156
                              shrink_to_fit=False,
157
                              indent=0)
158
159
    ws['C12'].font = notice_font
160
    ws['C12'].alignment = c_c_alignment
161
    ws['C12'] = '付款通知书'
162
163
    # img
164
    img = Image("excelexporters/myemslogo.png")
165
    img.width = 160
166
    img.height = 160
167
    ws.add_image(img, 'I12')
168
169
    has_lease_number_data_flag = True
170
    if "tenant" not in report.keys() or \
171
            report['tenant'] is None or \
172
            'lease_number' not in report['tenant'].keys() or \
173
            report['tenant']['lease_number'] is None:
174
        has_lease_number_data_flag = False
175
        ws.row_dimensions[24].height = 0.1
176
177
    if has_lease_number_data_flag:
178
        ws['B24'].font = name_font
179
        ws['B24'].alignment = b_r_alignment
180
        ws['B24'] = '租赁合同号码:'
181
        ws['C24'].alignment = b_l_alignment
182
        ws['C24'].font = name_font
183
        ws['C24'] = report['tenant']['lease_number']
184
185
    has_tenant_data_flag = True
186
    if "tenant" not in report.keys() or \
187
            report['tenant'] is None:
188
        has_tenant_data_flag = False
189
        for i in range(36, 41 + 1):
190
            ws.row_dimensions[i].height = 0.1
191
192
    if has_tenant_data_flag:
193
        report_tenant_data = report['tenant']
194
        for i in range(36, 41 + 1):
195
            ws['C' + str(i)].alignment = b_l_alignment
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable str does not seem to be defined.
Loading history...
196
            ws['C' + str(i)].font = name_font
197
198
        ws['C36'] = report_tenant_data['name']
199
        ws.merge_cells('E36:I36')
200
201
        ws['C37'] = report_tenant_data['rooms']
202
203
        ws['C38'] = report_tenant_data['floors']
204
205
        ws['C39'] = report_tenant_data['buildings']
206
207
        ws['C40'] = report_tenant_data['email']
208
209
        ws['C41'] = report_tenant_data['phone']
210
211
        for i in range(36, 41 + 1):
212
            ws['G' + str(i)].alignment = b_r_alignment
213
            ws['G' + str(i)].font = name_font
214
            ws['H' + str(i)].alignment = b_l_alignment
215
            ws['H' + str(i)].font = name_font
216
217
        ws['G37'] = '账单号码:'
218
        ws['G38'] = '租赁合同号码:'
219
        ws['G39'] = '账单日期:'
220
        ws['G40'] = '付款到期日:'
221
        ws['G41'] = '应付款金额:'
222
223
        # Simulated data
224
        ws['H37'] = ''
225
        ws['H38'] = report_tenant_data['lease_number']
226
        ws['H39'] = datetime.datetime.strptime(reporting_start_datetime_local, '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d')
227
        ws['H40'] = datetime.datetime.strptime(reporting_end_datetime_local, '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d')
228
        ws['H41'] = report['reporting_period']['currency_unit'] + \
229
            str(round(report['reporting_period']['total_cost']
230
                      if 'reporting_period' in report.keys() and 'total_cost' in report['reporting_period'].keys()
231
                and report['reporting_period']['total_cost'] is not None
232
                      else 0, 2))
233
234
    has_reporting_period_data_flag = True
235
236
    if 'reporting_period' not in report.keys() \
237
            or report['reporting_period'] is None:
238
        has_reporting_period_data_flag = False
239
240
    if has_reporting_period_data_flag:
241
        ws.row_dimensions[53].height = 30.0
242
        for i in range(ord('B'), ord('J')):
243
            ws[chr(i) + '53'].fill = table_fill
244
            ws[chr(i) + '53'].font = title_font
245
            ws[chr(i) + '53'].alignment = c_c_alignment
246
            ws[chr(i) + '53'].border = f_border
247
248
        ws['B53'] = '能耗分类'
249
        ws['C53'] = '结算期开始日期'
250
        ws['D53'] = '结算期结束日期'
251
        ws['E53'] = '数量'
252
        ws['F53'] = '单位'
253
        ws['G53'] = '金额'
254
        ws['H53'] = '税率'
255
        ws['I53'] = '税额'
256
257
        reporting_period_data = report['reporting_period']
258
        names = reporting_period_data['names']
259
        ca_len = len(names) if names is not None else 0
260
261
        for i in range(54, 54 + ca_len):
262
            ws.row_dimensions[i].height = 30.0
263
            for j in range(ord('B'), ord('J')):
264
                ws[chr(j) + str(i)].font = title_font
265
                ws[chr(j) + str(i)].alignment = c_c_alignment
266
                ws[chr(j) + str(i)].border = f_border
267
268
                if chr(j) == 'B':
269
                    ws[chr(j) + str(i)] = reporting_period_data['names'][i - 54]
270
                elif chr(j) == 'C':
271
                    ws[chr(j) + str(i)] = datetime.datetime.strptime(reporting_start_datetime_local,
272
                                                                     '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d')
273
                elif chr(j) == 'D':
274
                    ws[chr(j) + str(i)] = datetime.datetime.strptime(reporting_end_datetime_local,
275
                                                                     '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d')
276
                elif chr(j) == 'E':
277
                    ws[chr(j) + str(i)] = round(reporting_period_data['subtotals_input'][i - 54], 3)
278
                elif chr(j) == 'F':
279
                    ws[chr(j) + str(i)] = reporting_period_data['units'][i - 54]
280
                elif chr(j) == 'G':
281
                    ws[chr(j) + str(i)] = round(reporting_period_data['subtotals_cost'][i - 54], 2)
282
                elif chr(j) == 'H':
283
                    # Simulated data
284
                    ws[chr(j) + str(i)] = 0
285
                elif chr(j) == 'I':
286
                    # Simulated data
287
                    ws[chr(j) + str(i)] = 0
288
289
        ws.row_dimensions[54 + ca_len].height = 10.0
290
        ws.merge_cells('B{}:H{}'.format((54 + ca_len), (54 + ca_len)))
291
292
        current_row_number = 54 + ca_len + 1
293
        for i in range(current_row_number, current_row_number + 3):
294
            ws.row_dimensions[i].height = 30.0
295
            ws['B' + str(i)].alignment = b_r_alignment
296
            ws['B' + str(i)].font = name_font
297
            ws['H' + str(i)].alignment = b_l_alignment
298
            ws['H' + str(i)].font = name_font
299
            ws.merge_cells('B{}:G{}'.format(i, i))
300
            ws.merge_cells('H{}:I{}'.format(i, i))
301
302
        ws['B' + str(current_row_number)] = '小计:'
303
        ws['H' + str(current_row_number)] = report['reporting_period']['currency_unit'] + str(
304
            round(report['reporting_period']['total_cost']
305
                  if 'reporting_period' in report.keys() and 'total_cost' in report['reporting_period'].keys()
306
                     and report['reporting_period']['total_cost'] is not None
307
                  else 0, 2))
308
309
        current_row_number += 1
310
311
        # Simulated data
312
        taxes = Decimal(0.00)
313
314
        ws['B' + str(current_row_number)] = '增值税销项税金:'
315
        ws['H' + str(current_row_number)] = report['reporting_period']['currency_unit'] + str(round(taxes, 2))
316
317
        current_row_number += 1
318
319
        ws['B' + str(current_row_number)] = '应付金额合计:'
320
        ws['H' + str(current_row_number)] = report['reporting_period']['currency_unit'] + str(
321
            round(report['reporting_period']['total_cost'] + taxes
322
                  if 'reporting_period' in report.keys()
323
                     and 'total_cost' in report['reporting_period'].keys()
324
                     and report['reporting_period']['total_cost'] is not None
325
                  else 0 + taxes, 2))
326
327
    filename = str(uuid.uuid4()) + '.xlsx'
328
    wb.save(filename)
329
330
    return filename
331