Merge lp:~jfb-tempo-consulting/unifield-server/US-9119 into lp:unifield-server

Proposed by jftempo
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
Reviewer Review Type Date Requested Status
UniField Reviewer Team Pending
Review via email: mp+445623@code.launchpad.net
To post a comment you must log in.
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

lp:~dorian-kemps/unifield-server/US-6144-py3

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches