暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645
  1. """
  2. card_data
  3. CREATE TABLE htp_hr_cdata
  4. (
  5. cdata_date date NOT NULL,
  6. cdata_time character varying NOT NULL,
  7. cdata_time_value double precision NOT NULL,
  8. cdata_emp_no character varying NOT NULL,
  9. cdata_emp_name character varying,
  10. cdata_dept character varying,
  11. cdata_sysdate timestamp without time zone NOT NULL,
  12. PRIMARY KEY (cdata_date, cdata_time_value, cdata_emp_no)
  13. );
  14. working_times
  15. CREATE TABLE htp_hr_working_times
  16. (
  17. work_id int NOT NULL,
  18. work_beg_time timestamp without time zone NOT NULL,
  19. work_end_time timestamp without time zone NOT NULL,
  20. PRIMARY KEY (work_id, work_beg_time, work_end_time)
  21. );
  22. cshift
  23. CREATE TABLE htp_hr_cshift
  24. (
  25. cshift_emp_no character varying NOT NULL,
  26. cshift_dept character varying,
  27. cshift_no character varying NOT NULL,
  28. cshift_beg_date date NOT NULL,
  29. cshift_beg_time character varying NOT NULL,
  30. cshift_beg_time_value double precision NOT NULL,
  31. cshift_end_date date,
  32. cshift_end_time character varying,
  33. cshift_end_time_value double precision,
  34. cshift_leave_hours double precision,
  35. cshift_late character varying,
  36. cshift_late_value double precision,
  37. cshift_leave character varying,
  38. cshift_leave_value double precision,
  39. cshift_over character varying,
  40. cshift_over_value double precision,
  41. cshift_over_amt double precision DEFAULT 0,
  42. cshift_over_flag character varying DEFAULT '',
  43. cshift_over2 character varying, #加班2
  44. cshift_over2_value double precision,
  45. cshift_over2_amt double precision DEFAULT 0,
  46. cshift_over2_flag character varying DEFAULT '',
  47. cshift_over3 character varying, #加班3
  48. cshift_over3_value double precision,
  49. cshift_over3_amt double precision DEFAULT 0,
  50. cshift_over3_flag character varying DEFAULT '',
  51. cshift_over_beg_time character varying,#早加班開始時間
  52. cshift_over_end_time character varying,#晚加班結束時間
  53. cshift_total character varying,
  54. cshift_total_value double precision,
  55. cshift_resource_calendar_id int DEFAULT 0,
  56. cshift_sysdate timestamp without time zone NOT NULL,
  57. cshift_status character varying NOT NULL DEFAULT 'NA',
  58. PRIMARY KEY (cshift_emp_no, cshift_no, cshift_beg_date, cshift_beg_time_value)
  59. );
  60. ALTER TABLE htp_hr_cshift
  61. ADD COLUMN cshift_over2 character varying, #加班2
  62. ADD COLUMN cshift_over2_value double precision,
  63. ADD COLUMN cshift_over2_amt double precision DEFAULT 0,
  64. ADD COLUMN cshift_over2_flag character varying DEFAULT '';
  65. ALTER TABLE htp_hr_cshift
  66. ADD COLUMN cshift_over3 character varying, #加班3
  67. ADD COLUMN cshift_over3_value double precision,
  68. ADD COLUMN cshift_over3_amt double precision DEFAULT 0,
  69. ADD COLUMN cshift_over3_flag character varying DEFAULT '';
  70. ALTER TABLE htp_hr_cshift
  71. ADD COLUMN cshift_over_beg_time character varying DEFAULT '', #早加班開始時間
  72. ADD COLUMN cshift_over_end_time character varying DEFAULT ''; #晚加班結束時間
  73. ALTER TABLE htp_hr_cshift
  74. ADD COLUMN cshift_leave_hours double precision DEFAULT 0;
  75. ALTER TABLE htp_hr_cshift
  76. ADD COLUMN cshift_leave_type1_hours double precision DEFAULT 0,
  77. ADD COLUMN cshift_leave_type2_hours double precision DEFAULT 0,
  78. ADD COLUMN cshift_leave_type3_hours double precision DEFAULT 0,
  79. ADD COLUMN cshift_leave_type4_hours double precision DEFAULT 0,
  80. ADD COLUMN cshift_leave_type5_hours double precision DEFAULT 0,
  81. ADD COLUMN cshift_leave_type6_hours double precision DEFAULT 0,
  82. ADD COLUMN cshift_leave_type7_hours double precision DEFAULT 0,
  83. ADD COLUMN cshift_leave_type8_hours double precision DEFAULT 0,
  84. ADD COLUMN cshift_leave_type9_hours double precision DEFAULT 0,
  85. ADD COLUMN cshift_leave_type10_hours double precision DEFAULT 0,
  86. ADD COLUMN cshift_leave_type11_hours double precision DEFAULT 0,
  87. ADD COLUMN cshift_leave_type12_hours double precision DEFAULT 0,
  88. ADD COLUMN cshift_leave_type13_hours double precision DEFAULT 0,
  89. ADD COLUMN cshift_leave_type14_hours double precision DEFAULT 0;
  90. odoo 取工作時段
  91. hr_employee.resource_calendar_id
  92. resource_calendar.id
  93. resource_calendar_attendance.calendar_id
  94. resource_calendar_leaves.calendar_id
  95. """
  96. # By XZ
  97. import xlrd
  98. import xlwt
  99. import logging
  100. import dataset
  101. from sqlalchemy.sql import text
  102. import datetime
  103. import calendar
  104. import xmlrpc.client
  105. from datetime import tzinfo, timedelta
  106. import pytz
  107. import math
  108. import os
  109. import sys
  110. import glob
  111. from dateutil.relativedelta import relativedelta
  112. from shutil import copyfile
  113. # ==========================================================================
  114. #global odoo_url, odoo_db
  115. #odoo_url = 'http://0.0.0.0:8069'
  116. #odoo_url = 'http://192.168.80.11:8069'
  117. odoo_url = 'http://192.168.80.3:8069'
  118. #odoo_db = 'htp_hr'
  119. odoo_db = 'htp'
  120. # odoo_db = 'htp'
  121. odoo_username = 'admin'
  122. odoo_password = 'Htqweasd3366'
  123. datetime_fmt = '%Y-%m-%d %H:%M:%S'
  124. allow_none = False
  125. cust_end_time_days = ['2023-01-19', '2024-2-2'] #提前放假
  126. ShitftData = None
  127. def common_version():
  128. # provides meta-calls which don’t require authentication
  129. common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(odoo_url), allow_none=allow_none)
  130. # common.version()
  131. # print(common.version())
  132. return common
  133. def get_uid():
  134. # Logging in
  135. common = common_version()
  136. uid = common.authenticate(odoo_db, odoo_username, odoo_password, {})
  137. # print('uid:', uid)
  138. return uid
  139. def endpoint_object():
  140. # is used to call methods of odoo models via the execute_kw RPC function.
  141. return xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(odoo_url), allow_none=allow_none)
  142. # ==========================================================================
  143. prefix = 'htp_hr'
  144. # def float_to_datetime(fl):
  145. # return datetime.datetime.fromtimestamp(fl)
  146. def convert_excel_time(t, hour24=False):
  147. if t > 1:
  148. t = t % 1
  149. seconds = round(t*86400)
  150. minutes, seconds = divmod(seconds, 60)
  151. hours, minutes = divmod(minutes, 60)
  152. if hour24:
  153. if hours > 12:
  154. hours -= 12
  155. return "%02d:%02d:%02d PM" % (hours, minutes, seconds)
  156. else:
  157. return "%02d:%02d:%02d AM" % (hours, minutes, seconds)
  158. return "%02d:%02d:%02d" % (hours, minutes, seconds)
  159. def datetime2UTC(dt, tz='Asia/Taipei', fmt='%Y-%m-%d %H:%M:%S'):
  160. ret = dt
  161. if type(ret) == str:
  162. ret = datetime.datetime.strptime(ret, fmt)
  163. old_tz = pytz.timezone(tz)
  164. new_tz = pytz.timezone('UTC')
  165. ret = old_tz.localize(ret).astimezone(new_tz)
  166. return ret
  167. def date_diff2hours(dt, dt2):
  168. _dt = dt
  169. _dt2 = dt2
  170. if type(_dt) == str:
  171. _dt = datetime.datetime.strptime(_dt, '%Y-%m-%d %H:%M:%S')
  172. if type(_dt2) == str:
  173. _dt2 = datetime.datetime.strptime(_dt2, '%Y-%m-%d %H:%M:%S')
  174. return (_dt2-_dt).total_seconds() / 3600
  175. def ignore_sec():
  176. return 0.00011 # 十秒
  177. # return 0.00069 #六十秒
  178. def write_row(emplist, table, data):
  179. # print(data)
  180. vcdata_date = data['vcdata_date']
  181. vcdata_time_value = data['vcdata_time_value']
  182. vcdata_time = data['vcdata_time']
  183. vemp_no = data['vemp_no']
  184. vcdata_emp_name = data['vcdata_emp_name']
  185. vcdata_dept = data['vcdata_dept']
  186. if vemp_no in emplist:
  187. if emplist[vemp_no]+ignore_sec() >= vcdata_time_value: # 跟上筆差十秒內不存入
  188. return
  189. emplist[vemp_no] = vcdata_time_value
  190. if table.find_one(cdata_date=vcdata_date, cdata_time_value=vcdata_time_value, cdata_emp_no=vemp_no):
  191. table.delete(cdata_date=vcdata_date,
  192. cdata_time_value=vcdata_time_value, cdata_emp_no=vemp_no)
  193. table.insert(dict(cdata_date=vcdata_date,
  194. cdata_time=vcdata_time,
  195. cdata_time_value=vcdata_time_value,
  196. cdata_emp_no=vemp_no,
  197. cdata_emp_name=vcdata_emp_name,
  198. cdata_dept=vcdata_dept,
  199. cdata_sysdate=datetime.datetime.now()))
  200. def run_hr_cdata(db, filename):
  201. # 日期時間小到大
  202. #logger = logging.getLogger('cdata')
  203. _filename = filename
  204. wb = xlrd.open_workbook(_filename)
  205. sheet = wb.sheet_by_index(0)
  206. _db = db
  207. table = _db[prefix+'_cdata']
  208. # sheet.cell_value(0, 0)
  209. # init
  210. emplist = {}
  211. data = {}
  212. _db.begin()
  213. cdata = []
  214. for i in range(1, sheet.nrows):
  215. row = sheet.row_values(i)
  216. row[0] = 0
  217. cdata.insert(0, row)
  218. #cdata = [sheet.row_values(i)[1:-1] for i in range(1, sheet.nrows)]
  219. cdata.sort()
  220. try:
  221. tagDate = ''
  222. for row in cdata:
  223. # for i in range(1, sheet.nrows):
  224. # row = sheet.row_values(i)
  225. logging.info(row)
  226. #logging.debug(row)
  227. vcdata_date = datetime.datetime(
  228. *xlrd.xldate_as_tuple(row[1], wb.datemode)) # 日期
  229. if tagDate != vcdata_date.strftime('%Y-%m-%d'):
  230. tagDate = vcdata_date.strftime('%Y-%m-%d')
  231. emplist.clear()
  232. #print(tagDate)
  233. vcdata_time_value = row[2] # 時間
  234. vcdata_time = convert_excel_time(vcdata_time_value)
  235. vemp_no = row[3]
  236. data['vcdata_date'] = vcdata_date
  237. data['vcdata_time_value'] = vcdata_time_value
  238. data['vcdata_time'] = vcdata_time
  239. data['vemp_no'] = vemp_no
  240. data['vcdata_emp_name'] = row[4]
  241. data['vcdata_dept'] = row[5]
  242. if vemp_no != '':
  243. write_row(emplist, table, data)
  244. # print(i)
  245. _db.commit()
  246. logging.info('OK')
  247. except:
  248. _db.rollback()
  249. def getShitftTest(db):
  250. ret = {}
  251. lst1 = []
  252. #時間1不要用, 轉換問題, 0.9999取代
  253. #sf1 = {'name': '0800-1700', 'begin': 0,
  254. # 'btime': 0.33333, 'etime': 0.70833, 'end': 0.9999, 'rest_hours': 1, 'rest_btime': 0.50000, 'rest_etime': 0.54167} # rest 休息時數
  255. #lst1.append(sf1)
  256. #ret[1] = lst1 # Standard 40 hours/week
  257. sf1 = {'name': '0800-1200', 'begin': 0, 'btime': 0.33333, 'etime': 0.50000, 'end': 0.52167, 'rest_hours': 0}
  258. lst1.append(sf1)
  259. sf2 = {'name': '1300-1700', 'begin': 0.52168, 'btime': 0.54167, 'etime': 0.70833, 'end': 0.9999, 'rest_hours': 0}
  260. lst1.append(sf2)
  261. ret[1] = lst1 # Standard 40 hours/week
  262. ret[5] = lst1 # Standard 40 hours/week
  263. return ret
  264. def getShitft(db):
  265. ret = {}
  266. lst1 = []
  267. #時間1不要用, 轉換問題, 0.9999取代
  268. sf1 = {'name': '0800-1700', 'begin': 0,
  269. 'btime': 0.33333, 'etime': 0.70833, 'end': 0.9999, 'rest_hours': 1, 'rest_btime': 0.50000, 'rest_etime': 0.54167} # rest 休息時數
  270. lst1.append(sf1)
  271. ret[1] = lst1 # Standard 40 hours/week
  272. ret[5] = lst1 # Standard 40 hours/week (20230127)
  273. # sf1 = {'name': '0800-1200', 'begin': 0, 'btime': 0.33333, 'etime': 0.50000,
  274. # 'end': 0.52167,'rest_hours': 0}
  275. # lst1.append(sf1)
  276. # sf2 = {'name': '1300-1700', 'begin': 0.52168, 'btime': 0.54167, 'etime': 0.70833,
  277. # 'end': 0.74000, 'rest_hours': 0}
  278. # lst1.append(sf2)
  279. # sf3 = {'name': '1800-2100', 'begin': 0.74001,
  280. # 'btime': 0.75000, 'etime': 0.87500, 'end': 1,'rest_hours': 0}
  281. # lst1.append(sf3)
  282. return ret
  283. def getShitftTable(sfList):
  284. ret = {}
  285. for item in sfList:
  286. ret[item['name']] = item
  287. return ret
  288. def time2dict(timelist, sfTable):
  289. ret = {}
  290. for i in range(len(timelist)):
  291. time = timelist[i]
  292. for sf in sfTable:
  293. if sf['name'] not in ret:
  294. ret[sf['name']] = []
  295. if sf['begin'] <= time and sf['end'] >= time:
  296. if len(ret[sf['name']]) <= 1:
  297. ret[sf['name']].append(time)
  298. else:
  299. ret[sf['name']][1] = time
  300. break
  301. return ret
  302. def loadXlsEmp():
  303. gXlsEmp = {}
  304. _path = '/home/xz/xzwork/htp/xls2table/'
  305. _filename = _path+'emplist.xlsx'
  306. wb = xlrd.open_workbook(_filename)
  307. sheet = wb.sheet_by_index(0)
  308. for i in range(1, sheet.nrows):
  309. row = sheet.row_values(i)
  310. empno = row[1] # 工號
  311. data = {}
  312. data['dept'] = row[3] # 部門
  313. data['resource_calendar_id'] = 1 # 工作表
  314. gXlsEmp[empno] = data
  315. return gXlsEmp
  316. def loadOdooEmp(db):
  317. gXlsEmp = {}
  318. # t_hr_employee = db['hr_employee']
  319. # data_rows = t_hr_employee.all() #全取, 暫無條件actve
  320. flds = 'wage, food_subsidy, allowance1, allowance2, allowance3, allowance4 '
  321. _sql = 'select emp.*, dept.name as dept_name from hr_employee as emp '
  322. _sql += 'left join hr_department as dept on (dept.id = emp.department_id) '
  323. _sql += 'where emp.emp_no is not null and coalesce(emp.no_attendance, false) = false and emp.active = true '
  324. _sql += 'order by emp.emp_no'
  325. data_rows = db.query(_sql)
  326. for row in data_rows:
  327. empno = row['emp_no'] # 工號
  328. #_sql = "SELECT wage FROM hr_contract where active = True and employee_id = (select id from hr_employee where emp_no = '%s') LIMIT 1" % (empno)
  329. _sql = "SELECT %s FROM hr_contract where active = True and employee_id = (select id from hr_employee where emp_no = '%s') LIMIT 1" % (flds,empno)
  330. _wage = 0
  331. query_data = db.query(_sql)
  332. for data in query_data:
  333. _wage = float(data['wage'])+float(data['food_subsidy'])+float(data['allowance1'])+float(data['allowance2'])+float(data['allowance3'])+float(data['allowance4'])
  334. data = {}
  335. data['dept'] = row['dept_name'] # 部門
  336. data['resource_calendar_id'] = row['resource_calendar_id'] # 工作表
  337. data['wage'] = _wage
  338. gXlsEmp[empno] = data
  339. return gXlsEmp
  340. def getEmployee(emplist, run_emp_no=None):
  341. ret = emplist
  342. # ret['202009001'] = '資訊部'
  343. if run_emp_no is not None:
  344. ret = {}
  345. ret[run_emp_no] = emplist[run_emp_no]
  346. return ret
  347. def getWorkDays(db, res_cal_id, sdatetime): # 檢核是否上班日
  348. ret = [False, 0]
  349. dt = datetime2UTC(sdatetime)
  350. wday = dt.weekday()
  351. _sql = 'select * from htp_hr_working_times '
  352. _sql += 'where work_id = %d and work_beg_time <= \'%s\' and work_end_time >= \'%s\' ' % (
  353. res_cal_id, sdatetime, sdatetime)
  354. data_rows = db.query(_sql)
  355. for row in data_rows:
  356. ret[0] = True
  357. ret[1] = wday
  358. break
  359. return ret
  360. def getHoliday(db, res_cal_id, sdatetime): # 特殊放假
  361. ret = [False, '']
  362. # ret.append('2021-02-10')
  363. _sql = 'select rcl.* from resource_calendar_leaves as rcl '
  364. _sql += 'where rcl.resource_id is null and rcl.holiday_id is null and rcl.calendar_id = %d and rcl.date_from <= \'%s\' and rcl.date_to >= \'%s\' ' % (
  365. res_cal_id, sdatetime, sdatetime)
  366. data_rows = db.query(_sql)
  367. for row in data_rows:
  368. ret[0] = True
  369. ret[1] = row['name']
  370. if row['name'] == '天災':
  371. ret = False
  372. break
  373. return ret
  374. def check_work_date(run_date): # 檢核是否上班日
  375. wday = run_date.weekday()
  376. sday = run_date.strftime("%Y-%m-%d")
  377. if wday <= 4: # 星期1到星期5上班
  378. ret = True
  379. # if sday in getWorkDays():
  380. # ret = True
  381. # if sday in getHoliday():
  382. # ret = False
  383. return ret
  384. def initEmployee(db, run_date, run_emp_no=None):
  385. ret = {}
  386. _db = db
  387. tcshift = _db[prefix+'_cshift']
  388. t_hr_employee = _db['hr_employee']
  389. sday = run_date.strftime("%Y-%m-%d")
  390. uid = get_uid()
  391. models = endpoint_object()
  392. _db.begin()
  393. try:
  394. emplist = getEmployee(_db.vars['emplist'], run_emp_no=run_emp_no)
  395. sfList = getShitft(_db)
  396. if len(sfList) <= 0:
  397. return ret
  398. for emp_no in emplist:
  399. _sql = "SELECT date_end FROM hr_contract where active = True and employee_id = (select id from hr_employee where emp_no = '%s') LIMIT 1" % (emp_no)
  400. query_data = db.query(_sql)
  401. exit_emp = False
  402. for data in query_data:
  403. if data['date_end']: #離職人員處理
  404. if data['date_end'].strftime("%Y-%m-%d") <= sday:
  405. exit_emp = True
  406. if exit_emp:
  407. continue
  408. sfTable = getShitftTable(sfList[emplist[emp_no]['resource_calendar_id']])
  409. # 有上班init Emp
  410. if getWorkDays(db, emplist[emp_no]['resource_calendar_id'], sday+' 11:00:00')[0]:
  411. for cshift_no in sfTable:
  412. cshift_beg_time = convert_excel_time(0)
  413. cshift_end_time = convert_excel_time(0)
  414. cshift_beg_time_value = 0
  415. cshift_end_time_value = 0
  416. cshift_late_value = 0
  417. cshift_late = convert_excel_time(cshift_late_value)
  418. cshift_over_value = 0
  419. cshift_over = convert_excel_time(cshift_over_value)
  420. cshift_total_value = 0
  421. cshift_total = convert_excel_time(cshift_total_value)
  422. # cshift_leave_value = sfTable[cshift_no]['etime'] - \
  423. # sfTable[cshift_no]['btime']
  424. cshift_leave_value = 0
  425. cshift_leave = convert_excel_time(cshift_leave_value)
  426. row = dict(cshift_emp_no=emp_no,
  427. cshift_dept=emplist[emp_no]['dept'], cshift_no=cshift_no,
  428. cshift_beg_date=run_date, cshift_beg_time=cshift_beg_time, cshift_beg_time_value=cshift_beg_time_value,
  429. cshift_end_date=run_date, cshift_end_time=cshift_end_time, cshift_end_time_value=cshift_end_time_value,
  430. cshift_late=cshift_late, cshift_late_value=cshift_late_value,
  431. cshift_leave=cshift_leave, cshift_leave_value=cshift_leave_value,
  432. cshift_over=cshift_over, cshift_over_value=cshift_over_value, cshift_over_amt=0, cshift_over_flag='',
  433. cshift_total=cshift_total, cshift_total_value=cshift_total_value,
  434. cshift_leave_type1_hours=0, cshift_leave_type2_hours=0, cshift_leave_type3_hours=0,
  435. cshift_leave_type4_hours=0, cshift_leave_type5_hours=0, cshift_leave_type6_hours=0,
  436. cshift_leave_type7_hours=0, cshift_leave_type8_hours=0, cshift_leave_type9_hours=0,
  437. cshift_leave_type10_hours=0, cshift_leave_type11_hours=0, cshift_leave_type12_hours=0,
  438. cshift_leave_type13_hours=0, cshift_leave_type14_hours=0,
  439. cshift_sysdate=datetime.datetime.now())
  440. #判斷請假單
  441. _btime_str = sday+' '+convert_excel_time(sfTable[cshift_no]['btime'])
  442. _etime_str = sday+' '+convert_excel_time(sfTable[cshift_no]['etime'])
  443. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  444. '', emp_no, _btime_str, _etime_str])
  445. if data[0]: # 找到假單
  446. hours = date_diff2hours(_btime_str, _etime_str)
  447. #ret[emp_no] = data[2]
  448. ret[emp_no] = {'hours': data[2], 'types': data[5], 'types_hour': data[6]}
  449. if sfTable[cshift_no]['rest_hours'] > 0:
  450. hours -= sfTable[cshift_no]['rest_hours']
  451. if data[2] >= hours: #改成出現整天請假人員
  452. if data[2] >= 8:
  453. cshift_beg_time = '99:99:99'
  454. cshift_end_time = '99:99:99'
  455. row['cshift_beg_time'] = cshift_beg_time
  456. row['cshift_end_time'] = cshift_end_time
  457. row['cshift_leave_hours'] = data[2]
  458. leave_types = data[5]
  459. leave_types_hour = data[6]
  460. i = 0
  461. filter1 = []
  462. cshift_leave_hours = 0
  463. for t in leave_types:
  464. if t in filter1:
  465. i += 1
  466. continue
  467. if t == '特':
  468. row['cshift_leave_type1_hours'] += leave_types_hour[i]
  469. elif t == '婚':
  470. row['cshift_leave_type2_hours'] += leave_types_hour[i]
  471. elif t == '喪':
  472. row['cshift_leave_type3_hours'] += leave_types_hour[i]
  473. elif t == '一般病':
  474. row['cshift_leave_type4_hours'] += leave_types_hour[i]
  475. elif t == '公傷病':
  476. row['cshift_leave_type5_hours'] += leave_types_hour[i]
  477. elif t == '事':
  478. row['cshift_leave_type6_hours'] += leave_types_hour[i]
  479. elif t == '公':
  480. row['cshift_leave_type7_hours'] += leave_types_hour[i]
  481. elif t == '家庭照護':
  482. row['cshift_leave_type8_hours'] += leave_types_hour[i]
  483. elif t == '產':
  484. row['cshift_leave_type9_hours'] += leave_types_hour[i]
  485. elif t == '產檢':
  486. row['cshift_leave_type10_hours'] += leave_types_hour[i]
  487. elif t == '生理':
  488. row['cshift_leave_type11_hours'] += leave_types_hour[i]
  489. elif t == '疫苗接種':
  490. row['cshift_leave_type12_hours'] += leave_types_hour[i]
  491. elif t == '補':
  492. row['cshift_leave_type13_hours'] += leave_types_hour[i]
  493. elif t == '育嬰留停':
  494. row['cshift_leave_type14_hours'] += leave_types_hour[i]
  495. if t not in filter1:
  496. cshift_leave_hours += leave_types_hour[i]
  497. filter1.append(t)
  498. i += 1
  499. # continue
  500. if cshift_leave_hours > 0:
  501. row['cshift_leave_hours'] = cshift_leave_hours
  502. tcshift.insert(row)
  503. _db.commit()
  504. return ret
  505. except Exception as e:
  506. logging.error(str(e))
  507. #print(str(e))
  508. _db.rollback()
  509. return {}
  510. #加總遲到
  511. def check_odoo_late(db, emp, run_date, btime, etime, late_value): # 找遲到請假單
  512. emp_no = emp['emp_no']
  513. ret = late_value
  514. if ret <= 0:
  515. return ret
  516. uid = get_uid()
  517. models = endpoint_object()
  518. _date_str = datetime.datetime.strftime(run_date, '%Y-%m-%d')
  519. _btime_str = _date_str+' '+convert_excel_time(btime)
  520. _etime_str = _date_str+' '+convert_excel_time(etime)
  521. if uid:
  522. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  523. '', emp_no, _btime_str, _etime_str])
  524. if data[0] and ret > 0: # 找到假單
  525. #sum_late_minutes = 0
  526. #sql = 'SELECT sum(cshift_late_value) as late_value FROM '+ prefix + \
  527. # '_cshift where where cshift_emp_no = %s and date_part(\'year\', cshift_beg_date) = %d and date_part(\'month\', cshift_beg_date) = %d ' % (emp_no, run_date.year, run_date.month)
  528. #rows = db.query(sql)
  529. #for row in rows:
  530. # if row > 0:
  531. # seconds = round(row*86400)
  532. # sum_late_minutes, seconds = divmod(seconds, 60)
  533. if data[2] > 0: # 小時
  534. #btime_dt = datetime.datetime.strptime(_btime_str, datetime_fmt)
  535. #leave_dt = data[3]
  536. #if leave_dt != 0:
  537. # leave_dt = datetime.datetime.strptime(data[3], datetime_fmt)
  538. # if leave_dt > btime_dt: #大於八點, 一律給30分(只能請30分)
  539. # return (0.5 / 24)
  540. asSec = data[2] / 24
  541. ret = ret - asSec # 依核准時數
  542. if ret < 0: # 負數歸零
  543. ret = 0
  544. return ret
  545. def check_odoo_leaves(db, emp, run_date, btime, etime, late_value): # 找出早退請假單
  546. emp_no = emp['emp_no']
  547. ret = late_value
  548. uid = get_uid()
  549. models = endpoint_object()
  550. _date_str = datetime.datetime.strftime(run_date, '%Y-%m-%d')
  551. _btime_str = _date_str+' '+convert_excel_time(btime)
  552. _btime_str = _btime_str[0:14]+'00:00' #取小時取整數
  553. _etime_str = _date_str+' '+convert_excel_time(etime)
  554. if uid:
  555. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  556. '', emp_no, _btime_str, _etime_str])
  557. if data[0] and ret > 0: # 找到假單
  558. #if data[1] > 0.5: # 多天
  559. # ret = 0
  560. if data[2] > 0: # 小時
  561. asSec = data[2] / 24
  562. ret = ret - asSec # 依核准時數
  563. if ret < 0: # 負數歸零
  564. ret = 0
  565. return ret
  566. def getHours(sfTable, btime, etime): #休息時間扣除
  567. t = etime-btime
  568. hours = (round(t*86400) / 60) / 60
  569. if (sfTable['rest_btime'] > btime) and (sfTable['rest_etime'] < etime):
  570. hours -= sfTable['rest_hours']
  571. return hours
  572. def check_odoo_overtime_all2(db, emp, run_date, calendar_id, btime, etime, sfTable): # 全改寫, 依刷卡及加班單
  573. _db = db
  574. emp_no = emp['emp_no']
  575. ret = [0, 0, 0, '', ''] #0.一般加班, 1.加班2, 2.加班3, 3.最早加班時段 4.最晚加班時段
  576. uid = get_uid()
  577. models = endpoint_object()
  578. wday = run_date.weekday()
  579. sday = run_date.strftime("%Y-%m-%d")
  580. _btime = btime #刷起
  581. if sfTable['btime'] > _btime: #早到五十四分內都不算, 依8點整
  582. if (sfTable['btime'] - _btime) <= (0.9 / 24):
  583. _btime = sfTable['btime']
  584. _etime = etime #實刷迄
  585. over_value = 0 #實刷
  586. t = _etime-_btime
  587. hours = (round(t*86400) / 60) / 60
  588. t = sfTable['etime']-sfTable['btime']
  589. #hours2 = (round(t*86400) / 60) / 60
  590. _date_str = datetime.datetime.strftime(run_date, '%Y-%m-%d')
  591. hours3 = 0 #加班
  592. hours32 = 0 #加班2
  593. hours33 = 0 #加班3
  594. if hours > 0:
  595. if wday == 5 or wday == 6 or getHoliday(_db, calendar_id, sday)[0]:#放假加班(國定假日)
  596. _btime_str = _date_str+' '+convert_excel_time(sfTable['begin'])
  597. _etime_str = _date_str+' '+convert_excel_time(sfTable['end'])
  598. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  599. 'over', emp_no, _btime_str, _etime_str])
  600. #t = _etime-btime #實刷
  601. #hours = (round(t*86400) / 60) / 60
  602. hours = getHours(sfTable, btime, _etime)
  603. if data[0] and data[2] > 0:
  604. hours3 = data[2]
  605. if hours < data[2]:
  606. hours3 = hours
  607. #加班2
  608. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  609. 'over2', emp_no, _btime_str, _etime_str])
  610. if data[0] and data[2] > 0:
  611. hours32 = data[2]
  612. if hours < data[2]:
  613. hours32 = hours
  614. #加班3
  615. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  616. 'over3', emp_no, _btime_str, _etime_str])
  617. if data[0] and data[2] > 0:
  618. hours33 = data[2]
  619. if hours < data[2]:
  620. hours33 = hours
  621. else: #平日
  622. #早上加班
  623. t = sfTable['btime']-btime
  624. calc_hours = (round(t*86400) / 60) / 60
  625. if calc_hours >= (0.5 / 24):
  626. _btime_str = _date_str+' '+convert_excel_time(sfTable['begin'])
  627. _etime_str = _date_str+' '+convert_excel_time(sfTable['btime'])
  628. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  629. 'over', emp_no, _btime_str, _etime_str])
  630. if data[0] and data[2] > 0:
  631. hours3 = data[2]
  632. if calc_hours < data[2]:
  633. hours3 = calc_hours
  634. #晚上加班
  635. t = _etime-sfTable['etime']
  636. calc_hours = (round(t*86400) / 60) / 60
  637. if calc_hours >= (0.5 / 24):
  638. _btime_str = _date_str+' '+convert_excel_time(sfTable['etime'])
  639. _etime_str = _date_str+' '+convert_excel_time(sfTable['end'])
  640. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  641. 'over', emp_no, _btime_str, _etime_str])
  642. if data[0] and data[2] > 0:
  643. if calc_hours < data[2]:
  644. hours3 += calc_hours
  645. else:
  646. hours3 += data[2]
  647. #中午加班
  648. if sfTable['rest_hours'] > 0 and 'rest_btime' in sfTable:
  649. _btime_str = _date_str+' '+convert_excel_time(sfTable['rest_btime']) #中午休息一小時
  650. _etime_str = _date_str+' '+convert_excel_time(sfTable['rest_etime'])
  651. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  652. 'over', emp_no, _btime_str, _etime_str])
  653. if data[0] and data[2] > 0:
  654. hours3 += data[2]
  655. #早上加班2
  656. t = sfTable['btime']-btime
  657. calc_hours = (round(t*86400) / 60) / 60
  658. if calc_hours >= (0.5 / 24):
  659. _btime_str = _date_str+' '+convert_excel_time(sfTable['begin'])
  660. _etime_str = _date_str+' '+convert_excel_time(sfTable['btime'])
  661. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  662. 'over2', emp_no, _btime_str, _etime_str])
  663. if data[0] and data[2] > 0:
  664. hours32 = data[2]
  665. if calc_hours < data[2]:
  666. hours32 = calc_hours
  667. #晚上加班2
  668. t = _etime-sfTable['etime']
  669. calc_hours = (round(t*86400) / 60) / 60
  670. if calc_hours >= (0.5 / 24):
  671. _btime_str = _date_str+' '+convert_excel_time(sfTable['etime'])
  672. _etime_str = _date_str+' '+convert_excel_time(sfTable['end'])
  673. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  674. 'over2', emp_no, _btime_str, _etime_str])
  675. if data[0] and data[2] > 0:
  676. if calc_hours < data[2]:
  677. hours32 += calc_hours
  678. else:
  679. hours32 += data[2]
  680. #中午加班2
  681. if sfTable['rest_hours'] > 0 and 'rest_btime' in sfTable:
  682. _btime_str = _date_str+' '+convert_excel_time(sfTable['rest_btime']) #中午休息一小時
  683. _etime_str = _date_str+' '+convert_excel_time(sfTable['rest_etime'])
  684. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  685. 'over2', emp_no, _btime_str, _etime_str])
  686. if data[0] and data[2] > 0:
  687. hours32 += data[2]
  688. #早上加班3
  689. t = sfTable['btime']-btime
  690. calc_hours = (round(t*86400) / 60) / 60
  691. if calc_hours >= (0.5 / 24):
  692. _btime_str = _date_str+' '+convert_excel_time(sfTable['begin'])
  693. _etime_str = _date_str+' '+convert_excel_time(sfTable['btime'])
  694. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  695. 'over3', emp_no, _btime_str, _etime_str])
  696. if data[0] and data[2] > 0:
  697. hours33 = data[2]
  698. if calc_hours < data[2]:
  699. hours33 = calc_hours
  700. #晚上加班3
  701. t = _etime-sfTable['etime']
  702. calc_hours = (round(t*86400) / 60) / 60
  703. if calc_hours >= (0.5 / 24):
  704. _btime_str = _date_str+' '+convert_excel_time(sfTable['etime'])
  705. _etime_str = _date_str+' '+convert_excel_time(sfTable['end'])
  706. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  707. 'over3', emp_no, _btime_str, _etime_str])
  708. if data[0] and data[2] > 0:
  709. if calc_hours < data[2]:
  710. hours33 += calc_hours
  711. else:
  712. hours33 += data[2]
  713. #中午加班3
  714. if sfTable['rest_hours'] > 0 and 'rest_btime' in sfTable:
  715. _btime_str = _date_str+' '+convert_excel_time(sfTable['rest_btime']) #中午休息一小時
  716. _etime_str = _date_str+' '+convert_excel_time(sfTable['rest_etime'])
  717. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  718. 'over3', emp_no, _btime_str, _etime_str])
  719. if data[0] and data[2] > 0:
  720. hours33 += data[2]
  721. if hours3 > 0:
  722. over_value = hours3 / 24
  723. ret[0] = over_value
  724. if hours32 > 0:
  725. over_value = hours32 / 24
  726. ret[1] = over_value
  727. if hours33 > 0:
  728. over_value = hours33 / 24
  729. ret[2] = over_value
  730. _btime_str = _date_str+' '+convert_excel_time(sfTable['begin'])
  731. _etime_str = _date_str+' '+convert_excel_time(sfTable['end'])
  732. if (ret[0] > 0) or (ret[1] > 0) or (ret[2] > 0): #取最大最小時間
  733. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves_over', [
  734. emp_no, _btime_str, _etime_str])
  735. if data[0] and data[2] > 0:
  736. ret[3] = data[3]
  737. ret[4] = data[4]
  738. if convert_excel_time(sfTable['btime']) < ret[3]:
  739. ret[3] = ''
  740. return ret
  741. def check_odoo_overtime_all(db, emp, run_date, calendar_id, btime, etime, sfTable): # 全改寫, 依刷卡及加班單
  742. _db = db
  743. emp_no = emp['emp_no']
  744. ret = [0, 0, '', '']
  745. uid = get_uid()
  746. models = endpoint_object()
  747. wday = run_date.weekday()
  748. sday = run_date.strftime("%Y-%m-%d")
  749. _btime = btime #實刷起
  750. if sfTable['btime'] > _btime: #早到五十四分內都不算, 依8點整
  751. if (sfTable['btime'] - _btime) <= (0.9 / 24):
  752. _btime = sfTable['btime']
  753. _etime = etime #實刷迄
  754. over_value = 0 #實刷
  755. t = _etime-_btime
  756. hours = (round(t*86400) / 60) / 60
  757. t = sfTable['etime']-sfTable['btime']
  758. hours2 = (round(t*86400) / 60) / 60
  759. _date_str = datetime.datetime.strftime(run_date, '%Y-%m-%d')
  760. if hours > 0:
  761. hours3 = hours
  762. if wday == 5 or wday == 6 or getHoliday(_db, calendar_id, sday)[0]:#放假加班(國定假日)
  763. pass
  764. else: #平日
  765. #必要扣休息時間
  766. if hours3 >= hours2:
  767. hours3 -= sfTable['rest_hours']
  768. hours3 = hours3-(hours2-sfTable['rest_hours'])
  769. if sfTable['rest_hours'] > 0 and 'rest_btime' in sfTable:
  770. _btime_str = _date_str+' '+convert_excel_time(sfTable['rest_btime']) #中午休息一小時
  771. _etime_str = _date_str+' '+convert_excel_time(sfTable['rest_etime'])
  772. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  773. 'over', emp_no, _btime_str, _etime_str])
  774. if data[0] and data[2] > 0: #休息時間,有加班單不扣
  775. hours3 += data[2]
  776. if hours3 > 0:
  777. over_value = hours3 / 24
  778. #print('加班實刷: '+convert_excel_time(over_value))
  779. _btime_str2 = _date_str+' '+convert_excel_time(_btime)
  780. _etime_str2 = _date_str+' '+convert_excel_time(_etime)
  781. if uid:
  782. #找出忘刷卡假
  783. _st_etime = sfTable['end']
  784. if _st_etime == 1: #不可以24小時, 調整少十分鐘
  785. _st_etime = _st_etime - (0.1 / 24)
  786. _btime_str = _date_str+' '+convert_excel_time(sfTable['begin'])
  787. _etime_str = _date_str+' '+convert_excel_time(_st_etime)
  788. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  789. 'nocheck', emp_no, _btime_str, _etime_str])
  790. if data[0]:
  791. _btime_str2 = data[2]
  792. _etime_str2 = data[3]
  793. over_value = data[1] / 24 #實刷
  794. #
  795. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  796. 'over', emp_no, _btime_str2, _etime_str2])
  797. if data[0] and data[2] > 0:
  798. asSec = data[2] / 24
  799. ret[0] = asSec # 依核准時數
  800. if over_value < (0.5 / 24): # 實刷不滿30分,不計算
  801. ret[0] = 0
  802. elif asSec > over_value: # 小於核准時數, 依實刷時數計算
  803. ret[0] = over_value
  804. #加班2(特殊加班)
  805. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  806. 'over2', emp_no, _btime_str2, _etime_str2])
  807. if data[0] and data[2] > 0:
  808. asSec = data[2] / 24
  809. ret[1] = asSec # 依核准時數
  810. if over_value < (0.5 / 24): # 實刷不滿30分,不計算
  811. ret[1] = 0
  812. elif asSec > over_value: # 小於核准時數, 依實刷時數計算
  813. ret[1] = over_value
  814. if (ret[0] > 0) or (ret[1] > 0): #取最大最小時間
  815. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves_over', [
  816. emp_no, _btime_str, _etime_str])
  817. if data[0] and data[2] > 0:
  818. ret[2] = data[3]
  819. ret[3] = data[4]
  820. if convert_excel_time(sfTable['btime']) < ret[2]:
  821. ret[2] = ''
  822. return ret
  823. def check_odoo_overtime(db, emp, run_date, btime, etime, over_value): # 找出加班單
  824. _db = db
  825. emp_no = emp['emp_no']
  826. ret = 0
  827. uid = get_uid()
  828. models = endpoint_object()
  829. wday = run_date.weekday()
  830. _date_str = datetime.datetime.strftime(run_date, '%Y-%m-%d')
  831. _btime_str = _date_str+' '+convert_excel_time(btime)
  832. _etime_str = _date_str+' '+convert_excel_time(etime)
  833. sday = run_date.strftime("%Y-%m-%d")+' '+convert_excel_time(btime)
  834. if uid and over_value > 0:
  835. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  836. 'over', emp_no, _btime_str, _etime_str])
  837. if data[0] and data[2] > 0:
  838. asSec = data[2] / 24
  839. ret = asSec # 依核准時數
  840. if over_value < (0.5 / 24): # 實刷不滿30分,不計算
  841. ret = 0
  842. elif asSec > over_value: # 小於核准時數, 依實刷時數計算
  843. ret = over_value
  844. return ret
  845. def check_odoo_overtime2(db, emp, run_date, btime, etime, over_value): # 平日找出加班單, 下班前的單據
  846. _db = db
  847. emp_no = emp['emp_no']
  848. ret = over_value
  849. uid = get_uid()
  850. models = endpoint_object()
  851. wday = run_date.weekday()
  852. _date_str = datetime.datetime.strftime(run_date, '%Y-%m-%d')
  853. _btime_str = _date_str+' '+convert_excel_time(btime)
  854. _etime_str = _date_str+' '+convert_excel_time(etime)
  855. sday = run_date.strftime("%Y-%m-%d")+' '+convert_excel_time(btime)
  856. if uid:
  857. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  858. 'over', emp_no, _btime_str, _etime_str])
  859. if data[0] and data[2] > 0:
  860. asSec = data[2] / 24
  861. ret = ret+asSec # 依核准時數+下班加班時數
  862. return ret
  863. def calc_over_amt(db, emp, run_date, over_value): # 加班計算
  864. _db = db
  865. ret = [0, '']
  866. if over_value <= 0:
  867. return ret
  868. wday = run_date.weekday()
  869. sday = run_date.strftime("%Y-%m-%d")
  870. hours = (round(over_value*86400) / 60) / 60
  871. if hours > 0:
  872. # if wday <= 4: # 星期1到星期5上班(平日)
  873. if getWorkDays(_db, emp['resource_calendar_id'], sday+' 11:00:00')[0]: # 假日加班(是為平常日)
  874. wday = 0
  875. if getHoliday(_db, emp['resource_calendar_id'], sday)[0]: # 國定假日(是為例假日)
  876. wday = 5
  877. ret[0] = hours*1.34
  878. ret[1] = '平日'
  879. if hours > 2:
  880. ret[0] = 2*1.34
  881. ret[0] += (hours-2) * 1.67
  882. if wday == 5: # 星期6上班(休息日)
  883. h = hours
  884. ret[0] = h*1.34
  885. ret[1] = '休息日'
  886. if h > 2:
  887. ret[0] = 2*1.34
  888. h -= 2
  889. if h <= 6:
  890. ret[0] += h*1.67
  891. else:
  892. ret[0] += 6*1.67
  893. h -= 6
  894. if h > 0:
  895. ret[0] += h*2.67
  896. if wday == 6: # 星期日上班(例假日)U
  897. h = hours
  898. ret[0] = h
  899. ret[1] = '例假日'
  900. if h >= 1 and h <= 8: # 小於八,給8小時
  901. ret[0] = 8
  902. elif h > 8:
  903. ret[0] = 8
  904. h -= 8
  905. if getHoliday(db, emp['resource_calendar_id'], sday)[0]: # 國定假日
  906. if h > 2:
  907. ret[0] += 2*1.34
  908. ret[0] += (h-2)*1.67
  909. else:
  910. ret[0] += h*1.34
  911. else:
  912. ret[0] += h*2
  913. emplist =_db.vars['emplist']
  914. if ret[0] > 0 and emp['emp_no'] in emplist:
  915. amt = emplist[emp['emp_no']]['wage'] / 30 / 8
  916. ret[0] = math.ceil(amt*ret[0])
  917. return ret
  918. def calc_over2_amt(db, emp, run_date, over_value): # 加班2計算(特殊加班)
  919. _db = db
  920. ret = [0, '']
  921. if over_value <= 0:
  922. return ret
  923. wday = run_date.weekday()
  924. sday = run_date.strftime("%Y-%m-%d")
  925. hours = (round(over_value*86400) / 60) / 60
  926. if hours > 0:
  927. if getWorkDays(_db, emp['resource_calendar_id'], sday+' 11:00:00')[0]: # 假日加班(是為平常日)
  928. wday = 0
  929. if getHoliday(_db, emp['resource_calendar_id'], sday)[0]: # 國定假日(是為例假日)
  930. wday = 5
  931. ret[0] = hours*1.67
  932. ret[1] = '平日'
  933. if wday == 5: # 星期6上班(休息日)
  934. ret[1] = '休息日'
  935. if wday == 6: # 星期日上班(例假日)
  936. ret[0] = 0
  937. ret[1] = '例假日'
  938. emplist =_db.vars['emplist']
  939. if ret[0] > 0 and emp['emp_no'] in emplist:
  940. amt = emplist[emp['emp_no']]['wage'] / 30 / 8
  941. ret[0] = math.ceil(amt*ret[0])
  942. return ret
  943. def calc_over3_amt(db, emp, run_date, over_value): # 加班3計算(特殊加班)
  944. _db = db
  945. ret = [0, '']
  946. if over_value <= 0:
  947. return ret
  948. wday = run_date.weekday()
  949. sday = run_date.strftime("%Y-%m-%d")
  950. hours = (round(over_value*86400) / 60) / 60
  951. if hours > 0:
  952. if getWorkDays(_db, emp['resource_calendar_id'], sday+' 11:00:00')[0]: # 假日加班(是為平常日)
  953. wday = 0
  954. if getHoliday(_db, emp['resource_calendar_id'], sday)[0]: # 國定假日(是為例假日)
  955. wday = 5
  956. ret[0] = hours*2.5
  957. ret[1] = '平日'
  958. if wday == 5: # 星期6上班(休息日)
  959. ret[1] = '休息日'
  960. if wday == 6: # 星期日上班(例假日)
  961. ret[0] = 0
  962. ret[1] = '例假日'
  963. emplist =_db.vars['emplist']
  964. if ret[0] > 0 and emp['emp_no'] in emplist:
  965. amt = emplist[emp['emp_no']]['wage'] / 30 / 8
  966. ret[0] = math.ceil(amt*ret[0])
  967. return ret
  968. #提前放假時間處理
  969. def custom_end_time_value(sday, emp_no, cshift_end_time_value):
  970. ret = cshift_end_time_value
  971. if sday in cust_end_time_days:
  972. #判斷請假單
  973. uid = get_uid()
  974. models = endpoint_object()
  975. _btime_str = sday+' '+convert_excel_time(0.33333)
  976. _etime_str = sday+' '+convert_excel_time(0.70833)
  977. data = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'check_leaves', [
  978. '', emp_no, _btime_str, _etime_str])
  979. if not data[0]: # 找不到假單
  980. ret = 0.70833 #改下午五點
  981. return ret
  982. def run_hr_cshift(db, run_date, run_emp_no=None):
  983. #logger = logging.getLogger('cshift')
  984. _db = db
  985. #tcdata = _db[prefix+'_cdata']
  986. tcshift = _db[prefix+'_cshift']
  987. t_hr_employee = _db['hr_employee']
  988. _orderby = ['cdata_emp_no', 'cdata_date', 'cdata_time_value']
  989. emplist = {}
  990. #data_rows = tcdata.find(cdata_date=run_date, order_by=_orderby)
  991. #if run_emp_no is not None:
  992. # data_rows = tcdata.find(cdata_date=run_date,
  993. # cdata_emp_no=run_emp_no, order_by=_orderby)
  994. #改成加入htp_checkin忘刷單
  995. run_date_str = run_date.strftime("%Y-%m-%d")
  996. _sql = 'SELECT cdata_emp_no, cdata_date, cdata_time_value, cdata_emp_name, cdata_dept '
  997. _sql += 'FROM htp_hr_cdata inner join hr_employee b on (cdata_emp_no = b.emp_no and coalesce(b.no_attendance, false) = false) where cdata_date = \'%s\' ' % (run_date_str)
  998. if run_emp_no is not None:
  999. _sql += ' and cdata_emp_no = \'%s\' ' % (run_emp_no)
  1000. _sql += 'UNION '
  1001. _sql += 'SELECT b.emp_no, a.ck_date, a.ck_time, b.name, c.name '
  1002. _sql += 'FROM htp_checkin a inner join hr_employee b on (a.employee_id = b.id and coalesce(b.no_attendance, false) = false) '
  1003. _sql += 'left join hr_department c on (b.department_id = c.id) '
  1004. _sql += 'where a.ck_time <> 0 and a.state = \'done\' and a.ck_date = \'%s\' and b.emp_no is not null ' % (run_date_str)
  1005. if run_emp_no is not None:
  1006. _sql += ' and b.emp_no = \'%s\' ' % (run_emp_no)
  1007. _sql += 'order by cdata_emp_no, cdata_date, cdata_time_value '
  1008. data_rows = _db.query(_sql)
  1009. if run_emp_no is not None:
  1010. tcshift.delete(cshift_beg_date=run_date, cshift_emp_no=run_emp_no)
  1011. else:
  1012. tcshift.delete(cshift_beg_date=run_date)
  1013. leave_hours = initEmployee(_db, run_date, run_emp_no=run_emp_no) # init Employee
  1014. for row in data_rows:
  1015. if row['cdata_emp_no'] in emplist:
  1016. if emplist[row['cdata_emp_no']]['timelist'][-1] <= row['cdata_time_value']:
  1017. emplist[row['cdata_emp_no']]['timelist'].append(
  1018. row['cdata_time_value'])
  1019. else:
  1020. emplist[row['cdata_emp_no']] = {}
  1021. emplist[row['cdata_emp_no']
  1022. ]['emp_no'] = row['cdata_emp_no'] # emp_no
  1023. emplist[row['cdata_emp_no']]['emp_name'] = row['cdata_emp_name']
  1024. emplist[row['cdata_emp_no']]['dept'] = row['cdata_dept']
  1025. emplist[row['cdata_emp_no']]['timelist'] = [
  1026. row['cdata_time_value']]
  1027. #emp_row = t_hr_employee.find_one(emp_no=row['cdata_emp_no'])
  1028. emp_row = t_hr_employee.find_one(emp_no=row['cdata_emp_no'], no_attendance=False, active=True)
  1029. if emp_row:
  1030. emplist[row['cdata_emp_no']
  1031. ]['resource_calendar_id'] = emp_row['resource_calendar_id']
  1032. else:
  1033. #print(row['cdata_emp_no']) # 找不到員工基本資料, 或已封存及不加入考勤
  1034. logging.warning('找不到此員工 '+row['cdata_emp_no'])
  1035. del emplist[row['cdata_emp_no']]
  1036. if len(emplist) <= 0:
  1037. return
  1038. _db.begin()
  1039. sfList = getShitft(_db)
  1040. if len(sfList) <= 0:
  1041. return
  1042. wday = run_date.weekday()
  1043. sday = run_date.strftime("%Y-%m-%d")
  1044. try:
  1045. for emp_no in emplist:
  1046. sfTable = getShitftTable(sfList[emplist[emp_no]['resource_calendar_id']])
  1047. timelist = emplist[emp_no]['timelist']
  1048. if len(timelist) <= 0:
  1049. continue
  1050. ppTimedict = time2dict(timelist, sfList[emplist[emp_no]['resource_calendar_id']])
  1051. for cshift_no in ppTimedict:
  1052. if len(ppTimedict[cshift_no]) == 1:
  1053. if ppTimedict[cshift_no][0] > sfTable[cshift_no]['etime']: # 早上忘刷
  1054. cshift_beg_time_value = sfTable[cshift_no]['etime']
  1055. cshift_end_time_value = ppTimedict[cshift_no][0]
  1056. else:
  1057. cshift_beg_time_value = ppTimedict[cshift_no][0]
  1058. cshift_end_time_value = sfTable[cshift_no]['btime']
  1059. else: #有刷二筆
  1060. cshift_beg_time_value = ppTimedict[cshift_no][0]
  1061. cshift_end_time_value = ppTimedict[cshift_no][1]
  1062. cshift_end_time_value = custom_end_time_value(sday, emp_no, cshift_end_time_value) #提前放假時間處理
  1063. cshift_beg_time = convert_excel_time(cshift_beg_time_value)
  1064. cshift_end_time = convert_excel_time(cshift_end_time_value)
  1065. cshift_late_value = 0
  1066. if cshift_beg_time_value > sfTable[cshift_no]['btime']:
  1067. cshift_late_value = cshift_beg_time_value - \
  1068. sfTable[cshift_no]['btime']
  1069. if sfTable[cshift_no]['rest_hours'] > 0 and cshift_late_value > (4 / 24): # 扣掉休息時間, 大於四小時
  1070. cshift_late_value = cshift_late_value - \
  1071. (sfTable[cshift_no]['rest_hours'] / 24)
  1072. # check odoo 請假單 遲到
  1073. cshift_late_value = check_odoo_late(_db, emplist[emp_no], run_date, sfTable[cshift_no]['btime'],
  1074. cshift_beg_time_value, cshift_late_value)
  1075. cshift_late = convert_excel_time(cshift_late_value)
  1076. #
  1077. cshift_leave_value = 0
  1078. if sfTable[cshift_no]['btime'] < cshift_end_time_value and cshift_end_time_value < sfTable[cshift_no]['etime']:
  1079. cshift_leave_value = sfTable[cshift_no]['etime'] - cshift_end_time_value
  1080. if sfTable[cshift_no]['rest_hours'] > 0 and cshift_leave_value > (4 / 24): # 扣掉休息時間, 大於四小時
  1081. cshift_leave_value = cshift_leave_value - \
  1082. (sfTable[cshift_no]['rest_hours'] / 24)
  1083. # check odoo 請假單 早退
  1084. cshift_leave_value = check_odoo_leaves(_db,
  1085. emplist[emp_no], run_date, cshift_end_time_value, sfTable[cshift_no]['etime'], cshift_leave_value)
  1086. cshift_leave = convert_excel_time(cshift_leave_value)
  1087. #
  1088. cshift_over_value = [0,0]
  1089. #if cshift_end_time_value > sfTable[cshift_no]['etime']:
  1090. # cshift_over_value = cshift_end_time_value - \
  1091. # sfTable[cshift_no]['etime']
  1092. # check odoo 請假單 加班
  1093. cshift_over_value = check_odoo_overtime_all2(_db, emplist[emp_no], run_date, emplist[emp_no]['resource_calendar_id'], cshift_beg_time_value, cshift_end_time_value, sfTable[cshift_no])
  1094. #特殊加班另外加欄位及check_odoo_overtime_all_167方式
  1095. cshift_over_beg_time = cshift_over_value[3]
  1096. cshift_over_end_time = cshift_over_value[4]
  1097. # 放假加班
  1098. if wday == 5 or wday == 6 or getHoliday(_db, emplist[emp_no]['resource_calendar_id'], sday)[0]:
  1099. # 遲到早退歸零
  1100. cshift_late_value = 0
  1101. cshift_late = convert_excel_time(cshift_late_value)
  1102. cshift_leave_value = 0
  1103. cshift_leave = convert_excel_time(cshift_leave_value)
  1104. # cshift_over_value = check_odoo_overtime2(db,
  1105. # emplist[emp_no], run_date, sfTable[cshift_no]['begin'], cshift_end_time_value, 0) # 零點開始
  1106. #else:
  1107. # cshift_over_value = check_odoo_overtime(db,
  1108. # emplist[emp_no], run_date, sfTable[cshift_no]['etime'], cshift_end_time_value, cshift_over_value) # 下班開始
  1109. # # 因中午休息時間一小時,再取一次表單(不做出勤比對), 早上到下班時間
  1110. # cshift_over_value = check_odoo_overtime2(db,
  1111. # emplist[emp_no], run_date, sfTable[cshift_no]['btime'], sfTable[cshift_no]['etime'], cshift_over_value)
  1112. cshift_over = convert_excel_time(cshift_over_value[0])
  1113. cshift_over_amt = calc_over_amt(_db, emplist[emp_no],
  1114. run_date, cshift_over_value[0]) # 加班算金額
  1115. #加班2(特殊加班)
  1116. cshift_over2 = convert_excel_time(cshift_over_value[1])
  1117. cshift_over2_amt = calc_over2_amt(_db, emplist[emp_no],
  1118. run_date, cshift_over_value[1]) # 加班算金額
  1119. #加班3(特殊加班)
  1120. cshift_over3 = convert_excel_time(cshift_over_value[2])
  1121. cshift_over3_amt = calc_over3_amt(_db, emplist[emp_no],
  1122. run_date, cshift_over_value[2]) # 加班算金額
  1123. cshift_total_value = cshift_end_time_value - cshift_beg_time_value
  1124. if sfTable[cshift_no]['rest_hours'] > 0 and cshift_total_value > 0: # 扣掉休息時間
  1125. cshift_total_value = cshift_total_value - \
  1126. (sfTable[cshift_no]['rest_hours'] / 24)
  1127. cshift_total = convert_excel_time(cshift_total_value)
  1128. #請假總時數
  1129. cshift_leave_hours = 0
  1130. cshift_leave_type1_hours = 0
  1131. cshift_leave_type2_hours = 0
  1132. cshift_leave_type3_hours = 0
  1133. cshift_leave_type4_hours = 0
  1134. cshift_leave_type5_hours = 0
  1135. cshift_leave_type6_hours = 0
  1136. cshift_leave_type7_hours = 0
  1137. cshift_leave_type8_hours = 0
  1138. cshift_leave_type9_hours = 0
  1139. cshift_leave_type10_hours = 0
  1140. cshift_leave_type11_hours = 0
  1141. cshift_leave_type12_hours = 0
  1142. cshift_leave_type13_hours = 0
  1143. cshift_leave_type14_hours = 0
  1144. if emp_no in leave_hours:
  1145. cshift_leave_hours = leave_hours[emp_no]['hours']
  1146. leave_types = leave_hours[emp_no]['types']
  1147. leave_types_hour = leave_hours[emp_no]['types_hour']
  1148. i = 0
  1149. for t in leave_types:
  1150. if t == '特':
  1151. cshift_leave_type1_hours += leave_types_hour[i]
  1152. elif t == '婚':
  1153. cshift_leave_type2_hours += leave_types_hour[i]
  1154. elif t == '喪':
  1155. cshift_leave_type3_hours += leave_types_hour[i]
  1156. elif t == '一般病':
  1157. cshift_leave_type4_hours += leave_types_hour[i]
  1158. elif t == '公傷病':
  1159. cshift_leave_type5_hours += leave_types_hour[i]
  1160. elif t == '事':
  1161. cshift_leave_type6_hours += leave_types_hour[i]
  1162. elif t == '公':
  1163. cshift_leave_type7_hours += leave_types_hour[i]
  1164. elif t == '家庭照護':
  1165. cshift_leave_type8_hours += leave_types_hour[i]
  1166. elif t == '產':
  1167. cshift_leave_type9_hours += leave_types_hour[i]
  1168. elif t == '產檢':
  1169. cshift_leave_type10_hours += leave_types_hour[i]
  1170. elif t == '生理':
  1171. cshift_leave_type11_hours += leave_types_hour[i]
  1172. elif t == '疫苗接種':
  1173. cshift_leave_type12_hours += leave_types_hour[i]
  1174. elif t == '補':
  1175. cshift_leave_type13_hours += leave_types_hour[i]
  1176. elif t == '育嬰留停':
  1177. cshift_leave_type14_hours += leave_types_hour[i]
  1178. i += 1
  1179. row = dict(cshift_emp_no=emp_no,
  1180. cshift_dept=emplist[emp_no]['dept'], cshift_no=cshift_no,
  1181. cshift_beg_date=run_date, cshift_beg_time=cshift_beg_time, cshift_beg_time_value=cshift_beg_time_value,
  1182. cshift_end_date=run_date, cshift_end_time=cshift_end_time, cshift_end_time_value=cshift_end_time_value,
  1183. cshift_leave_hours=cshift_leave_hours,
  1184. cshift_late=cshift_late, cshift_late_value=cshift_late_value,
  1185. cshift_leave=cshift_leave, cshift_leave_value=cshift_leave_value,
  1186. cshift_over=cshift_over,
  1187. cshift_over_value=cshift_over_value[0], cshift_over_amt=cshift_over_amt[0], cshift_over_flag=cshift_over_amt[1],
  1188. cshift_over2=cshift_over2,
  1189. cshift_over2_value=cshift_over_value[1], cshift_over2_amt=cshift_over2_amt[0], cshift_over2_flag=cshift_over2_amt[1],
  1190. cshift_over3=cshift_over3,
  1191. cshift_over3_value=cshift_over_value[2], cshift_over3_amt=cshift_over3_amt[0], cshift_over3_flag=cshift_over3_amt[1],
  1192. cshift_over_beg_time=cshift_over_beg_time, cshift_over_end_time=cshift_over_end_time,
  1193. cshift_resource_calendar_id=emplist[emp_no]['resource_calendar_id'],
  1194. cshift_total=cshift_total, cshift_total_value=cshift_total_value,
  1195. cshift_leave_type1_hours=cshift_leave_type1_hours, cshift_leave_type2_hours=cshift_leave_type2_hours, cshift_leave_type3_hours=cshift_leave_type3_hours,
  1196. cshift_leave_type4_hours=cshift_leave_type4_hours, cshift_leave_type5_hours=cshift_leave_type5_hours, cshift_leave_type6_hours=cshift_leave_type6_hours,
  1197. cshift_leave_type7_hours=cshift_leave_type7_hours, cshift_leave_type8_hours=cshift_leave_type8_hours, cshift_leave_type9_hours=cshift_leave_type9_hours,
  1198. cshift_leave_type10_hours=cshift_leave_type10_hours, cshift_leave_type11_hours=cshift_leave_type11_hours, cshift_leave_type12_hours=cshift_leave_type12_hours,
  1199. cshift_leave_type13_hours=cshift_leave_type13_hours, cshift_leave_type14_hours=cshift_leave_type14_hours,
  1200. cshift_sysdate=datetime.datetime.now())
  1201. if tcshift.find_one(cshift_emp_no=emp_no, cshift_no=cshift_no, cshift_beg_date=run_date):
  1202. tcshift.delete(
  1203. cshift_emp_no=emp_no, cshift_no=cshift_no, cshift_beg_date=run_date)
  1204. tcshift.insert(row)
  1205. _db.commit()
  1206. except Exception as e:
  1207. logging.error(str(e))
  1208. _db.rollback()
  1209. def run_hr_cmonth(db, year, month, days=None, run_emp_no=None):
  1210. #logger = logging.getLogger('cmonth')
  1211. _db = db
  1212. reload_working_times(_db, year, month) # 工作天數
  1213. _days = days
  1214. if _days is None:
  1215. _days = calendar.monthrange(year, month)[1]
  1216. now_date = datetime.datetime.now().strftime("%H:%M:%S")
  1217. str1 = 'hr_cmonth %d-%d-%d start: %s' % (year, month, _days, now_date)
  1218. logging.info(str1)
  1219. for day in range(_days):
  1220. _day = day+1
  1221. run_date = datetime.date(year, month, _day)
  1222. run_hr_cshift(_db, run_date, run_emp_no=run_emp_no)
  1223. now_date = datetime.datetime.now().strftime("%H:%M:%S")
  1224. str1 = 'hr_cmonth %d-%d-%d end: %s' % (year, month, _days, now_date)
  1225. logging.info(str1)
  1226. #run_export_cshift_file(_db, year, month, run_emp_no=run_emp_no)
  1227. def run_hr_attendance(db, year, month, run_emp_no=None): # 刷卡資料轉入odoo考勤
  1228. #logger = logging.getLogger('hr_attendance')
  1229. _db = db
  1230. models = endpoint_object()
  1231. uid = get_uid()
  1232. #thr_attendance = _db['hr_attendance']
  1233. days = calendar.monthrange(year, month)[1]
  1234. date_start = '%04d-%02d-%02d' % (year, month, 1)
  1235. date_end = '%04d-%02d-%02d' % (year, month, days)
  1236. now_date = datetime.datetime.now().strftime("%H:%M:%S")
  1237. logging.info('hr_attendance start: '+now_date)
  1238. _sql = 'SELECT he.id as emp_id, hhc.* FROM htp_hr_cshift as hhc inner join hr_employee as he on (he.emp_no = hhc.cshift_emp_no) '
  1239. _sql += 'where he.id is not null and hhc.cshift_beg_date BETWEEN \'%s\' and \'%s\' and hhc.cshift_beg_time_value > 0 ' % (
  1240. date_start, date_end)
  1241. if run_emp_no:
  1242. _sql += 'and he.emp_no = \'%s\' ' % (run_emp_no)
  1243. _sql += 'order by hhc.cshift_beg_date, hhc.cshift_beg_time '
  1244. data_rows = _db.query(_sql)
  1245. if data_rows:
  1246. datestr = date_start+' 00:00:00'
  1247. dt = datetime2UTC(datestr)
  1248. datestr = datetime.datetime.strftime(dt, '%Y-%m-%d %H:%M:%S')
  1249. datestr2 = date_end+' 00:00:00'
  1250. dt = datetime2UTC(datestr2)
  1251. datestr2 = datetime.datetime.strftime(dt, '%Y-%m-%d %H:%M:%S')
  1252. del_ids = None
  1253. if run_emp_no:
  1254. _sql = 'SELECT id as emp_id FROM hr_employee where emp_no = \'%s\' ' % (run_emp_no)
  1255. emp_row = _db.query(_sql)
  1256. for emp in emp_row:
  1257. del_ids = models.execute_kw(odoo_db, uid, odoo_password, 'hr.attendance', 'search', [[
  1258. ['employee_id', '=', emp['emp_id']], ['check_in', '>=', datestr], ['check_in', '<=', datestr2]]])
  1259. else:
  1260. del_ids = models.execute_kw(odoo_db, uid, odoo_password, 'hr.attendance', 'search', [[
  1261. ['check_in', '>=', datestr], ['check_in', '<=', datestr2]]])
  1262. if del_ids:
  1263. models.execute_kw(odoo_db, uid, odoo_password,
  1264. 'hr.attendance', 'unlink', [del_ids])
  1265. #_sql = 'delete from hr_attendance where date_part(\'year\', check_out) = %d and date_part(\'month\', check_out) = %d ' % (year, month)
  1266. #if run_emp_no:
  1267. # _sql += ' and employee_id = (select id from hr_employee where emp_no = \'%s\') ' % (run_emp_no)
  1268. #stmt = text(_sql)
  1269. #_db.executable.execute(stmt)
  1270. for row in data_rows:
  1271. datestr = '%s %s' % (row['cshift_beg_date'], row['cshift_beg_time'])
  1272. dt = datetime2UTC(datestr)
  1273. datestr = datetime.datetime.strftime(dt, '%Y-%m-%d %H:%M:%S')
  1274. datestr2 = '%s %s' % (row['cshift_beg_date'], row['cshift_end_time'])
  1275. dt = datetime2UTC(datestr2)
  1276. datestr2 = datetime.datetime.strftime(dt, '%Y-%m-%d %H:%M:%S')
  1277. # 找不到寫入
  1278. #if (thr_attendance.find_one(employee_id=row['emp_id'], check_in=datestr, check_out=datestr2)) and (datestr <= datestr2):
  1279. # if thr_attendance.find_one(employee_id=row['emp_id'], check_in=datestr):
  1280. # thr_attendance.delete(employee_id=row['emp_id'], check_in=datestr)
  1281. if datestr <= datestr2:
  1282. models.execute_kw(odoo_db, uid, odoo_password, 'hr.attendance', 'create', [{
  1283. 'employee_id': row['emp_id'], 'check_in': datestr, 'check_out': datestr2,
  1284. }])
  1285. now_date = datetime.datetime.now().strftime("%H:%M:%S")
  1286. #print()
  1287. logging.info('hr_attendance end: '+now_date)
  1288. def test():
  1289. sfList = getShitft()
  1290. timelist = [0.2, 0.41, 0.51, 0.53, 0.71, 0.73, 0.8]
  1291. # timelist = [0.2, 0.41, 0.51, 0.53, 0.71, 0.73, 0.8]
  1292. # timelist = [0.51, 0.52, 0.71, 0.73] # 前後忘刷
  1293. # timelist = [0.2, 0.51, 0.71, 0.73] # 前後忘刷
  1294. print(time2dict(timelist, sfList))
  1295. def run_export_cshift_file(db, year, month, run_emp_no=None):
  1296. #logger = logging.getLogger('run_export_cshift_file')
  1297. _db = db
  1298. tcdata = _db[prefix+'_cdata']
  1299. tcshift = _db[prefix+'_cshift']
  1300. _strdate = '%04d%02d' % (year, month)
  1301. sql = 'SELECT * FROM '+prefix + \
  1302. '_cshift where date_part(\'year\', cshift_beg_date) = %d and date_part(\'month\', cshift_beg_date) = %d ORDER BY cshift_beg_date, cshift_emp_no, cshift_no' % (
  1303. year, month)
  1304. if run_emp_no is not None:
  1305. sql = 'SELECT * FROM '+prefix + \
  1306. '_cshift where date_part(\'year\', cshift_beg_date) = %d and date_part(\'month\', cshift_beg_date) = %d and cshift_emp_no = \'%s\' ORDER BY cshift_beg_date, cshift_emp_no, cshift_no' % (
  1307. year, month, run_emp_no)
  1308. data_rows = _db.query(sql)
  1309. wb = xlwt.Workbook()
  1310. sheet = wb.add_sheet(_strdate)
  1311. # sheet.write(0, 0, '123')
  1312. # sheet.write(0, 1, '567')
  1313. # sheet.write(1, 0, '999') #第二行
  1314. titlelist = ['員工編號', '姓名', '部門', '時段', '開始日期', '開始時間',
  1315. '結束日期', '結束時間', '遲到時間', '早退時間', '加班時間', '上班時間']
  1316. i = 0
  1317. for item in titlelist:
  1318. sheet.write(0, i, item)
  1319. i += 1
  1320. i = 1
  1321. for row in data_rows:
  1322. empno = row['cshift_emp_no']
  1323. empname = row['cshift_emp_no']
  1324. dept = row['cshift_dept']
  1325. cshift_no = row['cshift_no']
  1326. cshift_beg_date = row['cshift_beg_date'].strftime("%Y-%m-%d")
  1327. cshift_beg_time = row['cshift_beg_time']
  1328. cshift_end_date = row['cshift_end_date'].strftime("%Y-%m-%d")
  1329. cshift_end_time = row['cshift_end_time']
  1330. cshift_late = row['cshift_late']
  1331. cshift_leave = row['cshift_leave']
  1332. cshift_over = row['cshift_over']
  1333. cshift_total = row['cshift_total']
  1334. tcrow = tcdata.find_one(cdata_emp_no=empno)
  1335. if tcrow:
  1336. empname = tcrow['cdata_emp_name']
  1337. sheet.write(i, 0, empno)
  1338. sheet.write(i, 1, empname)
  1339. sheet.write(i, 2, dept)
  1340. sheet.write(i, 3, cshift_no)
  1341. sheet.write(i, 4, cshift_beg_date)
  1342. sheet.write(i, 5, cshift_beg_time)
  1343. sheet.write(i, 6, cshift_end_date)
  1344. sheet.write(i, 7, cshift_end_time)
  1345. sheet.write(i, 8, cshift_late)
  1346. sheet.write(i, 9, cshift_leave)
  1347. sheet.write(i, 10, cshift_over)
  1348. sheet.write(i, 11, cshift_total)
  1349. i += 1
  1350. wb.save('cshitft_'+_strdate+'.xls')
  1351. def reload_working_times(db, year, month): # 轉存table
  1352. _db = db
  1353. uid = get_uid()
  1354. models = endpoint_object()
  1355. _table = _db[prefix+'_working_times']
  1356. _table.delete()
  1357. _btime_str = '%04d-%02d-01 00:00:00' % (year, month)
  1358. days = calendar.monthrange(year, month)[1]
  1359. _etime_str = '%04d-%02d-%02d 23:59:59' % (year, month, days)
  1360. main_rows = _db.query('SELECT * FROM resource_calendar ORDER BY id ASC ')
  1361. if uid and main_rows:
  1362. _db.begin()
  1363. try:
  1364. for row in main_rows:
  1365. work_times = models.execute_kw(odoo_db, uid, odoo_password, 'hr.payslip', 'get_working_times', [
  1366. row['id'], _btime_str, _etime_str])
  1367. # print(data)
  1368. for item in work_times:
  1369. if getHoliday(db, row['id'], item[0])[0]: # 國定假日
  1370. continue
  1371. data = dict(
  1372. work_id=row['id'], work_beg_time=item[0], work_end_time=item[1])
  1373. _table.insert(data)
  1374. _db.commit()
  1375. except Exception as e:
  1376. logging.error(str(e))
  1377. _db.rollback()
  1378. def test_over_amt(db): # 測試加班
  1379. reload_working_times(db, 2021, 3)
  1380. emp = {}
  1381. emp['resource_calendar_id'] = 1
  1382. hours = 10*60*60 # 小時
  1383. price = 100
  1384. # _amt = calc_over_amt(
  1385. # db, emp, datetime.datetime(2021, 3, 18), hours) # 加班算金額 (平日)
  1386. # print(_amt)
  1387. # print(_amt[0]*price)
  1388. # _amt = calc_over_amt(
  1389. # db, emp, datetime.datetime(2021, 4, 6), hours) # 加班算金額 (例假日)
  1390. # print(_amt)
  1391. # print(_amt[0]*price)
  1392. _amt = calc_over_amt(
  1393. db, emp, datetime.datetime(2021, 3, 28), hours) # 加班算金額 (休息日)
  1394. print(_amt)
  1395. print(_amt[0]*price)
  1396. def run_hr_cdata_dir(db, base_dir):
  1397. ret = False
  1398. _db = db
  1399. _base_dir = base_dir
  1400. _bak_dir = _base_dir+'/bak'
  1401. # if not os.path.exists(_bak_dir):
  1402. os.makedirs(_bak_dir, exist_ok=True)
  1403. arr = glob.glob(_base_dir+'/*.xlsx')
  1404. ret = (len(arr) > 0)
  1405. for filename in arr:
  1406. #print(filename)
  1407. run_hr_cdata(_db, filename) # 輸入
  1408. fsa = filename.split('/')
  1409. copyfile(filename, _bak_dir+'/'+fsa[-1])
  1410. os.remove(filename)
  1411. return ret
  1412. def run_now(db, filedir=None, now=None):
  1413. _db = db
  1414. _filedir = filedir
  1415. if _filedir is None:
  1416. _filedir = '/media/Share'
  1417. # FMT = '%(asctime)s %(filename)s %(funcName)s %(levelname)s %(message)s'
  1418. # logging.basicConfig(format=FMT, filename=_filedir+'/hr_carddata.log', level=logging.INFO)
  1419. # sudo mount -t cifs //192.168.80.5/carddata /media/Share -o username='hhli',password='Ht1230136',uid=1000,domain=hantecprecision
  1420. #fstab
  1421. #//192.168.80.5/carddata /media/Share cifs username=hhli,password=Ht1230136,uid=1000,domain=hantecprecision
  1422. #NFS
  1423. # mount -t nfs 192.168.80.5:/volume1/carddata /media/Share
  1424. _now = now
  1425. if _now is None:
  1426. _now = datetime.datetime.now()
  1427. if run_hr_cdata_dir(_db, _filedir): # 取目錄資料
  1428. if _now.day in [1,2,3,4]: #每月1-3日重新計算上個月
  1429. _now2 =_now+relativedelta(months=-1)
  1430. run_hr_cmonth(_db, _now2.year, _now2.month) # 計算上個月
  1431. run_hr_cmonth(_db, _now.year, _now.month, _now.day) # 計算
  1432. run_hr_attendance(_db, _now.year, _now.month) # 轉入odoo考勤
  1433. def run_month(year, month, days=None, url='http://192.168.80.3:8069', dbname='htp', dburl='postgresql://odoo:odootyughj@192.168.80.3:5432/htp'):
  1434. global odoo_url, odoo_db
  1435. odoo_url = url
  1436. odoo_db = dbname
  1437. db = dataset.connect(dburl)
  1438. db.vars = {}
  1439. db.vars['emplist'] = loadOdooEmp(db)
  1440. run_hr_cmonth(db, year, month, days)
  1441. def run_htp(url='http://192.168.80.3:8069', dbname='htp', dburl='postgresql://odoo:odootyughj@192.168.80.3:5432/htp'):
  1442. global odoo_url, odoo_db
  1443. #odoo_url = 'http://192.168.80.3:8069'
  1444. odoo_url = url
  1445. #odoo_db = 'htp'
  1446. odoo_db = dbname
  1447. #db = dataset.connect('postgresql://odoo:1230136@192.168.80.3:5432/htp')
  1448. db = dataset.connect(dburl)
  1449. db.vars = {}
  1450. db.vars['emplist'] = loadOdooEmp(db)
  1451. #run_now(db, now=datetime.datetime(2021, 10, 31))
  1452. run_now(db)
  1453. if __name__ == "__main__":
  1454. FMT = '%(asctime)s %(filename)s %(funcName)s %(levelname)s %(message)s'
  1455. #logging.basicConfig(format=FMT, filename='hr.log', level=logging.DEBUG)
  1456. logging.basicConfig(format=FMT, level=logging.INFO)#直列
  1457. if len(sys.argv) > 1:
  1458. if sys.argv[1] == 'now':
  1459. run_htp(url='http://192.168.80.3:8069', dbname='htp', dburl='postgresql://odoo:odootyughj@192.168.80.3:5432/htp')
  1460. print('Run end.')
  1461. else:
  1462. try:
  1463. dd = datetime.datetime.strptime(sys.argv[1], '%Y%m%d').date()
  1464. _db = dataset.connect('postgresql://odoo:odootyughj@192.168.80.3:5432/htp') #正式
  1465. _db.vars = {}
  1466. _db.vars['emplist'] = loadOdooEmp(_db)
  1467. run_hr_cmonth(_db, dd.year, dd.month, dd.day)
  1468. print('Run end.')
  1469. except:
  1470. print('Error date format.')
  1471. exit()
  1472. allow_none = True #debug
  1473. #run_month(2021, 10, url='http://0.0.0.0:8069', dbname='htp', dburl='postgresql://odoo:odoo@192.168.80.94:5432/htp')
  1474. #exit()
  1475. # print(math.ceil(1.1)) #無修件進位
  1476. #print(math.floor(140.60)) #無條件去位
  1477. #run_htp(url='http://192.168.80.3:8069', dbname='htp', dburl='postgresql://odoo:odoo@192.168.80.3:5432/htp')
  1478. #exit()
  1479. #_db = dataset.connect('postgresql://odoo13:odoo@192.168.80.50:5432/htp')
  1480. _db = dataset.connect('postgresql://odoo:odootyughj@192.168.80.3:5432/htp') #正式
  1481. _db.vars = {}
  1482. # run_hr_attendance(_db, 2021, 6) # 轉入odoo考勤
  1483. # exit()
  1484. # _db.vars['emplist'] = loadXlsEmp()
  1485. _db.vars['emplist'] = loadOdooEmp(_db)
  1486. _path = '/home/xz/htp/odoo13/extension/xls2table/tmp/'
  1487. _filename = _path+'exm2024022728.xls'
  1488. #_filename = _path+'exmbyxz.xlsx'
  1489. #run_hr_cdata(_db, _filename) # 輸入
  1490. # test_over_amt(_db)
  1491. # run_hr_cshift(_db, datetime.date(2021, 1, 6))
  1492. #run_hr_cmonth(_db, 2024, 2, 17, run_emp_no='202009001') # 計算
  1493. #run_hr_cmonth(_db, 2024, 2, 29) # 計算
  1494. #run_hr_cmonth(_db, 2023, 12) # 計算
  1495. # run_export_cshift_file(_db, 2021, 1) #匯出excel
  1496. #run_hr_attendance(_db, 2023, 10, run_emp_no='202111001') # 轉入odoo考勤