Merge lp:~jfb-tempo-consulting/unifield-server/US-9119 into lp:unifield-server
- US-9119
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~jfb-tempo-consulting/unifield-server/US-9119 |
Merge into: | lp:unifield-server |
Diff against target: |
739 lines (+297/-185) (has conflicts) 9 files modified
bin/addons/hr/hr_view.xml (+1/-0) bin/addons/msf_homere_interface/hr.py (+3/-1) bin/addons/msf_homere_interface/hr_view.xml (+1/-0) bin/addons/msf_homere_interface/wizard/hr_payroll_employee_import.py (+191/-174) bin/addons/msf_homere_interface/wizard/hr_payroll_import.py (+24/-6) bin/addons/msf_profile/data/patches.xml (+3/-0) bin/addons/msf_profile/i18n/fr_MF.po (+67/-1) bin/addons/msf_profile/msf_profile.py (+6/-0) bin/addons/stock/product.py (+1/-3) Text conflict in bin/addons/msf_homere_interface/wizard/hr_payroll_employee_import.py Text conflict in bin/addons/msf_profile/i18n/fr_MF.po Text conflict in bin/addons/msf_profile/msf_profile.py |
To merge this branch: | bzr merge lp:~jfb-tempo-consulting/unifield-server/US-9119 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email: mp+445623@code.launchpad.net |
Commit message
Description of the change
- 6120. By jftempo
-
US-11689 [FIX] Deleted object on py3: replace method
- 6121. By jftempo
-
US-7008 [FIX] Full report: error if register has draft entries (no sequence_
for_reference) - 6122. By jftempo
-
US-11778 [FIX] malformed_
xml_spreadsheet : "growing nodeset hit limit" on big file - 6123. By jftempo
-
[MERGE] UF30.0rc1
- 6124. By jftempo
-
[MERGE] UF30.0rc2
- 6125. By jftempo
-
US-10787 [FIX] Signature follow-up domain on open doc
- 6126. By jftempo
-
US-3612 [FIX] Adv. return wizard: employee with AD on the return line raises error
- 6127. By jftempo
-
[MERGE] UF30.0
- 6128. By jftempo
-
[IMP] Product Attributes Data: do not update data
- 6129. By jftempo
-
Python win lib: do not force version
- 6130. By jftempo
-
Python win lib: freeze pip version
- 6131. By jftempo
-
Release UF30.0py3
- 6132. By jftempo
-
[MERGE] UF30.1rc1
- 6133. By jftempo
-
US-2645 [FIX] PO line sorted by supplier code: py3 lmf
- 6134. By jftempo
-
[FIX] Expiry quantities: lmf on sort by location
- 6135. By jftempo
-
US-4242 [FIX] PO Import wizard: double click on import button: lmf
- 6136. By jftempo
-
[MERGE] UF30.1rc1
- 6137. By jftempo
-
Release UF30.1rc1py3
- 6138. By jftempo
-
US-12011 [MERGE] PO Confirmation with MML non-conform product
- 6139. By jftempo
-
[MERGE] UF30.1
- 6140. By jftempo
-
Release UF30.1
- 6141. By jftempo
-
US-5946 [FIX] Import expact
- allow integer as Indentifier
- end date: issue depending on server locale (fr_MF)
- Tools > Import : allow to import file with or without end date - 6142. By jftempo
-
US-12041 [FIX] Import payroll: lmf if envoi.ini is ISO-8859 encoded with special char
- 6143. By jftempo
-
US-12130 [FIX] JI / JI Selector: pink screen if Display HQ Code is enabled on Company configuration
- 6144. By jftempo
-
US-12069 [IMP] OCP Webservice to update res.currency.table
- 6145. By jftempo
-
US-US-5912 [FIX] Export PO f/up: too many lines, replace Lmf by a warning message
- 6146. By jftempo
-
US-5376 [FIX] HQ entries import: allow B/S account
- 6147. By jftempo
-
US-6516 [FIX] OCG VI Finance: py3 error on itekeys
- 6148. By jftempo
-
[MERGE] UF31.0rc0
- 6149. By jftempo
-
[MERGE] UF31.0rc1
- 6150. By jftempo
-
[FIX] UF30.1 py3 migration
- 6151. By jftempo
-
[FIX] Asset py3: int, long
- 6152. By jftempo
-
US-12185 |FIX] PI import with ED date 11-2222 nothing happens
- dateutil.parser. parse does not raise a ValueError
- Exception.message no longer exists in py3 - 6153. By jftempo
-
Exception has no more message attribute
- 6154. By jftempo
-
[MERGE] UF31.0rc2
- 6155. By jftempo
-
US-11950 [FIX] Product asset sync down state
- 6156. By jftempo
-
[IMP] RB: create asset data
- 6157. By jftempo
-
Upgrade python lib
- 6158. By jftempo
-
Upgrade python lib
- 6159. By jftempo
-
Upgrade python lib
- 6160. By jftempo
-
upgrade from pip-audit
- 6161. By jftempo
-
Upgrade lib from safety tool
- 6162. By jftempo
-
[IMP] replace deprecated currentThread() / isDaemon() by current_thread() / daemon
- 6163. By jftempo
-
[FIX] Py3 Pillow 10: getsize replaced by getbbox
- 6164. By jftempo
-
US-12244 [FIX] Periodical forecast: fixed date check for dates in the future
- 6165. By jftempo
-
US-6144-py3 [FIX] Sourcing: fixed name filtering for python 3 during creation/
modification - 6166. By jftempo
-
[FIX] Generate translation file to py3
- 6167. By jftempo
-
Release UF31.0py3
- 6168. By jftempo
-
[MERGE] UF31.1
- 6169. By jftempo
-
unifield-
version. txt: typo in version - 6170. By jftempo
-
[MERGE] US-9119 + UF31.1py3
- 6171. By jftempo
-
Homere employee update: if duplicate uuid , add id_staff
- 6172. By jftempo
-
id_staff match
- 6173. By jftempo
-
Search view: add homere uuid
- 6174. By jftempo
-
id_staff match
- 6175. By jftempo
-
Translation
- 6176. By jftempo
-
Lmf when staff.csv is incomplete
Unmerged revisions
- 6176. By jftempo
-
Lmf when staff.csv is incomplete
- 6175. By jftempo
-
Translation
- 6174. By jftempo
-
id_staff match
- 6173. By jftempo
-
Search view: add homere uuid
- 6172. By jftempo
-
id_staff match
- 6171. By jftempo
-
Homere employee update: if duplicate uuid , add id_staff
- 6170. By jftempo
-
[MERGE] US-9119 + UF31.1py3
Preview Diff
1 | === modified file 'bin/addons/hr/hr_view.xml' |
2 | --- bin/addons/hr/hr_view.xml 2023-08-16 13:46:02 +0000 |
3 | +++ bin/addons/hr/hr_view.xml 2024-01-25 08:44:54 +0000 |
4 | @@ -110,6 +110,7 @@ |
5 | <separator orientation="vertical" /> |
6 | <field name="name"/> |
7 | <field name="identification_id"/> |
8 | + <field name="homere_uuid_key" /> |
9 | <field name="job_name"/> |
10 | <newline/> |
11 | <group> |
12 | |
13 | === modified file 'bin/addons/msf_homere_interface/hr.py' |
14 | --- bin/addons/msf_homere_interface/hr.py 2023-11-03 15:04:29 +0000 |
15 | +++ bin/addons/msf_homere_interface/hr.py 2024-01-25 08:44:54 +0000 |
16 | @@ -139,7 +139,7 @@ |
17 | 'homere_codeterrain': fields.char(string='Homere field: codeterrain', size=20, readonly=True, required=False), |
18 | 'homere_id_staff': fields.integer(string='Homere field: id_staff', size=10, readonly=True, required=False), |
19 | 'homere_id_unique': fields.char(string='Homere field: id_unique', size=42, readonly=True, required=False), |
20 | - 'homere_uuid_key': fields.char(string='Homere field: UUID_key', size=64, readonly=True, required=False), |
21 | + 'homere_uuid_key': fields.char(string='Homere field: UUID_key', size=64, readonly=True, required=False, select=1), |
22 | 'gender': fields.selection([('male', 'Male'),('female', 'Female'), ('unknown', 'Unknown')], 'Gender'), |
23 | 'private_phone': fields.char(string='Private Phone', size=32), |
24 | 'name_resource': fields.related('resource_id', 'name', string="Name", type='char', size=128, store=True, write_relate=False), |
25 | @@ -160,6 +160,7 @@ |
26 | 'homere_id_unique': lambda *a: '', |
27 | 'gender': lambda *a: 'unknown', |
28 | 'ex_allow_edition': lambda *a: True, |
29 | + 'homere_uuid_key': False, |
30 | } |
31 | |
32 | def _set_sync_update_as_run(self, cr, uid, data, sdref, context=None): |
33 | @@ -211,6 +212,7 @@ |
34 | (_check_unicity, "Another employee has the same Identification No.", ['identification_id']), |
35 | ] |
36 | |
37 | + |
38 | def _check_employee_cc_compatibility(self, cr, uid, employee_id, context=None): |
39 | """ |
40 | Raises an error in case the employee "Destination and Cost Center" or "Funding Pool and Cost Center" are not compatible. |
41 | |
42 | === modified file 'bin/addons/msf_homere_interface/hr_view.xml' |
43 | --- bin/addons/msf_homere_interface/hr_view.xml 2023-08-16 13:46:02 +0000 |
44 | +++ bin/addons/msf_homere_interface/hr_view.xml 2024-01-25 08:44:54 +0000 |
45 | @@ -174,6 +174,7 @@ |
46 | <separator orientation="vertical" /> |
47 | <field name="name"/> |
48 | <field name="identification_id"/> |
49 | + <field name="homere_uuid_key" /> |
50 | <field name="job_name"/> |
51 | <newline/> |
52 | <group> |
53 | |
54 | === modified file 'bin/addons/msf_homere_interface/wizard/hr_payroll_employee_import.py' |
55 | --- bin/addons/msf_homere_interface/wizard/hr_payroll_employee_import.py 2023-12-13 13:18:06 +0000 |
56 | +++ bin/addons/msf_homere_interface/wizard/hr_payroll_employee_import.py 2024-01-25 08:44:54 +0000 |
57 | @@ -224,125 +224,6 @@ |
58 | for err in errors[wiz_id]: |
59 | error_obj.create(cr, uid, {'wizard_id': wiz_id, 'msg': err}, context=context) |
60 | |
61 | - def update_employee_check(self, cr, uid, |
62 | - staffcode=False, missioncode=False, staff_id=False, uniq_id=False, |
63 | - wizard_id=None, employee_name=False, registered_keys=None, homere_fields=None, errors=None): |
64 | - """ |
65 | - Check that: |
66 | - - no more than 1 employee exist for "missioncode + staff_id + uniq_id" |
67 | - - only one employee have this staffcode |
68 | - :return (ok, what_changed) |
69 | - :rtype tuple |
70 | - """ |
71 | - |
72 | - if homere_fields is None: |
73 | - homere_fields = {} |
74 | - |
75 | - def changed(mission1, mission2, staff1, staff2, unique1, unique2): |
76 | - res = None |
77 | - if mission1 != mission2: |
78 | - res = 'mission' |
79 | - elif staff1 != staff2: |
80 | - res = 'staff' |
81 | - elif unique1 != unique2: |
82 | - res = 'unique' |
83 | - return res |
84 | - |
85 | - res = False |
86 | - what_changed = None |
87 | - |
88 | - # Checks |
89 | - if not staffcode or not missioncode or not staff_id or not uniq_id: |
90 | - name = employee_name or _('Nonamed Employee') |
91 | - message = _('Unknown error for employee %s') % name |
92 | - if not staffcode: |
93 | - message = _('No "code_staff" found for employee %s!') % (name,) |
94 | - elif not missioncode: |
95 | - message = _('No "code_terrain" found for employee %s!') % (name,) |
96 | - elif not staff_id: |
97 | - message = _('No "id_staff" found for employee %s!') % (name,) |
98 | - elif not uniq_id: |
99 | - message = _('No "id_unique" found for employee %s!') % (name,) |
100 | - self.store_error(errors, wizard_id, message) |
101 | - return (res, what_changed) |
102 | - |
103 | - # Check employees |
104 | - |
105 | - # US-1404: check duplicates on the import files itself |
106 | - # => as not already in db |
107 | - check_key = missioncode + staff_id + uniq_id |
108 | - if check_key in registered_keys: |
109 | - # if check_key is in homere_fields BUT its value is empty, the related msg has already been created => skip the msg creation part |
110 | - if check_key not in homere_fields or homere_fields.get(check_key): |
111 | - # if possible list all the duplicated employees |
112 | - if homere_fields.get(check_key): |
113 | - list_duplicates = ['%s (%s)' % (empl, _('Import File')) for empl in homere_fields[check_key]] |
114 | - # empty the list so that the msg with all employees is displayed only once (and not once per duplicated employee) |
115 | - homere_fields[check_key] = [] |
116 | - # if not possible only the current employee name will be displayed |
117 | - else: |
118 | - list_duplicates = ['%s (%s)' % (employee_name, _('Import File'))] |
119 | - self.store_error(errors, wizard_id, |
120 | - _('Several employees have the same combination key codeterrain/id_staff/(id_unique) "%s / %s / (%s)": %s') % |
121 | - (missioncode, staff_id, uniq_id, ' ; '.join(list_duplicates)) |
122 | - ) |
123 | - return (res, what_changed) |
124 | - |
125 | - # check duplicates already in db |
126 | - search_ids = self.pool.get('hr.employee').search(cr, uid, [('homere_codeterrain', '=', missioncode), ('homere_id_staff', '=', staff_id), ('homere_id_unique', '=', uniq_id)]) |
127 | - if search_ids and len(search_ids) > 1: |
128 | - emp_duplicates = self.pool.get('hr.employee').browse(cr, uid, search_ids, fields_to_fetch=['name']) |
129 | - # create a list with the employee from the file... |
130 | - name_duplicates = ['%s (%s)' % (employee_name, _('Import File'))] |
131 | - # ... and the duplicates already in UniField |
132 | - name_duplicates.extend(['%s (UniField)' % emp.name for emp in emp_duplicates if emp.name]) |
133 | - self.store_error(errors, wizard_id, |
134 | - _('Several employees have the same combination key codeterrain/id_staff/(id_unique) "%s / %s / (%s)": %s') % |
135 | - (missioncode, staff_id, uniq_id, ' ; '.join(name_duplicates)) |
136 | - ) |
137 | - return (res, what_changed) |
138 | - |
139 | - # Check staffcode |
140 | - staffcode_ids = self.pool.get('hr.employee').search(cr, uid, [('identification_id', '=', staffcode)]) |
141 | - if staffcode_ids: |
142 | - employee_error_list = [] |
143 | - # UTP-1098: Do not make an error if the employee have the same code staff and the same name |
144 | - for employee in self.pool.get('hr.employee').browse(cr, uid, staffcode_ids): |
145 | - what_changed = changed(employee.homere_codeterrain, missioncode, str(employee.homere_id_staff), staff_id, employee.homere_id_unique, uniq_id) |
146 | - if employee.name == employee_name: |
147 | - continue |
148 | - if what_changed != None: |
149 | - # duplicated employees in UniField |
150 | - employee_error_list.append("%s (UniField)" % (employee.name,)) |
151 | - if employee_error_list: |
152 | - # add the duplicated employee from Import File |
153 | - message = _('Several employees have the same Identification No "%s": %s') % \ |
154 | - (staffcode, ' ; '.join(["%s (%s)" % (employee_name, _('Import File'))] + employee_error_list)) |
155 | - self.store_error(errors, wizard_id, message) |
156 | - return (res, what_changed) |
157 | - |
158 | - res = True |
159 | - return (res, what_changed) |
160 | - |
161 | - def _check_identification_id_duplication(self, cr, uid, vals, employee_check, what_changed, current_id=None, context=None): |
162 | - """ |
163 | - Method used to check if the Identification No to be used for the employee about to be created/edited doesn't |
164 | - already exist for another employee in UniField. |
165 | - Returns False if there is a duplication AND we are in the use case where the related and detailed error has |
166 | - already been stored in the list of errors to display (but the process wasn't blocked earlier since "what_changed" had a value). |
167 | - Otherwise returns True => the generic create/write checks will then apply (i.e. a generic error msg will be displayed) |
168 | - """ |
169 | - if context is None: |
170 | - context = {} |
171 | - employee_obj = self.pool.get('hr.employee') |
172 | - if not employee_check and what_changed and vals.get('identification_id'): |
173 | - employee_dom = [('identification_id', '=', vals['identification_id'])] |
174 | - if current_id is not None: |
175 | - employee_dom.append(('id', '!=', current_id)) |
176 | - if employee_obj.search_exist(cr, uid, employee_dom, context=context): |
177 | - return False |
178 | - return True |
179 | - |
180 | def read_employee_infos(self, cr, uid, line='', context=None): |
181 | """ |
182 | Read each line to extract infos (code, name and surname) |
183 | @@ -356,39 +237,46 @@ |
184 | return res |
185 | |
186 | def update_employee_infos(self, cr, uid, employee_data='', wizard_id=None, |
187 | - line_number=None, registered_keys=None, homere_fields=None, errors=None, context=None): |
188 | + line_number=None, errors=None, context=None): |
189 | """ |
190 | Get employee infos and set them to DB. |
191 | + return (status (True/False), is_new (0/1), is_update (0/1)) |
192 | + |
193 | + if status is False: full import is blocked |
194 | + |
195 | """ |
196 | - # Some verifications |
197 | - created = 0 |
198 | - updated = 0 |
199 | - if homere_fields is None: |
200 | - homere_fields = {} |
201 | |
202 | if context is None: |
203 | context = {} |
204 | + |
205 | if line_number is not None: |
206 | line_number = line_number + 2 # cf. the count starts at "1" and the header line is ignored |
207 | +<<<<<<< TREE |
208 | +======= |
209 | + |
210 | + payment_method_obj = self.pool.get('hr.payment.method') |
211 | +>>>>>>> MERGE-SOURCE |
212 | if not employee_data or not wizard_id: |
213 | message = _('No data found for this line: %s.') % line_number |
214 | self.store_error(errors, wizard_id, message) |
215 | - return False, created, updated |
216 | + return False, 0, 0 |
217 | + |
218 | # Prepare some values |
219 | vals = {} |
220 | # Extract information |
221 | try: |
222 | - code_staff = employee_data.get('code_staff', False) |
223 | + code_staff = employee_data.get('code_staff', False) # UF identification_id |
224 | codeterrain = employee_data.get('codeterrain', False) |
225 | decede = employee_data.get('decede', False) |
226 | id_staff = employee_data.get('id_staff', False) |
227 | id_unique = employee_data.get('id_unique', False) |
228 | - uuid_key = employee_data.get('uuid_key', False) |
229 | + uuid_key = employee_data.get('uuid_key', False) # UF home_uuid_key |
230 | nom = employee_data.get('nom', False) |
231 | prenom = employee_data.get('prenom', False) |
232 | except ValueError as e: |
233 | raise osv.except_osv(_('Error'), _('The given file is probably corrupted!\n%s') % (e)) |
234 | - # Process data |
235 | + |
236 | + # check max uuid size |
237 | uuid_field = self.pool.get('hr.employee')._columns.get('homere_uuid_key') |
238 | if uuid_key and uuid_field: |
239 | uuid_key = ustr(uuid_key) |
240 | @@ -396,11 +284,13 @@ |
241 | if len(uuid_key) > uuid_field_size: |
242 | message = _('Line %s. The UUID_key has more than %d characters.') % (line_number, uuid_field_size) |
243 | self.store_error(errors, wizard_id, message) |
244 | - return False, created, updated |
245 | + return False, 0, 0 |
246 | + |
247 | # Due to UF-1742, if no id_unique, we fill it with "empty" |
248 | uniq_id = id_unique or False |
249 | if not id_unique: |
250 | uniq_id = 'empty' |
251 | +<<<<<<< TREE |
252 | if codeterrain and id_staff and code_staff: |
253 | # Employee name |
254 | nom = nom and nom.strip() or '' |
255 | @@ -465,23 +355,140 @@ |
256 | # Desactivate employee if no current contract |
257 | if not current_contract: |
258 | vals.update({'active': False}) |
259 | +======= |
260 | + |
261 | + if not codeterrain or not id_staff or not code_staff: |
262 | + message = _('Line %s. One of this column is missing: code_terrain, id_unique or id_staff. This often happens when the line is empty.') % (line_number, ) |
263 | + self.store_error(errors, wizard_id, message) |
264 | + return False, 0, 0 |
265 | + |
266 | + if not uuid_key: |
267 | + self.store_error(errors, wizard_id, _('Line %s. Required Homere uuid_key field is missing in the file.') % (line_number, )) |
268 | + return False, 0, 0 |
269 | + |
270 | + # Employee name |
271 | + nom = nom and nom.strip() or '' |
272 | + prenom = prenom and prenom.strip() or '' |
273 | + employee_name = (nom and prenom and ustr(nom) + ', ' + ustr(prenom)) or (nom and ustr(nom)) or (prenom and ustr(prenom)) or False |
274 | + |
275 | + |
276 | + # employee by uuid_key |
277 | + e_ids = self.pool.get('hr.employee').search(cr, uid, [('homere_uuid_key', '=', uuid_key)]) |
278 | + if len(e_ids) > 1: |
279 | + with_id_staff_ids = self.pool.get('hr.employee').search(cr, uid, [('homere_uuid_key', '=', uuid_key), ('homere_id_staff', '=', id_staff)]) |
280 | + if len(with_id_staff_ids) == 1: |
281 | + e_ids = with_id_staff_ids |
282 | + else: |
283 | + dups = self.pool.get('hr.employee').browse(cr, uid, e_ids, fields_to_fetch=['name', 'homere_id_staff']) |
284 | + if len(with_id_staff_ids) > 1: |
285 | + self.store_error(errors, wizard_id, _('Homere uuid_key %s is duplicated in the UF database, Homere id_staff: %s, number of records: %d: %s') % (uuid_key, id_staff, len(with_id_staff_ids), '; '.join([x.name for x in dups]))) |
286 | + return False, 0, 0 |
287 | + else: |
288 | + self.store_error(errors, wizard_id, _('Homere uuid_key %s is duplicated in the UF database, but no match with id_staff %s, number of records: %d: %s') % (uuid_key, id_staff, len(e_ids), '; '.join(['%s %s'%(x.name, x.homere_id_staff) for x in dups]))) |
289 | + return False, 0, 0 |
290 | + if not e_ids: |
291 | + # else no uuid, same name, same identification_id |
292 | + e_ids = self.pool.get('hr.employee').search(cr, uid, [('identification_id','=', code_staff), ('name', '=', employee_name), ('homere_uuid_key', '=', False)]) |
293 | + if len(e_ids) > 1: |
294 | + self.store_error(errors, wizard_id, |
295 | + _('%d employees in the db have the same combination identification_id/name/empty uuid "%s / %s "') % |
296 | + (len(e_ids), code_staff, employee_name) |
297 | + ) |
298 | + return False, 0, 0 |
299 | + |
300 | +>>>>>>> MERGE-SOURCE |
301 | if not e_ids: |
302 | - if not self._check_identification_id_duplication(cr, uid, vals, employee_check, what_changed, context=context): |
303 | - return False, created, updated |
304 | - res = self.pool.get('hr.employee').create(cr, uid, vals, {'from': 'import'}) |
305 | - if res: |
306 | - created += 1 |
307 | + # Search employee regarding a unique trio: codeterrain, id_staff, id_unique |
308 | + e_ids = self.pool.get('hr.employee').search(cr, uid, [('homere_codeterrain', '=', codeterrain), ('homere_id_staff', '=', id_staff), ('homere_id_unique', '=', uniq_id), ('homere_uuid_key', '=', False)]) |
309 | + if len(e_ids) > 1: |
310 | + dups = self.pool.get('hr.employee').browse(cr, uid, e_ids, fields_to_fetch=['name']) |
311 | + self.store_error(errors, wizard_id, |
312 | + _('Several employees in the db have the same combination codeterrain/id_staff/(id_unique)/empty uuid "%s / %s / (%s)": %s') % |
313 | + (codeterrain, id_staff, uniq_id, ' ; '.join([x.name for x in dups])) |
314 | + ) |
315 | + return False, 0, 0 |
316 | + |
317 | + if code_staff: |
318 | + employee_dom = [('identification_id', '=', code_staff)] |
319 | + if e_ids: |
320 | + employee_dom.append(('id', '!=', e_ids[0])) |
321 | + dup_ids = self.pool.get('hr.employee').search(cr, uid, employee_dom, context=context) |
322 | + if dup_ids: |
323 | + dups = self.pool.get('hr.employee').browse(cr, uid, dup_ids, fields_to_fetch=['name']) |
324 | + self.store_error(errors, wizard_id, |
325 | + _('Several employees have the same identification_id %s: %s (Import file), %s') % |
326 | + (code_staff, employee_name, ','.join(['%s (UniField)' % x.name for x in dups])) |
327 | + ) |
328 | + return False, 0, 0 |
329 | + |
330 | + vals = { |
331 | + 'active': True, |
332 | + 'employee_type': 'local', |
333 | + 'homere_codeterrain': codeterrain, |
334 | + 'homere_id_staff': id_staff, |
335 | + 'homere_id_unique': uniq_id, |
336 | + 'homere_uuid_key': uuid_key, |
337 | + 'photo': False, |
338 | + 'identification_id': code_staff or False, |
339 | + 'name': employee_name, |
340 | + 'bank_name': bqnom, |
341 | + 'bank_account_number': bqnumerocompte, |
342 | + } |
343 | + |
344 | + |
345 | + # Update the payment method |
346 | + payment_method_id = False |
347 | + if bqmodereglement: |
348 | + payment_method_ids = payment_method_obj.search(cr, uid, [('name', '=', bqmodereglement)], limit=1, context=context) |
349 | + if payment_method_ids: |
350 | + payment_method_id = payment_method_ids[0] |
351 | else: |
352 | - if not self._check_identification_id_duplication(cr, uid, vals, employee_check, what_changed, current_id=e_ids[0], context=context): |
353 | - return False, created, updated |
354 | - res = self.pool.get('hr.employee').write(cr, uid, e_ids, vals, {'from': 'import'}) |
355 | - if res: |
356 | - updated += 1 |
357 | - registered_keys[codeterrain + id_staff + uniq_id] = True |
358 | + message = _('Payment Method %s not found for line: %s. Please fix Homere configuration or request a new Payment Method to the HQ.') % (ustr(bqmodereglement), line_number) |
359 | + self.store_error(errors, wizard_id, message) |
360 | + return False, 0, 0 |
361 | + |
362 | + vals.update({'payment_method_id': payment_method_id}) |
363 | + |
364 | + # In case of death, desactivate employee |
365 | + if decede and decede == 'Y': |
366 | + vals.update({'active': False}) |
367 | + # Desactivate employee if: |
368 | + # - no contract line found |
369 | + # - end of current contract exists and is inferior to current date |
370 | + # - no contract line found with current = True |
371 | + |
372 | + # sort contract: get current one, then by start date |
373 | + contract_ids = self.pool.get('hr.contract.msf').search(cr, uid, [('homere_codeterrain', '=', codeterrain), ('homere_id_staff', '=', id_staff)], order='current desc,date_start desc') |
374 | + if not contract_ids: |
375 | + vals.update({'active': False}) |
376 | + current_contract = False |
377 | + if contract_ids: |
378 | + contract = self.pool.get('hr.contract.msf').browse(cr, uid, contract_ids[0]) |
379 | + # Check current contract |
380 | + if contract.current: |
381 | + current_contract = True |
382 | + if contract.date_end and contract.date_end < strftime('%Y-%m-%d'): |
383 | + vals.update({'active': False}) |
384 | + # Check job |
385 | + if contract.job_name: |
386 | + vals.update({'job_name': contract.job_name}) |
387 | + # Check the contract dates |
388 | + vals.update({'contract_start_date': contract.date_start or False}) |
389 | + vals.update({'contract_end_date': contract.date_end or False}) |
390 | + # Desactivate employee if no current contract |
391 | + if not current_contract: |
392 | + vals.update({'active': False}) |
393 | + |
394 | + created = 0 |
395 | + updated = 0 |
396 | + |
397 | + if not e_ids: |
398 | + self.pool.get('hr.employee').create(cr, uid, vals, {'from': 'import'}) |
399 | + created = 1 |
400 | else: |
401 | - message = _('Line %s. One of this column is missing: code_terrain, id_unique or id_staff. This often happens when the line is empty.') % (line_number) |
402 | - self.store_error(errors, wizard_id, message) |
403 | - return False, created, updated |
404 | + self.pool.get('hr.employee').write(cr, uid, e_ids, vals, {'from': 'import'}) |
405 | + updated = 1 |
406 | + |
407 | |
408 | return True, created, updated |
409 | |
410 | @@ -614,7 +621,6 @@ |
411 | updated = 0 |
412 | processed = 0 |
413 | filename = "" |
414 | - registered_keys = {} |
415 | errors = {} |
416 | for wiz in self.browse(cr, uid, ids): |
417 | if not wiz.file: |
418 | @@ -640,10 +646,17 @@ |
419 | contract_ids = self.update_contract(cr, uid, ids, contract_reader, context=context) |
420 | # UF-2472: Read all lines to check employee's code before importing |
421 | staff_data = [] |
422 | - staff_codes = [] |
423 | - duplicates = [] |
424 | staff_seen = [] |
425 | - homere_fields = {} |
426 | + |
427 | + staff_codes_seen = {} |
428 | + staff_codes_duplicated = {} |
429 | + |
430 | + codeterrain_id_staff_seen = {} |
431 | + codeterrain_id_staff_duplicated = {} |
432 | + |
433 | + uuid_seen = {} |
434 | + uuid_duplicated = {} |
435 | + |
436 | for line in staff_reader: |
437 | staff_seen.append(line) |
438 | data = self.read_employee_infos(cr, uid, line) |
439 | @@ -651,28 +664,26 @@ |
440 | if data: # to avoid False value in staff_data list |
441 | staff_data.append(data) |
442 | code = data[0] |
443 | - if code in staff_codes: |
444 | - duplicates.append(code) |
445 | - staff_codes.append(code) |
446 | - # store the Homere fields combination for all employees |
447 | - if line.get('nom'): |
448 | - # "no id_unique" is replaced by the string "empty" |
449 | - homere_fields_key = "%s%s%s" % (line.get('codeterrain', ''), line.get('id_staff', ''), line.get('id_unique') or 'empty') |
450 | - if homere_fields_key not in homere_fields: |
451 | - homere_fields[homere_fields_key] = [] |
452 | - homere_fields[homere_fields_key].append(line['nom']) |
453 | - # Delete duplicates of… duplicates! |
454 | - duplicates = list(set(duplicates)) |
455 | - details = {} |
456 | - for employee_infos in staff_data: |
457 | - employee_code = employee_infos[0] |
458 | - if employee_code in duplicates: |
459 | - # add (Import File) after the employee info so that it is clearer for the user that the duplicates are inside the file itself |
460 | - if employee_code not in details: |
461 | - details[employee_code] = [] |
462 | - details[employee_code].append(','.join([ustr(employee_infos[1]), "%s (%s)" % (ustr(employee_infos[2]), _('Import File'))])) |
463 | + |
464 | + # code_staff (uf identification_id) unicity |
465 | + if code in staff_codes_seen: |
466 | + staff_codes_duplicated[code] =True |
467 | + staff_codes_seen.setdefault(code, []).append('%s, %s (%s)' % (ustr(data[1]), ustr(data[2]),_('Import File'))) |
468 | + |
469 | + |
470 | + if line.get('codeterrain') and line.get('id_staff'): # if not, error will be raised later |
471 | + codeterrain_id_staff_key = (line['codeterrain'], line['id_staff']) |
472 | + if codeterrain_id_staff_key in codeterrain_id_staff_seen: |
473 | + codeterrain_id_staff_duplicated[codeterrain_id_staff_key] = True |
474 | + codeterrain_id_staff_seen.setdefault(codeterrain_id_staff_key, []).append('%s, %s (%s)' % (ustr(data[1]), ustr(data[2]),_('Import File'))) |
475 | + |
476 | + if line.get('uuid_key'): # if not, error raised later |
477 | + if line['uuid_key'] in uuid_seen: |
478 | + uuid_duplicated[line['uuid_key']] = True |
479 | + uuid_seen.setdefault(line['uuid_key'], []).append('%s, %s (%s)' % (ustr(data[1]), ustr(data[2]), _('Import File'))) |
480 | + |
481 | res = True |
482 | - if not details: |
483 | + if not staff_codes_duplicated and not codeterrain_id_staff_duplicated and not uuid_duplicated: |
484 | created = 0 |
485 | processed = 0 |
486 | updated = 0 |
487 | @@ -681,7 +692,7 @@ |
488 | for i, employee_data in enumerate(staff_seen): |
489 | update, nb_created, nb_updated = self.update_employee_infos( |
490 | cr, uid, employee_data, wiz.id, i, |
491 | - registered_keys=registered_keys, homere_fields=homere_fields, errors=errors, context=context) |
492 | + errors=errors, context=context) |
493 | if not update: |
494 | res = False |
495 | created += nb_created |
496 | @@ -690,9 +701,16 @@ |
497 | else: |
498 | res = False |
499 | # create a different error line for each employee code being duplicated |
500 | - for emp_code in details: |
501 | - message = _('Several employees have the same Identification No "%s": %s') % (emp_code, ' ; '.join(details[emp_code])) |
502 | - self.store_error(errors, wiz.id, message) |
503 | + for emp_code in staff_codes_duplicated: |
504 | + message = _('Several employees have the same Identification No "%s": %s') % (emp_code, ' ; '.join(staff_codes_seen[emp_code])) |
505 | + self.store_error(errors, wiz.id, message) |
506 | + for codeterrain_dup, id_staff_dup in codeterrain_id_staff_duplicated: |
507 | + message = _('Several employees have the same combination codeterrain %s, id_staff %s : %s') % (codeterrain_dup, id_staff_dup , ' ; '.join(codeterrain_id_staff_seen[(codeterrain_dup, id_staff_dup)])) |
508 | + self.store_error(errors, wiz.id, message) |
509 | + for uuid_dup in uuid_duplicated: |
510 | + message = _('Several employees have the same uuid_key %s : %s') % (uuid_dup , ' ; '.join(uuid_seen[uuid_dup])) |
511 | + self.store_error(errors, wiz.id, message) |
512 | + |
513 | # Close Temporary File |
514 | # Delete previous created lines for employee's contracts |
515 | if contract_ids: |
516 | @@ -701,7 +719,6 @@ |
517 | to_close.close() |
518 | if tmpdir: |
519 | shutil.rmtree(tmpdir) |
520 | - del registered_keys |
521 | if res: |
522 | rejected = processed - created - updated |
523 | message = _("Employee import successful.") |
524 | |
525 | === modified file 'bin/addons/msf_homere_interface/wizard/hr_payroll_import.py' |
526 | --- bin/addons/msf_homere_interface/wizard/hr_payroll_import.py 2023-10-03 12:51:21 +0000 |
527 | +++ bin/addons/msf_homere_interface/wizard/hr_payroll_import.py 2024-01-25 08:44:54 +0000 |
528 | @@ -92,26 +92,44 @@ |
529 | employee_obj = self.pool.get('hr.employee') |
530 | employee_ids = [] |
531 | employee_identification_id = "" |
532 | + uuid_used = False |
533 | if third and third[0]: |
534 | # the Third column should contain the exact code of the employee |
535 | employee_identification_id = third[0] |
536 | - employee_ids = employee_obj.search(cr, uid, |
537 | - [('identification_id', '=', employee_identification_id)], |
538 | - context=context, order='NO_ORDER') |
539 | + employee_ids = employee_obj.search(cr, uid, [('homere_uuid_key', '=', employee_identification_id)], context=context) |
540 | + if not employee_ids: |
541 | + employee_ids = employee_obj.search(cr, uid, |
542 | + [('identification_id', '=', employee_identification_id)], |
543 | + context=context, order='NO_ORDER') |
544 | + else: |
545 | + uuid_used = True |
546 | # check the Secondary description if no employee found (no matter if the Third column is empty or not) |
547 | if not employee_ids and second_description and second_description[0]: |
548 | # Secondary description looks like "John Smith MWNP0001" => extract the employee code MWNP0001 |
549 | employee_identification_id = ustr(second_description[0]).split(' ')[-1] |
550 | - employee_ids = employee_obj.search(cr, uid, |
551 | - [('identification_id', '=', employee_identification_id)], |
552 | - context=context, order='NO_ORDER') |
553 | + employee_ids = employee_obj.search(cr, uid, [('homere_uuid_key', '=', employee_identification_id)], context=context) |
554 | + if not employee_ids: |
555 | + employee_ids = employee_obj.search(cr, uid, |
556 | + [('identification_id', '=', employee_identification_id)], |
557 | + context=context, order='NO_ORDER') |
558 | + else: |
559 | + uuid_used = True |
560 | + |
561 | if employee_identification_id and not employee_ids and account.is_analytic_addicted and not is_counterpart: |
562 | raise osv.except_osv(_('Error'), _('No employee found for this code: %s.\nDEBIT: %s.\nCREDIT: %s.') % ( |
563 | employee_identification_id, debit, credit,)) |
564 | if employee_ids and len(employee_ids) > 1: |
565 | + if uuid_used: |
566 | + raise osv.except_osv(_('Error'), _('More than one employee have the same uuid: %s') % ( |
567 | + employee_identification_id,)) |
568 | + |
569 | raise osv.except_osv(_('Error'), _('More than one employee have the same identification ID: %s') % ( |
570 | employee_identification_id,)) |
571 | employee_id = employee_ids and employee_ids[0] or False |
572 | + |
573 | + if employee_id and uuid_used: |
574 | + employee_identification_id = employee_obj.browse(cr, uid, employee_id, fields_to_fetch=['identification_id'], context=context).identification_id |
575 | + |
576 | return employee_identification_id, employee_id |
577 | |
578 | def update_payroll_entries(self, cr, uid, |
579 | |
580 | === modified file 'bin/addons/msf_profile/data/patches.xml' |
581 | --- bin/addons/msf_profile/data/patches.xml 2024-01-17 13:57:19 +0000 |
582 | +++ bin/addons/msf_profile/data/patches.xml 2024-01-25 08:44:54 +0000 |
583 | @@ -1034,5 +1034,8 @@ |
584 | |
585 | |
586 | |
587 | + <record id="us_9119_employee_uuid" model="patch.scripts"> |
588 | + <field name="method">us_9119_employee_uuid</field> |
589 | + </record> |
590 | </data> |
591 | </openerp> |
592 | |
593 | === modified file 'bin/addons/msf_profile/i18n/fr_MF.po' |
594 | --- bin/addons/msf_profile/i18n/fr_MF.po 2024-01-17 13:57:19 +0000 |
595 | +++ bin/addons/msf_profile/i18n/fr_MF.po 2024-01-25 08:44:54 +0000 |
596 | @@ -1301,6 +1301,7 @@ |
597 | #: view:hr.job:0 |
598 | #: field:hr.contract.msf,job_id:0 |
599 | #: view:hr.employee:0 |
600 | +#: field:hr.contract.msf,job_name:0 |
601 | msgid "Job" |
602 | msgstr "Poste" |
603 | |
604 | @@ -117257,8 +117258,9 @@ |
605 | msgid "number of moves" |
606 | msgstr "nombre de mouvements" |
607 | |
608 | -#. module: stock_override |
609 | +#. module: stock_override, msf_homere_interface |
610 | #: field:export.report.stock.move.progress,uuid:0 |
611 | +#: view:hr.employee:0 |
612 | msgid "uuid" |
613 | msgstr "uuid" |
614 | |
615 | @@ -121489,6 +121491,7 @@ |
616 | #, python-format |
617 | msgid "to open and compute" |
618 | msgstr "à ouvrir et générer" |
619 | +<<<<<<< TREE |
620 | |
621 | #. module: account_override |
622 | #: model:ir.actions.act_window,name:account_override.action_inkind_donation |
623 | @@ -121631,3 +121634,66 @@ |
624 | #, python-format |
625 | msgid "This record is not linked to any Picking." |
626 | msgstr "Cet enregistrement n'est lié à aucun Picking. " |
627 | +======= |
628 | + |
629 | +#. module: msf_homere_interface |
630 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:271 |
631 | +#, python-format |
632 | +msgid "Homere uuid_key %s is duplicated in the file: %s / %s" |
633 | +msgstr "Homere uuid_key %s est dupliqué dans le fichier: %s / %s" |
634 | + |
635 | +#. module: msf_homere_interface |
636 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:423 |
637 | +#, python-format |
638 | +msgid "Line %s. Required Homere uuid_key field is missing in the file." |
639 | +msgstr "Ligne %s. Le champ requis Homere uuid_key est absent du fichier." |
640 | + |
641 | +#. module: msf_homere_interface |
642 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_import.py:123 |
643 | +#, python-format |
644 | +msgid "More than one employee have the same uuid: %s" |
645 | +msgstr "Plus d'un employé ont le même uuid: %s" |
646 | + |
647 | +#. module: msf_homere_interface |
648 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:318 |
649 | +#, python-format |
650 | +msgid "%d employees in the db have the same combination identification_id/name/empty uuid \"%s / %s \"" |
651 | +msgstr "%d employés dans la base ont la même combinaison identification_id/name/empty uuid \"%s / %s \"" |
652 | + |
653 | +#. module: msf_homere_interface |
654 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:664 |
655 | +#, python-format |
656 | +msgid "Several employees have the same combination codeterrain %s, id_staff %s : %s" |
657 | +msgstr "Plusieurs employés ont la même combinaison codeterrain %s, id_staff %s : %s" |
658 | + |
659 | +#. module: msf_homere_interface |
660 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:342 |
661 | +#, python-format |
662 | +msgid "Several employees have the same identification_id %s: %s (Import file), %s" |
663 | +msgstr "Plusieurs employés ont le même identification_id %s: %s (Fichier import), %s" |
664 | + |
665 | +#. module: msf_homere_interface |
666 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:667 |
667 | +#, python-format |
668 | +msgid "Several employees have the same uuid_key %s : %s" |
669 | +msgstr "Plusieurs employés ont le même uuid_key %s : %s" |
670 | + |
671 | +#. module: msf_homere_interface |
672 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:329 |
673 | +#, python-format |
674 | +msgid "Several employees in the db have the same combination codeterrain/id_staff/(id_unique)/empty uuid \"%s / %s / (%s)\": %s" |
675 | +msgstr "Plusieurs employés de la base ont la même combinaison codeterrain/id_staff/(id_unique)/empty uuid \"%s / %s / (%s)\": %s" |
676 | + |
677 | +#. module: msf_homere_interface |
678 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:318 |
679 | +#, python-format |
680 | +msgid "Homere uuid_key %s is duplicated in the UF database, Homere id_staff: %s, number of records: %d: %s" |
681 | +msgstr "Champ Homere uuid_key %s dupliqué dans la base UF, Homere id_staff: %s, nombre d'enregistrements: %d: %s" |
682 | + |
683 | +#. module: msf_homere_interface |
684 | +#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:321 |
685 | +#, python-format |
686 | +msgid "Homere uuid_key %s is duplicated in the UF database, but no match with id_staff %s, number of records: %d: %s" |
687 | +msgstr "Champ Homere uuid_key %s dupliqué dans la base UF, aucune correspondance avec id_staff %s, nombre d'enregistrements: %d: %s" |
688 | + |
689 | +>>>>>>> MERGE-SOURCE |
690 | |
691 | === modified file 'bin/addons/msf_profile/msf_profile.py' |
692 | --- bin/addons/msf_profile/msf_profile.py 2024-01-17 13:57:19 +0000 |
693 | +++ bin/addons/msf_profile/msf_profile.py 2024-01-25 08:44:54 +0000 |
694 | @@ -57,6 +57,7 @@ |
695 | 'model': lambda *a: 'patch.scripts', |
696 | } |
697 | |
698 | +<<<<<<< TREE |
699 | # UF32.0 |
700 | def us_12076_remove_po_audittrail_rule_domain(self, cr, uid, *a, **b): |
701 | ''' |
702 | @@ -112,6 +113,10 @@ |
703 | if instance and instance.level == 'section': |
704 | self.pool.get('sync.trigger.something').create(cr, uid, {'name': 'US-12110-Sup_Fin_Read'}) |
705 | return True |
706 | +======= |
707 | + def us_9119_employee_uuid(self, cr, uid, *a, **b): |
708 | + cr.execute("update hr_employee set homere_uuid_key=NULL where homere_uuid_key=''") |
709 | +>>>>>>> MERGE-SOURCE |
710 | |
711 | # python 3 |
712 | def us_9321_2_remove_location_colors(self, cr, uid, *a, **b): |
713 | @@ -688,6 +693,7 @@ |
714 | |
715 | return True |
716 | |
717 | + |
718 | def us_10652_chg_partn_property_fields(self, cr, uid, *a, **b): |
719 | ''' |
720 | Update the data of the res_partner's fields property_product_pricelist_purchase, property_product_pricelist, |
721 | |
722 | === modified file 'bin/addons/stock/product.py' |
723 | --- bin/addons/stock/product.py 2024-01-17 13:57:19 +0000 |
724 | +++ bin/addons/stock/product.py 2024-01-25 08:44:54 +0000 |
725 | @@ -305,13 +305,11 @@ |
726 | cr.execute(''' |
727 | select sum(pol.product_qty) as qty, pol.product_id, pol.product_uom, t.uom_id |
728 | from |
729 | - purchase_order_line pol, product_product p, product_template t, purchase_order po |
730 | + purchase_order_line pol, product_product p, product_template t |
731 | where |
732 | p.id = pol.product_id and |
733 | t.id = p.product_tmpl_id and |
734 | - po.id = pol.order_id and |
735 | p.id in %%(product_id)s and |
736 | - po.order_type != 'direct' and |
737 | pol.state in ('validated', 'validated_n', 'sourced_sy', 'sourced_v', 'sourced_n') and |
738 | location_dest_id in %%(location_id)s |
739 | %s |