Merge lp:~julie-w/unifield-server/US-8001 into lp:unifield-server
- US-8001
- Merge into trunk
Proposed by
jftempo
Status: | Merged |
---|---|
Merged at revision: | 5993 |
Proposed branch: | lp:~julie-w/unifield-server/US-8001 |
Merge into: | lp:unifield-server |
Diff against target: |
2031 lines (+1072/-124) (has conflicts) 30 files modified
bin/addons/account_corrections/wizard/analytic_distribution_wizard.py (+18/-31) bin/addons/account_hq_entries/hq_entries.py (+11/-0) bin/addons/account_hq_entries/wizard/hq_entries_split.py (+3/-1) bin/addons/analytic_distribution/account_commitment.py (+16/-2) bin/addons/analytic_distribution/analytic_account_view.xml (+24/-8) bin/addons/analytic_distribution/analytic_distribution.py (+27/-9) bin/addons/analytic_distribution/analytic_line.py (+33/-14) bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py (+5/-1) bin/addons/analytic_override/__init__.py (+2/-0) bin/addons/analytic_override/__openerp__.py (+2/-0) bin/addons/analytic_override/analytic_account.py (+197/-29) bin/addons/analytic_override/analytic_line.py (+6/-0) bin/addons/analytic_override/dest_cc_link.py (+174/-0) bin/addons/analytic_override/dest_cc_link.xml (+49/-0) bin/addons/analytic_override/multiple_cc_selection_wizard.py (+56/-0) bin/addons/analytic_override/multiple_cc_selection_wizard.xml (+30/-0) bin/addons/financing_contract/financing_contract_account_quadruplet.py (+9/-8) bin/addons/msf_audittrail/__openerp__.py (+4/-0) bin/addons/msf_audittrail/data/audittrail_dest_cc_link.yml (+39/-0) bin/addons/msf_doc_import/msf_import_export.py (+118/-11) bin/addons/msf_doc_import/msf_import_export_conf.py (+3/-1) bin/addons/msf_homere_interface/hr_payroll.py (+28/-1) bin/addons/msf_profile/data/patches.xml (+8/-0) bin/addons/msf_profile/i18n/fr_MF.po (+152/-3) bin/addons/msf_profile/msf_profile.py (+17/-0) bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv (+1/-0) bin/addons/sync_client/update.py (+1/-0) bin/addons/sync_common/common.py (+1/-0) bin/addons/sync_so/specific_xml_id.py (+24/-0) bin/osv/orm.py (+14/-5) Text conflict in bin/addons/msf_audittrail/__openerp__.py Text conflict in bin/addons/msf_profile/data/patches.xml Text conflict in bin/addons/msf_profile/msf_profile.py |
To merge this branch: | bzr merge lp:~julie-w/unifield-server/US-8001 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email: mp+402434@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 2020-09-22 13:17:55 +0000 |
3 | +++ bin/addons/account_corrections/wizard/analytic_distribution_wizard.py 2021-05-07 16:01:07 +0000 |
4 | @@ -283,38 +283,25 @@ |
5 | old_line = self.pool.get('funding.pool.distribution.line').browse(cr, uid, wiz_line.distribution_line_id.id) |
6 | |
7 | if old_line: |
8 | - #US-714: For HQ Entries, always create the COR and REV even the period is closed |
9 | - original_al_id = ana_line_obj.search(cr, uid, [('distrib_line_id', '=', 'funding.pool.distribution.line,%d'%old_line.id), ('is_reversal', '=', False), ('is_reallocated', '=', False)]) |
10 | - |
11 | - is_HQ_entries = False |
12 | - if original_al_id and len(original_al_id) == 1: |
13 | - original_al = ana_line_obj.browse(cr, uid, original_al_id[0], context) |
14 | - if original_al.journal_id.type == 'hq': |
15 | - is_HQ_entries = True |
16 | - |
17 | - # In case it's an HQ entries, just generate the REV and COR |
18 | - if is_HQ_entries: |
19 | - to_reverse.append(wiz_line) |
20 | - else: |
21 | - # existing line, test modifications |
22 | - # for FP, percentage, CC or destination changes regarding contracts |
23 | - if old_line.analytic_id.id != wiz_line.analytic_id.id \ |
24 | - or old_line.percentage != wiz_line.percentage \ |
25 | - or old_line.cost_center_id.id != wiz_line.cost_center_id.id \ |
26 | - or old_line.destination_id.id != wiz_line.destination_id.id: |
27 | - # FP account changed or % modified |
28 | - if self.pool.get('account.analytic.account').is_blocked_by_a_contract(cr, uid, [old_line.analytic_id.id]): |
29 | - raise osv.except_osv(_('Error'), _("Funding pool is on a soft/hard closed contract: %s")%(old_line.analytic_id.code)) |
30 | - |
31 | - if (old_line.cost_center_id.id != wiz_line.cost_center_id.id or |
32 | - old_line.destination_id.id != wiz_line.destination_id.id or |
33 | - old_line.percentage != wiz_line.percentage): |
34 | - if self._check_period_closed_on_fp_distrib_line(cr, uid, old_line.id): |
35 | - to_reverse.append(wiz_line) |
36 | - else: |
37 | - to_override.append(wiz_line) |
38 | - elif old_line.analytic_id.id != wiz_line.analytic_id.id: |
39 | + # existing line, test modifications |
40 | + # for FP, percentage, CC or destination changes regarding contracts |
41 | + if old_line.analytic_id.id != wiz_line.analytic_id.id \ |
42 | + or old_line.percentage != wiz_line.percentage \ |
43 | + or old_line.cost_center_id.id != wiz_line.cost_center_id.id \ |
44 | + or old_line.destination_id.id != wiz_line.destination_id.id: |
45 | + # FP account changed or % modified |
46 | + if self.pool.get('account.analytic.account').is_blocked_by_a_contract(cr, uid, [old_line.analytic_id.id]): |
47 | + raise osv.except_osv(_('Error'), _("Funding pool is on a soft/hard closed contract: %s")%(old_line.analytic_id.code)) |
48 | + |
49 | + if (old_line.cost_center_id.id != wiz_line.cost_center_id.id or |
50 | + old_line.destination_id.id != wiz_line.destination_id.id or |
51 | + old_line.percentage != wiz_line.percentage): |
52 | + if self._check_period_closed_on_fp_distrib_line(cr, uid, old_line.id, is_HQ_origin=is_HQ_origin): |
53 | + to_reverse.append(wiz_line) |
54 | + else: |
55 | to_override.append(wiz_line) |
56 | + elif old_line.analytic_id.id != wiz_line.analytic_id.id: |
57 | + to_override.append(wiz_line) |
58 | |
59 | old_line_ok.append(old_line.id) |
60 | |
61 | |
62 | === modified file 'bin/addons/account_hq_entries/hq_entries.py' |
63 | --- bin/addons/account_hq_entries/hq_entries.py 2021-05-05 16:04:38 +0000 |
64 | +++ bin/addons/account_hq_entries/hq_entries.py 2021-05-07 16:01:07 +0000 |
65 | @@ -44,6 +44,7 @@ |
66 | res = {} |
67 | logger = netsvc.Logger() |
68 | ad_obj = self.pool.get('analytic.distribution') |
69 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
70 | # Search MSF Private Fund element, because it's valid with all accounts |
71 | try: |
72 | fp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', |
73 | @@ -87,6 +88,13 @@ |
74 | res[line.id] = 'invalid' |
75 | logger.notifyChannel('account_hq_entries', netsvc.LOG_WARNING, _('%s: inactive DEST (%s)') % (line.id or '', dest.code or '')) |
76 | continue |
77 | + if line.destination_id and line.cost_center_id and line.date and \ |
78 | + dest_cc_link_obj.is_inactive_dcl(cr, uid, line.destination_id.id, line.cost_center_id.id, line.date, context=context): |
79 | + res[line.id] = 'invalid' |
80 | + logger.notifyChannel('account_hq_entries', netsvc.LOG_WARNING, |
81 | + _('%s: inactive combination (%s - %s)') % |
82 | + (line.id or '', line.destination_id.code or '', line.cost_center_id.code or '')) |
83 | + continue |
84 | # G Check |
85 | if line.analytic_id: |
86 | fp = self.pool.get('account.analytic.account').browse(cr, uid, line.analytic_id.id, context={'date': line.document_date}) |
87 | @@ -485,6 +493,9 @@ |
88 | def _check_cc(self, cr, uid, ids, context=None): |
89 | """ |
90 | At synchro time sets HQ entry to Not Run if the Cost Center used in the line doesn't exist or is inactive |
91 | + |
92 | + Note: if the CC is active but the Dest/CC combination is inactive, the sync update is NOT blocked: |
93 | + the HQ entry will be created with an invalid AD to be fixed before validation. |
94 | """ |
95 | if isinstance(ids, (int, long)): |
96 | ids = [ids] |
97 | |
98 | === modified file 'bin/addons/account_hq_entries/wizard/hq_entries_split.py' |
99 | --- bin/addons/account_hq_entries/wizard/hq_entries_split.py 2020-11-02 17:29:34 +0000 |
100 | +++ bin/addons/account_hq_entries/wizard/hq_entries_split.py 2021-05-07 16:01:07 +0000 |
101 | @@ -42,7 +42,9 @@ |
102 | # Process |
103 | for line in self.browse(cr, uid, ids, context=context): |
104 | res[line.id] = {'state_info': False, 'state': 'none'} |
105 | - state, info = self.pool.get('analytic.distribution').analytic_state_from_info(cr, uid, line.account_id.id, line.destination_id.id, line.cost_center_id.id, line.analytic_id.id, context=context) |
106 | + state, info = self.pool.get('analytic.distribution').analytic_state_from_info(cr, uid, line.account_id.id, line.destination_id.id, |
107 | + line.cost_center_id.id, line.analytic_id.id, |
108 | + posting_date=line.wizard_id.date, context=context) |
109 | res[line.id].update({'state_info': info, 'state': state,}) |
110 | return res |
111 | |
112 | |
113 | === modified file 'bin/addons/analytic_distribution/account_commitment.py' |
114 | --- bin/addons/analytic_distribution/account_commitment.py 2020-05-07 10:01:57 +0000 |
115 | +++ bin/addons/analytic_distribution/account_commitment.py 2021-05-07 16:01:07 +0000 |
116 | @@ -169,6 +169,7 @@ |
117 | aal_obj = self.pool.get('account.analytic.line') |
118 | curr_obj = self.pool.get('res.currency') |
119 | user_obj = self.pool.get('res.users') |
120 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
121 | # Browse elements if 'date' in vals |
122 | if vals.get('date', False): |
123 | date = vals.get('date') |
124 | @@ -188,8 +189,21 @@ |
125 | raise osv.except_osv(_('Warning'), _('No analytic distribution found for %s %s') % (cl.account_id.code, cl.initial_amount)) |
126 | for distrib_lines in [distrib.cost_center_lines, distrib.funding_pool_lines, distrib.free_1_lines, distrib.free_2_lines]: |
127 | for distrib_line in distrib_lines: |
128 | - if (distrib_line.analytic_id.date_start and date < distrib_line.analytic_id.date_start) or (distrib_line.analytic_id.date and date > distrib_line.analytic_id.date): |
129 | - raise osv.except_osv(_('Error'), _('The analytic account %s is not active for given date.') % (distrib_line.analytic_id.name,)) |
130 | + if distrib_line.analytic_id and \ |
131 | + (distrib_line.analytic_id.date_start and date < distrib_line.analytic_id.date_start or |
132 | + distrib_line.analytic_id.date and date >= distrib_line.analytic_id.date): |
133 | + raise osv.except_osv(_('Error'), _('The analytic account %s is not active for given date.') % |
134 | + (distrib_line.analytic_id.name,)) |
135 | + dest_cc_tuples = set() # check each Dest/CC combination only once |
136 | + for distrib_cc_l in distrib.cost_center_lines: |
137 | + if distrib_cc_l.analytic_id: # non mandatory field |
138 | + dest_cc_tuples.add((distrib_cc_l.destination_id, distrib_cc_l.analytic_id)) |
139 | + for distrib_fp_l in distrib.funding_pool_lines: |
140 | + dest_cc_tuples.add((distrib_fp_l.destination_id, distrib_fp_l.cost_center_id)) |
141 | + for dest, cc in dest_cc_tuples: |
142 | + if dest_cc_link_obj.is_inactive_dcl(cr, uid, dest.id, cc.id, date, context=context): |
143 | + raise osv.except_osv(_('Error'), _("The combination \"%s - %s\" is not active at this date: %s") % |
144 | + (dest.code or '', cc.code or '', date)) |
145 | # update the dates and fctal amounts of the related analytic lines |
146 | context.update({'currency_date': date}) # same date used for doc, posting and source date of all lines |
147 | for aal in cl.analytic_lines: |
148 | |
149 | === modified file 'bin/addons/analytic_distribution/analytic_account_view.xml' |
150 | --- bin/addons/analytic_distribution/analytic_account_view.xml 2020-10-08 13:11:14 +0000 |
151 | +++ bin/addons/analytic_distribution/analytic_account_view.xml 2021-05-07 16:01:07 +0000 |
152 | @@ -132,13 +132,28 @@ |
153 | </field> |
154 | </page> |
155 | <page string="Cost Centers" attrs="{'invisible': [('category', '!=', 'DEST')]}"> |
156 | - <field name="allow_all_cc" colspan="4" on_change="on_change_allow_all_cc(allow_all_cc, dest_cc_ids)"/> |
157 | - <button name="button_dest_cc_clear" type="object" string="Remove all" icon="gtk-clear" colspan="4"/> |
158 | + <field name="allow_all_cc" colspan="4" on_change="on_change_allow_all_cc(allow_all_cc, dest_cc_link_ids)"/> |
159 | + <button name="button_dest_cc_clear" type="object" string="Remove all" icon="gtk-clear" colspan="4" |
160 | + confirm="Do you really want to remove all the Cost Centers selected?" |
161 | + /> |
162 | <separator/> |
163 | - <field name="dest_cc_ids" nolabel="1" colspan="4" on_change="on_change_cc_ids(dest_cc_ids)"> |
164 | - <tree string="Cost Centers"> |
165 | - <field name="code"/> |
166 | - <field name="name"/> |
167 | + <group colspan="6" col="4"> |
168 | + <button icon="gtk-add" string="Add several Cost Centers" colspan="1" |
169 | + name="open_multiple_cc_selection_wizard" type="object" |
170 | + context="{'current_destination_id': record_id}"/> |
171 | + <label string="" colspan="3"/> |
172 | + </group> |
173 | + <field name="dest_cc_link_ids" nolabel="1" colspan="4" |
174 | + on_change="on_change_cc_ids(dest_cc_link_ids)" |
175 | + context="{'current_destination_id': record_id}"> |
176 | + <tree string="Cost Centers" editable="bottom"> |
177 | + <field name="current_id" invisible="1"/> |
178 | + <field name="cc_id" string="Code" |
179 | + on_change="on_change_cc_id(cc_id)" |
180 | + attrs="{'readonly': [('current_id', '!=', False)]}"/> |
181 | + <field name="cc_name" string="Name"/> |
182 | + <field name="active_from"/> |
183 | + <field name="inactive_from"/> |
184 | </tree> |
185 | </field> |
186 | </page> |
187 | @@ -262,9 +277,10 @@ |
188 | <field name="inherit_id" ref="account.view_account_analytic_account_list"/> |
189 | <field name="arch" type="xml"> |
190 | <tree string="Analytic Accounts" position="replace"> |
191 | - <tree toolbar="1" colors="red:(date and date<=current_date or dest_without_cc==True)" |
192 | - string="Analytic Accounts"> |
193 | + <tree toolbar="1" colors="red:(date and date<=current_date or dest_without_cc==True);grey:selected_in_dest" |
194 | + notselectable="selected_in_dest" string="Analytic Accounts"> |
195 | <field name="dest_without_cc" invisible="1"/> |
196 | + <field name="selected_in_dest" invisible="1"/> |
197 | <field name="name"/> |
198 | <field name="code"/> |
199 | <field name="description"/> |
200 | |
201 | === modified file 'bin/addons/analytic_distribution/analytic_distribution.py' |
202 | --- bin/addons/analytic_distribution/analytic_distribution.py 2020-11-02 17:29:34 +0000 |
203 | +++ bin/addons/analytic_distribution/analytic_distribution.py 2021-05-07 16:01:07 +0000 |
204 | @@ -36,13 +36,16 @@ |
205 | if context is None: |
206 | context = {} |
207 | analytic_acc_obj = self.pool.get('account.analytic.account') |
208 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
209 | + ret = True # by default if either dest or cc is missing |
210 | if destination_id and cost_center_id: |
211 | - dest = analytic_acc_obj.browse(cr, uid, destination_id, fields_to_fetch=['category', 'allow_all_cc', 'dest_cc_ids'], context=context) |
212 | - cc = analytic_acc_obj.browse(cr, uid, cost_center_id, fields_to_fetch=['category'], context=context) |
213 | - if dest and cc and dest.category == 'DEST' and cc.category == 'OC' and not dest.allow_all_cc and \ |
214 | - cc.id not in [c.id for c in dest.dest_cc_ids]: |
215 | - return False |
216 | - return True |
217 | + if analytic_acc_obj.search_exist(cr, uid, [('id', '=', destination_id), ('allow_all_cc', '=', True)], context=context): |
218 | + ret = True |
219 | + elif dest_cc_link_obj.search_exist(cr, uid, [('dest_id', '=', destination_id), ('cc_id', '=', cost_center_id)], context=context): |
220 | + ret = True |
221 | + else: |
222 | + ret = False |
223 | + return ret |
224 | |
225 | def check_fp_cc_compatibility(self, cr, uid, fp_id, cost_center_id, context=None): |
226 | """ |
227 | @@ -146,6 +149,7 @@ |
228 | if context is None: |
229 | context = {} |
230 | analytic_acc_obj = self.pool.get('account.analytic.account') |
231 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
232 | # Have an analytic distribution on another account than analytic-a-holic account make no sense. So their analytic distribution is valid |
233 | if account_id: |
234 | account = self.pool.get('account.account').read(cr, uid, account_id, ['is_analytic_addicted']) |
235 | @@ -153,7 +157,8 @@ |
236 | return 'valid' |
237 | if not distrib_id: |
238 | if parent_id: |
239 | - return self._get_distribution_state(cr, uid, parent_id, False, account_id, context, amount=amount) |
240 | + return self._get_distribution_state(cr, uid, parent_id, False, account_id, context=context, |
241 | + doc_date=doc_date, posting_date=posting_date, manual=manual, amount=amount) |
242 | return 'none' |
243 | distrib = self.browse(cr, uid, distrib_id) |
244 | if not distrib.funding_pool_lines: |
245 | @@ -183,6 +188,9 @@ |
246 | return 'invalid' |
247 | if not analytic_acc_obj.is_account_active(fp_line.cost_center_id, posting_date): |
248 | return 'invalid' |
249 | + if dest_cc_link_obj.is_inactive_dcl(cr, uid, fp_line.destination_id.id, fp_line.cost_center_id.id, |
250 | + posting_date, context=context): |
251 | + return 'invalid' |
252 | if doc_date and fp_line.analytic_id and not analytic_acc_obj.is_account_active(fp_line.analytic_id, doc_date): |
253 | return 'invalid' |
254 | if fp_line.destination_id.id not in account.get('destination_ids', []): |
255 | @@ -206,7 +214,7 @@ |
256 | return 'invalid' |
257 | return 'valid' |
258 | |
259 | - def analytic_state_from_info(self, cr, uid, account_id, destination_id, cost_center_id, analytic_id, context=None): |
260 | + def analytic_state_from_info(self, cr, uid, account_id, destination_id, cost_center_id, analytic_id, posting_date=False, context=None): |
261 | """ |
262 | Give analytic state from the given information. |
263 | Return result and some info if needed. |
264 | @@ -217,6 +225,7 @@ |
265 | # Prepare some values |
266 | res = 'valid' |
267 | info = '' |
268 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
269 | account = self.pool.get('account.account').browse(cr, uid, account_id, context=context) |
270 | # DISTRIBUTION VERIFICATION |
271 | # Check that destination is compatible with account |
272 | @@ -225,6 +234,9 @@ |
273 | # Check that Destination and Cost Center are compatible |
274 | if not self.check_dest_cc_compatibility(cr, uid, destination_id, cost_center_id, context=context): |
275 | return 'invalid', _('Cost Center not compatible with destination') |
276 | + # Check that their combination is active |
277 | + if posting_date and dest_cc_link_obj.is_inactive_dcl(cr, uid, destination_id, cost_center_id, posting_date, context=context): |
278 | + return 'invalid', _('Inactive DEST/CC combination') |
279 | # Check that cost center is compatible with FP |
280 | if not self.check_fp_cc_compatibility(cr, uid, analytic_id, cost_center_id, context=context): |
281 | return 'invalid', _('Cost Center not compatible with FP') |
282 | @@ -236,10 +248,11 @@ |
283 | def check_cc_distrib_active(self, cr, uid, distrib_br, posting_date=False, prefix='', from_supply=False): |
284 | """ |
285 | Checks the Cost Center Distribution Lines of the distribution in param.: |
286 | - raises an error if the CC or the Dest. used is not active at the posting date selected (or today's date) |
287 | + raises an error if the CC, the Dest., or their combination is not active at the posting date selected (or today's date) |
288 | If needed a "prefix" can be added to the error message. |
289 | """ |
290 | cc_distrib_line_obj = self.pool.get('cost.center.distribution.line') |
291 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
292 | if distrib_br: |
293 | if not posting_date: |
294 | posting_date = time.strftime('%Y-%m-%d') |
295 | @@ -257,6 +270,11 @@ |
296 | else: |
297 | raise osv.except_osv(_('Error'), _('%sDestination %s is either inactive at the date %s, or it allows no Cost Center.') % |
298 | (prefix, cline.destination_id.code or '', posting_date)) |
299 | + if cline.destination_id and cline.analytic_id and \ |
300 | + dest_cc_link_obj.is_inactive_dcl(cr, uid, cline.destination_id.id, cline.analytic_id.id, posting_date): |
301 | + raise osv.except_osv(_('Error'), _("%sThe combination \"%s - %s\" is not active at this date: %s") % |
302 | + (prefix, cline.destination_id.code or '', cline.analytic_id.code or '', posting_date)) |
303 | + |
304 | |
305 | |
306 | analytic_distribution() |
307 | |
308 | === modified file 'bin/addons/analytic_distribution/analytic_line.py' |
309 | --- bin/addons/analytic_distribution/analytic_line.py 2020-12-01 17:29:45 +0000 |
310 | +++ bin/addons/analytic_distribution/analytic_line.py 2021-05-07 16:01:07 +0000 |
311 | @@ -413,6 +413,8 @@ |
312 | ids = [ids] |
313 | # Prepare some value |
314 | ad_obj = self.pool.get('analytic.distribution') |
315 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
316 | + period_obj = self.pool.get('account.period') |
317 | account = self.pool.get('account.analytic.account').read(cr, uid, account_id, ['category', 'date_start', 'date'], context=context) |
318 | account_type = account and account.get('category', False) or False |
319 | res = [] |
320 | @@ -422,6 +424,9 @@ |
321 | date_start = account and account.get('date_start', False) or False |
322 | date_stop = account and account.get('date', False) or False |
323 | # Date verification for all lines and fetch all necessary elements sorted by analytic distribution |
324 | + cmp_dates = {} |
325 | + wiz_period_open = period_obj.search_exist(cr, uid, [('date_start', '<=', wiz_date), ('date_stop', '>=', wiz_date), |
326 | + ('special', '=', False), ('state', '=', 'draft')], context=context) |
327 | for aline in self.browse(cr, uid, ids): |
328 | # UTP-800: Change date comparison regarding FP. If FP, use document date. Otherwise use date. |
329 | aline_cmp_date = aline.date |
330 | @@ -435,13 +440,25 @@ |
331 | if aline.journal_id.type == 'hq' or aline.period_id and aline.period_id.state in ['done', 'mission-closed']: |
332 | aline_cmp_date = wiz_date |
333 | # these lines will be reverted, check if the reverted line is active |
334 | - oc_dest_date_start = max(aline.cost_center_id.date_start, aline.destination_id.date_start) |
335 | - oc_dest_date_stop = min(aline.cost_center_id.date or '9999-01-01', aline.destination_id.date or '9999-01-01') |
336 | - if (oc_dest_date_start and wiz_date < oc_dest_date_start) or (oc_dest_date_stop and wiz_date >= oc_dest_date_stop): |
337 | + if not wiz_period_open: |
338 | expired_date_ids.append(aline.id) |
339 | + else: |
340 | + oc_dest_date_start = max(aline.cost_center_id.date_start, aline.destination_id.date_start) |
341 | + oc_dest_date_stop = min(aline.cost_center_id.date or '9999-01-01', aline.destination_id.date or '9999-01-01') |
342 | + if (oc_dest_date_start and wiz_date < oc_dest_date_start) or (oc_dest_date_stop and wiz_date >= oc_dest_date_stop): |
343 | + expired_date_ids.append(aline.id) |
344 | + else: |
345 | + # check the Dest/CC link validity with the original Dest and CC which will be used in the REV |
346 | + destination_id = aline.destination_id and aline.destination_id.id or False |
347 | + cost_center_id = aline.cost_center_id and aline.cost_center_id.id or False |
348 | + if destination_id and cost_center_id and \ |
349 | + dest_cc_link_obj.is_inactive_dcl(cr, uid, destination_id, cost_center_id, wiz_date, context=context): |
350 | + expired_date_ids.append(aline.id) |
351 | if (date_start and aline_cmp_date < date_start) or (date_stop and aline_cmp_date >= date_stop): |
352 | expired_date_ids.append(aline.id) |
353 | + cmp_dates[aline.id] = aline_cmp_date |
354 | # Process regarding account_type |
355 | + ids = [i for i in ids if i not in expired_date_ids] # exclude the AJI in expired_date_ids |
356 | if account_type == 'OC': |
357 | for aline in self.browse(cr, uid, ids): |
358 | # Verify that: |
359 | @@ -449,10 +466,11 @@ |
360 | check_accounts = self.pool.get('account.analytic.account').is_blocked_by_a_contract(cr, uid, [aline.account_id.id]) |
361 | if check_accounts and aline.account_id.id in check_accounts: |
362 | continue |
363 | - if ad_obj.check_dest_cc_compatibility(cr, uid, aline.destination_id and aline.destination_id.id or False, |
364 | - account_id, context=context): |
365 | - if ad_obj.check_fp_cc_compatibility(cr, uid, aline.account_id.id, account_id, context=context): |
366 | - res.append(aline.id) |
367 | + dest_id = aline.destination_id and aline.destination_id.id or False |
368 | + if ad_obj.check_dest_cc_compatibility(cr, uid, dest_id, account_id, context=context) and \ |
369 | + ad_obj.check_fp_cc_compatibility(cr, uid, aline.account_id.id, account_id, context=context) and \ |
370 | + not dest_cc_link_obj.is_inactive_dcl(cr, uid, dest_id, account_id, cmp_dates[aline.id], context=context): |
371 | + res.append(aline.id) |
372 | elif account_type == 'FUNDING': |
373 | # Browse all analytic line to verify them |
374 | for aline in self.browse(cr, uid, ids): |
375 | @@ -475,19 +493,16 @@ |
376 | for aline in self.browse(cr, uid, ids, context=context): |
377 | # the following check is included into check_fp_acc_dest_compatibility: |
378 | # account_id in [x.id for x in aline.general_account_id.destination_ids] |
379 | - if ad_obj.check_dest_cc_compatibility(cr, uid, account_id, aline.cost_center_id and aline.cost_center_id.id or False, |
380 | - context=context) and \ |
381 | + cc_id = aline.cost_center_id and aline.cost_center_id.id or False |
382 | + if ad_obj.check_dest_cc_compatibility(cr, uid, account_id, cc_id, context=context) and \ |
383 | ad_obj.check_fp_acc_dest_compatibility(cr, uid, aline.account_id.id, aline.general_account_id.id, |
384 | - account_id, context=context): |
385 | + account_id, context=context) and \ |
386 | + not dest_cc_link_obj.is_inactive_dcl(cr, uid, account_id, cc_id, cmp_dates[aline.id], context=context): |
387 | res.append(aline.id) |
388 | else: |
389 | # Case of FREE1 and FREE2 lines |
390 | for i in ids: |
391 | res.append(i) |
392 | - # Delete elements that are in expired_date_ids |
393 | - for e in expired_date_ids: |
394 | - if e in res: |
395 | - res.remove(e) |
396 | return res |
397 | |
398 | def check_dest_cc_fp_compatibility(self, cr, uid, ids, |
399 | @@ -513,6 +528,7 @@ |
400 | new_cc_id, new_cc_br, |
401 | new_fp_id, new_fp_br): |
402 | ad_obj = self.pool.get('analytic.distribution') |
403 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
404 | if not general_account_br.is_analytic_addicted: |
405 | res.append((id, entry_sequence, '')) |
406 | return False |
407 | @@ -549,6 +565,9 @@ |
408 | if not check_date(new_cc_br, posting_date): |
409 | res.append((id, entry_sequence, _('CC date'))) |
410 | return False |
411 | + if new_dest_id and new_cc_id and dest_cc_link_obj.is_inactive_dcl(cr, uid, new_dest_id, new_cc_id, posting_date, context=context): |
412 | + res.append((id, entry_sequence, _('DEST/CC combination date'))) |
413 | + return False |
414 | if new_fp_id != msf_pf_id and not \ |
415 | check_date(new_fp_br, posting_date): |
416 | res.append((id, entry_sequence, _('FP date'))) |
417 | |
418 | === modified file 'bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py' |
419 | --- bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py 2021-04-26 09:35:14 +0000 |
420 | +++ bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py 2021-05-07 16:01:07 +0000 |
421 | @@ -1008,6 +1008,7 @@ |
422 | if isinstance(ids, (int, long)): |
423 | ids = [ids] |
424 | distrib_obj = self.pool.get('analytic.distribution') |
425 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
426 | for w in self.browse(cr, uid, ids): |
427 | # UF-1678 |
428 | # For Cost center and destination analytic accounts, check is done on POSTING date. It HAVE TO BE in context to be well processed (filter_active is a function that need a context) |
429 | @@ -1021,6 +1022,9 @@ |
430 | if not fpline.destination_id.filter_active: |
431 | raise osv.except_osv(_('Error'), _('Destination %s is either inactive at the date %s, or it allows no Cost Center.') |
432 | % (fpline.destination_id.code or '', w.posting_date)) |
433 | + if dest_cc_link_obj.is_inactive_dcl(cr, uid, fpline.destination_id.id, fpline.cost_center_id.id, w.posting_date): |
434 | + raise osv.except_osv(_('Error'), _("The combination \"%s - %s\" is not active at this date: %s") % |
435 | + (fpline.destination_id.code or '', fpline.cost_center_id.code or '', w.posting_date)) |
436 | # UF-1678 |
437 | # For funding pool analytic account, check is done on DOCUMENT date. It HAVE TO BE in context to be well processed (filter_active is a function that need a context) |
438 | if w.distribution_id and w.document_date: |
439 | @@ -1081,7 +1085,7 @@ |
440 | self.wizard_verifications(cr, uid, wiz.id, context=context) |
441 | # And do distribution creation if necessary |
442 | distrib_id = wiz.distribution_id and wiz.distribution_id.id or False |
443 | - if not distrib_id: |
444 | + if not distrib_id or not self.pool.get('analytic.distribution').exists(cr, uid, distrib_id, context=context): |
445 | # create a new analytic distribution |
446 | analytic_vals = {} |
447 | if wiz.partner_type:#UF-2138: added the ref to partner type of FO/PO |
448 | |
449 | === modified file 'bin/addons/analytic_override/__init__.py' |
450 | --- bin/addons/analytic_override/__init__.py 2014-03-14 09:40:12 +0000 |
451 | +++ bin/addons/analytic_override/__init__.py 2021-05-07 16:01:07 +0000 |
452 | @@ -22,5 +22,7 @@ |
453 | import analytic_distribution |
454 | import analytic_account |
455 | import analytic_line |
456 | +import dest_cc_link |
457 | +import multiple_cc_selection_wizard |
458 | |
459 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
460 | \ No newline at end of file |
461 | |
462 | === modified file 'bin/addons/analytic_override/__openerp__.py' |
463 | --- bin/addons/analytic_override/__openerp__.py 2014-10-29 13:47:46 +0000 |
464 | +++ bin/addons/analytic_override/__openerp__.py 2021-05-07 16:01:07 +0000 |
465 | @@ -32,6 +32,8 @@ |
466 | "init_xml" : [], |
467 | "update_xml": [ |
468 | 'security/ir.model.access.csv', |
469 | + 'dest_cc_link.xml', |
470 | + 'multiple_cc_selection_wizard.xml', |
471 | ], |
472 | 'test': [], |
473 | 'demo_xml': [ |
474 | |
475 | === modified file 'bin/addons/analytic_override/analytic_account.py' |
476 | --- bin/addons/analytic_override/analytic_account.py 2020-10-30 17:31:31 +0000 |
477 | +++ bin/addons/analytic_override/analytic_account.py 2021-05-07 16:01:07 +0000 |
478 | @@ -40,8 +40,8 @@ |
479 | if context is None: |
480 | context = {} |
481 | res = {} |
482 | - for a in self.browse(cr, uid, ids, fields_to_fetch=['category', 'type', 'allow_all_cc', 'dest_cc_ids'], context=context): |
483 | - if a.category == 'DEST' and a.type == 'normal' and not a.allow_all_cc and not a.dest_cc_ids: |
484 | + for a in self.browse(cr, uid, ids, fields_to_fetch=['category', 'type', 'allow_all_cc', 'dest_cc_link_ids'], context=context): |
485 | + if a.category == 'DEST' and a.type != 'view' and not a.allow_all_cc and not a.dest_cc_link_ids: |
486 | res[a.id] = True |
487 | else: |
488 | res[a.id] = False |
489 | @@ -95,7 +95,7 @@ |
490 | arg.append(('category', '!=', 'DEST')) |
491 | arg.append(('type', '=', 'view')) |
492 | arg.append(('allow_all_cc', '=', True)) |
493 | - arg.append(('dest_cc_ids', '!=', False)) |
494 | + arg.append(('dest_cc_link_ids', '!=', False)) |
495 | # filter: inactive |
496 | elif x[0] == 'filter_active' and x[2] is False: |
497 | arg.append('|') |
498 | @@ -106,9 +106,9 @@ |
499 | arg.append('&') |
500 | arg.append('&') |
501 | arg.append(('category', '=', 'DEST')) |
502 | - arg.append(('type', '=', 'normal')) |
503 | + arg.append(('type', '!=', 'view')) |
504 | arg.append(('allow_all_cc', '=', False)) |
505 | - arg.append(('dest_cc_ids', '=', False)) |
506 | + arg.append(('dest_cc_link_ids', '=', False)) |
507 | return arg |
508 | |
509 | def _get_fake(self, cr, uid, ids, *a, **b): |
510 | @@ -282,11 +282,20 @@ |
511 | cc = arg[2] |
512 | if operator != '=' or not isinstance(cc, (int, long)): |
513 | raise osv.except_osv(_('Error'), _('Filter not implemented on Destinations.')) |
514 | - all_dest_ids = self.search(cr, uid, [('category', '=', 'DEST')], context=context) |
515 | - compatible_dest_ids = [] |
516 | - for dest in self.browse(cr, uid, all_dest_ids, fields_to_fetch=['allow_all_cc', 'dest_cc_ids'], context=context): |
517 | - if dest.allow_all_cc or (cc and cc in [c.id for c in dest.dest_cc_ids]): |
518 | - compatible_dest_ids.append(dest.id) |
519 | + if not cc: |
520 | + # by default if no CC is selected display only the Destinations compatible with all CC |
521 | + compatible_dest_ids = self.search(cr, uid, [('category', '=', 'DEST'), |
522 | + ('type', '!=', 'view'), |
523 | + ('allow_all_cc', '=', True)], context=context) |
524 | + else: |
525 | + compatible_dest_sql = """ |
526 | + SELECT id |
527 | + FROM account_analytic_account |
528 | + WHERE category = 'DEST' AND type != 'view' |
529 | + AND (allow_all_cc = 't' OR id IN (SELECT dest_id FROM dest_cc_link WHERE cc_id = %s)); |
530 | + """ |
531 | + cr.execute(compatible_dest_sql, (cc,)) |
532 | + compatible_dest_ids = [x[0] for x in cr.fetchall()] |
533 | dom.append(('id', 'in', compatible_dest_ids)) |
534 | return dom |
535 | |
536 | @@ -442,6 +451,54 @@ |
537 | } |
538 | return res |
539 | |
540 | + def _get_selected_in_dest(self, cr, uid, cc_ids, name=False, args=False, context=None): |
541 | + """ |
542 | + Returns True for the Cost Centers already selected in the Destination: |
543 | + they will be displayed in grey in the list and won't be re-selectable. |
544 | + """ |
545 | + if context is None: |
546 | + context = {} |
547 | + if isinstance(cc_ids, (int, long)): |
548 | + cc_ids = [cc_ids] |
549 | + selected = [] |
550 | + dest_id = context.get('current_destination_id') or False |
551 | + if dest_id: |
552 | + dest = self.browse(cr, uid, dest_id, fields_to_fetch=['dest_cc_link_ids'], context=context) |
553 | + selected = [dest_cc_link.cc_id.id for dest_cc_link in dest.dest_cc_link_ids] |
554 | + res = {} |
555 | + for cc_id in cc_ids: |
556 | + res[cc_id] = cc_id in selected |
557 | + return res |
558 | + |
559 | + def _get_dest_cc_link_dates(self, cr, uid, ids, field_name, args, context=None): |
560 | + """ |
561 | + Returns a dict with key = id of the analytic account, |
562 | + and value = dict with dest_cc_link_active_from and dest_cc_link_inactive_from dates separated by commas (String). |
563 | + Note that the date format is the same in EN and FR, and that empty dates are not ignored. |
564 | + E.g.: '2021-03-02,2021-03-01,,2021-03-03,' |
565 | + |
566 | + This is used in Destination Import Tools, in particular for the Export of existing entries used as examples. |
567 | + """ |
568 | + if context is None: |
569 | + context = {} |
570 | + if isinstance(ids, (int, long)): |
571 | + ids = [ids] |
572 | + res = {} |
573 | + for a in self.browse(cr, uid, ids, fields_to_fetch=['category', 'dest_cc_link_ids'], context=context): |
574 | + active_date_list = [] |
575 | + inactive_date_list = [] |
576 | + if a.category == 'DEST': |
577 | + for cc_link in a.dest_cc_link_ids: |
578 | + active_date_str = "%s" % (cc_link.active_from or "") |
579 | + active_date_list.append(active_date_str) |
580 | + inactive_date_str = "%s" % (cc_link.inactive_from or "") |
581 | + inactive_date_list.append(inactive_date_str) |
582 | + res[a.id] = { |
583 | + 'dest_cc_link_active_from': ",".join(active_date_list), |
584 | + 'dest_cc_link_inactive_from': ",".join(inactive_date_list), |
585 | + } |
586 | + return res |
587 | + |
588 | _columns = { |
589 | 'name': fields.char('Name', size=128, required=True, translate=1), |
590 | 'code': fields.char('Code', size=24), |
591 | @@ -463,6 +520,17 @@ |
592 | 'dest_cc_ids': fields.many2many('account.analytic.account', 'destination_cost_center_rel', |
593 | 'destination_id', 'cost_center_id', string='Cost Centers', |
594 | domain="[('type', '!=', 'view'), ('category', '=', 'OC')]"), |
595 | + 'dest_cc_link_ids': fields.one2many('dest.cc.link', 'dest_id', string="Cost Centers", required=False), |
596 | + 'dest_cc_link_active_from': fields.function(_get_dest_cc_link_dates, method=True, type='char', |
597 | + store=False, readonly=True, |
598 | + string='Activation Combination Dest / CC from', |
599 | + help="Technical field used for Import Tools only", |
600 | + multi="dest_cc_link_dates"), |
601 | + 'dest_cc_link_inactive_from': fields.function(_get_dest_cc_link_dates, method=True, type='char', |
602 | + store=False, readonly=True, |
603 | + string='Inactivation Combination Dest / CC from', |
604 | + help="Technical field used for Import Tools only", |
605 | + multi="dest_cc_link_dates"), |
606 | 'allow_all_cc': fields.boolean(string="Allow all Cost Centers"), # for the Destinations |
607 | 'allow_all_cc_with_fp': fields.boolean(string="Allow all Cost Centers"), # for the Funding Pools |
608 | 'dest_compatible_with_cc_ids': fields.function(_get_fake, method=True, store=False, |
609 | @@ -498,6 +566,8 @@ |
610 | 'fp_account_ids': fields.many2many('account.account', 'fp_account_rel', 'fp_id', 'account_id', string='G/L Accounts', |
611 | domain="[('type', '!=', 'view'), ('is_analytic_addicted', '=', True), ('active', '=', 't')]", |
612 | help="G/L accounts linked to the Funding Pool", order_by='code'), |
613 | + 'selected_in_dest': fields.function(_get_selected_in_dest, string='Selected in Destination', method=True, |
614 | + type='boolean', store=False), |
615 | } |
616 | |
617 | _defaults ={ |
618 | @@ -577,39 +647,49 @@ |
619 | res['domain']['parent_id'] = [('category', '=', category), ('type', '=', 'view')] |
620 | return res |
621 | |
622 | - def on_change_allow_all_cc(self, cr, uid, ids, allow_all_cc, cc_ids, acc_type='destination', field_name='allow_all_cc', context=None): |
623 | + def on_change_allow_all_cc(self, cr, uid, ids, allow_all_cc, cc_ids, acc_type='destination', field_name='allow_all_cc', |
624 | + m2m=False, context=None): |
625 | """ |
626 | If the user tries to tick the box "Allow all Cost Centers" whereas CC are selected, |
627 | informs him that he has to remove the CC first |
628 | (acc_type = name of the Analytic Account Type to which the CC are linked, displayed in the warning msg) |
629 | """ |
630 | res = {} |
631 | - if allow_all_cc and cc_ids and cc_ids[0][2]: # e.g. [(6, 0, [1, 2])] |
632 | - # NOTE: the msg is stored in a variable on purpose, otherwise the ".po" translation files would wrongly contain Python code |
633 | - msg = 'Please remove the Cost Centers linked to the %s before ticking this box.' % acc_type.title() |
634 | - warning = { |
635 | - 'title': _('Warning!'), |
636 | - 'message': _(msg) |
637 | - } |
638 | - res['warning'] = warning |
639 | - res['value'] = {field_name: False, } |
640 | + if allow_all_cc: |
641 | + if m2m: |
642 | + cc_filled_in = cc_ids and cc_ids[0][2] or False # e.g. [(6, 0, [1, 2])] |
643 | + else: |
644 | + cc_filled_in = cc_ids or False |
645 | + if cc_filled_in: |
646 | + # NOTE: the msg is stored in a variable on purpose, otherwise the ".po" translation files would wrongly contain Python code |
647 | + msg = 'Please remove the Cost Centers linked to the %s before ticking this box.' % acc_type.title() |
648 | + warning = { |
649 | + 'title': _('Warning!'), |
650 | + 'message': _(msg) |
651 | + } |
652 | + res['warning'] = warning |
653 | + res['value'] = {field_name: False, } |
654 | return res |
655 | |
656 | def on_change_allow_all_cc_with_fp(self, cr, uid, ids, allow_all_cc_with_fp, cost_center_ids, context=None): |
657 | return self.on_change_allow_all_cc(cr, uid, ids, allow_all_cc_with_fp, cost_center_ids, acc_type='funding pool', |
658 | - field_name='allow_all_cc_with_fp', context=context) |
659 | + field_name='allow_all_cc_with_fp', m2m=True, context=context) |
660 | |
661 | - def on_change_cc_ids(self, cr, uid, ids, cc_ids, field_name='allow_all_cc', context=None): |
662 | + def on_change_cc_ids(self, cr, uid, ids, cc_ids, field_name='allow_all_cc', m2m=False, context=None): |
663 | """ |
664 | If at least a CC is selected, unticks the box "Allow all Cost Centers" |
665 | """ |
666 | res = {} |
667 | - if cc_ids and cc_ids[0][2]: # e.g. [(6, 0, [1, 2])] |
668 | + if m2m: |
669 | + cc_filled_in = cc_ids and cc_ids[0][2] or False # e.g. [(6, 0, [1, 2])] |
670 | + else: |
671 | + cc_filled_in = cc_ids or False |
672 | + if cc_filled_in: |
673 | res['value'] = {field_name: False, } |
674 | return res |
675 | |
676 | def on_change_cc_with_fp(self, cr, uid, ids, cost_center_ids, context=None): |
677 | - return self.on_change_cc_ids(cr, uid, ids, cost_center_ids, field_name='allow_all_cc_with_fp', context=context) |
678 | + return self.on_change_cc_ids(cr, uid, ids, cost_center_ids, field_name='allow_all_cc_with_fp', m2m=True, context=context) |
679 | |
680 | def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): |
681 | if not context: |
682 | @@ -685,6 +765,7 @@ |
683 | if vals['category'] != 'DEST': |
684 | vals['destination_ids'] = [(6, 0, [])] |
685 | vals['dest_cc_ids'] = [(6, 0, [])] |
686 | + vals['dest_cc_link_ids'] = [] # related dest.cc.links (if any) are deleted in _clean_dest_cc_link |
687 | vals['allow_all_cc'] = False # default value |
688 | if vals['category'] != 'FUNDING': |
689 | vals['tuple_destination_account_ids'] = [(6, 0, [])] |
690 | @@ -727,6 +808,7 @@ |
691 | default['tuple_destination_summary'] = [] |
692 | default['line_ids'] = [] |
693 | default['dest_cc_ids'] = [] |
694 | + default['dest_cc_link_ids'] = [] |
695 | return super(analytic_account, self).copy(cr, uid, a_id, default, context=context) |
696 | |
697 | def _check_name_unicity(self, cr, uid, ids, context=None): |
698 | @@ -785,6 +867,57 @@ |
699 | self.log(cr, uid, analytic_account_id, _('At least one Analytic Journal Item using the Analytic Account %s ' |
700 | 'has a Posting Date outside the activation dates selected.') % (analytic_acc.code)) |
701 | |
702 | + def _clean_dest_cc_link(self, cr, uid, ids, vals, context=None): |
703 | + """ |
704 | + In case Dest CC Links are reset in an analytic account: deletes the related existing Dest CC Links if any. |
705 | + Probable UC: Dest CC Links selected on a destination, then account changed to another category. |
706 | + """ |
707 | + if context is None: |
708 | + context = {} |
709 | + if isinstance(ids, (int, long)): |
710 | + ids = [ids] |
711 | + if 'dest_cc_link_ids' in vals and not vals['dest_cc_link_ids']: |
712 | + dcl_ids = [] |
713 | + for analytic_acc in self.browse(cr, uid, ids, fields_to_fetch=['dest_cc_link_ids'], context=context): |
714 | + dcl_ids.extend([dcl.id for dcl in analytic_acc.dest_cc_link_ids]) |
715 | + if dcl_ids: |
716 | + self.pool.get('dest.cc.link').unlink(cr, uid, dcl_ids, context=context) |
717 | + return True |
718 | + |
719 | + def _dest_cc_ids_must_be_updated(self, vals, context): |
720 | + """ |
721 | + Returns True if dest_cc_ids in vals must be changed to dest_cc_link_ids (the goal of this method is to ensure |
722 | + that the same condition is used everywhere and that the UC where all CC are removed is taken into account) |
723 | + """ |
724 | + if context and vals and context.get('sync_update_execution') and vals.get('dest_cc_ids') and vals['dest_cc_ids'][0][2] is not None: |
725 | + return True |
726 | + return False |
727 | + |
728 | + def _update_synched_dest_cc_ids(self, cr, uid, dest_ids, vals, context): |
729 | + """ |
730 | + For synch made before or while US-7295 was released: changes the dest_cc_ids into dest_cc_link_ids |
731 | + """ |
732 | + if self._dest_cc_ids_must_be_updated(vals, context): |
733 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
734 | + if isinstance(dest_ids, (int, long)): |
735 | + dest_ids = [dest_ids] |
736 | + for dest_id in dest_ids: |
737 | + dest = self.browse(cr, uid, dest_id, fields_to_fetch=['dest_cc_link_ids'], context=context) |
738 | + # note: after US-7295 patch script no instance has any dest_cc_ids, all CC links are necessarily dest.cc.link |
739 | + current_cc_ids = [dest_cc_link.cc_id.id for dest_cc_link in dest.dest_cc_link_ids] |
740 | + new_cc_ids = vals['dest_cc_ids'][0][2] or [] # take into account the UC where all CC are removed |
741 | + # delete the CC to be deleted |
742 | + cc_to_be_deleted = [c for c in current_cc_ids if c not in new_cc_ids] |
743 | + if cc_to_be_deleted: |
744 | + dcl_to_be_deleted = dest_cc_link_obj.search(cr, uid, [('dest_id', '=', dest_id), ('cc_id', 'in', cc_to_be_deleted)], |
745 | + order='NO_ORDER', context=context) |
746 | + dest_cc_link_obj.unlink(cr, uid, dcl_to_be_deleted, context=context) |
747 | + # create the CC to be created |
748 | + for cc_id in [c for c in new_cc_ids if c not in current_cc_ids]: |
749 | + dest_cc_link_obj.create(cr, uid, {'dest_id': dest_id, 'cc_id': cc_id}, context=context) |
750 | + del vals['dest_cc_ids'] |
751 | + return True |
752 | + |
753 | def create(self, cr, uid, vals, context=None): |
754 | """ |
755 | Some verifications before analytic account creation |
756 | @@ -797,6 +930,9 @@ |
757 | self._check_date(vals) |
758 | self.set_funding_pool_parent(cr, uid, vals) |
759 | vals = self.remove_inappropriate_links(vals, context=context) |
760 | + vals_copy = vals.copy() |
761 | + if self._dest_cc_ids_must_be_updated(vals, context): |
762 | + del vals['dest_cc_ids'] # replaced by dest_cc_link_ids in _update_synched_dest_cc_ids (called after create as it uses the new id) |
763 | # for auto instance creation, fx gain has been stored, need HQ sync + instance sync to get CC |
764 | if context.get('sync_update_execution') and vals.get('code') and vals.get('category') == 'OC': |
765 | param = self.pool.get('ir.config_parameter') |
766 | @@ -804,9 +940,11 @@ |
767 | if init_cc_fx_gain and vals.get('code') == init_cc_fx_gain: |
768 | vals['for_fx_gain_loss'] = True |
769 | param.set_param(cr, 1, 'INIT_CC_FX_GAIN', '') |
770 | - ids = super(analytic_account, self).create(cr, uid, vals, context=context) |
771 | - self._check_name_unicity(cr, uid, ids, context=context) |
772 | - return ids |
773 | + analytic_acc_id = super(analytic_account, self).create(cr, uid, vals, context=context) |
774 | + self._check_name_unicity(cr, uid, analytic_acc_id, context=context) |
775 | + self._clean_dest_cc_link(cr, uid, analytic_acc_id, vals, context=context) |
776 | + self._update_synched_dest_cc_ids(cr, uid, analytic_acc_id, vals_copy, context) |
777 | + return analytic_acc_id |
778 | |
779 | def write(self, cr, uid, ids, vals, context=None): |
780 | """ |
781 | @@ -822,7 +960,9 @@ |
782 | self._check_date(vals) |
783 | self.set_funding_pool_parent(cr, uid, vals) |
784 | vals = self.remove_inappropriate_links(vals, context=context) |
785 | + self._update_synched_dest_cc_ids(cr, uid, ids, vals, context) |
786 | res = super(analytic_account, self).write(cr, uid, ids, vals, context=context) |
787 | + self._clean_dest_cc_link(cr, uid, ids, vals, context=context) |
788 | self.check_access_rule(cr, uid, ids, 'write', context=context) |
789 | if context.get('from_web', False) or context.get('from_import_menu', False): |
790 | cat_instance = self.read(cr, uid, ids, ['category', 'instance_id', 'is_pf'], context=context)[0] |
791 | @@ -919,9 +1059,15 @@ |
792 | |
793 | def button_dest_cc_clear(self, cr, uid, ids, context=None): |
794 | """ |
795 | - Removes all Cost Centers selected in the Destination view |
796 | + Removes all Dest / CC combinations selected in the Cost Centers tab of the Destination form |
797 | """ |
798 | - self.write(cr, uid, ids, {'dest_cc_ids': [(6, 0, [])]}, context=context) |
799 | + if context is None: |
800 | + context = {} |
801 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
802 | + for dest in self.browse(cr, uid, ids, fields_to_fetch=['dest_cc_link_ids'], context=context): |
803 | + dest_cc_link_ids = [dcl.id for dcl in dest.dest_cc_link_ids] |
804 | + if dest_cc_link_ids: |
805 | + dest_cc_link_obj.unlink(cr, uid, dest_cc_link_ids, context=context) |
806 | return True |
807 | |
808 | def button_dest_clear(self, cr, uid, ids, context=None): |
809 | @@ -968,6 +1114,28 @@ |
810 | return False |
811 | return True |
812 | |
813 | + def open_multiple_cc_selection_wizard(self, cr, uid, ids, context=None): |
814 | + """ |
815 | + Creates and displays a Multiple CC Selection Wizard linked to the current Destination |
816 | + """ |
817 | + if context is None: |
818 | + context = {} |
819 | + if isinstance(ids, (int, long)): |
820 | + ids = [ids] |
821 | + multiple_cc_wiz_obj = self.pool.get('multiple.cc.selection.wizard') |
822 | + if ids: |
823 | + multiple_cc_wiz_id = multiple_cc_wiz_obj.create(cr, uid, {'dest_id': ids[0]}, context=context) |
824 | + return { |
825 | + 'type': 'ir.actions.act_window', |
826 | + 'res_model': 'multiple.cc.selection.wizard', |
827 | + 'view_type': 'form', |
828 | + 'view_mode': 'form', |
829 | + 'target': 'new', |
830 | + 'res_id': [multiple_cc_wiz_id], |
831 | + 'context': context, |
832 | + } |
833 | + return True |
834 | + |
835 | |
836 | analytic_account() |
837 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
838 | |
839 | === modified file 'bin/addons/analytic_override/analytic_line.py' |
840 | --- bin/addons/analytic_override/analytic_line.py 2021-04-23 12:31:26 +0000 |
841 | +++ bin/addons/analytic_override/analytic_line.py 2021-05-07 16:01:07 +0000 |
842 | @@ -159,6 +159,7 @@ |
843 | return True |
844 | |
845 | account_obj = self.pool.get('account.analytic.account') |
846 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
847 | |
848 | #US-419: Use the document date and not posting date when checking the validity of analytic account |
849 | # tech: replaced all date by document_date |
850 | @@ -171,6 +172,8 @@ |
851 | raise osv.except_osv(_('Error'), _("The analytic account selected '%s' is not active.") % (account.name or '',)) |
852 | if 'date' in vals and vals['date'] is not False: |
853 | date = vals['date'] |
854 | + dest = False |
855 | + cc = False |
856 | if vals.get('cost_center_id', False): |
857 | cc = account_obj.browse(cr, uid, vals['cost_center_id'], context=context) |
858 | if date < cc.date_start or (cc.date != False and date >= cc.date): |
859 | @@ -181,6 +184,9 @@ |
860 | if date < dest.date_start or (dest.date != False and date >= dest.date): |
861 | if 'from' not in context or context.get('from') != 'mass_reallocation': |
862 | raise osv.except_osv(_('Error'), _("The analytic account selected '%s' is not active.") % (dest.name or '',)) |
863 | + if context.get('from') != 'mass_reallocation' and dest and cc and \ |
864 | + dest_cc_link_obj.is_inactive_dcl(cr, uid, dest.id, cc.id, date, context=context): |
865 | + raise osv.except_osv(_('Error'), _("The combination \"%s - %s\" is not active.") % (dest.code or '', cc.code or '')) |
866 | return True |
867 | |
868 | def _check_document_date(self, cr, uid, ids): |
869 | |
870 | === added file 'bin/addons/analytic_override/dest_cc_link.py' |
871 | --- bin/addons/analytic_override/dest_cc_link.py 1970-01-01 00:00:00 +0000 |
872 | +++ bin/addons/analytic_override/dest_cc_link.py 2021-05-07 16:01:07 +0000 |
873 | @@ -0,0 +1,174 @@ |
874 | +# -*- coding: utf-8 -*- |
875 | +############################################################################## |
876 | +# |
877 | +# OpenERP, Open Source Management Solution |
878 | +# Copyright (C) 2021 MSF, TeMPO Consulting. |
879 | +# |
880 | +# This program is free software: you can redistribute it and/or modify |
881 | +# it under the terms of the GNU Affero General Public License as |
882 | +# published by the Free Software Foundation, either version 3 of the |
883 | +# License, or (at your option) any later version. |
884 | +# |
885 | +# This program is distributed in the hope that it will be useful, |
886 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
887 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
888 | +# GNU Affero General Public License for more details. |
889 | +# |
890 | +# You should have received a copy of the GNU Affero General Public License |
891 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
892 | +# |
893 | +############################################################################## |
894 | + |
895 | +from osv import osv |
896 | +from osv import fields |
897 | +from tools.translate import _ |
898 | + |
899 | + |
900 | +class dest_cc_link(osv.osv): |
901 | + _name = "dest.cc.link" |
902 | + _description = "Destination / Cost Center Combination" |
903 | + _rec_name = "cc_id" |
904 | + _trace = True |
905 | + |
906 | + def _get_current_id(self, cr, uid, ids, field_name, args, context=None): |
907 | + """ |
908 | + Returns a dict with key = value = current DB id. |
909 | + |
910 | + current_id is an internal field used to make the CC read-only except for new lines (= without DB id). |
911 | + The goal is to prevent the edition of a Dest CC Link with a CC linked to a different coordo than the previous CC. |
912 | + """ |
913 | + res = {} |
914 | + for i in ids: |
915 | + res[i] = i |
916 | + return res |
917 | + |
918 | + def _get_cc_code(self, cr, uid, ids, name, args, context=None): |
919 | + """ |
920 | + Returns a dict with key = Dest CC Link id, and value = related Cost Center code. |
921 | + """ |
922 | + if context is None: |
923 | + context = {} |
924 | + if isinstance(ids, (int, long)): |
925 | + ids = [ids] |
926 | + res = {} |
927 | + for dcl in self.browse(cr, uid, ids, fields_to_fetch=['cc_id'], context=context): |
928 | + res[dcl.id] = dcl.cc_id.code or '' |
929 | + return res |
930 | + |
931 | + def _get_dest_cc_link_to_update(self, cr, uid, analytic_acc_ids, context=None): |
932 | + """ |
933 | + Returns the list of Dest CC Links for which the CC code should be updated. |
934 | + """ |
935 | + if context is None: |
936 | + context = {} |
937 | + if isinstance(analytic_acc_ids, (int, long)): |
938 | + analytic_acc_ids = [analytic_acc_ids] |
939 | + return self.pool.get('dest.cc.link').search(cr, uid, [('cc_id', 'in', analytic_acc_ids)], order='NO_ORDER', context=context) |
940 | + |
941 | + _columns = { |
942 | + 'dest_id': fields.many2one('account.analytic.account', string="Destination", required=True, |
943 | + domain="[('category', '=', 'DEST'), ('type', '!=', 'view')]", ondelete='cascade', select=1), |
944 | + 'cc_id': fields.many2one('account.analytic.account', string="Cost Center", required=True, sort_column='cc_code', |
945 | + domain="[('category', '=', 'OC'), ('type', '!=', 'view')]", ondelete='cascade', select=1), |
946 | + 'cc_code': fields.function(_get_cc_code, method=True, string="Cost Center Code", type='char', size=24, |
947 | + readonly=True, |
948 | + store={ |
949 | + 'account.analytic.account': (_get_dest_cc_link_to_update, ['code'], 10), |
950 | + 'dest.cc.link': (lambda self, cr, uid, ids, c=None: ids, ['cc_id'], 20), |
951 | + }), |
952 | + 'cc_name': fields.related('cc_id', 'name', type="char", string="Cost Center Name", readonly=True, write_relate=False, store=False), |
953 | + 'active_from': fields.date('Activation Combination Dest / CC from', required=False), |
954 | + 'inactive_from': fields.date('Inactivation Combination Dest / CC from', required=False), |
955 | + 'current_id': fields.function(_get_current_id, method=1, type='integer', internal=1, string="DB Id (used by the UI)"), |
956 | + } |
957 | + |
958 | + _order = 'dest_id, cc_code, id' |
959 | + |
960 | + _sql_constraints = [ |
961 | + ('dest_cc_uniq', 'UNIQUE(dest_id, cc_id)', 'Each Cost Center can only be added once to the same Destination.'), |
962 | + ('dest_cc_date_check', 'CHECK(active_from < inactive_from)', 'The Activation date of the "Combination Dest / CC" ' |
963 | + 'must be before the Inactivation date.') |
964 | + ] |
965 | + |
966 | + def _check_analytic_lines(self, cr, uid, ids, context=None): |
967 | + """ |
968 | + Displays a non-blocking message on the top of the page in case some AJI using the Dest/CC link have been booked |
969 | + outside its activation dates. |
970 | + """ |
971 | + if context is None: |
972 | + context = {} |
973 | + if not context.get('sync_update_execution'): |
974 | + aal_obj = self.pool.get('account.analytic.line') |
975 | + if isinstance(ids, (int, long)): |
976 | + ids = [ids] |
977 | + for dcl in self.browse(cr, uid, ids, context=context): |
978 | + if dcl.active_from or dcl.inactive_from: |
979 | + dcl_dom = [('cost_center_id', '=', dcl.cc_id.id), ('destination_id', '=', dcl.dest_id.id)] |
980 | + if dcl.active_from and dcl.inactive_from: |
981 | + dcl_dom.append('|') |
982 | + if dcl.active_from: |
983 | + dcl_dom.append(('date', '<', dcl.active_from)) |
984 | + if dcl.inactive_from: |
985 | + dcl_dom.append(('date', '>=', dcl.inactive_from)) |
986 | + if aal_obj.search_exist(cr, uid, dcl_dom, context=context): |
987 | + self.log(cr, uid, dcl.id, _('At least one Analytic Journal Item using the combination \"%s - %s\" ' |
988 | + 'has a Posting Date outside the activation dates selected.') % |
989 | + (dcl.dest_id.code or '', dcl.cc_id.code or '')) |
990 | + |
991 | + def create(self, cr, uid, vals, context=None): |
992 | + """ |
993 | + Creates the Dest CC Combination, and: |
994 | + - displays an informative message on the top of the page if existing AJIs are using the combination outside its activation interval. |
995 | + - unticks the box "Allow all Cost Centers" from the related Dest. |
996 | + (UC: edit a Dest. having the box ticked, untick the box, add a CC and click on Cancel. |
997 | + CC isn't removed by the Cancel button as it is a o2m, so the box should remain unticked.) |
998 | + """ |
999 | + if context is None: |
1000 | + context = {} |
1001 | + analytic_acc_obj = self.pool.get('account.analytic.account') |
1002 | + res = super(dest_cc_link, self).create(cr, uid, vals, context=context) |
1003 | + self._check_analytic_lines(cr, uid, res, context=context) |
1004 | + dest_id = self.read(cr, uid, res, ['dest_id'], context=context)['dest_id'][0] |
1005 | + if analytic_acc_obj.search_exist(cr, uid, [('id', '=', dest_id), ('allow_all_cc', '=', True)], context=context): |
1006 | + analytic_acc_obj.write(cr, uid, dest_id, {'allow_all_cc': False}, context=context) |
1007 | + return res |
1008 | + |
1009 | + def write(self, cr, uid, ids, vals, context=None): |
1010 | + """ |
1011 | + See _check_analytic_lines |
1012 | + """ |
1013 | + res = super(dest_cc_link, self).write(cr, uid, ids, vals, context=context) |
1014 | + self._check_analytic_lines(cr, uid, ids, context=context) |
1015 | + return res |
1016 | + |
1017 | + def is_inactive_dcl(self, cr, uid, dest_id, cc_id, posting_date, context=None): |
1018 | + """ |
1019 | + Returns True if the Dest CC Link with the dest_id and cc_id exists and that the posting_date |
1020 | + is outside its validity date range. |
1021 | + """ |
1022 | + if context is None: |
1023 | + context = {} |
1024 | + inactive_dcl = False |
1025 | + if dest_id and cc_id and posting_date: |
1026 | + dcl_ids = self.search(cr, uid, [('dest_id', '=', dest_id), ('cc_id', '=', cc_id)], limit=1, context=context) |
1027 | + if dcl_ids: |
1028 | + dcl = self.browse(cr, uid, dcl_ids[0], fields_to_fetch=['active_from', 'inactive_from'], context=context) |
1029 | + inactive_dcl = (dcl.active_from and posting_date < dcl.active_from) or (dcl.inactive_from and posting_date >= dcl.inactive_from) |
1030 | + return inactive_dcl |
1031 | + |
1032 | + def on_change_cc_id(self, cr, uid, ids, cc_id): |
1033 | + """ |
1034 | + Fills in the CC Name as soon as a CC is selected |
1035 | + """ |
1036 | + res = {} |
1037 | + analytic_acc_obj = self.pool.get('account.analytic.account') |
1038 | + if cc_id: |
1039 | + name = analytic_acc_obj.read(cr, uid, cc_id, ['name'])['name'] |
1040 | + else: |
1041 | + name = False |
1042 | + res['value'] = {'cc_name': name, } |
1043 | + return res |
1044 | + |
1045 | + |
1046 | +dest_cc_link() |
1047 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1048 | |
1049 | === added file 'bin/addons/analytic_override/dest_cc_link.xml' |
1050 | --- bin/addons/analytic_override/dest_cc_link.xml 1970-01-01 00:00:00 +0000 |
1051 | +++ bin/addons/analytic_override/dest_cc_link.xml 2021-05-07 16:01:07 +0000 |
1052 | @@ -0,0 +1,49 @@ |
1053 | +<?xml version="1.0"?> |
1054 | +<openerp> |
1055 | + <data> |
1056 | + <!-- DEST CC LINK - FORM VIEW --> |
1057 | + <record id="view_dest_cc_link_form" model="ir.ui.view"> |
1058 | + <field name="name">dest.cc.link.form</field> |
1059 | + <field name="model">dest.cc.link</field> |
1060 | + <field name="type">form</field> |
1061 | + <field name="arch" type="xml"> |
1062 | + <form noteditable="1"> |
1063 | + <field name="cc_id"/> |
1064 | + <newline/> |
1065 | + <field name="active_from"/> |
1066 | + <field name="inactive_from"/> |
1067 | + </form> |
1068 | + </field> |
1069 | + </record> |
1070 | + |
1071 | + <!-- DEST CC LINK - TREE VIEW --> |
1072 | + <record id="view_dest_cc_link_tree" model="ir.ui.view"> |
1073 | + <field name="name">dest.cc.link.tree</field> |
1074 | + <field name="model">dest.cc.link</field> |
1075 | + <field name="type">tree</field> |
1076 | + <field name="arch" type="xml"> |
1077 | + <tree> |
1078 | + <field name="cc_id"/> |
1079 | + <field name="active_from"/> |
1080 | + <field name="inactive_from"/> |
1081 | + </tree> |
1082 | + </field> |
1083 | + </record> |
1084 | + |
1085 | + <!-- DEST CC LINK - SEARCH VIEW --> |
1086 | + <record id="view_dest_cc_link_search" model="ir.ui.view"> |
1087 | + <field name="name">dest.cc.link.search</field> |
1088 | + <field name="model">dest.cc.link</field> |
1089 | + <field name="type">search</field> |
1090 | + <field name="arch" type="xml"> |
1091 | + <search> |
1092 | + <group> |
1093 | + <field name="cc_id"/> |
1094 | + <field name="active_from"/> |
1095 | + <field name="inactive_from"/> |
1096 | + </group> |
1097 | + </search> |
1098 | + </field> |
1099 | + </record> |
1100 | + </data> |
1101 | +</openerp> |
1102 | |
1103 | === added file 'bin/addons/analytic_override/multiple_cc_selection_wizard.py' |
1104 | --- bin/addons/analytic_override/multiple_cc_selection_wizard.py 1970-01-01 00:00:00 +0000 |
1105 | +++ bin/addons/analytic_override/multiple_cc_selection_wizard.py 2021-05-07 16:01:07 +0000 |
1106 | @@ -0,0 +1,56 @@ |
1107 | +# -*- coding: utf-8 -*- |
1108 | +############################################################################## |
1109 | +# |
1110 | +# OpenERP, Open Source Management Solution |
1111 | +# Copyright (C) 2021 MSF, TeMPO Consulting. |
1112 | +# |
1113 | +# This program is free software: you can redistribute it and/or modify |
1114 | +# it under the terms of the GNU Affero General Public License as |
1115 | +# published by the Free Software Foundation, either version 3 of the |
1116 | +# License, or (at your option) any later version. |
1117 | +# |
1118 | +# This program is distributed in the hope that it will be useful, |
1119 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1120 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1121 | +# GNU Affero General Public License for more details. |
1122 | +# |
1123 | +# You should have received a copy of the GNU Affero General Public License |
1124 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1125 | +# |
1126 | +############################################################################## |
1127 | + |
1128 | +from osv import fields |
1129 | +from osv import osv |
1130 | + |
1131 | + |
1132 | +class multiple_cc_selection_wizard(osv.osv_memory): |
1133 | + _name = 'multiple.cc.selection.wizard' |
1134 | + |
1135 | + _columns = { |
1136 | + 'dest_id': fields.many2one('account.analytic.account', string="Destination", required=True, |
1137 | + domain="[('category', '=', 'DEST'), ('type', '!=', 'view')]"), |
1138 | + 'cc_ids': fields.many2many('account.analytic.account', 'multiple_cc_wiz_rel', 'wizard_id', 'cost_center_id', |
1139 | + string="Cost Centers", domain="[('category', '=', 'OC'), ('type', '!=', 'view')]"), |
1140 | + } |
1141 | + |
1142 | + def multiple_cc_add(self, cr, uid, ids, context=None): |
1143 | + """ |
1144 | + Adds the Cost Centers selected in the wizard to the current destination |
1145 | + without filling in the activation and inactivation dates of the related combinations. |
1146 | + """ |
1147 | + if context is None: |
1148 | + context = {} |
1149 | + if isinstance(ids, (int, long)): |
1150 | + ids = [ids] |
1151 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
1152 | + analytic_acc_obj = self.pool.get('account.analytic.account') |
1153 | + wiz = self.browse(cr, uid, ids[0], context=context) |
1154 | + if wiz.cc_ids: |
1155 | + for cc in wiz.cc_ids: |
1156 | + # note: this automatically unticks the box "Allow all Cost Centers" (as for a manual CC addition) |
1157 | + dest_cc_link_obj.create(cr, uid, {'dest_id': wiz.dest_id.id, 'cc_id': cc.id}, context=context) |
1158 | + return {'type': 'ir.actions.act_window_close'} |
1159 | + |
1160 | + |
1161 | +multiple_cc_selection_wizard() |
1162 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1163 | |
1164 | === added file 'bin/addons/analytic_override/multiple_cc_selection_wizard.xml' |
1165 | --- bin/addons/analytic_override/multiple_cc_selection_wizard.xml 1970-01-01 00:00:00 +0000 |
1166 | +++ bin/addons/analytic_override/multiple_cc_selection_wizard.xml 2021-05-07 16:01:07 +0000 |
1167 | @@ -0,0 +1,30 @@ |
1168 | +<?xml version="1.0" encoding="utf-8"?> |
1169 | +<openerp> |
1170 | + <data> |
1171 | + |
1172 | + <!-- MULTIPLE CC SELECTION WIZARD - FORM VIEW --> |
1173 | + <record id="multiple_cc_selection_wizard_form_view" model="ir.ui.view"> |
1174 | + <field name="name">multiple.cc.selection.wizard.form</field> |
1175 | + <field name="model">multiple.cc.selection.wizard</field> |
1176 | + <field name="type">form</field> |
1177 | + <field name="arch" type="xml"> |
1178 | + <form string="Add several Cost Centers"> |
1179 | + <label nolabel="1" colspan="6" |
1180 | + string="This wizard enables you to select several Cost Centers at once to be added to the Destination. The activation and inactivation dates of the related Dest / CC combinations will remain empty."/> |
1181 | + <field name="cc_ids" nolabel="1" colspan="6"> |
1182 | + <tree string="Cost Centers"> |
1183 | + <field name="code"/> |
1184 | + <field name="name"/> |
1185 | + </tree> |
1186 | + </field> |
1187 | + <group colspan="6" col="4"> |
1188 | + <label string="" colspan="2"/> |
1189 | + <button icon="gtk-cancel" string="Cancel" special="cancel" colspan="1"/> |
1190 | + <button icon="gtk-add" string="Add" name="multiple_cc_add" type="object" colspan="1"/> |
1191 | + </group> |
1192 | + </form> |
1193 | + </field> |
1194 | + </record> |
1195 | + |
1196 | + </data> |
1197 | +</openerp> |
1198 | |
1199 | === modified file 'bin/addons/financing_contract/financing_contract_account_quadruplet.py' |
1200 | --- bin/addons/financing_contract/financing_contract_account_quadruplet.py 2020-11-20 15:52:12 +0000 |
1201 | +++ bin/addons/financing_contract/financing_contract_account_quadruplet.py 2021-05-07 16:01:07 +0000 |
1202 | @@ -89,14 +89,15 @@ |
1203 | funding_pool_associated_destinations fpad, |
1204 | account_destination_link lnk, |
1205 | account_analytic_account dest |
1206 | - LEFT JOIN destination_cost_center_rel dest_cc_rel ON dest_cc_rel.destination_id = dest.id |
1207 | + LEFT JOIN dest_cc_link ON dest_cc_link.dest_id = dest.id |
1208 | + |
1209 | WHERE |
1210 | fpacc.funding_pool_id = fp.id AND |
1211 | fpacc.cost_center_id = cc.id AND |
1212 | lnk.id = fpad.tuple_id AND |
1213 | fp.id = fpad.funding_pool_id AND |
1214 | lnk.destination_id = dest.id AND |
1215 | - (dest.allow_all_cc = 't' or dest_cc_rel.cost_center_id = cc.id) |
1216 | + (dest.allow_all_cc = 't' or dest_cc_link.cc_id = cc.id) |
1217 | |
1218 | UNION |
1219 | |
1220 | @@ -111,7 +112,7 @@ |
1221 | account_destination_link lnk, |
1222 | account_account gl_account, |
1223 | account_analytic_account dest |
1224 | - LEFT JOIN destination_cost_center_rel dest_cc_rel ON dest_cc_rel.destination_id = dest.id |
1225 | + LEFT JOIN dest_cc_link ON dest_cc_link.dest_id = dest.id |
1226 | where |
1227 | fp.allow_all_cc_with_fp = 't' and |
1228 | cc.type != 'view' and |
1229 | @@ -123,7 +124,7 @@ |
1230 | fp_account_rel.account_id= gl_account.id and |
1231 | lnk.account_id = gl_account.id and |
1232 | lnk.destination_id = dest.id and |
1233 | - (dest.allow_all_cc = 't' or dest_cc_rel.cost_center_id = cc.id) |
1234 | + (dest.allow_all_cc = 't' or dest_cc_link.cc_id = cc.id) |
1235 | |
1236 | UNION |
1237 | |
1238 | @@ -138,7 +139,7 @@ |
1239 | account_destination_link lnk, |
1240 | account_account gl_account, |
1241 | account_analytic_account dest |
1242 | - LEFT JOIN destination_cost_center_rel dest_cc_rel ON dest_cc_rel.destination_id = dest.id |
1243 | + LEFT JOIN dest_cc_link ON dest_cc_link.dest_id = dest.id |
1244 | where |
1245 | fp.allow_all_cc_with_fp = 'f' and |
1246 | fpacc.funding_pool_id = fp.id and |
1247 | @@ -148,7 +149,7 @@ |
1248 | fp_account_rel.account_id= gl_account.id and |
1249 | lnk.account_id = gl_account.id and |
1250 | lnk.destination_id = dest.id and |
1251 | - (dest.allow_all_cc = 't' or dest_cc_rel.cost_center_id = cc.id) |
1252 | + (dest.allow_all_cc = 't' or dest_cc_link.cc_id = cc.id) |
1253 | |
1254 | UNION |
1255 | |
1256 | @@ -162,7 +163,7 @@ |
1257 | account_target_costcenter target, |
1258 | account_destination_link lnk, |
1259 | account_analytic_account dest |
1260 | - LEFT JOIN destination_cost_center_rel dest_cc_rel ON dest_cc_rel.destination_id = dest.id |
1261 | + LEFT JOIN dest_cc_link ON dest_cc_link.dest_id = dest.id |
1262 | where |
1263 | fp.allow_all_cc_with_fp = 't' and |
1264 | cc.type != 'view' and |
1265 | @@ -173,7 +174,7 @@ |
1266 | lnk.id = fpad.tuple_id and |
1267 | fp.id = fpad.funding_pool_id and |
1268 | lnk.destination_id = dest.id and |
1269 | - (dest.allow_all_cc = 't' or dest_cc_rel.cost_center_id = cc.id) |
1270 | + (dest.allow_all_cc = 't' or dest_cc_link.cc_id = cc.id) |
1271 | ) AS combinations |
1272 | )""") |
1273 | return res |
1274 | |
1275 | === modified file 'bin/addons/msf_audittrail/__openerp__.py' |
1276 | --- bin/addons/msf_audittrail/__openerp__.py 2021-05-05 16:04:38 +0000 |
1277 | +++ bin/addons/msf_audittrail/__openerp__.py 2021-05-07 16:01:07 +0000 |
1278 | @@ -57,7 +57,11 @@ |
1279 | 'data/audittrail_account_account.yml', |
1280 | 'data/audittrail_account_tax.yml', |
1281 | 'data/audittrail_res_company.yml', |
1282 | +<<<<<<< TREE |
1283 | 'data/audittrail_hq_entry.yml', |
1284 | +======= |
1285 | + 'data/audittrail_dest_cc_link.yml', |
1286 | +>>>>>>> MERGE-SOURCE |
1287 | 'audittrail_report.xml', |
1288 | 'audittrail_invoice_data.yml', |
1289 | ], |
1290 | |
1291 | === added file 'bin/addons/msf_audittrail/data/audittrail_dest_cc_link.yml' |
1292 | --- bin/addons/msf_audittrail/data/audittrail_dest_cc_link.yml 1970-01-01 00:00:00 +0000 |
1293 | +++ bin/addons/msf_audittrail/data/audittrail_dest_cc_link.yml 2021-05-07 16:01:07 +0000 |
1294 | @@ -0,0 +1,39 @@ |
1295 | +- |
1296 | + For Dest CC Links (dest.cc.link), track the changes on the Destinations |
1297 | +- |
1298 | + !python {model: audittrail.rule}: | |
1299 | + name = 'Dest / CC Combinations' |
1300 | + object_ids = self.pool.get('ir.model').search(cr, uid, [('model', '=', 'dest.cc.link')], context=context) |
1301 | + rule_id = self.search(cr, uid, [('object_id', 'in', object_ids)], context=context) |
1302 | + if object_ids: |
1303 | + # Create the rule |
1304 | + fields = ['cc_id', 'active_from', 'inactive_from'] |
1305 | + fields_ids = self.pool.get('ir.model.fields').search(cr, uid, [('model', '=', 'dest.cc.link'), ('name', 'in', fields)], context=context) |
1306 | + field_name = self.pool.get('ir.model.fields').search(cr, uid, [('model', '=', 'dest.cc.link'), ('name', '=', 'cc_id')], context=context) |
1307 | + field_parent = self.pool.get('ir.model.fields').search(cr, uid, [('model', '=', 'dest.cc.link'), ('name', '=', 'dest_id')], context=context) |
1308 | + |
1309 | + name_id = False |
1310 | + parent_id = False |
1311 | + |
1312 | + if field_parent: |
1313 | + parent_id = field_parent[0] |
1314 | + if field_name: |
1315 | + name_id = field_name[0] |
1316 | + |
1317 | + vals = { |
1318 | + 'name': name, |
1319 | + 'object_id': object_ids[0], |
1320 | + 'log_write': True, |
1321 | + 'log_unlink': True, |
1322 | + 'log_create': True, |
1323 | + 'field_ids': [(6, 0, fields_ids)], |
1324 | + 'parent_field_id': parent_id, |
1325 | + 'name_get_field_id': name_id, |
1326 | + } |
1327 | + |
1328 | + if not rule_id: |
1329 | + rule_id = self.create(cr, uid, vals, context=context) |
1330 | + elif rule_id: |
1331 | + self.write(cr, uid, rule_id, vals, context=context) |
1332 | + # Subscribe to the rule |
1333 | + self.subscribe(cr, uid, rule_id) |
1334 | |
1335 | === modified file 'bin/addons/msf_doc_import/msf_import_export.py' |
1336 | --- bin/addons/msf_doc_import/msf_import_export.py 2019-05-27 10:02:18 +0000 |
1337 | +++ bin/addons/msf_doc_import/msf_import_export.py 2021-05-07 16:01:07 +0000 |
1338 | @@ -32,6 +32,7 @@ |
1339 | from tempfile import TemporaryFile |
1340 | from lxml import etree |
1341 | from lxml.etree import XMLSyntaxError |
1342 | +from datetime import datetime |
1343 | |
1344 | from msf_doc_import.wizard.abstract_wizard_import import ImportHeader |
1345 | from msf_doc_import.msf_import_export_conf import MODEL_DICT |
1346 | @@ -626,6 +627,58 @@ |
1347 | # thread.join(wait_time) |
1348 | return self.bg_import(cr, uid, wiz, expected_headers, rows, raise_on_error=raise_on_error, context=context) |
1349 | |
1350 | + def _handle_dest_cc_dates(self, cr, uid, data, dest_cc_list, dest_cc_tuple_list, context=None): |
1351 | + """ |
1352 | + Gets and checks the dest_cc_link_active_from and dest_cc_link_inactive_from dates. |
1353 | + Updates the dest_cc_tuple_list with tuples containing (cost_center, active_date, inactive_date) |
1354 | + """ |
1355 | + if context is None: |
1356 | + context = {} |
1357 | + dest_cc_active_date_list = [] |
1358 | + dest_cc_inactive_date_list = [] |
1359 | + active_from = (True, 'dest_cc_link_active_from', _("Activation Combination Dest / CC from")) |
1360 | + inactive_from = (False, 'dest_cc_link_inactive_from', _("Inactivation Combination Dest / CC from")) |
1361 | + for t in [active_from, inactive_from]: |
1362 | + active = t[0] |
1363 | + col_name = t[1] |
1364 | + col_str = t[2] |
1365 | + dest_cc_date_list = [] |
1366 | + if data.get(col_name): |
1367 | + split_char = ';' |
1368 | + if split_char not in data.get(col_name): |
1369 | + split_char = ',' |
1370 | + for cost_center_date in data.get(col_name).split(split_char): |
1371 | + cc_date = cost_center_date.strip() |
1372 | + if cc_date: |
1373 | + cc_date = cc_date.replace(' 00:00:00.00', '') # can be if there is only one date in the cell |
1374 | + try: |
1375 | + cc_date = datetime.strptime(cc_date, "%Y-%m-%d") |
1376 | + except ValueError: |
1377 | + raise Exception(_('The dates in the column "%s" should use the format YYYY-MM-DD.') % col_str) |
1378 | + else: |
1379 | + cc_date = False # the related Dest/CC combination has no activation/inactivation date |
1380 | + dest_cc_date_list.append(cc_date) |
1381 | + del data[col_name] |
1382 | + if len(dest_cc_date_list) > len(dest_cc_list): |
1383 | + raise Exception(_('The number of dates in the column "%s" exceeds the number of Cost Centers indicated.') % col_str) |
1384 | + if active: |
1385 | + dest_cc_active_date_list = dest_cc_date_list[:] |
1386 | + else: |
1387 | + dest_cc_inactive_date_list = dest_cc_date_list[:] |
1388 | + for num, cc in enumerate(dest_cc_list): |
1389 | + try: |
1390 | + dest_cc_active_date = dest_cc_active_date_list[num] |
1391 | + except IndexError: |
1392 | + dest_cc_active_date = False |
1393 | + try: |
1394 | + dest_cc_inactive_date = dest_cc_inactive_date_list[num] |
1395 | + except IndexError: |
1396 | + dest_cc_inactive_date = False |
1397 | + if dest_cc_active_date and dest_cc_inactive_date and dest_cc_active_date >= dest_cc_inactive_date: |
1398 | + cc_code = self.pool.get('account.analytic.account').read(cr, uid, cc, ['code'], context=context)['code'] or '' |
1399 | + raise Exception(_('The activation date related to the Cost Center %s must be before the inactivation date.') % cc_code) |
1400 | + dest_cc_tuple_list.append((cc, dest_cc_active_date, dest_cc_inactive_date)) |
1401 | + |
1402 | def bg_import(self, cr, uid, import_brw, headers, rows, raise_on_error=False, context=None): |
1403 | """ |
1404 | Run the import of lines in background |
1405 | @@ -647,6 +700,7 @@ |
1406 | acc_obj = self.pool.get('account.account') |
1407 | acc_analytic_obj = self.pool.get('account.analytic.account') |
1408 | acc_dest_obj = self.pool.get('account.destination.link') |
1409 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
1410 | |
1411 | cost_centers_cache = {} |
1412 | gl_account_cache = {} |
1413 | @@ -731,7 +785,7 @@ |
1414 | # custom process to retrieve CC, Destination_ids |
1415 | custom_m2m = [] |
1416 | if import_brw.model_list_selection == 'destinations': |
1417 | - custom_m2m = ['dest_cc_ids', 'destination_ids'] |
1418 | + custom_m2m = ['destination_ids'] |
1419 | elif import_brw.model_list_selection == 'funding_pools': |
1420 | custom_m2m = ['cost_center_ids', 'tuple_destination_account_ids'] |
1421 | for c_m2m in custom_m2m: |
1422 | @@ -1025,6 +1079,7 @@ |
1423 | data['tuple_destination_account_ids'] = [(6, 0, [])] |
1424 | |
1425 | # Destinations |
1426 | + dest_cc_tuple_list = [] |
1427 | if import_brw.model_list_selection == 'destinations': |
1428 | context['from_import_menu'] = True |
1429 | data['category'] = 'DEST' |
1430 | @@ -1042,14 +1097,14 @@ |
1431 | if data['type'] not in ['normal', 'view']: |
1432 | raise Exception(_('The Type must be either "Normal" or "View".')) |
1433 | # Cost Centers |
1434 | - if data.get('dest_cc_ids'): |
1435 | + dest_cc_list = [] |
1436 | + if data.get('dest_cc_link_ids'): |
1437 | if data.get('allow_all_cc'): |
1438 | raise Exception(_("Please either list the Cost Centers to allow, or allow all Cost Centers.")) |
1439 | - dest_cc_list = [] |
1440 | split_char = ';' |
1441 | - if split_char not in data.get('dest_cc_ids'): |
1442 | + if split_char not in data.get('dest_cc_link_ids'): |
1443 | split_char = ',' |
1444 | - for cost_center in data.get('dest_cc_ids').split(split_char): |
1445 | + for cost_center in data.get('dest_cc_link_ids').split(split_char): |
1446 | cc = cost_center.strip() |
1447 | if cc not in cost_centers_cache: |
1448 | cc_dom = [('category', '=', 'OC'), ('type', '=', 'normal'), ('code', '=', cc)] |
1449 | @@ -1059,9 +1114,7 @@ |
1450 | dest_cc_list.append(cc_ids[0]) |
1451 | else: |
1452 | raise Exception(_('Cost Center "%s" not found.') % cc) |
1453 | - data['dest_cc_ids'] = [(6, 0, dest_cc_list)] |
1454 | - else: |
1455 | - data['dest_cc_ids'] = [(6, 0, [])] |
1456 | + self._handle_dest_cc_dates(cr, uid, data, dest_cc_list, dest_cc_tuple_list, context=context) |
1457 | # Accounts |
1458 | if data.get('destination_ids'): # "destinations_ids" corresponds to G/L accounts... |
1459 | acc_list = [] |
1460 | @@ -1089,8 +1142,6 @@ |
1461 | # in case of empty columns on non-required fields, existing values should be deleted |
1462 | if 'date' not in data: |
1463 | data['date'] = False |
1464 | - if 'dest_cc_ids' not in data: |
1465 | - data['dest_cc_ids'] = [(6, 0, [])] |
1466 | if 'allow_all_cc' not in data: |
1467 | data['allow_all_cc'] = False |
1468 | if 'destination_ids' not in data: |
1469 | @@ -1164,6 +1215,7 @@ |
1470 | |
1471 | data.update(forced_values) |
1472 | |
1473 | + id_created = False |
1474 | if data.get('comment') == '[DELETE]': |
1475 | impobj.unlink(cr, uid, ids_to_update, context=context) |
1476 | nb_lines_deleted += len(ids_to_update) |
1477 | @@ -1182,11 +1234,66 @@ |
1478 | line_created = impobj.create(cr, uid, data, context=context) |
1479 | lines_already_updated.append(line_created) |
1480 | else: |
1481 | - impobj.create(cr, uid, data, context=context) |
1482 | + id_created = impobj.create(cr, uid, data, context=context) |
1483 | nb_succes += 1 |
1484 | processed.append((row_index+1, line_data)) |
1485 | if allow_partial: |
1486 | cr.commit() |
1487 | + # For Dest CC Links: create, update or delete the links if necessary |
1488 | + if import_brw.model_list_selection == 'destinations': |
1489 | + if isinstance(ids_to_update, (int, long)): |
1490 | + ids_to_update = [ids_to_update] |
1491 | + if not dest_cc_tuple_list and ids_to_update: |
1492 | + # UC1: Dest CC Link column empty => delete all current Dest/CC combinations attached to the Dest |
1493 | + old_dcl_ids = dest_cc_link_obj.search(cr, uid, [('dest_id', 'in', ids_to_update)], order='NO_ORDER', context=context) |
1494 | + if old_dcl_ids: |
1495 | + dest_cc_link_obj.unlink(cr, uid, old_dcl_ids, context=context) |
1496 | + else: |
1497 | + # UC2: new dest |
1498 | + if id_created: |
1499 | + for cc, active_date, inactive_date in dest_cc_tuple_list: |
1500 | + dest_cc_link_obj.create(cr, uid, {'cc_id': cc, 'dest_id': id_created, |
1501 | + 'active_from': active_date, 'inactive_from': inactive_date}, |
1502 | + context=context) |
1503 | + elif ids_to_update: |
1504 | + for dest_id in ids_to_update: |
1505 | + dest = acc_analytic_obj.browse(cr, uid, dest_id, fields_to_fetch=['dest_cc_link_ids'], context=context) |
1506 | + current_cc_ids = [dest_cc_link.cc_id.id for dest_cc_link in dest.dest_cc_link_ids] |
1507 | + new_cc_ids = [] |
1508 | + for cc, active_date, inactive_date in dest_cc_tuple_list: |
1509 | + new_cc_ids.append(cc) |
1510 | + # UC3: new combinations in existing Destinations |
1511 | + if cc not in current_cc_ids: |
1512 | + dest_cc_link_obj.create(cr, uid, {'cc_id': cc, 'dest_id': dest_id, |
1513 | + 'active_from': active_date, 'inactive_from': inactive_date}, |
1514 | + context=context) |
1515 | + else: |
1516 | + # UC4: combinations to be updated with new dates |
1517 | + dcl_ids = dest_cc_link_obj.search(cr, uid, |
1518 | + [('dest_id', '=', dest_id), ('cc_id', '=', cc)], |
1519 | + limit=1, context=context) |
1520 | + if dcl_ids: |
1521 | + dest_cc_link = dest_cc_link_obj.read(cr, uid, dcl_ids[0], |
1522 | + ['active_from', 'inactive_from'], context=context) |
1523 | + if dest_cc_link['active_from']: |
1524 | + current_active_dt = datetime.strptime(dest_cc_link['active_from'], "%Y-%m-%d") |
1525 | + else: |
1526 | + current_active_dt = False |
1527 | + if dest_cc_link['inactive_from']: |
1528 | + current_inactive_dt = datetime.strptime(dest_cc_link['inactive_from'], "%Y-%m-%d") |
1529 | + else: |
1530 | + current_inactive_dt = False |
1531 | + if (current_active_dt != active_date) or (current_inactive_dt != inactive_date): |
1532 | + dest_cc_link_obj.write(cr, uid, dest_cc_link['id'], |
1533 | + {'active_from': active_date, 'inactive_from': inactive_date}, |
1534 | + context=context) |
1535 | + # UC5: combinations to be deleted in existing Destinations |
1536 | + cc_to_be_deleted = [c for c in current_cc_ids if c not in new_cc_ids] |
1537 | + if cc_to_be_deleted: |
1538 | + dcl_to_be_deleted = dest_cc_link_obj.search(cr, uid, |
1539 | + [('dest_id', '=', dest_id), ('cc_id', 'in', cc_to_be_deleted)], |
1540 | + order='NO_ORDER', context=context) |
1541 | + dest_cc_link_obj.unlink(cr, uid, dcl_to_be_deleted, context=context) |
1542 | except (osv.except_osv, orm.except_orm) , e: |
1543 | logging.getLogger('import data').info('Error %s' % e.value) |
1544 | if raise_on_error: |
1545 | |
1546 | === modified file 'bin/addons/msf_doc_import/msf_import_export_conf.py' |
1547 | --- bin/addons/msf_doc_import/msf_import_export_conf.py 2019-05-27 09:37:55 +0000 |
1548 | +++ bin/addons/msf_doc_import/msf_import_export_conf.py 2021-05-07 16:01:07 +0000 |
1549 | @@ -549,7 +549,9 @@ |
1550 | 'type', |
1551 | 'date_start', |
1552 | 'date', # "inactive from" |
1553 | - 'dest_cc_ids', |
1554 | + 'dest_cc_link_ids', |
1555 | + 'dest_cc_link_active_from', |
1556 | + 'dest_cc_link_inactive_from', |
1557 | 'destination_ids', |
1558 | 'allow_all_cc', |
1559 | ], |
1560 | |
1561 | === modified file 'bin/addons/msf_homere_interface/hr_payroll.py' |
1562 | --- bin/addons/msf_homere_interface/hr_payroll.py 2020-10-13 10:14:53 +0000 |
1563 | +++ bin/addons/msf_homere_interface/hr_payroll.py 2021-05-07 16:01:07 +0000 |
1564 | @@ -43,6 +43,7 @@ |
1565 | # Prepare some values |
1566 | res = {} |
1567 | ad_obj = self.pool.get('analytic.distribution') |
1568 | + dest_cc_link_obj = self.pool.get('dest.cc.link') |
1569 | # Search MSF Private Fund element, because it's valid with all accounts |
1570 | try: |
1571 | fp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', |
1572 | @@ -84,6 +85,10 @@ |
1573 | if dest and dest.filter_active is False: |
1574 | res[line.id] = 'invalid' |
1575 | continue |
1576 | + if line.destination_id and line.cost_center_id: |
1577 | + if dest_cc_link_obj.is_inactive_dcl(cr, uid, line.destination_id.id, line.cost_center_id.id, line.date, context=context): |
1578 | + res[line.id] = 'invalid' |
1579 | + continue |
1580 | # G Check |
1581 | if line.funding_pool_id: |
1582 | fp = self.pool.get('account.analytic.account').browse(cr, uid, line.funding_pool_id.id, context={'date': line.document_date}) |
1583 | @@ -202,6 +207,26 @@ |
1584 | ]) |
1585 | return to_update |
1586 | |
1587 | + def _get_trigger_state_dest_cc_link(self, cr, uid, ids, context=None): |
1588 | + """ |
1589 | + Returns the list of Payroll Entries for which the AD state should be re-computed |
1590 | + """ |
1591 | + if context is None: |
1592 | + context = {} |
1593 | + if isinstance(ids, (int, long)): |
1594 | + ids = [ids] |
1595 | + cc_ids = [] |
1596 | + dest_ids = [] |
1597 | + payroll_obj = self.pool.get('hr.payroll.msf') |
1598 | + for dest_cc_link in self.browse(cr, uid, ids, context=context): |
1599 | + cc_ids.append(dest_cc_link.cc_id.id) |
1600 | + dest_ids.append(dest_cc_link.dest_id.id) |
1601 | + payroll_ids = payroll_obj.search(cr, uid, [('state', '=', 'draft'), |
1602 | + '|', |
1603 | + ('cost_center_id', 'in', cc_ids), |
1604 | + ('destination_id', 'in', dest_ids)], order='NO_ORDER', context=context) |
1605 | + return payroll_ids |
1606 | + |
1607 | def _has_third_party(self, cr, uid, ids, name, arg, context=None): |
1608 | """ |
1609 | Returns True if the Payroll entry is linked to either an Employee or a Supplier |
1610 | @@ -242,12 +267,14 @@ |
1611 | 'hr.payroll.msf': (lambda self, cr, uid, ids, c=None: ids, ['account_id', 'cost_center_id', 'funding_pool_id', 'destination_id'], 10), |
1612 | 'account.account': (_get_trigger_state_account, ['user_type_code', 'destination_ids'], 20), |
1613 | 'account.analytic.account': (_get_trigger_state_ana, ['date', 'date_start', 'allow_all_cc', |
1614 | - 'dest_cc_ids', 'allow_all_cc_with_fp', |
1615 | + 'allow_all_cc_with_fp', |
1616 | 'cost_center_ids', 'select_accounts_only', |
1617 | 'fp_account_ids', |
1618 | 'tuple_destination_account_ids'], |
1619 | 20), |
1620 | 'account.destination.link': (_get_trigger_state_dest_link, ['account_id', 'destination_id'], 30), |
1621 | + 'dest.cc.link': (_get_trigger_state_dest_cc_link, |
1622 | + ['cc_id', 'dest_id', 'active_from', 'inactive_from'], 40), |
1623 | } |
1624 | ), |
1625 | 'partner_type': fields.function(_get_third_parties, type='reference', method=True, string="Third Parties", readonly=True, |
1626 | |
1627 | === modified file 'bin/addons/msf_profile/data/patches.xml' |
1628 | --- bin/addons/msf_profile/data/patches.xml 2021-02-25 15:48:01 +0000 |
1629 | +++ bin/addons/msf_profile/data/patches.xml 2021-05-07 16:01:07 +0000 |
1630 | @@ -647,9 +647,17 @@ |
1631 | <field name="method">us_6796_hide_prod_status_inconsistencies</field> |
1632 | </record> |
1633 | |
1634 | +<<<<<<< TREE |
1635 | <record id="us_8166_hide_consolidated_sm_report" model="patch.scripts"> |
1636 | <field name="method">us_8166_hide_consolidated_sm_report</field> |
1637 | </record> |
1638 | |
1639 | +======= |
1640 | + <!-- UF21.0 --> |
1641 | + <record id="us_7295_update_new_dest_cc_link" model="patch.scripts"> |
1642 | + <field name="method">us_7295_update_new_dest_cc_link</field> |
1643 | + </record> |
1644 | + |
1645 | +>>>>>>> MERGE-SOURCE |
1646 | </data> |
1647 | </openerp> |
1648 | |
1649 | === modified file 'bin/addons/msf_profile/i18n/fr_MF.po' |
1650 | --- bin/addons/msf_profile/i18n/fr_MF.po 2021-05-06 15:52:15 +0000 |
1651 | +++ bin/addons/msf_profile/i18n/fr_MF.po 2021-05-07 16:01:07 +0000 |
1652 | @@ -21113,6 +21113,7 @@ |
1653 | #: report:kitting.order.report:0 |
1654 | #: field:replenishment.inventory.review.line.exp,name:0 |
1655 | #: field:replenishment.segment.line.amc.month_exp,name:0 |
1656 | +#: view:account.analytic.account:0 |
1657 | #, python-format |
1658 | msgid "Name" |
1659 | msgstr "Nom" |
1660 | @@ -34812,6 +34813,7 @@ |
1661 | #: field:products.situation.report,p_code:0 |
1662 | #: report:addons/msf_tools/report/report_stock_pipe_per_product_instance_xls.mako:86 |
1663 | #: field:account.target.costcenter,cost_center_code:0 |
1664 | +#: view:account.analytic.account:0 |
1665 | #, python-format |
1666 | msgid "Code" |
1667 | msgstr "Code" |
1668 | @@ -44531,9 +44533,10 @@ |
1669 | msgid "No donation account found for this line: %s. (product: %s)" |
1670 | msgstr "No donation account found for this line: %s. (product: %s)" |
1671 | |
1672 | -#. modules: account, base |
1673 | +#. modules: account, base, analytic_override |
1674 | #: view:account.addtmpl.wizard:0 |
1675 | #: view:res.widget.wizard:0 |
1676 | +#: view:multiple.cc.selection.wizard:0 |
1677 | msgid "Add" |
1678 | msgstr "Ajouter" |
1679 | |
1680 | @@ -47155,7 +47158,7 @@ |
1681 | #: code:addons/analytic_distribution/wizard/commitment_analytic_reallocation.py:140 |
1682 | #, python-format |
1683 | msgid "Non compatible entries found: %s" |
1684 | -msgstr "Non compatible entries found: %s" |
1685 | +msgstr "Ecritures non compatibles trouvées : %s" |
1686 | |
1687 | #. modules: delivery_mechanism, tender_flow, analytic_distribution_supply, product_nomenclature, return_claim, sync_client, res_currency_tables, supplier_catalogue, import_data, stock_batch_recall, stock, product, reason_types_moves, consumption_calculation, register_accounting, specific_rules, kit, base, account_period_closing_level, account_subscription, msf_cross_docking, purchase, account, msf_outgoing, resource, procurement_auto, msf_config_locations, sale, account_override, sourcing, sync_so, res_currency_functional, account_hq_entries |
1688 | #: code:addons/account/account.py:445 |
1689 | @@ -66095,6 +66098,9 @@ |
1690 | #: report:addons/account/report/free_allocation_report.mako:176 |
1691 | #: field:free.allocation.wizard,cost_center_ids:0 |
1692 | #: field:account.analytic.account,dest_cc_ids:0 |
1693 | +#: field:account.analytic.account,dest_cc_link_ids:0 |
1694 | +#: view:multiple.cc.selection.wizard:0 |
1695 | +#: field:multiple.cc.selection.wizard,cc_ids:0 |
1696 | msgid "Cost Centers" |
1697 | msgstr "Centres de Coût" |
1698 | |
1699 | @@ -80576,6 +80582,7 @@ |
1700 | #: code:addons/register_accounting/wizard/wizard_register_import.py:570 |
1701 | #: report:addons/account/report/free_allocation_report.mako:205 |
1702 | #: code:addons/msf_doc_import/wizard/wizard_po_simulation_screen.py:606 |
1703 | +#: field:dest.cc.link,cc_id:0 |
1704 | #, python-format |
1705 | msgid "Cost Center" |
1706 | msgstr "Centre de Coût" |
1707 | @@ -94527,6 +94534,8 @@ |
1708 | #: code:addons/stock_override/report/report_stock_move.py:759 |
1709 | #: report:addons/account/report/invoice_excel_export.mako:75 |
1710 | #: field:financing.contract.account.quadruplet,account_destination_id:0 |
1711 | +#: field:dest.cc.link,dest_id:0 |
1712 | +#: field:multiple.cc.selection.wizard,dest_id:0 |
1713 | #, python-format |
1714 | msgid "Destination" |
1715 | msgstr "Destination" |
1716 | @@ -95899,7 +95908,7 @@ |
1717 | msgid "Search Uninvoiced Lines" |
1718 | msgstr "Rechercher Lignes non-facturées" |
1719 | |
1720 | -#. modules: res_currency_functional, financing_contract, msf_tools, account_hq_entries, account_override, product_attributes, base_report_designer, register_accounting, procurement_cycle, msf_accrual, finance, sync_client, purchase_followup, account_mcdb, res_currency_tables, supplier_catalogue, procurement_request, purchase_compare_rfq, board, stock_override, msf_doc_import, analytic_distribution, threshold_value, msf_homere_interface, msf_instance, account_reconciliation, consumption_calculation, purchase_override, specific_rules, kit, base, account_period_closing_level, msf_currency_revaluation, msf_supply_doc_export, product_list, procurement_report, msf_budget, account_corrections, account, msf_outgoing, stock_move_tracking, purchase_allocation_report, procurement_auto, documents_done, sale, msf_config_locations, sales_followup, vertical_integration, procurement, sourcing, purchase, msf_audittrail, tender_flow, stock, msf_profile |
1721 | +#. modules: res_currency_functional, financing_contract, msf_tools, account_hq_entries, account_override, product_attributes, base_report_designer, register_accounting, procurement_cycle, msf_accrual, finance, sync_client, purchase_followup, account_mcdb, res_currency_tables, supplier_catalogue, procurement_request, purchase_compare_rfq, board, stock_override, msf_doc_import, analytic_distribution, threshold_value, msf_homere_interface, msf_instance, account_reconciliation, consumption_calculation, purchase_override, specific_rules, kit, base, account_period_closing_level, msf_currency_revaluation, msf_supply_doc_export, product_list, procurement_report, msf_budget, account_corrections, account, msf_outgoing, stock_move_tracking, purchase_allocation_report, procurement_auto, documents_done, sale, msf_config_locations, sales_followup, vertical_integration, procurement, sourcing, purchase, msf_audittrail, tender_flow, stock, msf_profile, analytic_override |
1722 | #: view:account.addtmpl.wizard:0 |
1723 | #: view:account.aged.trial.balance:0 |
1724 | #: view:account.analytic.Journal.report:0 |
1725 | @@ -96133,6 +96142,7 @@ |
1726 | #: view:product.stock_out:0 |
1727 | #: view:replenishment.parent.segment:0 |
1728 | #: view:view.expired.expiring.stock:0 |
1729 | +#: view:multiple.cc.selection.wizard:0 |
1730 | #, python-format |
1731 | msgid "Cancel" |
1732 | msgstr "Annuler" |
1733 | @@ -99911,6 +99921,12 @@ |
1734 | msgstr "%s: FP inactif (%s)" |
1735 | |
1736 | #. module: account_hq_entries |
1737 | +#: code:addons/account_hq_entries/hq_entries.py:94 |
1738 | +#, python-format |
1739 | +msgid "%s: inactive combination (%s - %s)" |
1740 | +msgstr "%s: combinaison inactive (%s - %s)" |
1741 | + |
1742 | +#. module: account_hq_entries |
1743 | #: field:hq.entries,is_account_partner_compatible:0 |
1744 | msgid "Account and partner compatible ?" |
1745 | msgstr "Compte et partenaire compatibles ?" |
1746 | @@ -100222,11 +100238,23 @@ |
1747 | msgstr "Date du CC" |
1748 | |
1749 | #. module: analytic_distribution |
1750 | +#: code:addons/analytic_distribution/analytic_line.py:563 |
1751 | +#, python-format |
1752 | +msgid "DEST/CC combination date" |
1753 | +msgstr "Date de la combinaison DEST/CC" |
1754 | + |
1755 | +#. module: analytic_distribution |
1756 | #: code:addons/analytic_distribution/analytic_line.py:548 |
1757 | #, python-format |
1758 | msgid "FP date" |
1759 | msgstr "Date du FP" |
1760 | |
1761 | +#. module: analytic_distribution |
1762 | +#: code:addons/analytic_distribution/analytic_distribution.py:237 |
1763 | +#, python-format |
1764 | +msgid "Inactive DEST/CC combination" |
1765 | +msgstr "Combinaison DEST/CC inactive" |
1766 | + |
1767 | #. module: msf_printed_documents |
1768 | #: code:addons/msf_printed_documents/report/report_reception.py:80 |
1769 | #, python-format |
1770 | @@ -112023,3 +112051,124 @@ |
1771 | #, python-format |
1772 | msgid "You must have at least one line to create the Internal Move" |
1773 | msgstr "Vous devez avoir au moins une ligne pour pouvoir créer le Mouvement Interne" |
1774 | + |
1775 | +#. module: analytic_distribution |
1776 | +#: view:account.analytic.account:0 |
1777 | +msgid "Remove all" |
1778 | +msgstr "Supprimer tout" |
1779 | + |
1780 | +#. module: analytic_distribution |
1781 | +#: view:account.analytic.account:0 |
1782 | +msgid "Do you really want to remove all the Cost Centers selected?" |
1783 | +msgstr "Voulez-vous vraiment supprimer tous les Centres de Coût sélectionnés ?" |
1784 | + |
1785 | +#. modules: analytic_override, analytic_distribution |
1786 | +#: view:account.analytic.account:0 |
1787 | +#: view:multiple.cc.selection.wizard:0 |
1788 | +msgid "Add several Cost Centers" |
1789 | +msgstr "Ajouter plusieurs Centres de Coût" |
1790 | + |
1791 | +#. modules: msf_doc_import, analytic_override |
1792 | +#: field:account.analytic.account,dest_cc_link_active_from:0 |
1793 | +#: field:dest.cc.link,active_from:0 |
1794 | +#: code:addons/msf_doc_import/msf_import_export.py:639 |
1795 | +#, python-format |
1796 | +msgid "Activation Combination Dest / CC from" |
1797 | +msgstr "Activation Combinaison Dest / CC à partir du" |
1798 | + |
1799 | +#. modules: msf_doc_import, analytic_override |
1800 | +#: field:account.analytic.account,dest_cc_link_inactive_from:0 |
1801 | +#: field:dest.cc.link,inactive_from:0 |
1802 | +#: code:addons/msf_doc_import/msf_import_export.py:640 |
1803 | +#, python-format |
1804 | +msgid "Inactivation Combination Dest / CC from" |
1805 | +msgstr "Inactivation Combinaison Dest / CC à partir du" |
1806 | + |
1807 | +#. module: analytic_override |
1808 | +#: help:account.analytic.account,dest_cc_link_active_from:0 |
1809 | +#: help:account.analytic.account,dest_cc_link_inactive_from:0 |
1810 | +msgid "Technical field used for Import Tools only" |
1811 | +msgstr "Champ technique utilisé pour les Outils d'Import uniquement" |
1812 | + |
1813 | +#. module: analytic_override |
1814 | +#: field:account.analytic.account,selected_in_dest:0 |
1815 | +msgid "Selected in Destination" |
1816 | +msgstr "Sélectionné dans la Destination" |
1817 | + |
1818 | +#. module: analytic_override |
1819 | +#: model:ir.model,name:analytic_override.model_dest_cc_link |
1820 | +msgid "Destination / Cost Center Combination" |
1821 | +msgstr "Combinaison Destination / Centre de Coût" |
1822 | + |
1823 | +#. module: analytic_override |
1824 | +#: field:dest.cc.link,cc_code:0 |
1825 | +msgid "Cost Center Code" |
1826 | +msgstr "Code du Centre de Coût" |
1827 | + |
1828 | +#. module: analytic_override |
1829 | +#: field:dest.cc.link,cc_name:0 |
1830 | +msgid "Cost Center Name" |
1831 | +msgstr "Nom du Centre de Coût" |
1832 | + |
1833 | +#. module: analytic_override |
1834 | +#: sql_constraint:dest.cc.link:0 |
1835 | +msgid "Each Cost Center can only be added once to the same Destination." |
1836 | +msgstr "Chaque Centre de Coût ne peut être ajouté qu'une seule fois à une même Destination." |
1837 | + |
1838 | +#. module: analytic_override |
1839 | +#: sql_constraint:dest.cc.link:0 |
1840 | +msgid "The Activation date of the \"Combination Dest / CC\" must be before the Inactivation date." |
1841 | +msgstr "La date d'Activation de la \"Combinaison Dest / CC\" doit précéder la date d'Inactivation." |
1842 | + |
1843 | +#. module: msf_doc_import |
1844 | +#: code:addons/msf_doc_import/msf_import_export.py:663 |
1845 | +#, python-format |
1846 | +msgid "The number of dates in the column \"%s\" exceeds the number of Cost Centers indicated." |
1847 | +msgstr "Le nombre de dates dans la colonne \"%s\" dépasse le nombre de Centres de Coût indiqués." |
1848 | + |
1849 | +#. module: msf_doc_import |
1850 | +#: code:addons/msf_doc_import/msf_import_export.py:679 |
1851 | +#, python-format |
1852 | +msgid "The activation date related to the Cost Center %s must be before the inactivation date." |
1853 | +msgstr "La date d'activation associée au Centre de Coût %s doit précéder la date d'inactivation." |
1854 | + |
1855 | +#. module: msf_doc_import |
1856 | +#: code:addons/msf_doc_import/msf_import_export.py:657 |
1857 | +#, python-format |
1858 | +msgid "The dates in the column \"%s\" should use the format YYYY-MM-DD." |
1859 | +msgstr "Les dates dans la colonne \"%s\" doivent utiliser le format AAAA-MM-JJ." |
1860 | + |
1861 | +#. module: analytic_override |
1862 | +#: view:multiple.cc.selection.wizard:0 |
1863 | +msgid "This wizard enables you to select several Cost Centers at once to be added to the Destination. The activation and inactivation dates of the related Dest / CC combinations will remain empty." |
1864 | +msgstr "Cet assistant vous permet de sélectionner en une fois plusieurs Centres de Coût à ajouter à la Destination. Les dates d'activation et d'inactivation des Combinaisons Dest / CC associées resteront vides." |
1865 | + |
1866 | +#. module: analytic_override |
1867 | +#: field:dest.cc.link,current_id:0 |
1868 | +msgid "DB Id (used by the UI)" |
1869 | +msgstr "Id BD (utilisé par l'UI)" |
1870 | + |
1871 | +#. module: analytic_override |
1872 | +#: code:addons/analytic_override/analytic_line.py:192 |
1873 | +#, python-format |
1874 | +msgid "The combination \"%s - %s\" is not active." |
1875 | +msgstr "La combinaison \"%s - %s\" n'est pas active." |
1876 | + |
1877 | +#. module: analytic_distribution |
1878 | +#: code:addons/analytic_distribution/wizard/analytic_distribution_wizard.py:1024 |
1879 | +#: code:addons/analytic_distribution/account_commitment.py:204 |
1880 | +#, python-format |
1881 | +msgid "The combination \"%s - %s\" is not active at this date: %s" |
1882 | +msgstr "La combinaison \"%s - %s\" n'est pas active à cette date : %s" |
1883 | + |
1884 | +#. module: analytic_distribution |
1885 | +#: code:addons/analytic_distribution/analytic_distribution.py:264 |
1886 | +#, python-format |
1887 | +msgid "%sThe combination \"%s - %s\" is not active at this date: %s" |
1888 | +msgstr "%sLa combinaison \"%s - %s\" n'est pas active à cette date : %s" |
1889 | + |
1890 | +#. module: analytic_override |
1891 | +#: code:addons/analytic_override/dest_cc_link.py:72 |
1892 | +#, python-format |
1893 | +msgid "At least one Analytic Journal Item using the combination \"%s - %s\" has a Posting Date outside the activation dates selected." |
1894 | +msgstr "Au moins une Ligne d'Ecriture Analytique utilisant la combinaison \"%s - %s\" a une Date de Comptabilisation en dehors des dates d'activation sélectionnées." |
1895 | |
1896 | === modified file 'bin/addons/msf_profile/msf_profile.py' |
1897 | --- bin/addons/msf_profile/msf_profile.py 2021-05-05 07:42:20 +0000 |
1898 | +++ bin/addons/msf_profile/msf_profile.py 2021-05-07 16:01:07 +0000 |
1899 | @@ -52,6 +52,7 @@ |
1900 | 'model': lambda *a: 'patch.scripts', |
1901 | } |
1902 | |
1903 | +<<<<<<< TREE |
1904 | # UF21.0 |
1905 | def us_8166_hide_consolidated_sm_report(self, cr, uid, *a, **b): |
1906 | instance = self.pool.get('res.users').browse(cr, uid, uid, fields_to_fetch=['company_id']).company_id.instance_id |
1907 | @@ -61,6 +62,22 @@ |
1908 | self.pool.get('ir.ui.menu').write(cr, uid, consolidated_sm_report_menu_id, {'active': instance.level == 'coordo'}, context={}) |
1909 | return True |
1910 | |
1911 | +======= |
1912 | + # UF21.0 |
1913 | + def us_7295_update_new_dest_cc_link(self, cr, uid, *a, **b): |
1914 | + """ |
1915 | + CC Tab of the Destinations: replaces the old field "dest_cc_ids" by the new field "dest_cc_link_ids" |
1916 | + => recreates the links without activation/inactivation dates |
1917 | + """ |
1918 | + cr.execute(""" |
1919 | + INSERT INTO dest_cc_link(dest_id, cc_id) |
1920 | + SELECT destination_id, cost_center_id FROM destination_cost_center_rel |
1921 | + """) |
1922 | + cr.execute("DELETE FROM destination_cost_center_rel") |
1923 | + self._logger.warn('Destinations: %s Dest CC Links generated.', cr.rowcount) |
1924 | + return True |
1925 | + |
1926 | +>>>>>>> MERGE-SOURCE |
1927 | # UF20.0 |
1928 | def us_7866_fill_in_target_cc_code(self, cr, uid, *a, **b): |
1929 | """ |
1930 | |
1931 | === modified file 'bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv' |
1932 | --- bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv 2021-04-12 09:46:40 +0000 |
1933 | +++ bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv 2021-05-07 16:01:07 +0000 |
1934 | @@ -34,6 +34,7 @@ |
1935 | 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 |
1936 | 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 |
1937 | 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 |
1938 | +msf_sync_data_server.dest_cc_link,TRUE,TRUE,TRUE,TRUE,bidirectional,Bidirectional-Private,"[]","['dest_id/id', 'cc_id/id', 'active_from', 'inactive_from']",OC,dest.cc.link,cc_id,Destination / Cost Center Combinations,Valid,,146 |
1939 | 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 |
1940 | msf_sync_data_server.analytic_distribution,FALSE,TRUE,FALSE,FALSE,bidirectional,Bidirectional,[],['name'],HQ + MISSION,analytic.distribution,,Analytic Distribution,Valid,,200 |
1941 | 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 |
1942 | |
1943 | === modified file 'bin/addons/sync_client/update.py' |
1944 | --- bin/addons/sync_client/update.py 2021-01-18 14:22:04 +0000 |
1945 | +++ bin/addons/sync_client/update.py 2021-05-07 16:01:07 +0000 |
1946 | @@ -58,6 +58,7 @@ |
1947 | 'account.mcdb', |
1948 | 'wizard.template', |
1949 | 'account.analytic.account', |
1950 | + 'dest.cc.link', |
1951 | ] |
1952 | |
1953 | |
1954 | |
1955 | === modified file 'bin/addons/sync_common/common.py' |
1956 | --- bin/addons/sync_common/common.py 2020-10-20 07:15:50 +0000 |
1957 | +++ bin/addons/sync_common/common.py 2021-05-07 16:01:07 +0000 |
1958 | @@ -168,6 +168,7 @@ |
1959 | 'cash.request.liquidity.total', |
1960 | 'hr.payment.method', |
1961 | 'wizard.template', |
1962 | + 'dest.cc.link', |
1963 | ] |
1964 | |
1965 | OC_LIST = ['OCA', 'OCB', 'OCBA', 'OCG', 'OCP'] |
1966 | |
1967 | === modified file 'bin/addons/sync_so/specific_xml_id.py' |
1968 | --- bin/addons/sync_so/specific_xml_id.py 2020-11-09 10:40:25 +0000 |
1969 | +++ bin/addons/sync_so/specific_xml_id.py 2021-05-07 16:01:07 +0000 |
1970 | @@ -307,6 +307,30 @@ |
1971 | |
1972 | account_analytic_account() |
1973 | |
1974 | +class dest_cc_link(osv.osv): |
1975 | + _inherit = 'dest.cc.link' |
1976 | + |
1977 | + def get_destination_name(self, cr, uid, ids, dest_field, context=None): |
1978 | + ''' |
1979 | + same destination as CC |
1980 | + ''' |
1981 | + if not ids: |
1982 | + return [] |
1983 | + |
1984 | + if isinstance(ids, (long, int)): |
1985 | + ids = [ids] |
1986 | + res = dict.fromkeys(ids, False) |
1987 | + mapping = {} |
1988 | + uniq_cc_ids = {} |
1989 | + for dest_cc_link in self.browse(cr, uid, ids, fields_to_fetch=['cc_id'], context=context): |
1990 | + mapping[dest_cc_link.id] = dest_cc_link.cc_id.id |
1991 | + uniq_cc_ids[dest_cc_link.cc_id.id] = True |
1992 | + cc_destination = self.pool.get('account.analytic.account').get_destination_name(cr, uid, uniq_cc_ids.keys(), 'category', context) |
1993 | + for dest_cc_link_id in mapping: |
1994 | + res[dest_cc_link_id] = cc_destination.get(mapping[dest_cc_link_id], []) |
1995 | + return res |
1996 | + |
1997 | +dest_cc_link() |
1998 | |
1999 | #US-113: Sync only to the mission with attached prop instance |
2000 | class financing_contract_contract(osv.osv): |
2001 | |
2002 | === modified file 'bin/osv/orm.py' |
2003 | --- bin/osv/orm.py 2021-02-02 10:20:51 +0000 |
2004 | +++ bin/osv/orm.py 2021-05-07 16:01:07 +0000 |
2005 | @@ -733,12 +733,21 @@ |
2006 | |
2007 | if no_data: |
2008 | dt = '' |
2009 | + rel_table_name = r[0]._table_name |
2010 | + name_relation = self.pool.get(rel_table_name)._rec_name |
2011 | + if isinstance(r[0][name_relation], browse_record): |
2012 | + rel = True |
2013 | + rel_table_name = r[0][name_relation]._table_name |
2014 | + all_rr = [rr[name_relation].id for rr in r] |
2015 | + else: |
2016 | + rel = False |
2017 | + all_rr = [rr.id for rr in r] |
2018 | + all_name_get = dict(self.pool.get(rel_table_name).name_get(cr, uid, all_rr, context=context)) |
2019 | for rr in r: |
2020 | - name_relation = self.pool.get(rr._table_name)._rec_name |
2021 | - if isinstance(rr[name_relation], browse_record): |
2022 | - rr = rr[name_relation] |
2023 | - rr_name = self.pool.get(rr._table_name).name_get(cr, uid, [rr.id], context=context) |
2024 | - rr_name = rr_name and rr_name[0] and rr_name[0][1] or '' |
2025 | + if not rel: |
2026 | + rr_name = all_name_get.get(rr.id, '') |
2027 | + else: |
2028 | + rr_name = all_name_get.get(rr[name_relation].id, '') |
2029 | dt += tools.ustr(rr_name or '') + ',' |
2030 | data[fpos] = dt[:-1] |
2031 | break |