Merge lp:~julie-w/unifield-server/US-5224 into lp:unifield-server
- US-5224
- Merge into trunk
Proposed by
jftempo
Status: | Merged |
---|---|
Merged at revision: | 5231 |
Proposed branch: | lp:~julie-w/unifield-server/US-5224 |
Merge into: | lp:unifield-server |
Diff against target: |
301 lines (+75/-107) 5 files modified
bin/addons/analytic/analytic.py (+0/-7) bin/addons/analytic_override/analytic_account.py (+51/-55) bin/addons/base/ir/ir_translation.py (+17/-12) bin/addons/msf_instance/add_instance.py (+0/-30) bin/addons/msf_profile/i18n/fr_MF.po (+7/-3) |
To merge this branch: | bzr merge lp:~julie-w/unifield-server/US-5224 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email:
|
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/addons/analytic/analytic.py' | |||
2 | --- bin/addons/analytic/analytic.py 2018-04-03 10:18:51 +0000 | |||
3 | +++ bin/addons/analytic/analytic.py 2019-02-06 10:02:24 +0000 | |||
4 | @@ -193,13 +193,6 @@ | |||
5 | 193 | (check_currency, 'Error! The currency has to be the same as the currency of the selected company', ['currency_id', 'company_id']), | 193 | (check_currency, 'Error! The currency has to be the same as the currency of the selected company', ['currency_id', 'company_id']), |
6 | 194 | ] | 194 | ] |
7 | 195 | 195 | ||
8 | 196 | def copy(self, cr, uid, id, default=None, context=None): | ||
9 | 197 | if not default: | ||
10 | 198 | default = {} | ||
11 | 199 | default['code'] = False | ||
12 | 200 | default['line_ids'] = [] | ||
13 | 201 | return super(account_analytic_account, self).copy(cr, uid, id, default, context=context) | ||
14 | 202 | |||
15 | 203 | def on_change_company(self, cr, uid, id, company_id): | 196 | def on_change_company(self, cr, uid, id, company_id): |
16 | 204 | if not company_id: | 197 | if not company_id: |
17 | 205 | return {} | 198 | return {} |
18 | 206 | 199 | ||
19 | === modified file 'bin/addons/analytic_override/analytic_account.py' | |||
20 | --- bin/addons/analytic_override/analytic_account.py 2018-04-18 08:17:23 +0000 | |||
21 | +++ bin/addons/analytic_override/analytic_account.py 2019-02-06 10:02:24 +0000 | |||
22 | @@ -235,14 +235,12 @@ | |||
23 | 235 | 'for_fx_gain_loss': lambda *a: False, | 235 | 'for_fx_gain_loss': lambda *a: False, |
24 | 236 | } | 236 | } |
25 | 237 | 237 | ||
27 | 238 | def _check_unicity(self, cr, uid, ids, context=None): | 238 | def _check_code_unicity(self, cr, uid, ids, context=None): |
28 | 239 | if not context: | 239 | if not context: |
29 | 240 | context = {} | 240 | context = {} |
31 | 241 | for account in self.read(cr, uid, ids, ['category', 'name', 'code'], context=context): | 241 | for account in self.read(cr, uid, ids, ['category', 'code'], context=context): |
32 | 242 | bad_ids = self.search(cr, uid, | 242 | bad_ids = self.search(cr, uid, |
33 | 243 | [('category', '=', account.get('category', '')), | 243 | [('category', '=', account.get('category', '')), |
34 | 244 | ('|'), | ||
35 | 245 | ('name', '=ilike', account.get('name', '')), | ||
36 | 246 | ('code', '=ilike', account.get('code', ''))], | 244 | ('code', '=ilike', account.get('code', ''))], |
37 | 247 | order='NO_ORDER', limit=2) | 245 | order='NO_ORDER', limit=2) |
38 | 248 | if len(bad_ids) and len(bad_ids) > 1: | 246 | if len(bad_ids) and len(bad_ids) > 1: |
39 | @@ -291,7 +289,7 @@ | |||
40 | 291 | return True | 289 | return True |
41 | 292 | 290 | ||
42 | 293 | _constraints = [ | 291 | _constraints = [ |
44 | 294 | (_check_unicity, 'You cannot have the same code or name between analytic accounts in the same category!', ['code', 'name', 'category']), | 292 | (_check_code_unicity, 'You cannot have the same code between analytic accounts in the same category!', ['code', 'category']), |
45 | 295 | (_check_gain_loss_account_unicity, 'You can only have one account used for FX gain/loss!', ['for_fx_gain_loss']), | 293 | (_check_gain_loss_account_unicity, 'You can only have one account used for FX gain/loss!', ['for_fx_gain_loss']), |
46 | 296 | (_check_gain_loss_account_type, 'You have to use a Normal account type and Cost Center category for FX gain/loss!', ['for_fx_gain_loss']), | 294 | (_check_gain_loss_account_type, 'You have to use a Normal account type and Cost Center category for FX gain/loss!', ['for_fx_gain_loss']), |
47 | 297 | (_check_default_destination, "You can't delete an account which has this destination as default", []), | 295 | (_check_default_destination, "You can't delete an account which has this destination as default", []), |
48 | @@ -390,37 +388,62 @@ | |||
49 | 390 | # validate that activation date | 388 | # validate that activation date |
50 | 391 | raise osv.except_osv(_('Warning !'), _('Activation date must be lower than inactivation date!')) | 389 | raise osv.except_osv(_('Warning !'), _('Activation date must be lower than inactivation date!')) |
51 | 392 | 390 | ||
52 | 391 | def copy_translations(self, cr, uid, old_id, new_id, context=None): | ||
53 | 392 | """ | ||
54 | 393 | Don't copy translations when duplicating an analytic account, i.e. we will have "name (copy)" in all languages | ||
55 | 394 | """ | ||
56 | 395 | return True | ||
57 | 396 | |||
58 | 393 | def copy(self, cr, uid, a_id, default=None, context=None, done_list=[], local=False): | 397 | def copy(self, cr, uid, a_id, default=None, context=None, done_list=[], local=False): |
59 | 398 | if context is None: | ||
60 | 399 | context = {} | ||
61 | 394 | account = self.browse(cr, uid, a_id, context=context) | 400 | account = self.browse(cr, uid, a_id, context=context) |
62 | 395 | if not default: | 401 | if not default: |
63 | 396 | default = {} | 402 | default = {} |
64 | 397 | default = default.copy() | 403 | default = default.copy() |
65 | 398 | name = '%s(copy)' % account['name'] or '' | 404 | name = '%s(copy)' % account['name'] or '' |
67 | 399 | default['code'] = (account['code'] or '') + '(copy)' | 405 | code = '%s(copy)' % account['code'] or '' |
68 | 400 | default['name'] = name | 406 | default['name'] = name |
69 | 407 | default['code'] = code | ||
70 | 401 | default['child_ids'] = [] # do not copy the child_ids | 408 | default['child_ids'] = [] # do not copy the child_ids |
71 | 402 | default['tuple_destination_summary'] = [] | 409 | default['tuple_destination_summary'] = [] |
82 | 403 | # code is deleted in copy method in addons | 410 | default['line_ids'] = [] |
83 | 404 | new_id = super(analytic_account, self).copy(cr, uid, a_id, default, context=context) | 411 | return super(analytic_account, self).copy(cr, uid, a_id, default, context=context) |
84 | 405 | # UFTP-83: Add name + context (very important) in order the translation to not display wrong element. This is because context is missing (wrong language) | 412 | |
85 | 406 | self.write(cr, uid, new_id, {'name': name,'code': '%s(copy)' % (account['code'] or '')}, context=context) | 413 | def _check_name_unicity(self, cr, uid, ids, context=None): |
86 | 407 | trans_obj = self.pool.get('ir.translation') | 414 | """ |
87 | 408 | trans_ids = trans_obj.search(cr, uid, [('name', '=', | 415 | Raises an error if the name chosen is already used by an analytic account of the same category |
88 | 409 | 'account.analytic.account,name'), ('res_id', '=', new_id),], | 416 | """ |
89 | 410 | order='NO_ORDER') | 417 | if context is None: |
90 | 411 | trans_obj.unlink(cr, uid, trans_ids) | 418 | context = {} |
91 | 412 | return new_id | 419 | # no check at sync time (note that there may be some accounts with duplicated names created before US-5224) |
92 | 420 | if not context.get('sync_update_execution', False): | ||
93 | 421 | if isinstance(ids, (int, long)): | ||
94 | 422 | ids = [ids] | ||
95 | 423 | for analytic_acc in self.read(cr, uid, ids, ['category', 'name'], context=context): | ||
96 | 424 | dom = [('category', '=', analytic_acc.get('category', '')), | ||
97 | 425 | ('name', '=ilike', analytic_acc.get('name', '')), | ||
98 | 426 | ('id', '!=', analytic_acc.get('id'))] | ||
99 | 427 | if self.search_exist(cr, uid, dom, context=context): | ||
100 | 428 | ir_trans = self.pool.get('ir.translation') | ||
101 | 429 | trans_ids = ir_trans.search(cr, uid, [('res_id', 'in', ids), ('name', '=', 'account.analytic.account,name')], context=context) | ||
102 | 430 | if trans_ids: | ||
103 | 431 | ir_trans.clear_transid(cr, uid, trans_ids, context=context) | ||
104 | 432 | raise osv.except_osv(_('Warning !'), _('You cannot have the same name between analytic accounts in the same category!')) | ||
105 | 433 | return True | ||
106 | 413 | 434 | ||
107 | 414 | def create(self, cr, uid, vals, context=None): | 435 | def create(self, cr, uid, vals, context=None): |
108 | 415 | """ | 436 | """ |
109 | 416 | Some verifications before analytic account creation | 437 | Some verifications before analytic account creation |
110 | 417 | """ | 438 | """ |
111 | 439 | if context is None: | ||
112 | 440 | context = {} | ||
113 | 441 | # Check that instance_id is filled in for FP | ||
114 | 442 | if context.get('from_web', False) or context.get('from_import_menu', False): | ||
115 | 443 | self.check_fp(cr, uid, vals, to_update=True, context=context) | ||
116 | 418 | self._check_date(vals) | 444 | self._check_date(vals) |
117 | 419 | self.set_funding_pool_parent(cr, uid, vals) | 445 | self.set_funding_pool_parent(cr, uid, vals) |
118 | 420 | vals = self.remove_inappropriate_links(vals, context=context) | 446 | vals = self.remove_inappropriate_links(vals, context=context) |
119 | 421 | if context is None: | ||
120 | 422 | context = {} | ||
121 | 423 | |||
122 | 424 | # for auto instance creation, fx gain has been stored, need HQ sync + instance sync to get CC | 447 | # for auto instance creation, fx gain has been stored, need HQ sync + instance sync to get CC |
123 | 425 | if context.get('sync_update_execution') and vals.get('code') and vals.get('category') == 'OC': | 448 | if context.get('sync_update_execution') and vals.get('code') and vals.get('category') == 'OC': |
124 | 426 | param = self.pool.get('ir.config_parameter') | 449 | param = self.pool.get('ir.config_parameter') |
125 | @@ -428,7 +451,9 @@ | |||
126 | 428 | if init_cc_fx_gain and vals.get('code') == init_cc_fx_gain: | 451 | if init_cc_fx_gain and vals.get('code') == init_cc_fx_gain: |
127 | 429 | vals['for_fx_gain_loss'] = True | 452 | vals['for_fx_gain_loss'] = True |
128 | 430 | param.set_param(cr, 1, 'INIT_CC_FX_GAIN', '') | 453 | param.set_param(cr, 1, 'INIT_CC_FX_GAIN', '') |
130 | 431 | return super(analytic_account, self).create(cr, uid, vals, context=context) | 454 | ids = super(analytic_account, self).create(cr, uid, vals, context=context) |
131 | 455 | self._check_name_unicity(cr, uid, ids, context=context) | ||
132 | 456 | return ids | ||
133 | 432 | 457 | ||
134 | 433 | def write(self, cr, uid, ids, vals, context=None): | 458 | def write(self, cr, uid, ids, vals, context=None): |
135 | 434 | """ | 459 | """ |
136 | @@ -438,47 +463,18 @@ | |||
137 | 438 | return True | 463 | return True |
138 | 439 | if context is None: | 464 | if context is None: |
139 | 440 | context = {} | 465 | context = {} |
140 | 466 | # US-166: Ids needs to always be a list | ||
141 | 441 | if isinstance(ids, (int, long)): | 467 | if isinstance(ids, (int, long)): |
142 | 442 | ids = [ids] | 468 | ids = [ids] |
143 | 443 | self._check_date(vals) | 469 | self._check_date(vals) |
144 | 444 | self.set_funding_pool_parent(cr, uid, vals) | 470 | self.set_funding_pool_parent(cr, uid, vals) |
145 | 445 | vals = self.remove_inappropriate_links(vals, context=context) | 471 | vals = self.remove_inappropriate_links(vals, context=context) |
146 | 446 | |||
147 | 447 | ###### US-113: I have moved the block that sql updates on the name causing the problem of sync (touched not update). The block is now moved to after the write | ||
148 | 448 | |||
149 | 449 | # US-399: First read the value from the database, and check if vals contains any of these values, use them for unicity check | ||
150 | 450 | new_values = self.read(cr, uid, ids, ['category', 'name', 'code'], context=context)[0] | ||
151 | 451 | if vals.get('name', False): | ||
152 | 452 | new_values['name'] = vals.get('name') | ||
153 | 453 | if vals.get('category', False): | ||
154 | 454 | new_values['category'] = vals.get('category') | ||
155 | 455 | if vals.get('code', False): | ||
156 | 456 | new_values['code'] = vals.get('code') | ||
157 | 457 | |||
158 | 458 | ###################################################### | ||
159 | 459 | # US-399: Now perform the check unicity manually! | ||
160 | 460 | bad_ids = self.search(cr, uid, | ||
161 | 461 | [('category', '=', new_values.get('category', '')), | ||
162 | 462 | ('|'), | ||
163 | 463 | ('name', '=ilike', new_values.get('name', '')), | ||
164 | 464 | ('code', '=ilike', new_values.get('code', ''))], | ||
165 | 465 | order='NO_ORDER', limit=2) | ||
166 | 466 | if len(bad_ids) and len(bad_ids) > 1: | ||
167 | 467 | raise osv.except_osv(_('Warning !'), _('You cannot have the same code or name between analytic accounts in the same category!')) | ||
168 | 468 | ###################################################### | ||
169 | 469 | |||
170 | 470 | res = super(analytic_account, self).write(cr, uid, ids, vals, context=context) | 472 | res = super(analytic_account, self).write(cr, uid, ids, vals, context=context) |
182 | 471 | # UFTP-83: Error after duplication, the _constraints is not called with right params. So the _check_unicity gets wrong. | 473 | if context.get('from_web', False) or context.get('from_import_menu', False): |
183 | 472 | if vals.get('name', False): | 474 | cat_instance = self.read(cr, uid, ids, ['category', 'instance_id'], context=context)[0] |
184 | 473 | cr.execute('UPDATE account_analytic_account SET name = %s WHERE id IN %s', (vals.get('name'), tuple(ids))) | 475 | if cat_instance: |
185 | 474 | # UFTP-83: Use name as SRC value for translations (to be done after WRITE()) | 476 | self.check_fp(cr, uid, cat_instance, context=context) |
186 | 475 | if vals.get('name', False): | 477 | self._check_name_unicity(cr, uid, ids, context=context) |
176 | 476 | trans_obj = self.pool.get('ir.translation') | ||
177 | 477 | trans_ids = trans_obj.search(cr, uid, [('name', '=', | ||
178 | 478 | 'account.analytic.account,name'), ('res_id', 'in', ids)], | ||
179 | 479 | order='NO_ORDER') | ||
180 | 480 | if trans_ids: | ||
181 | 481 | cr.execute('UPDATE ir_translation SET src = %s WHERE id IN %s', (vals.get('name'), tuple(trans_ids))) | ||
187 | 482 | return res | 478 | return res |
188 | 483 | 479 | ||
189 | 484 | def unlink(self, cr, uid, ids, context=None): | 480 | def unlink(self, cr, uid, ids, context=None): |
190 | 485 | 481 | ||
191 | === modified file 'bin/addons/base/ir/ir_translation.py' | |||
192 | --- bin/addons/base/ir/ir_translation.py 2018-03-28 08:50:44 +0000 | |||
193 | +++ bin/addons/base/ir/ir_translation.py 2019-02-06 10:02:24 +0000 | |||
194 | @@ -251,12 +251,7 @@ | |||
195 | 251 | 251 | ||
196 | 252 | ids = super(ir_translation, self).create(cursor, user, vals, context=context) | 252 | ids = super(ir_translation, self).create(cursor, user, vals, context=context) |
197 | 253 | if clear: | 253 | if clear: |
204 | 254 | for trans_obj in self.read(cursor, user, [ids], ['name','type','res_id','src','lang'], context=context): | 254 | self.clear_transid(cursor, user, ids, context=context) |
199 | 255 | self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) | ||
200 | 256 | self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) | ||
201 | 257 | self._get_ids_dict.clear_cache(cursor.dbname, user, | ||
202 | 258 | trans_obj['name'], trans_obj['type'], | ||
203 | 259 | trans_obj['lang'], [trans_obj['res_id']]) | ||
205 | 260 | return ids | 255 | return ids |
206 | 261 | 256 | ||
207 | 262 | def write(self, cursor, user, ids, vals, clear=True, context=None): | 257 | def write(self, cursor, user, ids, vals, clear=True, context=None): |
208 | @@ -287,14 +282,24 @@ | |||
209 | 287 | result = super(ir_translation, self).write(cursor, user, ids, vals, context=context) | 282 | result = super(ir_translation, self).write(cursor, user, ids, vals, context=context) |
210 | 288 | 283 | ||
211 | 289 | if clear: | 284 | if clear: |
218 | 290 | for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context): | 285 | self.clear_transid(cursor, user, ids, context=context) |
213 | 291 | self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) | ||
214 | 292 | self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) | ||
215 | 293 | self._get_ids_dict.clear_cache(cursor.dbname, user, | ||
216 | 294 | trans_obj['name'], trans_obj['type'], | ||
217 | 295 | trans_obj['lang'], [trans_obj['res_id']]) | ||
219 | 296 | return result | 286 | return result |
220 | 297 | 287 | ||
221 | 288 | def clear_transid(self, cr, uid, ids, context=None): | ||
222 | 289 | """ | ||
223 | 290 | Clears the translation cache | ||
224 | 291 | """ | ||
225 | 292 | if context is None: | ||
226 | 293 | context = {} | ||
227 | 294 | if isinstance(ids, (int, long)): | ||
228 | 295 | ids = [ids] | ||
229 | 296 | |||
230 | 297 | for trans_obj in self.read(cr, uid, ids, ['name','type','res_id','src','lang'], context=context): | ||
231 | 298 | self._get_source.clear_cache(cr.dbname, uid, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) | ||
232 | 299 | self._get_ids.clear_cache(cr.dbname, uid, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) | ||
233 | 300 | self._get_ids_dict.clear_cache(cr.dbname, uid, trans_obj['name'], trans_obj['type'],trans_obj['lang'], [trans_obj['res_id']]) | ||
234 | 301 | return True | ||
235 | 302 | |||
236 | 298 | def unlink(self, cursor, user, ids, clear=True, context=None): | 303 | def unlink(self, cursor, user, ids, clear=True, context=None): |
237 | 299 | if context is None: | 304 | if context is None: |
238 | 300 | context = {} | 305 | context = {} |
239 | 301 | 306 | ||
240 | === modified file 'bin/addons/msf_instance/add_instance.py' | |||
241 | --- bin/addons/msf_instance/add_instance.py 2018-11-15 17:16:13 +0000 | |||
242 | +++ bin/addons/msf_instance/add_instance.py 2019-02-06 10:02:24 +0000 | |||
243 | @@ -598,36 +598,6 @@ | |||
244 | 598 | raise osv.except_osv(_('Warning'), _('Funding Pools must have a Coordination Proprietary Instance.')) | 598 | raise osv.except_osv(_('Warning'), _('Funding Pools must have a Coordination Proprietary Instance.')) |
245 | 599 | return True | 599 | return True |
246 | 600 | 600 | ||
247 | 601 | def create(self, cr, uid, vals, context=None): | ||
248 | 602 | """ | ||
249 | 603 | Check FPs | ||
250 | 604 | """ | ||
251 | 605 | if context is None: | ||
252 | 606 | context = {} | ||
253 | 607 | # Check that instance_id is filled in for FP | ||
254 | 608 | if context.get('from_web', False) or context.get('from_import_menu', False): | ||
255 | 609 | self.check_fp(cr, uid, vals, to_update=True, context=context) | ||
256 | 610 | return super(account_analytic_account, self).create(cr, uid, vals, context=context) | ||
257 | 611 | |||
258 | 612 | def write(self, cr, uid, ids, vals, context=None): | ||
259 | 613 | """ | ||
260 | 614 | Check FPs | ||
261 | 615 | """ | ||
262 | 616 | if not ids: | ||
263 | 617 | return True | ||
264 | 618 | if context is None: | ||
265 | 619 | context = {} | ||
266 | 620 | |||
267 | 621 | # US-166: Ids needs to be always a list | ||
268 | 622 | if isinstance(ids, (int, long)): | ||
269 | 623 | ids = [ids] | ||
270 | 624 | |||
271 | 625 | res = super(account_analytic_account, self).write(cr, uid, ids, vals, context=context) | ||
272 | 626 | if context.get('from_web', False) or context.get('from_import_menu', False): | ||
273 | 627 | cat_instance = self.read(cr, uid, ids, ['category', 'instance_id'], context=context)[0] | ||
274 | 628 | if cat_instance: | ||
275 | 629 | self.check_fp(cr, uid, cat_instance, context=context) | ||
276 | 630 | return res | ||
277 | 631 | 601 | ||
278 | 632 | account_analytic_account() | 602 | account_analytic_account() |
279 | 633 | 603 | ||
280 | 634 | 604 | ||
281 | === modified file 'bin/addons/msf_profile/i18n/fr_MF.po' | |||
282 | --- bin/addons/msf_profile/i18n/fr_MF.po 2019-01-30 13:17:55 +0000 | |||
283 | +++ bin/addons/msf_profile/i18n/fr_MF.po 2019-02-06 10:02:24 +0000 | |||
284 | @@ -63940,10 +63940,14 @@ | |||
285 | 63940 | #: constraint:account.analytic.account:0 | 63940 | #: constraint:account.analytic.account:0 |
286 | 63941 | #: constraint:account.analytic.account:0 | 63941 | #: constraint:account.analytic.account:0 |
287 | 63942 | #: constraint:account.analytic.account:0 | 63942 | #: constraint:account.analytic.account:0 |
289 | 63943 | #: code:addons/analytic_override/analytic_account.py:467 | 63943 | msgid "You cannot have the same code between analytic accounts in the same category!" |
290 | 63944 | msgstr "Vous ne pouvez pas avoir le même code entre des comptes analytiques de même catégorie !" | ||
291 | 63945 | |||
292 | 63946 | #. module: analytic_override | ||
293 | 63947 | #: code:addons/analytic_override/analytic_account.py:417 | ||
294 | 63944 | #, python-format | 63948 | #, python-format |
297 | 63945 | msgid "You cannot have the same code or name between analytic accounts in the same category!" | 63949 | msgid "You cannot have the same name between analytic accounts in the same category!" |
298 | 63946 | msgstr "Vous ne pouvez pas avoir le même code ou nom entre des comptes analytiques de même catégorie!" | 63950 | msgstr "Vous ne pouvez pas avoir le même nom entre des comptes analytiques de même catégorie !" |
299 | 63947 | 63951 | ||
300 | 63948 | #. module: msf_tools | 63952 | #. module: msf_tools |
301 | 63949 | #: code:addons/msf_tools/automated_export.py:200 | 63953 | #: code:addons/msf_tools/automated_export.py:200 |