Merge lp:~julie-w/unifield-server/US-5771 into lp:unifield-server
- US-5771
- Merge into trunk
Proposed by
jftempo
Status: | Merged |
---|---|
Merged at revision: | 5372 |
Proposed branch: | lp:~julie-w/unifield-server/US-5771 |
Merge into: | lp:unifield-server |
Diff against target: |
1509 lines (+707/-170) 22 files modified
bin/addons/account_corrections/wizard/analytic_distribution_wizard.py (+6/-0) bin/addons/account_hq_entries/hq_entries.py (+10/-0) bin/addons/analytic_distribution/account.py (+5/-75) bin/addons/analytic_distribution/analytic_account_view.xml (+75/-4) bin/addons/analytic_distribution/analytic_distribution.py (+26/-1) bin/addons/analytic_distribution/analytic_distribution_wizard_view.xml (+10/-4) bin/addons/analytic_distribution/analytic_line.py (+16/-6) bin/addons/analytic_distribution/report/funding_pool.py (+0/-27) bin/addons/analytic_distribution/report/funding_pool.rml (+28/-28) bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py (+26/-4) bin/addons/analytic_override/analytic_account.py (+90/-0) bin/addons/msf_doc_import/account.py (+5/-0) bin/addons/msf_doc_import/msf_import_export.py (+123/-4) bin/addons/msf_doc_import/msf_import_export_conf.py (+91/-5) bin/addons/msf_homere_interface/hr.py (+25/-1) bin/addons/msf_homere_interface/hr_payroll.py (+7/-0) bin/addons/msf_homere_interface/hr_payroll_wizard.xml (+5/-2) bin/addons/msf_homere_interface/hr_view.xml (+1/-1) bin/addons/msf_profile/data/patches.xml (+5/-0) bin/addons/msf_profile/i18n/fr_MF.po (+134/-8) bin/addons/msf_profile/msf_profile.py (+18/-0) bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv (+1/-0) |
To merge this branch: | bzr merge lp:~julie-w/unifield-server/US-5771 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email: mp+366989@code.launchpad.net |
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/account_corrections/wizard/analytic_distribution_wizard.py' |
2 | --- bin/addons/account_corrections/wizard/analytic_distribution_wizard.py 2018-09-28 16:00:25 +0000 |
3 | +++ bin/addons/account_corrections/wizard/analytic_distribution_wizard.py 2019-05-06 14:14:05 +0000 |
4 | @@ -148,6 +148,7 @@ |
5 | context = {} |
6 | # Prepare some values |
7 | wizard = self.browse(cr, uid, wizard_id) |
8 | + ad_obj = self.pool.get('analytic.distribution') |
9 | company_currency_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.currency_id.id |
10 | ml = wizard.move_line_id |
11 | orig_date = ml.source_date or ml.date |
12 | @@ -240,6 +241,11 @@ |
13 | break |
14 | |
15 | for wiz_line in self.pool.get('analytic.distribution.wizard.fp.lines').browse(cr, uid, wiz_line_ids): |
16 | + if not ad_obj.check_dest_cc_compatibility(cr, uid, wiz_line.destination_id.id, wiz_line.cost_center_id.id, context=context): |
17 | + raise osv.except_osv(_('Error'), |
18 | + _('The Cost Center %s is not compatible with the Destination %s.') % |
19 | + (wiz_line.cost_center_id.code or '', wiz_line.destination_id.code or '')) |
20 | + |
21 | if not wiz_line.distribution_line_id or wiz_line.distribution_line_id.id not in old_line_ids: |
22 | # new distribution line |
23 | #if self.pool.get('account.analytic.account').is_blocked_by_a_contract(cr, uid, [wiz_line.analytic_id.id]): |
24 | |
25 | === modified file 'bin/addons/account_hq_entries/hq_entries.py' |
26 | --- bin/addons/account_hq_entries/hq_entries.py 2019-03-07 10:00:29 +0000 |
27 | +++ bin/addons/account_hq_entries/hq_entries.py 2019-05-06 14:14:05 +0000 |
28 | @@ -42,6 +42,7 @@ |
29 | # Prepare some values |
30 | res = {} |
31 | logger = netsvc.Logger() |
32 | + ad_obj = self.pool.get('analytic.distribution') |
33 | # Search MSF Private Fund element, because it's valid with all accounts |
34 | try: |
35 | fp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', |
36 | @@ -57,6 +58,7 @@ |
37 | # E/ DEST in list of available DEST in ACCOUNT |
38 | # F/ Check posting date with cost center and destination if exists |
39 | # G/ Check document date with funding pool |
40 | + # H/ Check Cost Center / Destination compatibility |
41 | ## CASES where FP is filled in (or not) and/or DEST is filled in (or not). |
42 | ## CC is mandatory, so always available: |
43 | # 1/ no FP, no DEST => Distro = valid |
44 | @@ -132,6 +134,14 @@ |
45 | res[line.id] = 'invalid' |
46 | logger.notifyChannel('account_hq_entries', netsvc.LOG_WARNING, _('%s: DEST (%s) not compatible with account (%s)') % (line.id or '', line.destination_id.code or '', account.code or '')) |
47 | continue |
48 | + # H check |
49 | + if line.destination_id and line.cost_center_id and \ |
50 | + not ad_obj.check_dest_cc_compatibility(cr, uid, line.destination_id.id, line.cost_center_id.id, context=context): |
51 | + res[line.id] = 'invalid' |
52 | + logger.notifyChannel('account_hq_entries', netsvc.LOG_WARNING, |
53 | + _('%s: CC (%s) not compatible with DEST (%s)') % |
54 | + (line.id or '', line.cost_center_id.code or '', line.destination_id.code or '')) |
55 | + continue |
56 | return res |
57 | |
58 | def _get_cc_changed(self, cr, uid, ids, field_name, arg, context=None): |
59 | |
60 | === modified file 'bin/addons/analytic_distribution/account.py' |
61 | --- bin/addons/analytic_distribution/account.py 2018-09-18 12:25:20 +0000 |
62 | +++ bin/addons/analytic_distribution/account.py 2019-05-06 14:14:05 +0000 |
63 | @@ -120,80 +120,9 @@ |
64 | _columns = { |
65 | 'account_id': fields.many2one('account.account', "G/L Account"), |
66 | 'funding_pool_id': fields.many2one('account.analytic.account', 'Funding Pool'), |
67 | + 'destination_id': fields.many2one('account.analytic.account', 'Destination'), |
68 | } |
69 | |
70 | - def fields_get(self, cr, uid, fields=None, context=None, with_uom_rounding=False): |
71 | - fields = super(account_destination_summary, self).fields_get(cr, uid, fields, context) |
72 | - dest_obj = self.pool.get('account.analytic.account') |
73 | - destination_ids = dest_obj.search(cr, uid, [('type', '!=', 'view'), ('category', '=', 'DEST'), ('parent_id', '!=', False)]) |
74 | - for dest in dest_obj.read(cr, uid, destination_ids, ['name']): |
75 | - fields['dest_%s'%(dest['id'])] = {'type': 'boolean', 'string': dest['name']} |
76 | - return fields |
77 | - |
78 | - def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): |
79 | - view = super(account_destination_summary, self).fields_view_get(cr, uid, view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu) |
80 | - if view_type == 'tree': |
81 | - fields_to_add = [] |
82 | - form = etree.fromstring(view['arch']) |
83 | - tree = form.xpath('//tree') |
84 | - for field in view.get('fields', {}): |
85 | - if field.startswith('dest_'): |
86 | - fields_to_add.append(int(field.split('_')[1])) |
87 | - |
88 | - if fields_to_add: |
89 | - for dest_order in self.pool.get('account.analytic.account').search(cr, uid, [('id', 'in', fields_to_add)], order='name'): |
90 | - new_field = etree.Element('field', attrib={'name': 'dest_%d'%dest_order}) |
91 | - tree[0].append(new_field) |
92 | - view['arch'] = etree.tostring(form) |
93 | - return view |
94 | - |
95 | - def read(self, cr, uid, ids, fields_to_read=None, context=None, load='_classic_read'): |
96 | - first = False |
97 | - if isinstance(ids, (int, long)): |
98 | - ids = [ids] |
99 | - first = True |
100 | - if fields_to_read is None: |
101 | - fields_to_read = [] |
102 | - ret = super(account_destination_summary, self).read(cr, uid, ids, fields_to_read, context, load) |
103 | - f_to_read = [] |
104 | - for field in fields_to_read: |
105 | - if field.startswith('dest_'): |
106 | - f_to_read.append(field) |
107 | - |
108 | - if f_to_read: |
109 | - cr.execute(''' |
110 | - SELECT |
111 | - sum.id, |
112 | - l.destination_id |
113 | - FROM |
114 | - account_destination_link l, |
115 | - account_destination_summary sum, |
116 | - funding_pool_associated_destinations d |
117 | - WHERE |
118 | - l.disabled = 'f' and |
119 | - d.tuple_id = l.id and |
120 | - sum.account_id = l.account_id and |
121 | - sum.funding_pool_id = d.funding_pool_id and |
122 | - sum.id in %s |
123 | - ''',(tuple(ids),) |
124 | - ) |
125 | - tmp_result = {} |
126 | - for x in cr.fetchall(): |
127 | - tmp_result.setdefault(x[0], []).append(x[1]) |
128 | - |
129 | - for x in ret: |
130 | - for dest in tmp_result.get(x['id'], []): |
131 | - x['dest_%s'%(dest,)] = True |
132 | - for false_value in f_to_read: |
133 | - if false_value not in x: |
134 | - x[false_value] = False |
135 | - |
136 | - if first: |
137 | - return ret[0] |
138 | - return ret |
139 | - |
140 | - |
141 | - |
142 | def init(self, cr): |
143 | # test if id exists in funding_pool_associated_destinations or create it |
144 | cr.execute("SELECT attr.attname FROM pg_attribute attr, pg_class class WHERE attr.attrelid = class.oid AND class.relname = 'funding_pool_associated_destinations' AND attr.attname='id'") |
145 | @@ -206,7 +135,8 @@ |
146 | SELECT |
147 | min(d.id) AS id, |
148 | l.account_id AS account_id, |
149 | - d.funding_pool_id AS funding_pool_id |
150 | + d.funding_pool_id AS funding_pool_id, |
151 | + l.destination_id AS destination_id |
152 | FROM |
153 | account_destination_link l, |
154 | funding_pool_associated_destinations d |
155 | @@ -214,10 +144,10 @@ |
156 | d.tuple_id = l.id and |
157 | l.disabled = 'f' |
158 | GROUP BY |
159 | - l.account_id,d.funding_pool_id |
160 | + l.account_id, d.funding_pool_id, l.destination_id |
161 | ) |
162 | """) |
163 | - _order = 'account_id' |
164 | + _order = 'funding_pool_id, account_id, destination_id' |
165 | account_destination_summary() |
166 | |
167 | class account_account(osv.osv): |
168 | |
169 | === modified file 'bin/addons/analytic_distribution/analytic_account_view.xml' |
170 | --- bin/addons/analytic_distribution/analytic_account_view.xml 2018-04-03 13:02:04 +0000 |
171 | +++ bin/addons/analytic_distribution/analytic_account_view.xml 2019-05-06 14:14:05 +0000 |
172 | @@ -97,9 +97,6 @@ |
173 | <separator/> |
174 | <field name="tuple_destination_account_ids" nolabel="1" context="{'dest_in_use':tuple_destination_account_ids}"/> |
175 | </page> |
176 | - <page string="Destinations by accounts" attrs="{'invisible': [('category', '!=', 'FUNDING')]}"> |
177 | - <field name="tuple_destination_summary" nolabel="1" readonly="1"/> |
178 | - </page> |
179 | <page string="Expense accounts" attrs="{'invisible': [('category', '!=', 'DEST')]}"> |
180 | <field name="destination_ids" nolabel="1" domain="[('type', '!=', 'view'), ('is_analytic_addicted', '=', True)]" context="{'destination_id': record_id}"> |
181 | <tree string="Expenses accounts list" colors="red:inactivated_for_dest"> |
182 | @@ -111,6 +108,17 @@ |
183 | </tree> |
184 | </field> |
185 | </page> |
186 | + <page string="Cost Centers" attrs="{'invisible': [('category', '!=', 'DEST')]}"> |
187 | + <field name="allow_all_cc" colspan="4" on_change="on_change_allow_all_cc(allow_all_cc, dest_cc_ids)"/> |
188 | + <button name="button_dest_cc_clear" type="object" string="Remove all" icon="gtk-clear" colspan="4"/> |
189 | + <separator/> |
190 | + <field name="dest_cc_ids" nolabel="1" colspan="4" on_change="on_change_dest_cc_ids(dest_cc_ids)"> |
191 | + <tree string="Cost Centers"> |
192 | + <field name="code"/> |
193 | + <field name="name"/> |
194 | + </tree> |
195 | + </field> |
196 | + </page> |
197 | </page> |
198 | </data> |
199 | </field> |
200 | @@ -121,8 +129,10 @@ |
201 | <field name="model">account.destination.summary</field> |
202 | <field name="type">tree</field> |
203 | <field name="arch" type="xml"> |
204 | - <tree string="Destinations by accounts"> |
205 | + <tree string="Destinations by accounts" hide_new_button="1" hide_edit_button="1" hide_delete_button="1"> |
206 | + <field name="funding_pool_id"/> |
207 | <field name="account_id" /> |
208 | + <field name="destination_id"/> |
209 | </tree> |
210 | </field> |
211 | </record> |
212 | @@ -275,6 +285,67 @@ |
213 | <field name="context">{'search_default_active': 1, 'filter_inactive_accounts': 1, 'from_web': True, 'display_disabled': 1}</field> |
214 | </record> |
215 | |
216 | + <!-- Destinations by accounts Search view --> |
217 | + <record id="view_account_destination_summary_search" model="ir.ui.view"> |
218 | + <field name="name">account.destination.summary.search</field> |
219 | + <field name="model">account.destination.summary</field> |
220 | + <field name="type">search</field> |
221 | + <field name="priority" eval="16"/> |
222 | + <field name="arch" type="xml"> |
223 | + <search> |
224 | + <group> |
225 | + <field name="funding_pool_id" domain="[('type', '!=', 'view'), ('category', '=', 'FUNDING')]"/> |
226 | + <field name="account_id" domain="[('type', '!=', 'view'), ('is_analytic_addicted', '=', True)]"/> |
227 | + <field name="destination_id" domain="[('type', '!=', 'view'), ('category', '=', 'DEST')]"/> |
228 | + </group> |
229 | + <newline/> |
230 | + <group expand="1" string="Group By..."> |
231 | + <filter string="Funding Pool" name="group_funding_pool_id" |
232 | + icon="terp-folder-blue" domain="[]" context="{'group_by':'funding_pool_id'}"/> |
233 | + <separator orientation="vertical"/> |
234 | + <filter string="G/L account" name="group_account_id" |
235 | + icon="terp-folder-orange" domain="[]" context="{'group_by':'account_id'}"/> |
236 | + <separator orientation="vertical"/> |
237 | + <filter string="Destination" name="group_destination_id" |
238 | + icon="terp-folder-violet" domain="[]" context="{'group_by':'destination_id'}"/> |
239 | + </group> |
240 | + </search> |
241 | + </field> |
242 | + </record> |
243 | + |
244 | + <!-- Destinations by accounts Form view --> |
245 | + <record id="view_account_destination_summary_form" model="ir.ui.view"> |
246 | + <field name="name">account.destination.summary.form</field> |
247 | + <field name="model">account.destination.summary</field> |
248 | + <field name="type">form</field> |
249 | + <field name="priority" eval="16"/> |
250 | + <field name="arch" type="xml"> |
251 | + <!-- this form must be read-only: acc/dest links must be created in the Destination tab of the FP --> |
252 | + <form noteditable="1" hide_delete_button="1" hide_new_button="1"> |
253 | + <field name="funding_pool_id"/> |
254 | + <newline/> |
255 | + <field name="account_id"/> |
256 | + <field name="destination_id"/> |
257 | + </form> |
258 | + </field> |
259 | + </record> |
260 | + |
261 | + <!-- Destinations by accounts Menu entry --> |
262 | + <record id="action_analytic_acc_dest_summary" model="ir.actions.server"> |
263 | + <field name="name">Destinations by accounts</field> |
264 | + <field name="model_id" ref="model_account_analytic_account"/> |
265 | + <field name="state">code</field> |
266 | + <field name="code">action = obj.get_destinations_by_accounts(context=context)</field> |
267 | + </record> |
268 | + <record id="ir_destinations_by_accounts_search" model="ir.values"> |
269 | + <field name="key2">client_action_relate</field> |
270 | + <field name="model">account.analytic.account</field> |
271 | + <field name="name">destinations_by_accounts</field> |
272 | + <field eval="'ir.actions.server,%d'%action_analytic_acc_dest_summary" name="value"/> |
273 | + <field eval="True" name="object"/> |
274 | + <field name="sequence" eval="110"/> |
275 | + </record> |
276 | + |
277 | <menuitem action="action_account_analytic_account_form" |
278 | id="account.account_analytic_def_account" |
279 | parent="account.menu_analytic_accounting" |
280 | |
281 | === modified file 'bin/addons/analytic_distribution/analytic_distribution.py' |
282 | --- bin/addons/analytic_distribution/analytic_distribution.py 2019-03-28 15:40:47 +0000 |
283 | +++ bin/addons/analytic_distribution/analytic_distribution.py 2019-05-06 14:14:05 +0000 |
284 | @@ -26,6 +26,22 @@ |
285 | _name = 'analytic.distribution' |
286 | _inherit = 'analytic.distribution' |
287 | |
288 | + def check_dest_cc_compatibility(self, cr, uid, destination_id, cost_center_id, context=None): |
289 | + """ |
290 | + Checks the compatibility between the Destination and the Cost Center (cf. CC tab in the Destination form). |
291 | + Returns False if they aren't compatible. |
292 | + """ |
293 | + if context is None: |
294 | + context = {} |
295 | + analytic_acc_obj = self.pool.get('account.analytic.account') |
296 | + if destination_id and cost_center_id: |
297 | + dest = analytic_acc_obj.browse(cr, uid, destination_id, fields_to_fetch=['category', 'allow_all_cc', 'dest_cc_ids'], context=context) |
298 | + cc = analytic_acc_obj.browse(cr, uid, cost_center_id, fields_to_fetch=['category'], context=context) |
299 | + if dest and cc and dest.category == 'DEST' and cc.category == 'OC' and not dest.allow_all_cc and \ |
300 | + cc.id not in [c.id for c in dest.dest_cc_ids]: |
301 | + return False |
302 | + return True |
303 | + |
304 | def _get_distribution_state(self, cr, uid, distrib_id, parent_id, account_id, context=None): |
305 | """ |
306 | Return distribution state |
307 | @@ -51,17 +67,23 @@ |
308 | except ValueError: |
309 | fp_id = 0 |
310 | account = self.pool.get('account.account').read(cr, uid, account_id, ['destination_ids']) |
311 | - # Check Cost Center lines with destination/account link |
312 | + # Check Cost Center lines regarding destination/account and destination/CC links |
313 | for cc_line in distrib.cost_center_lines: |
314 | if cc_line.destination_id.id not in account.get('destination_ids', []): |
315 | return 'invalid' |
316 | + if not self.check_dest_cc_compatibility(cr, uid, cc_line.destination_id.id, |
317 | + cc_line.analytic_id and cc_line.analytic_id.id or False, context=context): |
318 | + return 'invalid' |
319 | # Check Funding pool lines regarding: |
320 | # - destination / account |
321 | + # - destination / cost center |
322 | # - If analytic account is MSF Private funds |
323 | # - Cost center and funding pool compatibility |
324 | for fp_line in distrib.funding_pool_lines: |
325 | if fp_line.destination_id.id not in account.get('destination_ids', []): |
326 | return 'invalid' |
327 | + if not self.check_dest_cc_compatibility(cr, uid, fp_line.destination_id.id, fp_line.cost_center_id.id, context=context): |
328 | + return 'invalid' |
329 | # If fp_line is MSF Private Fund, all is ok |
330 | if fp_line.analytic_id.id == fp_id: |
331 | continue |
332 | @@ -96,6 +118,9 @@ |
333 | # Check that destination is compatible with account |
334 | if destination_id not in [x.id for x in account.destination_ids]: |
335 | return 'invalid', _('Destination not compatible with account') |
336 | + # Check that Destination and Cost Center are compatible |
337 | + if not self.check_dest_cc_compatibility(cr, uid, destination_id, cost_center_id, context=context): |
338 | + return 'invalid', _('Cost Center not compatible with destination') |
339 | if not is_private_fund: |
340 | # Check that cost center is compatible with FP (except if FP is MSF Private Fund) |
341 | if cost_center_id not in [x.id for x in fp.cost_center_ids]: |
342 | |
343 | === modified file 'bin/addons/analytic_distribution/analytic_distribution_wizard_view.xml' |
344 | --- bin/addons/analytic_distribution/analytic_distribution_wizard_view.xml 2018-06-22 09:57:41 +0000 |
345 | +++ bin/addons/analytic_distribution/analytic_distribution_wizard_view.xml 2019-05-06 14:14:05 +0000 |
346 | @@ -10,8 +10,10 @@ |
347 | <field name="arch" type='xml'> |
348 | <tree string="" editable="top"> |
349 | <field name="is_percentage_amount_touched" invisible="1" /> |
350 | + <field name="analytic_id" domain="[('type', '!=', 'view'), ('category', '=', 'OC'), ('state', '=', 'open')]" |
351 | + string="Cost Center" |
352 | + context="{'search_default_active': 1, 'hide_inactive': 1, 'date': context.get('posting_date')}"/> |
353 | <field name="destination_id" context="{'search_default_active': 1, 'hide_inactive': 1, 'date': context.get('posting_date')}"/> |
354 | - <field name="analytic_id" domain="[('type', '!=', 'view'), ('category', '=', 'OC'), ('state', '=', 'open')]" string="Cost Center" context="{'search_default_active': 1, 'hide_inactive': 1, 'date': context.get('posting_date')}"/> |
355 | <field name="percentage" sum="Total Percentage" digits="(16,2)"/> |
356 | <field name="amount" sum="Total Amount"/> |
357 | </tree> |
358 | @@ -25,9 +27,13 @@ |
359 | <field name="arch" type='xml'> |
360 | <tree string="" editable="top"> |
361 | <field name="is_percentage_amount_touched" invisible="1" /> |
362 | - <field name="destination_id" on_change="onchange_destination(destination_id, analytic_id, parent.account_id)" context="{'search_default_active': 1, 'hide_inactive': 1, 'date': context.get('posting_date')}"/> |
363 | - <field name="cost_center_id" on_change="onchange_cost_center(cost_center_id, analytic_id)" context="{'search_default_active': 1, 'hide_inactive': 1, 'date': context.get('posting_date')}"/> |
364 | - <field name="analytic_id" domain="[('type', '!=', 'view'), ('category', '=', 'FUNDING'), ('state', '=', 'open'), ('cost_center_ids', '=', cost_center_id)]" string="Funding Pool" context="{'search_default_active': 1, 'hide_inactive': 1, 'date': context.get('document_date')}"/> |
365 | + <field name="cost_center_id" on_change="onchange_cost_center(cost_center_id, analytic_id)" |
366 | + context="{'search_default_active': 1, 'hide_inactive': 1, 'date': context.get('posting_date')}"/> |
367 | + <field name="destination_id" on_change="onchange_destination(destination_id, analytic_id, parent.account_id)" |
368 | + context="{'search_default_active': 1, 'hide_inactive': 1, 'date': context.get('posting_date')}"/> |
369 | + <field name="analytic_id" |
370 | + domain="[('type', '!=', 'view'), ('category', '=', 'FUNDING'), ('state', '=', 'open'), ('cost_center_ids', '=', cost_center_id)]" |
371 | + string="Funding Pool" context="{'search_default_active': 1, 'hide_inactive': 1, 'date': context.get('document_date')}"/> |
372 | <field name="percentage" sum="Total Percentage" digits="(16,2)"/> |
373 | <field name="amount" sum="Total Amount"/> |
374 | </tree> |
375 | |
376 | === modified file 'bin/addons/analytic_distribution/analytic_line.py' |
377 | --- bin/addons/analytic_distribution/analytic_line.py 2018-08-21 13:08:14 +0000 |
378 | +++ bin/addons/analytic_distribution/analytic_line.py 2019-05-06 14:14:05 +0000 |
379 | @@ -401,6 +401,7 @@ |
380 | if isinstance(ids, (int, long)): |
381 | ids = [ids] |
382 | # Prepare some value |
383 | + ad_obj = self.pool.get('analytic.distribution') |
384 | account = self.pool.get('account.analytic.account').read(cr, uid, account_id, ['category', 'date_start', 'date'], context=context) |
385 | account_type = account and account.get('category', False) or False |
386 | res = [] |
387 | @@ -442,12 +443,13 @@ |
388 | check_accounts = self.pool.get('account.analytic.account').is_blocked_by_a_contract(cr, uid, [aline.account_id.id]) |
389 | if check_accounts and aline.account_id.id in check_accounts: |
390 | continue |
391 | - |
392 | - if aline.account_id and aline.account_id.id == msf_private_fund: |
393 | - res.append(aline.id) |
394 | - elif aline.account_id and aline.cost_center_id and aline.account_id.cost_center_ids: |
395 | - if account_id in [x and x.id for x in aline.account_id.cost_center_ids] or aline.account_id.id == msf_private_fund: |
396 | + if ad_obj.check_dest_cc_compatibility(cr, uid, aline.destination_id and aline.destination_id.id or False, |
397 | + account_id, context=context): |
398 | + if aline.account_id and aline.account_id.id == msf_private_fund: |
399 | res.append(aline.id) |
400 | + elif aline.account_id and aline.cost_center_id and aline.account_id.cost_center_ids: |
401 | + if account_id in [x and x.id for x in aline.account_id.cost_center_ids] or aline.account_id.id == msf_private_fund: |
402 | + res.append(aline.id) |
403 | elif account_type == 'FUNDING': |
404 | fp = self.pool.get('account.analytic.account').read(cr, uid, account_id, ['cost_center_ids', 'tuple_destination_account_ids'], context=context) |
405 | cc_ids = fp and fp.get('cost_center_ids', []) or [] |
406 | @@ -473,7 +475,8 @@ |
407 | res.append(aline.id) |
408 | elif account_type == "DEST": |
409 | for aline in self.browse(cr, uid, ids, context=context): |
410 | - if aline.general_account_id and account_id in [x.id for x in aline.general_account_id.destination_ids]: |
411 | + if ad_obj.check_dest_cc_compatibility(cr, uid, account_id, aline.cost_center_id and aline.cost_center_id.id or False, context=context) and \ |
412 | + aline.general_account_id and account_id in [x.id for x in aline.general_account_id.destination_ids]: |
413 | res.append(aline.id) |
414 | else: |
415 | # Case of FREE1 and FREE2 lines |
416 | @@ -507,6 +510,7 @@ |
417 | new_dest_id, new_dest_br, |
418 | new_cc_id, new_cc_br, |
419 | new_fp_id, new_fp_br): |
420 | + ad_obj = self.pool.get('analytic.distribution') |
421 | if not general_account_br.is_analytic_addicted: |
422 | res.append((id, entry_sequence, '')) |
423 | return False |
424 | @@ -518,6 +522,12 @@ |
425 | res.append((id, entry_sequence, _('DEST'))) |
426 | return False |
427 | |
428 | + # check cost center with destination |
429 | + if new_dest_id and new_cc_id: |
430 | + if not ad_obj.check_dest_cc_compatibility(cr, uid, new_dest_id, new_cc_id, context=context): |
431 | + res.append((id, entry_sequence, _('CC/DEST'))) |
432 | + return False |
433 | + |
434 | # check funding pool (expect for MSF Private Fund) |
435 | if not new_fp_id == msf_pf_id: # all OK for MSF Private Fund |
436 | # - cost center and funding pool compatibility |
437 | |
438 | === modified file 'bin/addons/analytic_distribution/report/funding_pool.py' |
439 | --- bin/addons/analytic_distribution/report/funding_pool.py 2014-10-29 16:27:26 +0000 |
440 | +++ bin/addons/analytic_distribution/report/funding_pool.py 2019-05-06 14:14:05 +0000 |
441 | @@ -21,7 +21,6 @@ |
442 | |
443 | from report import report_sxw |
444 | import locale |
445 | -import pooler |
446 | import time |
447 | |
448 | class funding(report_sxw.rml_parse): |
449 | @@ -29,37 +28,11 @@ |
450 | super(funding, self).__init__(cr, uid, name, context=context) |
451 | self.localcontext.update({ |
452 | 'locale': locale, |
453 | - 'getDest': self.getDestinations, |
454 | - 'getBoolDest': self.getBoolDest, |
455 | 'today': self.today, |
456 | }) |
457 | |
458 | def today(self): |
459 | return time.strftime('%Y-%m-%d',time.localtime()) |
460 | |
461 | - def getDestinations(self): |
462 | - """ |
463 | - Fetch destination analytic account: |
464 | - * ID |
465 | - * code |
466 | - Then sort by code |
467 | - """ |
468 | - res = [('Code', False), ('Name', False)] # We need the 2 first column header name |
469 | - pool = pooler.get_pool(self.cr.dbname) |
470 | - destination_ids = pool.get('account.analytic.account').search(self.cr, self.uid, [('category', '=', 'DEST'), ('type', '!=', 'view')], order='id') |
471 | - data = pool.get('account.analytic.account').read(self.cr, self.uid, destination_ids, ['code']) |
472 | - res += [(x.get('code'), x.get('id')) for x in data] |
473 | - return res |
474 | - |
475 | - def getBoolDest(self, line, o): |
476 | - pool = pooler.get_pool(self.cr.dbname) |
477 | - fields = [] |
478 | - for field in pool.get('account.destination.summary').fields_get(self.cr, self.uid, ['account_id']): |
479 | - fields.append(field) |
480 | - r = pool.get('account.destination.summary').read(self.cr, self.uid, line.id, fields) |
481 | - if r[o]: |
482 | - return 'x' |
483 | - return '' |
484 | - |
485 | report_sxw.report_sxw('report.funding.pool', 'account.analytic.account', 'addons/analytic_distribution/report/funding_pool.rml', parser=funding) |
486 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
487 | |
488 | === modified file 'bin/addons/analytic_distribution/report/funding_pool.rml' |
489 | --- bin/addons/analytic_distribution/report/funding_pool.rml 2017-08-28 12:25:59 +0000 |
490 | +++ bin/addons/analytic_distribution/report/funding_pool.rml 2019-05-06 14:14:05 +0000 |
491 | @@ -62,13 +62,7 @@ |
492 | <blockTableStyle id="Table4"> |
493 | <blockAlignment value="LEFT"/> |
494 | <blockValign value="TOP"/> |
495 | - <lineStyle kind="LINEBELOW" colorName="#000000" start="0,0" stop="0,0"/> |
496 | - <lineStyle kind="LINEBELOW" colorName="#000000" start="1,0" stop="1,0"/> |
497 | - <lineStyle kind="LINEBELOW" colorName="#000000" start="2,0" stop="2,0"/> |
498 | - <lineStyle kind="LINEBELOW" colorName="#000000" start="3,0" stop="3,0"/> |
499 | - <lineStyle kind="LINEBELOW" colorName="#000000" start="4,0" stop="4,0"/> |
500 | - <lineStyle kind="LINEBELOW" colorName="#000000" start="5,0" stop="5,0"/> |
501 | - <lineStyle kind="LINEBELOW" colorName="#000000" start="6,0" stop="6,0"/> |
502 | + <lineStyle kind="LINEBELOW" colorName="#000000" start="0,0" stop="-1,0"/> |
503 | </blockTableStyle> |
504 | <blockTableStyle id="Table5"> |
505 | <blockAlignment value="LEFT"/> |
506 | @@ -202,22 +196,22 @@ |
507 | </para> |
508 | <para style="P6">Cost centers:</para> |
509 | |
510 | - <blockTable colWidths="260.0,258.0" style="Table11" repeatRows="1"> |
511 | + <blockTable colWidths="260.0,260.0" style="Table11" repeatRows="1"> |
512 | <tr> |
513 | <td> |
514 | - <para style="P2" alignment="LEFT">Cost center name</para> |
515 | + <para style="P8">Cost center code</para> |
516 | </td> |
517 | <td> |
518 | - <para style="P2" alignment="LEFT">Cost center code</para> |
519 | + <para style="P8">Cost center name</para> |
520 | </td> |
521 | </tr> |
522 | <tr> |
523 | <para style="P17">[[repeatIn(o.cost_center_ids,'line')]]</para> |
524 | <td> |
525 | - <para style="P3" alignment="LEFT">[[ line.name ]]</para> |
526 | + <para style="P7">[[ line.code or '' ]]</para> |
527 | </td> |
528 | <td> |
529 | - <para style="P3" alignment="LEFT">[[ line.code ]]</para> |
530 | + <para style="P7">[[ line.name or '' ]]</para> |
531 | </td> |
532 | </tr> |
533 | </blockTable> |
534 | @@ -228,31 +222,37 @@ |
535 | <para style="P8"> |
536 | <font color="white"> </font> |
537 | </para> |
538 | - <para style="P6">Accounts:</para> |
539 | + <para style="P6">Account/Destination:</para> |
540 | |
541 | - <!-- Seems that its not possible to change colWidths regarding a condition. |
542 | - Cf. https://www.odoo.com/forum/help-1/question/reportlab-conditional-table-header-15143 |
543 | - Previous colWidths: colWidths="40.0,260.0,55.0,55.0,55.0,55.0" |
544 | - --> |
545 | - <blockTable repeatRows="1" style="Table4"> |
546 | + <blockTable repeatRows="1" style="Table4" colWidths="95.0,165.0,95.0,165.0"> |
547 | <tr> |
548 | <td> |
549 | - [[repeatIn(getDest(),'dest_data','td')]] |
550 | - <para style="P24" alignment="CENTER">[[ dest_data[0] ]]</para> |
551 | + <para style="P8">Account code</para> |
552 | + </td> |
553 | + <td> |
554 | + <para style="P8">Account name</para> |
555 | + </td> |
556 | + <td> |
557 | + <para style="P8">Destination code</para> |
558 | + </td> |
559 | + <td> |
560 | + <para style="P8">Destination name</para> |
561 | </td> |
562 | </tr> |
563 | |
564 | <tr> |
565 | [[repeatIn(o.tuple_destination_summary,'line')]] |
566 | <td> |
567 | - <para style="P16" alignment="LEFT">[[ line.account_id and line.account_id.code ]]</para> |
568 | - </td> |
569 | - <td> |
570 | - <para style="P11" alignment="LEFT">[[ line.account_id and line.account_id.name ]]</para> |
571 | - </td> |
572 | - <td> |
573 | - [[repeatIn(getDest()[2:],'dest_data','td')]] |
574 | - <para style="P28" alignment="CENTER">[[ getBoolDest(line,'dest_'+ str(dest_data[1])) ]]</para> |
575 | + <para style="P7">[[ line.account_id and line.account_id.code or '' ]]</para> |
576 | + </td> |
577 | + <td> |
578 | + <para style="P7">[[ line.account_id and line.account_id.name or '' ]]</para> |
579 | + </td> |
580 | + <td> |
581 | + <para style="P7">[[ line.destination_id and line.destination_id.code or '' ]]</para> |
582 | + </td> |
583 | + <td> |
584 | + <para style="P7">[[ line.destination_id and line.destination_id.name or '' ]]</para> |
585 | </td> |
586 | </tr> |
587 | </blockTable> |
588 | |
589 | === modified file 'bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py' |
590 | --- bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py 2018-09-28 16:00:25 +0000 |
591 | +++ bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py 2019-05-06 14:14:05 +0000 |
592 | @@ -159,6 +159,18 @@ |
593 | percentage = abs((amount / total_amount) * 100) |
594 | return {'value': {'percentage': percentage, 'is_percentage_amount_touched': True}} |
595 | |
596 | + def _dest_compatible_with_cc_domain_part(self, tree): |
597 | + """ |
598 | + Returns the domain condition to restrict the destination regarding the cost_center_id (for finance views), |
599 | + or if this field doesn't exist in the view, to the analytic_id (Cost Center in Supply views) |
600 | + """ |
601 | + dom_part = "" |
602 | + if tree.xpath('/tree/field[@name="cost_center_id"]'): |
603 | + dom_part = "('dest_compatible_with_cc_ids', '=', cost_center_id)" |
604 | + elif tree.xpath('/tree/field[@name="analytic_id"]'): |
605 | + dom_part = "('dest_compatible_with_cc_ids', '=', analytic_id)" |
606 | + return dom_part |
607 | + |
608 | def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): |
609 | """ |
610 | Rewrite view in order: |
611 | @@ -195,9 +207,14 @@ |
612 | or (context.get('direct_invoice_id', False) and isinstance(context.get('direct_invoice_id'), int)) \ |
613 | or (context.get('from_move', False) and isinstance(context.get('from_move'), int)) \ |
614 | or (context.get('from_cash_return', False) and isinstance(context.get('from_cash_return'), int)): |
615 | - field.set('domain', "[('type', '!=', 'view'), ('state', '=', 'open'), ('category', '=', 'DEST')]") |
616 | + domain_part = self._dest_compatible_with_cc_domain_part(tree) |
617 | + domain = "[('type', '!=', 'view'), ('category', '=', 'DEST') %s]" % (domain_part and ', %s' % domain_part or '') |
618 | + field.set('domain', domain) |
619 | else: |
620 | - field.set('domain', "[('type', '!=', 'view'), ('state', '=', 'open'), ('category', '=', 'DEST'), ('destination_ids', '=', parent.account_id)]") |
621 | + domain_part = self._dest_compatible_with_cc_domain_part(tree) |
622 | + domain = "[('type', '!=', 'view'), ('category', '=', 'DEST'), " \ |
623 | + "('destination_ids', '=', parent.account_id) %s]" % (domain_part and ', %s' % domain_part or '') |
624 | + field.set('domain', domain) |
625 | ## FUNDING POOL |
626 | if line_type == 'analytic.distribution.wizard.fp.lines': |
627 | # Change OC field |
628 | @@ -235,9 +252,14 @@ |
629 | or (context.get('from_move', False) and isinstance(context.get('from_move'), int)) \ |
630 | or (context.get('from_cash_return', False) and isinstance(context.get('from_cash_return'), int)): |
631 | |
632 | - field.set('domain', "[('type', '!=', 'view'), ('state', '=', 'open'), ('category', '=', 'DEST')]") |
633 | + domain_part = self._dest_compatible_with_cc_domain_part(tree) |
634 | + domain = "[('type', '!=', 'view'), ('category', '=', 'DEST') %s]" % (domain_part and ', %s' % domain_part or '') |
635 | + field.set('domain', domain) |
636 | else: |
637 | - field.set('domain', "[('type', '!=', 'view'), ('state', '=', 'open'), ('category', '=', 'DEST'), ('destination_ids', '=', parent.account_id)]") |
638 | + domain_part = self._dest_compatible_with_cc_domain_part(tree) |
639 | + domain = "[('type', '!=', 'view'), ('category', '=', 'DEST'), " \ |
640 | + "('destination_ids', '=', parent.account_id) %s]" % (domain_part and ', %s' % domain_part or '') |
641 | + field.set('domain', domain) |
642 | |
643 | ## FREE 1 |
644 | if line_type == 'analytic.distribution.wizard.f1.lines': |
645 | |
646 | === modified file 'bin/addons/analytic_override/analytic_account.py' |
647 | --- bin/addons/analytic_override/analytic_account.py 2019-03-20 10:39:41 +0000 |
648 | +++ bin/addons/analytic_override/analytic_account.py 2019-05-06 14:14:05 +0000 |
649 | @@ -211,6 +211,28 @@ |
650 | account_ids += tmp_ids |
651 | return account_ids |
652 | |
653 | + def _search_dest_compatible_with_cc_ids(self, cr, uid, obj, name, args, context=None): |
654 | + """ |
655 | + Returns a domain with all destinations compatible with the selected Cost Center |
656 | + Ex: to get the dest. compatible with the CC 2, use the dom [('dest_compatible_with_cc_ids', '=', 2)] |
657 | + """ |
658 | + dom = [] |
659 | + if context is None: |
660 | + context = {} |
661 | + for arg in args: |
662 | + if arg[0] == 'dest_compatible_with_cc_ids': |
663 | + operator = arg[1] |
664 | + cc = arg[2] |
665 | + if operator != '=' or not isinstance(cc, (int, long)): |
666 | + raise osv.except_osv(_('Error'), _('Filter not implemented on Destinations.')) |
667 | + all_dest_ids = self.search(cr, uid, [('category', '=', 'DEST')], context=context) |
668 | + compatible_dest_ids = [] |
669 | + for dest in self.browse(cr, uid, all_dest_ids, fields_to_fetch=['allow_all_cc', 'dest_cc_ids'], context=context): |
670 | + if dest.allow_all_cc or (cc and cc in [c.id for c in dest.dest_cc_ids]): |
671 | + compatible_dest_ids.append(dest.id) |
672 | + dom.append(('id', 'in', compatible_dest_ids)) |
673 | + return dom |
674 | + |
675 | _columns = { |
676 | 'name': fields.char('Name', size=128, required=True, translate=1), |
677 | 'code': fields.char('Code', size=24), |
678 | @@ -228,11 +250,20 @@ |
679 | 'filter_active': fields.function(_get_active, fnct_search=_search_filter_active, type="boolean", method=True, store=False, string="Show only active analytic accounts",), |
680 | 'intermission_restricted': fields.function(_get_fake, type="boolean", method=True, store=False, string="Domain to restrict intermission cc"), |
681 | 'balance': fields.function(_debit_credit_bal_qtty, method=True, type='float', string='Balance', digits_compute=dp.get_precision('Account'), multi='debit_credit_bal_qtty'), |
682 | + 'dest_cc_ids': fields.many2many('account.analytic.account', 'destination_cost_center_rel', |
683 | + 'destination_id', 'cost_center_id', string='Cost Centers', |
684 | + domain="[('type', '!=', 'view'), ('category', '=', 'OC')]"), |
685 | + 'allow_all_cc': fields.boolean(string="Allow all Cost Centers"), |
686 | + 'dest_compatible_with_cc_ids': fields.function(_get_fake, method=True, store=False, |
687 | + string='Destinations compatible with the Cost Center', |
688 | + type='many2many', relation='account.analytic.account', |
689 | + fnct_search=_search_dest_compatible_with_cc_ids), |
690 | } |
691 | |
692 | _defaults ={ |
693 | 'date_start': lambda *a: (datetime.today() + relativedelta(months=-3)).strftime('%Y-%m-%d'), |
694 | 'for_fx_gain_loss': lambda *a: False, |
695 | + 'allow_all_cc': lambda *a: False, |
696 | } |
697 | |
698 | def _check_code_unicity(self, cr, uid, ids, context=None): |
699 | @@ -304,6 +335,30 @@ |
700 | res['domain']['parent_id'] = [('category', '=', category), ('type', '=', 'view')] |
701 | return res |
702 | |
703 | + def on_change_allow_all_cc(self, cr, uid, ids, allow_all_cc, dest_cc_ids, context=None): |
704 | + """ |
705 | + If the user tries to tick the box "Allow all Cost Centers" whereas CC are selected, |
706 | + informs him that he has to remove the CC first |
707 | + """ |
708 | + res = {} |
709 | + if allow_all_cc and dest_cc_ids and dest_cc_ids[0][2]: # e.g. [(6, 0, [1, 2])] |
710 | + warning = { |
711 | + 'title': _('Warning!'), |
712 | + 'message': _('Please remove the Cost Centers linked to the Destination before ticking this box.') |
713 | + } |
714 | + res['warning'] = warning |
715 | + res['value'] = {'allow_all_cc': False, } |
716 | + return res |
717 | + |
718 | + def on_change_dest_cc_ids(self, cr, uid, ids, dest_cc_ids, context=None): |
719 | + """ |
720 | + If at least a CC is selected, unticks the box "Allow all Cost Centers" |
721 | + """ |
722 | + res = {} |
723 | + if dest_cc_ids and dest_cc_ids[0][2]: # e.g. [(6, 0, [1, 2])] |
724 | + res['value'] = {'allow_all_cc': False, } |
725 | + return res |
726 | + |
727 | def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): |
728 | if not context: |
729 | context = {} |
730 | @@ -377,6 +432,8 @@ |
731 | if 'category' in vals: |
732 | if vals['category'] != 'DEST': |
733 | vals['destination_ids'] = [(6, 0, [])] |
734 | + vals['dest_cc_ids'] = [(6, 0, [])] |
735 | + vals['allow_all_cc'] = False # default value |
736 | if vals['category'] != 'FUNDING': |
737 | vals['tuple_destination_account_ids'] = [(6, 0, [])] |
738 | vals['cost_center_ids'] = [(6, 0, [])] |
739 | @@ -408,6 +465,7 @@ |
740 | default['child_ids'] = [] # do not copy the child_ids |
741 | default['tuple_destination_summary'] = [] |
742 | default['line_ids'] = [] |
743 | + default['dest_cc_ids'] = [] |
744 | return super(analytic_account, self).copy(cr, uid, a_id, default, context=context) |
745 | |
746 | def _check_name_unicity(self, cr, uid, ids, context=None): |
747 | @@ -568,9 +626,41 @@ |
748 | self.write(cr, uid, ids, {'cost_center_ids':[(6, 0, [])]}, context=context) |
749 | return True |
750 | |
751 | + def button_dest_cc_clear(self, cr, uid, ids, context=None): |
752 | + """ |
753 | + Removes all Cost Centers selected in the Destination view |
754 | + """ |
755 | + self.write(cr, uid, ids, {'dest_cc_ids': [(6, 0, [])]}, context=context) |
756 | + return True |
757 | + |
758 | def button_dest_clear(self, cr, uid, ids, context=None): |
759 | self.write(cr, uid, ids, {'tuple_destination_account_ids':[(6, 0, [])]}, context=context) |
760 | return True |
761 | |
762 | + def get_destinations_by_accounts(self, cr, uid, ids, context=None): |
763 | + """ |
764 | + Returns a view with the Destinations by accounts (for the FP selected if any, otherwise for all the FP) |
765 | + """ |
766 | + if context is None: |
767 | + context = {} |
768 | + ir_model_obj = self.pool.get('ir.model.data') |
769 | + active_ids = context.get('active_ids', []) |
770 | + if active_ids: |
771 | + analytic_acc_category = self.browse(cr, uid, active_ids[0], fields_to_fetch=['category'], context=context).category or '' |
772 | + if analytic_acc_category == 'FUNDING': |
773 | + context.update({'search_default_funding_pool_id': active_ids[0]}) |
774 | + search_view_id = ir_model_obj.get_object_reference(cr, uid, 'analytic_distribution', 'view_account_destination_summary_search') |
775 | + search_view_id = search_view_id and search_view_id[1] or False |
776 | + return { |
777 | + 'name': _('Destinations by accounts'), |
778 | + 'type': 'ir.actions.act_window', |
779 | + 'res_model': 'account.destination.summary', |
780 | + 'view_type': 'form', |
781 | + 'view_mode': 'tree,form', |
782 | + 'search_view_id': [search_view_id], |
783 | + 'context': context, |
784 | + 'target': 'current', |
785 | + } |
786 | + |
787 | analytic_account() |
788 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
789 | |
790 | === modified file 'bin/addons/msf_doc_import/account.py' |
791 | --- bin/addons/msf_doc_import/account.py 2019-01-03 09:17:52 +0000 |
792 | +++ bin/addons/msf_doc_import/account.py 2019-05-06 14:14:05 +0000 |
793 | @@ -194,6 +194,7 @@ |
794 | self.pool.get('msf.doc.import.accounting.lines').unlink(cr, uid, old_lines_ids) |
795 | |
796 | # Check wizard data |
797 | + ad_obj = self.pool.get('analytic.distribution') |
798 | period_obj = self.pool.get('account.period') |
799 | period_ctx = context.copy() |
800 | period_ctx['extend_december'] = True |
801 | @@ -485,6 +486,10 @@ |
802 | errors.append(_('Line %s. The destination %s is not compatible with the account %s.') % |
803 | (current_line_num, line[cols['Destination']], line[cols['G/L Account']])) |
804 | continue |
805 | + if not ad_obj.check_dest_cc_compatibility(cr, uid, r_destination, r_cc, context=context): |
806 | + errors.append(_('Line %s. The Cost Center %s is not compatible with the Destination %s.') % |
807 | + (current_line_num, line[cols['Cost Centre']], line[cols['Destination']])) |
808 | + continue |
809 | # if the Fund. Pool used is NOT "PF" check the compatibility with the (account, dest) and the CC |
810 | if r_fp != msf_fp_id: |
811 | fp_fields = ['tuple_destination_account_ids', 'cost_center_ids'] |
812 | |
813 | === modified file 'bin/addons/msf_doc_import/msf_import_export.py' |
814 | --- bin/addons/msf_doc_import/msf_import_export.py 2018-11-16 10:06:13 +0000 |
815 | +++ bin/addons/msf_doc_import/msf_import_export.py 2019-05-06 14:14:05 +0000 |
816 | @@ -633,6 +633,7 @@ |
817 | model = MODEL_DICT[import_brw.model_list_selection]['model'] |
818 | impobj = self.pool.get(model) |
819 | acc_obj = self.pool.get('account.account') |
820 | + acc_analytic_obj = self.pool.get('account.analytic.account') |
821 | acc_dest_obj = self.pool.get('account.destination.link') |
822 | |
823 | import_data_obj = self.pool.get('import_data') |
824 | @@ -930,11 +931,20 @@ |
825 | if len(ids_to_update) > 1: |
826 | raise Exception('%d records found for rule=%s, model=%s' % (len(ids_to_update), data.get('name'), data.get('model_id'))) |
827 | |
828 | - # Analytic Accounts |
829 | - if import_brw.model_list_selection == 'analytic_accounts': |
830 | + # Funding Pools |
831 | + if import_brw.model_list_selection == 'funding_pools': |
832 | context['from_import_menu'] = True |
833 | + data['category'] = 'FUNDING' |
834 | + # Parent Analytic Account |
835 | + if data.get('parent_id'): |
836 | + parent_id = acc_analytic_obj.browse(cr, uid, data['parent_id'], |
837 | + fields_to_fetch=['type', 'category'], context=context) |
838 | + parent_type = parent_id.type or '' |
839 | + parent_category = parent_id.category or '' |
840 | + if parent_type != 'view' or parent_category != 'FUNDING': |
841 | + raise Exception(_('The Parent Analytic Account must be a View type Funding Pool.')) |
842 | # Cost Centers |
843 | - if data.get('cost_center_ids') and data.get('category', '') == 'FUNDING': |
844 | + if data.get('cost_center_ids'): |
845 | cc_list = [] |
846 | for cost_center in data.get('cost_center_ids').split(','): |
847 | cc = cost_center.strip() |
848 | @@ -949,7 +959,7 @@ |
849 | else: |
850 | data['cost_center_ids'] = [(6, 0, [])] |
851 | # Account/Destination |
852 | - if data.get('tuple_destination_account_ids') and data.get('category', '') == 'FUNDING': |
853 | + if data.get('tuple_destination_account_ids'): |
854 | dest_acc_list = [] |
855 | for destination_account in data.get('tuple_destination_account_ids').split(','): |
856 | dest_acc_ids = [] |
857 | @@ -969,6 +979,115 @@ |
858 | else: |
859 | data['tuple_destination_account_ids'] = [(6, 0, [])] |
860 | |
861 | + # Destinations |
862 | + if import_brw.model_list_selection == 'destinations': |
863 | + context['from_import_menu'] = True |
864 | + data['category'] = 'DEST' |
865 | + # Parent Analytic Account |
866 | + if data.get('parent_id'): |
867 | + parent_id = acc_analytic_obj.browse(cr, uid, data['parent_id'], fields_to_fetch=['type', 'category'], context=context) |
868 | + parent_type = parent_id.type or '' |
869 | + parent_category = parent_id.category or '' |
870 | + if parent_type != 'view' or parent_category != 'DEST': |
871 | + raise Exception(_('The Parent Analytic Account must be a View type Destination.')) |
872 | + # Type |
873 | + if data['type'] not in ['normal', 'view']: |
874 | + raise Exception(_('The Type must be either "Normal" or "View".')) |
875 | + # Cost Centers |
876 | + if data.get('dest_cc_ids'): |
877 | + if data.get('allow_all_cc'): |
878 | + raise Exception(_("Please either list the Cost Centers to allow, or allow all Cost Centers.")) |
879 | + dest_cc_list = [] |
880 | + for cost_center in data.get('dest_cc_ids').split(','): |
881 | + cc = cost_center.strip() |
882 | + cc_dom = [('category', '=', 'OC'), ('type', '=', 'normal'), |
883 | + '|', ('code', '=', cc), ('name', '=', cc)] |
884 | + cc_ids = impobj.search(cr, uid, cc_dom, order='id', limit=1, context=context) |
885 | + if cc_ids: |
886 | + dest_cc_list.append(cc_ids[0]) |
887 | + else: |
888 | + raise Exception(_('Cost Center "%s" not found.') % cc) |
889 | + data['dest_cc_ids'] = [(6, 0, dest_cc_list)] |
890 | + else: |
891 | + data['dest_cc_ids'] = [(6, 0, [])] |
892 | + # Accounts |
893 | + if data.get('destination_ids'): # "destinations_ids" corresponds to G/L accounts... |
894 | + acc_list = [] |
895 | + for account in data.get('destination_ids').split(','): |
896 | + acc = account.strip() |
897 | + acc_dom = [('type', '!=', 'view'), ('is_analytic_addicted', '=', True), ('code', '=', acc)] |
898 | + acc_ids = acc_obj.search(cr, uid, acc_dom, order='id', limit=1, context=context) |
899 | + if acc_ids: |
900 | + acc_list.append(acc_ids[0]) |
901 | + else: |
902 | + raise Exception(_("Account code \"%s\" doesn't exist or isn't allowed.") % acc) |
903 | + data['destination_ids'] = [(6, 0, acc_list)] |
904 | + else: |
905 | + data['destination_ids'] = [(6, 0, [])] |
906 | + # if the code matches with an existing destination: update it |
907 | + if data.get('code'): |
908 | + ids_to_update = impobj.search(cr, uid, [('category', '=', 'DEST'), ('code', '=', data['code'])], |
909 | + limit=1, context=context) |
910 | + if ids_to_update: |
911 | + # in case of empty columns on non-required fields, existing values should be deleted |
912 | + if 'date' not in data: |
913 | + data['date'] = False |
914 | + if 'dest_cc_ids' not in data: |
915 | + data['dest_cc_ids'] = [(6, 0, [])] |
916 | + if 'allow_all_cc' not in data: |
917 | + data['allow_all_cc'] = False |
918 | + if 'destination_ids' not in data: |
919 | + data['destination_ids'] = [(6, 0, [])] |
920 | + elif data['destination_ids'][0][2]: |
921 | + # accounts already linked to the destination: |
922 | + # - if they don't appear in the new list: will be automatically de-activated |
923 | + # - if they appear in the list: must be re-activated if they are currently disabled |
924 | + link_ids = acc_dest_obj.search(cr, uid, |
925 | + [('account_id', 'in', data['destination_ids'][0][2]), |
926 | + ('destination_id', '=', ids_to_update[0]), |
927 | + ('disabled', '=', True)], context=context) |
928 | + if link_ids: |
929 | + acc_dest_obj.write(cr, uid, link_ids, {'disabled': False}, context=context) |
930 | + |
931 | + # Cost Centers |
932 | + if import_brw.model_list_selection == 'cost_centers': |
933 | + context['from_import_menu'] = True |
934 | + data['category'] = 'OC' |
935 | + # Parent Analytic Account |
936 | + if data.get('parent_id'): |
937 | + parent_id = acc_analytic_obj.browse(cr, uid, data['parent_id'], |
938 | + fields_to_fetch=['type', 'category'], context=context) |
939 | + parent_type = parent_id.type or '' |
940 | + parent_category = parent_id.category or '' |
941 | + if parent_type != 'view' or parent_category != 'OC': |
942 | + raise Exception(_('The Parent Analytic Account must be a View type Cost Center.')) |
943 | + |
944 | + # Free 1 |
945 | + if import_brw.model_list_selection == 'free1': |
946 | + context['from_import_menu'] = True |
947 | + data['category'] = 'FREE1' |
948 | + # Parent Analytic Account |
949 | + if data.get('parent_id'): |
950 | + parent_id = acc_analytic_obj.browse(cr, uid, data['parent_id'], |
951 | + fields_to_fetch=['type', 'category'], context=context) |
952 | + parent_type = parent_id.type or '' |
953 | + parent_category = parent_id.category or '' |
954 | + if parent_type != 'view' or parent_category != 'FREE1': |
955 | + raise Exception(_('The Parent Analytic Account must be a View type Free 1 account.')) |
956 | + |
957 | + # Free 2 |
958 | + if import_brw.model_list_selection == 'free2': |
959 | + context['from_import_menu'] = True |
960 | + data['category'] = 'FREE2' |
961 | + # Parent Analytic Account |
962 | + if data.get('parent_id'): |
963 | + parent_id = acc_analytic_obj.browse(cr, uid, data['parent_id'], |
964 | + fields_to_fetch=['type', 'category'], context=context) |
965 | + parent_type = parent_id.type or '' |
966 | + parent_category = parent_id.category or '' |
967 | + if parent_type != 'view' or parent_category != 'FREE2': |
968 | + raise Exception(_('The Parent Analytic Account must be a View type Free 2 account.')) |
969 | + |
970 | if import_brw.model_list_selection == 'record_rules': |
971 | if not data.get('groups'): |
972 | data['groups'] = [(6, 0, [])] |
973 | |
974 | === modified file 'bin/addons/msf_doc_import/msf_import_export_conf.py' |
975 | --- bin/addons/msf_doc_import/msf_import_export_conf.py 2018-10-03 14:41:22 +0000 |
976 | +++ bin/addons/msf_doc_import/msf_import_export_conf.py 2019-05-06 14:14:05 +0000 |
977 | @@ -95,8 +95,28 @@ |
978 | 'domain_type': 'finance', |
979 | 'model': 'account.journal' |
980 | }, |
981 | - 'analytic_accounts': { |
982 | - 'name': 'Analytic Accounts', |
983 | + 'funding_pools': { |
984 | + 'name': 'Funding Pools', |
985 | + 'domain_type': 'finance', |
986 | + 'model': 'account.analytic.account' |
987 | + }, |
988 | + 'destinations': { |
989 | + 'name': 'Destinations', |
990 | + 'domain_type': 'finance', |
991 | + 'model': 'account.analytic.account' |
992 | + }, |
993 | + 'cost_centers': { |
994 | + 'name': 'Cost Centers', |
995 | + 'domain_type': 'finance', |
996 | + 'model': 'account.analytic.account' |
997 | + }, |
998 | + 'free1': { |
999 | + 'name': 'Free 1', |
1000 | + 'domain_type': 'finance', |
1001 | + 'model': 'account.analytic.account' |
1002 | + }, |
1003 | + 'free2': { |
1004 | + 'name': 'Free 2', |
1005 | 'domain_type': 'finance', |
1006 | 'model': 'account.analytic.account' |
1007 | }, |
1008 | @@ -466,11 +486,10 @@ |
1009 | 'analytic_journal_id.name', |
1010 | ], |
1011 | }, |
1012 | - 'analytic_accounts': { |
1013 | + 'funding_pools': { |
1014 | 'header_list': [ |
1015 | 'name', |
1016 | 'code', |
1017 | - 'category', |
1018 | 'parent_id.code', |
1019 | 'type', |
1020 | 'date_start', |
1021 | @@ -482,7 +501,74 @@ |
1022 | 'required_field_list': [ |
1023 | 'name', |
1024 | 'code', |
1025 | - 'category', |
1026 | + 'parent_id.code', |
1027 | + 'date_start', |
1028 | + ], |
1029 | + }, |
1030 | + 'cost_centers': { |
1031 | + 'header_list': [ |
1032 | + 'name', |
1033 | + 'code', |
1034 | + 'parent_id.code', |
1035 | + 'type', |
1036 | + 'date_start', |
1037 | + 'date', # "inactive from" |
1038 | + ], |
1039 | + 'required_field_list': [ |
1040 | + 'name', |
1041 | + 'code', |
1042 | + 'parent_id.code', |
1043 | + 'date_start', |
1044 | + ], |
1045 | + }, |
1046 | + 'destinations': { |
1047 | + 'header_list': [ |
1048 | + 'name', |
1049 | + 'code', |
1050 | + 'parent_id.code', |
1051 | + 'type', |
1052 | + 'date_start', |
1053 | + 'date', # "inactive from" |
1054 | + 'dest_cc_ids', |
1055 | + 'destination_ids', |
1056 | + 'allow_all_cc', |
1057 | + ], |
1058 | + 'required_field_list': [ |
1059 | + 'name', |
1060 | + 'code', |
1061 | + 'parent_id.code', |
1062 | + 'type', |
1063 | + 'date_start', |
1064 | + ], |
1065 | + }, |
1066 | + 'free1': { |
1067 | + 'header_list': [ |
1068 | + 'name', |
1069 | + 'code', |
1070 | + 'parent_id.code', |
1071 | + 'type', |
1072 | + 'date_start', |
1073 | + 'date', # "inactive from" |
1074 | + ], |
1075 | + 'required_field_list': [ |
1076 | + 'name', |
1077 | + 'code', |
1078 | + 'parent_id.code', |
1079 | + 'date_start', |
1080 | + ], |
1081 | + }, |
1082 | + 'free2': { |
1083 | + 'header_list': [ |
1084 | + 'name', |
1085 | + 'code', |
1086 | + 'parent_id.code', |
1087 | + 'type', |
1088 | + 'date_start', |
1089 | + 'date', # "inactive from" |
1090 | + ], |
1091 | + 'required_field_list': [ |
1092 | + 'name', |
1093 | + 'code', |
1094 | 'parent_id.code', |
1095 | 'date_start', |
1096 | ], |
1097 | |
1098 | === modified file 'bin/addons/msf_homere_interface/hr.py' |
1099 | --- bin/addons/msf_homere_interface/hr.py 2019-02-06 09:47:00 +0000 |
1100 | +++ bin/addons/msf_homere_interface/hr.py 2019-05-06 14:14:05 +0000 |
1101 | @@ -208,6 +208,22 @@ |
1102 | (_check_unicity, "Another employee has the same Identification No.", ['identification_id']), |
1103 | ] |
1104 | |
1105 | + def _check_employe_dest_cc_compatibility(self, cr, uid, employee_id, context=None): |
1106 | + """ |
1107 | + Raises an error in case the employee Destination and Cost Center are not compatible |
1108 | + """ |
1109 | + if context is None: |
1110 | + context = {} |
1111 | + ad_obj = self.pool.get('analytic.distribution') |
1112 | + employee_fields = ['destination_id', 'cost_center_id', 'name_resource'] |
1113 | + employee = self.browse(cr, uid, employee_id, fields_to_fetch=employee_fields, context=context) |
1114 | + emp_dest = employee.destination_id |
1115 | + emp_cc = employee.cost_center_id |
1116 | + if emp_dest and emp_cc: |
1117 | + if not ad_obj.check_dest_cc_compatibility(cr, uid, emp_dest.id, emp_cc.id, context=context): |
1118 | + raise osv.except_osv(_('Error'), _('Employee %s: the Cost Center %s is not compatible with the Destination %s.') % |
1119 | + (employee.name_resource, emp_cc.code or '', emp_dest.code or '')) |
1120 | + |
1121 | def create(self, cr, uid, vals, context=None): |
1122 | """ |
1123 | Block creation for local staff if no 'from' in context |
1124 | @@ -228,7 +244,9 @@ |
1125 | # Raise an error if employee is created manually |
1126 | if (not context.get('from', False) or context.get('from') not in ['yaml', 'import']) and not context.get('sync_update_execution', False) and not allow_edition: |
1127 | raise osv.except_osv(_('Error'), _('You are not allowed to create a local staff! Please use Import to create local staff.')) |
1128 | - return super(hr_employee, self).create(cr, uid, vals, context) |
1129 | + employee_id = super(hr_employee, self).create(cr, uid, vals, context) |
1130 | + self._check_employe_dest_cc_compatibility(cr, uid, employee_id, context=context) |
1131 | + return employee_id |
1132 | |
1133 | def write(self, cr, uid, ids, vals, context=None): |
1134 | """ |
1135 | @@ -277,6 +295,7 @@ |
1136 | employee_id = super(hr_employee, self).write(cr, uid, emp.id, new_vals, context) |
1137 | if employee_id: |
1138 | res.append(employee_id) |
1139 | + self._check_employe_dest_cc_compatibility(cr, uid, emp.id, context=context) |
1140 | return res |
1141 | |
1142 | def unlink(self, cr, uid, ids, context=None): |
1143 | @@ -322,6 +341,11 @@ |
1144 | fields = form.xpath('/' + view_type + '//field[@name="cost_center_id"]') |
1145 | for field in fields: |
1146 | field.set('domain', "[('type', '!=', 'view'), ('state', '=', 'open'), ('id', 'child_of', [%s])]" % oc_id) |
1147 | + # Change DEST field |
1148 | + dest_fields = form.xpath('/' + view_type + '//field[@name="destination_id"]') |
1149 | + for dest_field in dest_fields: |
1150 | + dest_field.set('domain', "[('category', '=', 'DEST'), ('type', '!=', 'view'), " |
1151 | + "('dest_compatible_with_cc_ids', '=', cost_center_id)]") |
1152 | # Change FP field |
1153 | try: |
1154 | fp_id = data_obj.get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_msf_private_funds')[1] |
1155 | |
1156 | === modified file 'bin/addons/msf_homere_interface/hr_payroll.py' |
1157 | --- bin/addons/msf_homere_interface/hr_payroll.py 2018-10-30 15:33:33 +0000 |
1158 | +++ bin/addons/msf_homere_interface/hr_payroll.py 2019-05-06 14:14:05 +0000 |
1159 | @@ -42,6 +42,7 @@ |
1160 | ids = [ids] |
1161 | # Prepare some values |
1162 | res = {} |
1163 | + ad_obj = self.pool.get('analytic.distribution') |
1164 | # Search MSF Private Fund element, because it's valid with all accounts |
1165 | try: |
1166 | fp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', |
1167 | @@ -57,6 +58,7 @@ |
1168 | # E/ DEST in list of available DEST in ACCOUNT |
1169 | # F/ Check posting date with cost center and destination if exists |
1170 | # G/ Check document date with funding pool |
1171 | + # H/ Check Cost Center / Destination compatibility |
1172 | ## CASES where FP is filled in (or not) and/or DEST is filled in (or not). |
1173 | ## CC is mandatory, so always available: |
1174 | # 1/ no FP, no DEST => Distro = valid |
1175 | @@ -124,6 +126,11 @@ |
1176 | if line.destination_id.id not in [x.id for x in account.destination_ids]: |
1177 | res[line.id] = 'invalid' |
1178 | continue |
1179 | + # H check |
1180 | + if line.destination_id and line.cost_center_id and \ |
1181 | + not ad_obj.check_dest_cc_compatibility(cr, uid, line.destination_id.id, line.cost_center_id.id, context=context): |
1182 | + res[line.id] = 'invalid' |
1183 | + continue |
1184 | return res |
1185 | |
1186 | def _get_third_parties(self, cr, uid, ids, field_name=None, arg=None, context=None): |
1187 | |
1188 | === modified file 'bin/addons/msf_homere_interface/hr_payroll_wizard.xml' |
1189 | --- bin/addons/msf_homere_interface/hr_payroll_wizard.xml 2019-01-21 09:53:32 +0000 |
1190 | +++ bin/addons/msf_homere_interface/hr_payroll_wizard.xml 2019-05-06 14:14:05 +0000 |
1191 | @@ -13,8 +13,11 @@ |
1192 | <field name="arch" type="xml"> |
1193 | <form string="Analytic Reallocation"> |
1194 | <group colspan="6" col="6"> |
1195 | - <field name="destination_id" context="{'search_default_active': 1, 'hide_inactive': 1}"/> |
1196 | - <field name="cost_center_id" on_change="onchange_cost_center(cost_center_id, funding_pool_id)" context="{'search_default_active': 1, 'hide_inactive': 1}"/> |
1197 | + <field name="cost_center_id" on_change="onchange_cost_center(cost_center_id, funding_pool_id)" |
1198 | + context="{'search_default_active': 1, 'hide_inactive': 1}"/> |
1199 | + <field name="destination_id" context="{'search_default_active': 1, 'hide_inactive': 1}" |
1200 | + domain="[('category', '=', 'DEST'), ('type', '!=', 'view'), |
1201 | + ('dest_compatible_with_cc_ids', '=', cost_center_id)]"/> |
1202 | <field name="funding_pool_id" context="{'search_default_active': 1, 'hide_inactive': 1}"/> |
1203 | </group> |
1204 | <newline/> |
1205 | |
1206 | === modified file 'bin/addons/msf_homere_interface/hr_view.xml' |
1207 | --- bin/addons/msf_homere_interface/hr_view.xml 2018-08-21 19:39:57 +0000 |
1208 | +++ bin/addons/msf_homere_interface/hr_view.xml 2019-05-06 14:14:05 +0000 |
1209 | @@ -27,8 +27,8 @@ |
1210 | <field name="homere_codeterrain" invisible="1"/> |
1211 | </group> |
1212 | <group colspan="4" col="8"> |
1213 | - <field name="destination_id" context="{'search_default_active': 1, 'hide_inactive': 1}"/> |
1214 | <field name="cost_center_id" on_change="onchange_cc(cost_center_id, funding_pool_id)" context="{'search_default_active': 1, 'hide_inactive': 1}"/> |
1215 | + <field name="destination_id" context="{'search_default_active': 1, 'hide_inactive': 1}"/> |
1216 | <field name="funding_pool_id" context="{'search_default_active': 1, 'hide_inactive': 1}"/> |
1217 | <newline /> |
1218 | <field name="free1_id" context="{'search_default_active': 1, 'hide_inactive': 1}"/> |
1219 | |
1220 | === modified file 'bin/addons/msf_profile/data/patches.xml' |
1221 | --- bin/addons/msf_profile/data/patches.xml 2019-03-28 13:22:15 +0000 |
1222 | +++ bin/addons/msf_profile/data/patches.xml 2019-05-06 14:14:05 +0000 |
1223 | @@ -411,5 +411,10 @@ |
1224 | <field name="method">us_5667_remove_contract_workflow</field> |
1225 | </record> |
1226 | |
1227 | + <!-- UF13.0 --> |
1228 | + <record id="us_5771_allow_all_cc_in_default_dest" model="patch.scripts"> |
1229 | + <field name="method">us_5771_allow_all_cc_in_default_dest</field> |
1230 | + </record> |
1231 | + |
1232 | </data> |
1233 | </openerp> |
1234 | |
1235 | === modified file 'bin/addons/msf_profile/i18n/fr_MF.po' |
1236 | --- bin/addons/msf_profile/i18n/fr_MF.po 2019-04-08 09:30:07 +0000 |
1237 | +++ bin/addons/msf_profile/i18n/fr_MF.po 2019-05-06 14:14:05 +0000 |
1238 | @@ -5227,8 +5227,9 @@ |
1239 | msgid "Close period (Mission)" |
1240 | msgstr "Clôturer la Période (Mission)" |
1241 | |
1242 | -#. module: msf_budget |
1243 | +#. modules: msf_budget, analytic_distribution |
1244 | #: report:addons/msf_budget/report/report_local_expenses_xls.mako:116 |
1245 | +#: report:funding.pool:0 |
1246 | msgid "Account name" |
1247 | msgstr "Nom du compte" |
1248 | |
1249 | @@ -16477,6 +16478,7 @@ |
1250 | #: view:threshold.value:0 |
1251 | #: view:international.transport.cost.report:0 |
1252 | #: view:local.transport.cost.report:0 |
1253 | +#: view:account.destination.summary:0 |
1254 | msgid "Group By..." |
1255 | msgstr "Grouper Par..." |
1256 | |
1257 | @@ -16779,7 +16781,7 @@ |
1258 | #. module: analytic_distribution |
1259 | #: view:account.analytic.account:0 |
1260 | msgid "Remove all" |
1261 | -msgstr "Remove all" |
1262 | +msgstr "Tout supprimer" |
1263 | |
1264 | #. module: vertical_integration |
1265 | #: code:addons/vertical_integration/report/hq_report_oca.py:176 |
1266 | @@ -31372,9 +31374,10 @@ |
1267 | msgid "Type of file" |
1268 | msgstr "Type de fichier" |
1269 | |
1270 | -#. module: msf_budget |
1271 | +#. modules: msf_budget, analytic_distribution |
1272 | #: report:addons/msf_budget/report/report_local_expenses_xls.mako:115 |
1273 | #: field:msf.budget.line,account_code:0 |
1274 | +#: report:funding.pool:0 |
1275 | msgid "Account code" |
1276 | msgstr "Code du compte" |
1277 | |
1278 | @@ -38475,6 +38478,7 @@ |
1279 | #: field:hr.payroll.msf,funding_pool_id:0 |
1280 | #: field:account.invoice.line,funding_pool_id:0 |
1281 | #: report:addons/account/report/free_allocation_report.mako:208 |
1282 | +#: view:account.destination.summary:0 |
1283 | #, python-format |
1284 | msgid "Funding Pool" |
1285 | msgstr "Funding Pool" |
1286 | @@ -47675,10 +47679,11 @@ |
1287 | msgid "America/Sitka" |
1288 | msgstr "America/Sitka" |
1289 | |
1290 | -#. module: account |
1291 | +#. modules: account, analytic_distribution |
1292 | #: view:account.analytic.line:0 |
1293 | +#: view:account.destination.summary:0 |
1294 | msgid "G/L account" |
1295 | -msgstr "G/L account" |
1296 | +msgstr "Compte Grand Livre" |
1297 | |
1298 | #. modules: account, register_accounting |
1299 | #: help:account.invoice,state:0 |
1300 | @@ -67403,6 +67408,7 @@ |
1301 | #: view:msf.instance:0 |
1302 | #: report:addons/account/report/free_allocation_report.mako:176 |
1303 | #: field:free.allocation.wizard,cost_center_ids:0 |
1304 | +#: field:account.analytic.account,dest_cc_ids:0 |
1305 | msgid "Cost Centers" |
1306 | msgstr "Centres de Coût" |
1307 | |
1308 | @@ -86607,10 +86613,12 @@ |
1309 | msgid "Total weight:" |
1310 | msgstr "Total weight:" |
1311 | |
1312 | -#. module: analytic_distribution |
1313 | +#. modules: analytic_distribution, analytic_override |
1314 | #: view:account.analytic.account:0 |
1315 | #: view:account.destination.summary:0 |
1316 | #: model:ir.model,name:analytic_distribution.model_account_destination_summary |
1317 | +#: model:ir.actions.server,name:analytic_distribution.action_analytic_acc_dest_summary |
1318 | +#: code:addons/analytic_override/analytic_account.py:652 |
1319 | msgid "Destinations by accounts" |
1320 | msgstr "Destinations par Compte" |
1321 | |
1322 | @@ -91150,8 +91158,8 @@ |
1323 | |
1324 | #. module: analytic_distribution |
1325 | #: report:funding.pool:0 |
1326 | -msgid "Accounts:" |
1327 | -msgstr "Comptes:" |
1328 | +msgid "Account/Destination:" |
1329 | +msgstr "Compte / Destination :" |
1330 | |
1331 | #. module: msf_outgoing |
1332 | #: help:return.pack.shipment.processor,address_id:0 |
1333 | @@ -96457,6 +96465,8 @@ |
1334 | #: view:sync.client.message_to_send:0 |
1335 | #: report:addons/account/report/free_allocation_report.mako:202 |
1336 | #: report:addons/stock_override/report/report_stock_move_xls.mako:143 |
1337 | +#: field:account.destination.summary,destination_id:0 |
1338 | +#: view:account.destination.summary:0 |
1339 | #, python-format |
1340 | msgid "Destination" |
1341 | msgstr "Destination" |
1342 | @@ -102110,6 +102120,12 @@ |
1343 | msgstr "%s: DEST (%s) incompatible avec le compte (%s)" |
1344 | |
1345 | #. module: account_hq_entries |
1346 | +#: code:addons/account_hq_entries/hq_entries.py:142 |
1347 | +#, python-format |
1348 | +msgid "%s: CC (%s) not compatible with DEST (%s)" |
1349 | +msgstr "%s : CC (%s) non compatible avec la DEST (%s)" |
1350 | + |
1351 | +#. module: account_hq_entries |
1352 | #: code:addons/account_hq_entries/hq_entries.py:103 |
1353 | #, python-format |
1354 | msgid "%s: No CC" |
1355 | @@ -105388,3 +105404,113 @@ |
1356 | #, python-format |
1357 | msgid "Product %s, BN: %s not enough stock to process quantity %s %s (stock level: %s)" |
1358 | msgstr "Produit %s, Lot: %s, pas assez de stock pour traiter la qantité %s %s (quantité en stock: %s)" |
1359 | + |
1360 | +#. module: analytic_distribution |
1361 | +#: code:addons/analytic_distribution/analytic_distribution.py:123 |
1362 | +#, python-format |
1363 | +msgid "Cost Center not compatible with destination" |
1364 | +msgstr "Centre de Coût non compatible avec la destination" |
1365 | + |
1366 | +#. module: analytic_distribution |
1367 | +#: code:addons/analytic_distribution/analytic_line.py:528 |
1368 | +#, python-format |
1369 | +msgid "CC/DEST" |
1370 | +msgstr "CC / DEST" |
1371 | + |
1372 | +#. module: analytic_distribution |
1373 | +#: report:funding.pool:0 |
1374 | +msgid "Destination code" |
1375 | +msgstr "Code de la destination" |
1376 | + |
1377 | +#. module: analytic_distribution |
1378 | +#: report:funding.pool:0 |
1379 | +msgid "Destination name" |
1380 | +msgstr "Nom de la destination" |
1381 | + |
1382 | +#. module: analytic_override |
1383 | +#: code:addons/analytic_override/analytic_account.py:227 |
1384 | +#, python-format |
1385 | +msgid "Filter not implemented on Destinations." |
1386 | +msgstr "Filtre non mis en oeuvre sur les Destinations." |
1387 | + |
1388 | +#. module: analytic_override |
1389 | +#: field:account.analytic.account,allow_all_cc:0 |
1390 | +msgid "Allow all Cost Centers" |
1391 | +msgstr "Autoriser tous les Centres de Coût" |
1392 | + |
1393 | +#. module: msf_doc_import |
1394 | +#: code:addons/msf_doc_import/msf_import_export.py:999 |
1395 | +#, python-format |
1396 | +msgid "Please either list the Cost Centers to allow, or allow all Cost Centers." |
1397 | +msgstr "Veuillez soit lister les Centres de Coût à autoriser, soit autoriser tous les Centres de Coût." |
1398 | + |
1399 | +#. module: analytic_override |
1400 | +#: field:account.analytic.account,dest_compatible_with_cc_ids:0 |
1401 | +msgid "Destinations compatible with the Cost Center" |
1402 | +msgstr "Destinations compatibles avec le Centre de Coût" |
1403 | + |
1404 | +#. module: analytic_override |
1405 | +#: code:addons/analytic_override/analytic_account.py:347 |
1406 | +#, python-format |
1407 | +msgid "Please remove the Cost Centers linked to the Destination before ticking this box." |
1408 | +msgstr "Veuillez supprimer les Centres de Coût liés à la Destination avant de cocher cette case." |
1409 | + |
1410 | +#. module: account_corrections |
1411 | +#: code:addons/account_corrections/wizard/analytic_distribution_wizard.py:246 |
1412 | +#, python-format |
1413 | +msgid "The Cost Center %s is not compatible with the Destination %s." |
1414 | +msgstr "Le Centre de Coût %s n'est pas compatible avec la Destination %s." |
1415 | + |
1416 | +#. module: msf_doc_import |
1417 | +#: code:addons/msf_doc_import/account.py:490 |
1418 | +#, python-format |
1419 | +msgid "Line %s. The Cost Center %s is not compatible with the Destination %s." |
1420 | +msgstr "Ligne %s. Le Centre de Coût %s n'est pas compatible avec la Destination %s." |
1421 | + |
1422 | +#. module: msf_doc_import |
1423 | +#: code:addons/msf_doc_import/msf_import_export.py:945 |
1424 | +#, python-format |
1425 | +msgid "The Parent Analytic Account must be a View type Funding Pool." |
1426 | +msgstr "Le Compte Analytique Parent doit être un Funding Pool de type Vue." |
1427 | + |
1428 | +#. module: msf_doc_import |
1429 | +#: code:addons/msf_doc_import/msf_import_export.py:992 |
1430 | +#, python-format |
1431 | +msgid "The Parent Analytic Account must be a View type Destination." |
1432 | +msgstr "Le Compte Analytique Parent doit être une Destination de type Vue." |
1433 | + |
1434 | +#. module: msf_doc_import |
1435 | +#: code:addons/msf_doc_import/msf_import_export.py:1063 |
1436 | +#, python-format |
1437 | +msgid "The Parent Analytic Account must be a View type Cost Center." |
1438 | +msgstr "Le Compte Analytique Parent doit être un Centre de Coût de type Vue." |
1439 | + |
1440 | +#. module: msf_doc_import |
1441 | +#: code:addons/msf_doc_import/msf_import_export.py:1076 |
1442 | +#, python-format |
1443 | +msgid "The Parent Analytic Account must be a View type Free 1 account." |
1444 | +msgstr "Le Compte Analytique Parent doit être un compte \"Option 1\" de type Vue." |
1445 | + |
1446 | +#. module: msf_doc_import |
1447 | +#: code:addons/msf_doc_import/msf_import_export.py:1089 |
1448 | +#, python-format |
1449 | +msgid "The Parent Analytic Account must be a View type Free 2 account." |
1450 | +msgstr "Le Compte Analytique Parent doit être un compte \"Option 2\" de type Vue." |
1451 | + |
1452 | +#. module: msf_doc_import |
1453 | +#: code:addons/msf_doc_import/msf_import_export.py:995 |
1454 | +#, python-format |
1455 | +msgid "The Type must be either \"Normal\" or \"View\"." |
1456 | +msgstr "Le Type doit être soit \"Normal\" soit \"Vue\"." |
1457 | + |
1458 | +#. module: msf_doc_import |
1459 | +#: code:addons/msf_doc_import/msf_import_export.py:1023 |
1460 | +#, python-format |
1461 | +msgid "Account code \"%s\" doesn't exist or isn't allowed." |
1462 | +msgstr "Le code comptable \"%s\" n'existe pas ou n'est pas autorisé." |
1463 | + |
1464 | +#. module: msf_homere_interface |
1465 | +#: code:addons/msf_homere_interface/hr.py:224 |
1466 | +#, python-format |
1467 | +msgid "Employee %s: the Cost Center %s is not compatible with the Destination %s." |
1468 | +msgstr "Employé %s : le Centre de Coût %s n'est pas compatible avec la Destination %s." |
1469 | |
1470 | === modified file 'bin/addons/msf_profile/msf_profile.py' |
1471 | --- bin/addons/msf_profile/msf_profile.py 2019-03-28 13:22:15 +0000 |
1472 | +++ bin/addons/msf_profile/msf_profile.py 2019-05-06 14:14:05 +0000 |
1473 | @@ -69,6 +69,24 @@ |
1474 | err_msg, |
1475 | ) |
1476 | |
1477 | + # UF13.0 |
1478 | + def us_5771_allow_all_cc_in_default_dest(self, cr, uid, *a, **b): |
1479 | + """ |
1480 | + Set the default created destinations (OPS/EXP/SUP/NAT) as "Allow all Cost Centers" |
1481 | + """ |
1482 | + update_dests = """ |
1483 | + UPDATE account_analytic_account |
1484 | + SET allow_all_cc = 't' |
1485 | + WHERE category = 'DEST' |
1486 | + AND id IN (SELECT res_id FROM ir_model_data WHERE module='analytic_distribution' AND name IN ( |
1487 | + 'analytic_account_destination_operation', |
1488 | + 'analytic_account_destination_expatriates', |
1489 | + 'analytic_account_destination_support', |
1490 | + 'analytic_account_destination_national_staff')); |
1491 | + """ |
1492 | + cr.execute(update_dests) |
1493 | + return True |
1494 | + |
1495 | # UF12.1 |
1496 | def us_5199_fix_cancel_partial_move_sol_id(self, cr, uid, *a, **b): |
1497 | ''' |
1498 | |
1499 | === modified file 'bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv' |
1500 | --- bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv 2019-02-28 15:19:06 +0000 |
1501 | +++ bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv 2019-05-06 14:14:05 +0000 |
1502 | @@ -31,6 +31,7 @@ |
1503 | msf_sync_data_server.periods_state,TRUE,TRUE,TRUE,TRUE,bidirectional,Up,[],"['state', 'period_id/id', 'instance_id/id']",HQ + MISSION,account.period.state,,Periods states,Valid,,129 |
1504 | msf_sync_data_server.fys_state,TRUE,TRUE,TRUE,TRUE,bidirectional,Up,[],"['state', 'fy_id/id', 'instance_id/id']",HQ + MISSION,account.fiscalyear.state,,Fiscal years states,Valid,,130 |
1505 | msf_sync_data_server.cost_center_cc_intermission,TRUE,TRUE,FALSE,TRUE,bidirectional,Down,"[('category' , '=' , 'OC'), ('code', '=', 'cc-intermission')]","['category', 'code', 'date', 'date_start', 'description', 'name', 'type']",OC,account.analytic.account,,CC-Intermission,Valid,,140 |
1506 | +msf_sync_data_server.destination_cc,TRUE,TRUE,TRUE,TRUE,bidirectional,Down,"[('category' , '=' , 'DEST')]","['dest_cc_ids/id', 'allow_all_cc']",OC,account.analytic.account,,Destinations: Cost Center fields,Valid,,145 |
1507 | msf_sync_data_server.gl_accounts_reconciliation,TRUE,TRUE,FALSE,TRUE,bidirectional,Down,[],"['reconciliation_debit_account_id/id', 'reconciliation_credit_account_id/id']",OC,account.account,,GL Accounts Reconciliation Accounts,Valid,,150 |
1508 | msf_sync_data_server.analytic_distribution,TRUE,TRUE,FALSE,FALSE,bidirectional,Bidirectional,[],['name'],HQ + MISSION,analytic.distribution,,Analytic Distribution,Valid,,200 |
1509 | msf_sync_data_server.cost_center_distribution_line,TRUE,TRUE,TRUE,FALSE,bidirectional,Bidirectional,"[('partner_type','=','internal')]","['amount', 'analytic_id/id', 'currency_id/id', 'date', 'destination_id/id', 'distribution_id/id', 'name', 'percentage', 'partner_type', 'source_date']",HQ + MISSION,cost.center.distribution.line,analytic_id,Cost Center Distribution Line - Internal partner,Valid,,201 |