attendance.lib.php 79 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * This file contains class used like library, provides functions for attendance tool.
  5. * It's also used like model to attendance_controller (MVC pattern).
  6. *
  7. * @author Christian Fasanando <christian1827@gmail.com>
  8. * @author Julio Montoya <gugli100@gmail.com> improvements
  9. *
  10. * @package chamilo.attendance
  11. */
  12. class Attendance
  13. {
  14. // constants
  15. const DONE_ATTENDANCE_LOG_TYPE = 'done_attendance_sheet';
  16. const UPDATED_ATTENDANCE_LOG_TYPE = 'updated_attendance_sheet';
  17. const LOCKED_ATTENDANCE_LOG_TYPE = 'locked_attendance_sheet';
  18. public $category_id;
  19. private $session_id;
  20. private $course_id;
  21. private $date_time;
  22. private $name;
  23. private $description;
  24. private $attendance_qualify_title;
  25. private $attendance_weight;
  26. private $course_int_id;
  27. /**
  28. * Constructor.
  29. */
  30. public function __construct()
  31. {
  32. //$this->course_int_id = api_get_course_int_id();
  33. }
  34. /**
  35. * Get the total number of attendance inside current course and current session.
  36. *
  37. * @param int $active
  38. *
  39. * @return int
  40. *
  41. * @see SortableTable#get_total_number_of_items()
  42. */
  43. public static function getNumberOfAttendances($active = -1)
  44. {
  45. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  46. $session_id = api_get_session_id();
  47. $condition_session = api_get_session_condition($session_id);
  48. $course_id = api_get_course_int_id();
  49. $sql = "SELECT COUNT(att.id) AS total_number_of_items
  50. FROM $tbl_attendance att
  51. WHERE c_id = $course_id $condition_session ";
  52. $active = (int) $active;
  53. if ($active === 1 || $active === 0) {
  54. $sql .= "AND att.active = $active";
  55. }
  56. $res = Database::query($sql);
  57. $obj = Database::fetch_object($res);
  58. return $obj->total_number_of_items;
  59. }
  60. /**
  61. * Get attendance list only the id, name and attendance_qualify_max fields.
  62. *
  63. * @param int $course_id course db name (optional)
  64. * @param int $session_id session id (optional)
  65. *
  66. * @return array attendances list
  67. */
  68. public function get_attendances_list($course_id = 0, $session_id = 0)
  69. {
  70. $table = Database::get_course_table(TABLE_ATTENDANCE);
  71. $course_id = (int) $course_id;
  72. if (empty($course_id)) {
  73. $course_id = api_get_course_int_id();
  74. }
  75. $session_id = !empty($session_id) ? (int) $session_id : api_get_session_id();
  76. $condition_session = api_get_session_condition($session_id);
  77. // Get attendance data
  78. $sql = "SELECT id, name, attendance_qualify_max
  79. FROM $table
  80. WHERE c_id = $course_id AND active = 1 $condition_session ";
  81. $result = Database::query($sql);
  82. $data = [];
  83. if (Database::num_rows($result) > 0) {
  84. while ($row = Database::fetch_array($result, 'ASSOC')) {
  85. $data[$row['id']] = $row;
  86. }
  87. }
  88. return $data;
  89. }
  90. /**
  91. * Get the attendances to display on the current page (fill the sortable-table).
  92. *
  93. * @param int offset of first user to recover
  94. * @param int Number of users to get
  95. * @param int Column to sort on
  96. * @param string Order (ASC,DESC)
  97. *
  98. * @see SortableTable#get_table_data($from)
  99. *
  100. * @return array
  101. */
  102. public static function get_attendance_data(
  103. $from,
  104. $number_of_items,
  105. $column,
  106. $direction
  107. ) {
  108. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  109. $course_id = api_get_course_int_id();
  110. $session_id = api_get_session_id();
  111. $condition_session = api_get_session_condition($session_id);
  112. $column = (int) $column;
  113. $from = (int) $from;
  114. $number_of_items = (int) $number_of_items;
  115. if (!in_array($direction, ['ASC', 'DESC'])) {
  116. $direction = 'ASC';
  117. }
  118. $active_plus = '';
  119. if ((isset($_GET['isStudentView']) && $_GET['isStudentView'] == 'true') ||
  120. !api_is_allowed_to_edit(null, true)
  121. ) {
  122. $active_plus = ' AND att.active = 1';
  123. }
  124. $sql = "SELECT
  125. att.id AS col0,
  126. att.name AS col1,
  127. att.description AS col2,
  128. att.attendance_qualify_max AS col3,
  129. att.locked AS col4,
  130. att.active AS col5,
  131. att.session_id
  132. FROM $tbl_attendance att
  133. WHERE
  134. att.active <> 2 AND
  135. c_id = $course_id $active_plus $condition_session
  136. ORDER BY col$column $direction
  137. LIMIT $from,$number_of_items ";
  138. $res = Database::query($sql);
  139. $attendances = [];
  140. $user_info = api_get_user_info();
  141. $allowDelete = api_get_setting('allow_delete_attendance');
  142. $student_param = '';
  143. $studentRequestId = isset($_GET['student_id']) ? (int) $_GET['student_id'] : 0;
  144. if (api_is_drh() && !empty($studentRequestId)) {
  145. $student_param = '&student_id='.$studentRequestId;
  146. }
  147. while ($attendance = Database::fetch_row($res)) {
  148. $session_star = '';
  149. if (api_get_session_id() == $attendance[6]) {
  150. $session_star = api_get_session_image(api_get_session_id(), $user_info['status']);
  151. }
  152. if ($attendance[5] == 1) {
  153. $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
  154. api_get_user_id(),
  155. api_get_course_info()
  156. ) || api_is_drh();
  157. if (api_is_allowed_to_edit(null, true) || $isDrhOfCourse) {
  158. // Link to edit
  159. $attendance[1] = '<a href="index.php?'.api_get_cidreq().'&action=attendance_sheet_list&attendance_id='.$attendance[0].$student_param.'">'.$attendance[1].'</a>'.$session_star;
  160. } else {
  161. // Link to view
  162. $attendance[1] = '<a href="index.php?'.api_get_cidreq().'&action=attendance_sheet_list_no_edit&attendance_id='.$attendance[0].$student_param.'">'.$attendance[1].'</a>'.$session_star;
  163. }
  164. } else {
  165. $attendance[1] = '<a class="muted" href="index.php?'.api_get_cidreq().'&action=attendance_sheet_list&attendance_id='.$attendance[0].$student_param.'">'.$attendance[1].'</a>'.$session_star;
  166. }
  167. if ($attendance[5] == 1) {
  168. $attendance[3] = '<center>'.$attendance[3].'</center>';
  169. } else {
  170. $attendance[3] = '<center><span class="muted">'.$attendance[3].'</span></center>';
  171. }
  172. $attendance[3] = '<center>'.$attendance[3].'</center>';
  173. if (api_is_allowed_to_edit(null, true)) {
  174. $actions = '';
  175. $actions .= '<center>';
  176. if (api_is_platform_admin()) {
  177. $actions .= '<a href="index.php?'.api_get_cidreq().'&action=attendance_edit&attendance_id='.$attendance[0].'">'.
  178. Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL).'</a>&nbsp;';
  179. // Visible
  180. if ($attendance[5] == 1) {
  181. $actions .= '<a href="index.php?'.api_get_cidreq().'&action=attendance_set_invisible&attendance_id='.$attendance[0].'">'.
  182. Display::return_icon('visible.png', get_lang('Hide'), [], ICON_SIZE_SMALL).'</a>';
  183. } else {
  184. $actions .= '<a href="index.php?'.api_get_cidreq().'&action=attendance_set_visible&attendance_id='.$attendance[0].'">'.
  185. Display::return_icon('invisible.png', get_lang('Show'), [], ICON_SIZE_SMALL).'</a>';
  186. $attendance[2] = '<span class="muted">'.$attendance[2].'</span>';
  187. }
  188. if ($allowDelete === 'true') {
  189. $actions .= '<a href="index.php?'.api_get_cidreq().'&action=attendance_delete&attendance_id='.$attendance[0].'">'.
  190. Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL).'</a>';
  191. }
  192. } else {
  193. $is_locked_attendance = self::is_locked_attendance($attendance[0]);
  194. if ($is_locked_attendance) {
  195. $actions .= Display::return_icon('edit_na.png', get_lang('Edit')).'&nbsp;';
  196. $actions .= Display::return_icon('visible.png', get_lang('Hide'));
  197. } else {
  198. $actions .= '<a href="index.php?'.api_get_cidreq().'&action=attendance_edit&attendance_id='.$attendance[0].'">'.
  199. Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL).'</a>&nbsp;';
  200. if ($attendance[5] == 1) {
  201. $actions .= ' <a href="index.php?'.api_get_cidreq().'&action=attendance_set_invisible&attendance_id='.$attendance[0].'">'.
  202. Display::return_icon('visible.png', get_lang('Hide'), [], ICON_SIZE_SMALL).'</a>';
  203. } else {
  204. $actions .= ' <a href="index.php?'.api_get_cidreq().'&action=attendance_set_visible&attendance_id='.$attendance[0].'">'.
  205. Display::return_icon('invisible.png', get_lang('Show'), [], ICON_SIZE_SMALL).'</a>';
  206. $attendance[2] = '<span class="muted">'.$attendance[2].'</span>';
  207. }
  208. if ($allowDelete === 'true') {
  209. $actions .= ' <a href="index.php?'.api_get_cidreq().'&action=attendance_delete&attendance_id='.$attendance[0].'">'.
  210. Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL).'</a>';
  211. }
  212. }
  213. }
  214. // display lock/unlock icon
  215. $is_done_all_calendar = self::is_all_attendance_calendar_done($attendance[0]);
  216. if ($is_done_all_calendar) {
  217. $locked = $attendance[4];
  218. if ($locked == 0) {
  219. if (api_is_platform_admin()) {
  220. $message_alert = get_lang('AreYouSureToLockTheAttendance');
  221. } else {
  222. $message_alert = get_lang('UnlockMessageInformation');
  223. }
  224. $actions .= '&nbsp;<a onclick="javascript:if(!confirm(\''.$message_alert.'\')) return false;" href="index.php?'.api_get_cidreq().'&action=lock_attendance&attendance_id='.$attendance[0].'">'.
  225. Display::return_icon('unlock.png', get_lang('LockAttendance')).'</a>';
  226. } else {
  227. if (api_is_platform_admin()) {
  228. $actions .= '&nbsp;<a onclick="javascript:if(!confirm(\''.get_lang('AreYouSureToUnlockTheAttendance').'\')) return false;" href="index.php?'.api_get_cidreq().'&action=unlock_attendance&attendance_id='.$attendance[0].'">'.
  229. Display::return_icon('locked.png', get_lang('UnlockAttendance')).'</a>';
  230. } else {
  231. $actions .= '&nbsp;'.Display::return_icon('locked_na.png', get_lang('LockedAttendance'));
  232. }
  233. }
  234. }
  235. $actions .= '</center>';
  236. $attendances[] = [
  237. $attendance[0],
  238. $attendance[1],
  239. $attendance[2],
  240. $attendance[3],
  241. $actions,
  242. ];
  243. } else {
  244. $attendance[0] = '&nbsp;';
  245. $attendances[] = [
  246. $attendance[0],
  247. $attendance[1],
  248. $attendance[2],
  249. $attendance[3],
  250. ];
  251. }
  252. }
  253. return $attendances;
  254. }
  255. /**
  256. * Get the attendances by id to display on the current page.
  257. *
  258. * @param int $attendanceId
  259. *
  260. * @return array attendance data
  261. */
  262. public function get_attendance_by_id($attendanceId)
  263. {
  264. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  265. $attendanceId = (int) $attendanceId;
  266. $course_id = api_get_course_int_id();
  267. $attendance_data = [];
  268. $sql = "SELECT * FROM $tbl_attendance
  269. WHERE c_id = $course_id AND id = '$attendanceId'";
  270. $res = Database::query($sql);
  271. if (Database::num_rows($res) > 0) {
  272. while ($row = Database::fetch_array($res)) {
  273. $attendance_data = $row;
  274. }
  275. }
  276. return $attendance_data;
  277. }
  278. /**
  279. * Add attendances sheet inside table. This is the *list of* dates, not
  280. * a specific date in itself.
  281. *
  282. * @param bool true for adding link in gradebook or false otherwise (optional)
  283. *
  284. * @return int last attendance id
  285. */
  286. public function attendance_add($link_to_gradebook = false)
  287. {
  288. $_course = api_get_course_info();
  289. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  290. $table_link = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
  291. $session_id = api_get_session_id();
  292. $user_id = api_get_user_id();
  293. $course_code = $_course['code'];
  294. $course_id = $_course['real_id'];
  295. $title_gradebook = $this->attendance_qualify_title;
  296. $value_calification = 0;
  297. $weight_calification = api_float_val($this->attendance_weight);
  298. $params = [
  299. 'c_id' => $course_id,
  300. 'name' => $this->name,
  301. 'description' => $this->description,
  302. 'attendance_qualify_title' => $title_gradebook,
  303. 'attendance_weight' => $weight_calification,
  304. 'session_id' => $session_id,
  305. 'active' => 1,
  306. 'attendance_qualify_max' => 0,
  307. 'locked' => 0,
  308. ];
  309. $last_id = Database::insert($tbl_attendance, $params);
  310. if (!empty($last_id)) {
  311. $sql = "UPDATE $tbl_attendance SET id = iid WHERE iid = $last_id";
  312. Database::query($sql);
  313. api_item_property_update(
  314. $_course,
  315. TOOL_ATTENDANCE,
  316. $last_id,
  317. "AttendanceAdded",
  318. $user_id
  319. );
  320. }
  321. // add link to gradebook
  322. if ($link_to_gradebook && !empty($this->category_id)) {
  323. $description = '';
  324. $link_info = GradebookUtils::isResourceInCourseGradebook(
  325. $course_code,
  326. 7,
  327. $last_id,
  328. $session_id
  329. );
  330. $link_id = $link_info['id'];
  331. if (!$link_info) {
  332. GradebookUtils::add_resource_to_course_gradebook(
  333. $this->category_id,
  334. $course_code,
  335. 7,
  336. $last_id,
  337. $title_gradebook,
  338. $weight_calification,
  339. $value_calification,
  340. $description,
  341. 1,
  342. $session_id
  343. );
  344. } else {
  345. Database::query('UPDATE '.$table_link.' SET weight='.$weight_calification.' WHERE id='.$link_id.'');
  346. }
  347. }
  348. return $last_id;
  349. }
  350. /**
  351. * edit attendances inside table.
  352. *
  353. * @param int attendance id
  354. * @param bool true for adding link in gradebook or false otherwise (optional)
  355. *
  356. * @return int last id
  357. */
  358. public function attendance_edit($attendanceId, $link_to_gradebook = false)
  359. {
  360. $_course = api_get_course_info();
  361. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  362. $table_link = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
  363. $session_id = api_get_session_id();
  364. $user_id = api_get_user_id();
  365. $attendanceId = (int) $attendanceId;
  366. $course_code = $_course['code'];
  367. $course_id = $_course['real_id'];
  368. $title_gradebook = $this->attendance_qualify_title;
  369. $value_calification = 0;
  370. $weight_calification = api_float_val($this->attendance_weight);
  371. if (!empty($attendanceId)) {
  372. $params = [
  373. 'name' => $this->name,
  374. 'description' => $this->description,
  375. 'attendance_qualify_title' => $title_gradebook,
  376. 'attendance_weight' => $weight_calification,
  377. ];
  378. Database::update(
  379. $tbl_attendance,
  380. $params,
  381. ['c_id = ? AND id = ?' => [$course_id, $attendanceId]]
  382. );
  383. api_item_property_update(
  384. $_course,
  385. TOOL_ATTENDANCE,
  386. $attendanceId,
  387. "AttendanceUpdated",
  388. $user_id
  389. );
  390. // add link to gradebook
  391. if ($link_to_gradebook && !empty($this->category_id)) {
  392. $description = '';
  393. $link_info = GradebookUtils::isResourceInCourseGradebook(
  394. $course_code,
  395. 7,
  396. $attendanceId,
  397. $session_id
  398. );
  399. if (!$link_info) {
  400. GradebookUtils::add_resource_to_course_gradebook(
  401. $this->category_id,
  402. $course_code,
  403. 7,
  404. $attendanceId,
  405. $title_gradebook,
  406. $weight_calification,
  407. $value_calification,
  408. $description,
  409. 1,
  410. $session_id
  411. );
  412. } else {
  413. Database::query('UPDATE '.$table_link.' SET weight='.$weight_calification.' WHERE id='.$link_info['id'].'');
  414. }
  415. }
  416. return $attendanceId;
  417. }
  418. return null;
  419. }
  420. /**
  421. * Restore attendance.
  422. *
  423. * @param int|array one or many attendances id
  424. *
  425. * @return int affected rows
  426. */
  427. public function attendance_restore($attendanceId)
  428. {
  429. $_course = api_get_course_info();
  430. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  431. $user_id = api_get_user_id();
  432. $course_id = $_course['real_id'];
  433. if (is_array($attendanceId)) {
  434. foreach ($attendanceId as $id) {
  435. $id = (int) $id;
  436. $sql = "UPDATE $tbl_attendance SET active = 1
  437. WHERE c_id = $course_id AND id = '$id'";
  438. $result = Database::query($sql);
  439. $affected_rows = Database::affected_rows($result);
  440. if (!empty($affected_rows)) {
  441. // update row item property table
  442. api_item_property_update(
  443. $_course,
  444. TOOL_ATTENDANCE,
  445. $id,
  446. 'restore',
  447. $user_id
  448. );
  449. }
  450. }
  451. } else {
  452. $attendanceId = (int) $attendanceId;
  453. $sql = "UPDATE $tbl_attendance SET active = 1
  454. WHERE c_id = $course_id AND id = '$attendanceId'";
  455. $result = Database::query($sql);
  456. $affected_rows = Database::affected_rows($result);
  457. if (!empty($affected_rows)) {
  458. // update row item property table
  459. api_item_property_update(
  460. $_course,
  461. TOOL_ATTENDANCE,
  462. $attendanceId,
  463. 'restore',
  464. $user_id
  465. );
  466. }
  467. }
  468. return $affected_rows;
  469. }
  470. /**
  471. * Delete attendances.
  472. *
  473. * @param int|array $attendanceId one or many attendances id
  474. *
  475. * @return int affected rows
  476. */
  477. public function attendance_delete($attendanceId)
  478. {
  479. $_course = api_get_course_info();
  480. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  481. $user_id = api_get_user_id();
  482. $course_id = $_course['real_id'];
  483. if (is_array($attendanceId)) {
  484. foreach ($attendanceId as $id) {
  485. $id = intval($id);
  486. $sql = "UPDATE $tbl_attendance SET active = 2
  487. WHERE c_id = $course_id AND id = '$id'";
  488. $result = Database::query($sql);
  489. $affected_rows = Database::affected_rows($result);
  490. if (!empty($affected_rows)) {
  491. // update row item property table
  492. api_item_property_update(
  493. $_course,
  494. TOOL_ATTENDANCE,
  495. $id,
  496. "delete",
  497. $user_id
  498. );
  499. }
  500. }
  501. } else {
  502. $attendanceId = intval($attendanceId);
  503. $sql = "UPDATE $tbl_attendance SET active = 2
  504. WHERE c_id = $course_id AND id = '$attendanceId'";
  505. $result = Database::query($sql);
  506. $affected_rows = Database::affected_rows($result);
  507. if (!empty($affected_rows)) {
  508. // update row item property table
  509. api_item_property_update(
  510. $_course,
  511. TOOL_ATTENDANCE,
  512. $attendanceId,
  513. "delete",
  514. $user_id
  515. );
  516. }
  517. }
  518. return $affected_rows;
  519. }
  520. /**
  521. * Changes visibility.
  522. *
  523. * @param int|array $attendanceId one or many attendances id
  524. * @param int $status
  525. *
  526. * @return int affected rows
  527. */
  528. public function changeVisibility($attendanceId, $status = 1)
  529. {
  530. $_course = api_get_course_info();
  531. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  532. $user_id = api_get_user_id();
  533. $course_id = $_course['real_id'];
  534. $status = (int) $status;
  535. $action = 'visible';
  536. if ($status == 0) {
  537. $action = 'invisible';
  538. }
  539. if (is_array($attendanceId)) {
  540. foreach ($attendanceId as $id) {
  541. $id = (int) $id;
  542. $sql = "UPDATE $tbl_attendance SET active = $status
  543. WHERE c_id = $course_id AND id = '$id'";
  544. $result = Database::query($sql);
  545. $affected_rows = Database::affected_rows($result);
  546. if (!empty($affected_rows)) {
  547. // update row item property table
  548. api_item_property_update(
  549. $_course,
  550. TOOL_ATTENDANCE,
  551. $id,
  552. $action,
  553. $user_id
  554. );
  555. }
  556. }
  557. } else {
  558. $attendanceId = (int) $attendanceId;
  559. $sql = "UPDATE $tbl_attendance SET active = $status
  560. WHERE c_id = $course_id AND id = '$attendanceId'";
  561. $result = Database::query($sql);
  562. $affected_rows = Database::affected_rows($result);
  563. if (!empty($affected_rows)) {
  564. // update row item property table
  565. api_item_property_update(
  566. $_course,
  567. TOOL_ATTENDANCE,
  568. $attendanceId,
  569. $action,
  570. $user_id
  571. );
  572. }
  573. }
  574. return $affected_rows;
  575. }
  576. /**
  577. * Lock or unlock an attendance.
  578. *
  579. * @param int attendance id
  580. * @param bool True to lock or false otherwise
  581. *
  582. * @return int
  583. */
  584. public function lock_attendance($attendanceId, $lock = true)
  585. {
  586. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  587. $course_id = api_get_course_int_id();
  588. $attendanceId = (int) $attendanceId;
  589. $locked = $lock ? 1 : 0;
  590. $upd = "UPDATE $tbl_attendance SET locked = $locked
  591. WHERE c_id = $course_id AND id = $attendanceId";
  592. $result = Database::query($upd);
  593. $affected_rows = Database::affected_rows($result);
  594. if ($affected_rows && $lock) {
  595. // Save attendance sheet log
  596. $this->saveAttendanceSheetLog(
  597. $attendanceId,
  598. api_get_utc_datetime(),
  599. self::LOCKED_ATTENDANCE_LOG_TYPE,
  600. api_get_user_id()
  601. );
  602. }
  603. return $affected_rows;
  604. }
  605. /**
  606. * Get registered users inside current course.
  607. *
  608. * @param int $attendanceId attendance id for showing attendance result field (optional)
  609. * @param int $groupId
  610. *
  611. * @return array users data
  612. */
  613. public function get_users_rel_course($attendanceId = 0, $groupId = 0)
  614. {
  615. $current_session_id = api_get_session_id();
  616. $current_course_id = api_get_course_id();
  617. $currentCourseIntId = api_get_course_int_id();
  618. $studentInGroup = [];
  619. if (!empty($current_session_id)) {
  620. $a_course_users = CourseManager:: get_user_list_from_course_code(
  621. $current_course_id,
  622. $current_session_id,
  623. '',
  624. 'lastname'
  625. );
  626. } else {
  627. $a_course_users = CourseManager:: get_user_list_from_course_code(
  628. $current_course_id,
  629. 0,
  630. '',
  631. 'lastname'
  632. );
  633. }
  634. if (!empty($groupId)) {
  635. $groupInfo = GroupManager::get_group_properties($groupId);
  636. $students = GroupManager::getStudents($groupInfo['iid']);
  637. if (!empty($students)) {
  638. foreach ($students as $student) {
  639. $studentInGroup[$student['user_id']] = true;
  640. }
  641. }
  642. }
  643. // get registered users inside current course
  644. $a_users = [];
  645. foreach ($a_course_users as $key => $user_data) {
  646. $value = [];
  647. $uid = $user_data['user_id'];
  648. $userInfo = api_get_user_info($uid);
  649. $status = $user_data['status'];
  650. if (!empty($groupId)) {
  651. if (!isset($studentInGroup[$uid])) {
  652. continue;
  653. }
  654. }
  655. $user_status_in_session = null;
  656. $user_status_in_course = null;
  657. if (api_get_session_id()) {
  658. $user_status_in_session = SessionManager::get_user_status_in_course_session(
  659. $uid,
  660. $currentCourseIntId,
  661. $current_session_id
  662. );
  663. } else {
  664. $user_status_in_course = CourseManager::getUserInCourseStatus(
  665. $uid,
  666. $currentCourseIntId
  667. );
  668. }
  669. // Not taking into account DRH or COURSEMANAGER
  670. if ($uid <= 1 ||
  671. $status == DRH ||
  672. $user_status_in_course == COURSEMANAGER ||
  673. $user_status_in_session == 2
  674. ) {
  675. continue;
  676. }
  677. if (!empty($attendanceId)) {
  678. $user_faults = $this->get_faults_of_user(
  679. $uid,
  680. $attendanceId,
  681. $groupId
  682. );
  683. $value['attendance_result'] = $user_faults['faults'].'/'.$user_faults['total'].' ('.$user_faults['faults_porcent'].'%)';
  684. $value['result_color_bar'] = $user_faults['color_bar'];
  685. }
  686. $photo = Display::img(
  687. $userInfo['avatar_small'],
  688. $userInfo['complete_name'],
  689. [],
  690. false
  691. );
  692. $value['photo'] = $photo;
  693. $value['firstname'] = $user_data['firstname'];
  694. $value['lastname'] = $user_data['lastname'];
  695. $value['username'] = $user_data['username'];
  696. $value['user_id'] = $uid;
  697. // Sending only 5 items in the array instead of 60
  698. $a_users[$key] = $value;
  699. }
  700. return $a_users;
  701. }
  702. /**
  703. * add attendances sheet inside table.
  704. *
  705. * @param int $calendar_id attendance calendar id
  706. * @param array $users_present present users during current class
  707. * @param int $attendanceId
  708. *
  709. * @return int affected rows
  710. */
  711. public function attendance_sheet_add($calendar_id, $users_present, $attendanceId)
  712. {
  713. $tbl_attendance_sheet = Database::get_course_table(TABLE_ATTENDANCE_SHEET);
  714. $tbl_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  715. $calendar_id = (int) $calendar_id;
  716. $attendanceId = (int) $attendanceId;
  717. $users = $this->get_users_rel_course();
  718. $course_id = api_get_course_int_id();
  719. $user_ids = array_keys($users);
  720. $users_absent = array_diff($user_ids, $users_present);
  721. $affected_rows = 0;
  722. // get last edit type
  723. $calendar_data = $this->get_attendance_calendar_by_id($calendar_id);
  724. $lastedit_type = self::DONE_ATTENDANCE_LOG_TYPE;
  725. if ($calendar_data['done_attendance']) {
  726. $lastedit_type = self::UPDATED_ATTENDANCE_LOG_TYPE;
  727. }
  728. // save users present in class
  729. foreach ($users_present as $user_present) {
  730. $uid = (int) $user_present;
  731. // check if user already was registered with the $calendar_id
  732. $sql = "SELECT user_id FROM $tbl_attendance_sheet
  733. WHERE c_id = $course_id AND user_id='$uid' AND attendance_calendar_id = '$calendar_id'";
  734. $rs = Database::query($sql);
  735. if (Database::num_rows($rs) == 0) {
  736. $sql = "INSERT INTO $tbl_attendance_sheet SET
  737. c_id = $course_id,
  738. user_id = '$uid',
  739. attendance_calendar_id = '$calendar_id',
  740. presence = 1";
  741. $result = Database::query($sql);
  742. $affected_rows += Database::affected_rows($result);
  743. } else {
  744. $sql = "UPDATE $tbl_attendance_sheet SET presence = 1
  745. WHERE
  746. c_id = $course_id AND
  747. user_id ='$uid' AND
  748. attendance_calendar_id = '$calendar_id'
  749. ";
  750. $result = Database::query($sql);
  751. $affected_rows += Database::affected_rows($result);
  752. }
  753. }
  754. // save users absent in class
  755. foreach ($users_absent as $user_absent) {
  756. $uid = intval($user_absent);
  757. // check if user already was registered with the $calendar_id
  758. $sql = "SELECT user_id FROM $tbl_attendance_sheet
  759. WHERE c_id = $course_id AND user_id='$uid' AND attendance_calendar_id = '$calendar_id'";
  760. $rs = Database::query($sql);
  761. if (Database::num_rows($rs) == 0) {
  762. $sql = "INSERT INTO $tbl_attendance_sheet SET
  763. c_id = $course_id,
  764. user_id ='$uid',
  765. attendance_calendar_id = '$calendar_id',
  766. presence = 0";
  767. $result = Database::query($sql);
  768. Database::insert_id();
  769. $affected_rows += Database::affected_rows($result);
  770. } else {
  771. $sql = "UPDATE $tbl_attendance_sheet SET presence = 0
  772. WHERE
  773. c_id = $course_id AND
  774. user_id ='$uid' AND
  775. attendance_calendar_id = '$calendar_id'";
  776. $result = Database::query($sql);
  777. $affected_rows += Database::affected_rows($result);
  778. }
  779. }
  780. // update done_attendance inside attendance calendar table
  781. $sql = "UPDATE $tbl_attendance_calendar SET done_attendance = 1
  782. WHERE c_id = $course_id AND id = '$calendar_id'";
  783. Database::query($sql);
  784. // save users' results
  785. $this->updateUsersResults($user_ids, $attendanceId);
  786. if ($affected_rows) {
  787. //save attendance sheet log
  788. $this->saveAttendanceSheetLog(
  789. $attendanceId,
  790. api_get_utc_datetime(),
  791. $lastedit_type,
  792. api_get_user_id(),
  793. $calendar_data['date_time']
  794. );
  795. }
  796. return $affected_rows;
  797. }
  798. /**
  799. * update users' attendance results.
  800. *
  801. * @param array $user_ids registered users inside current course
  802. * @param int $attendanceId
  803. */
  804. public function updateUsersResults($user_ids, $attendanceId)
  805. {
  806. $tbl_attendance_sheet = Database::get_course_table(TABLE_ATTENDANCE_SHEET);
  807. $tbl_attendance_result = Database::get_course_table(TABLE_ATTENDANCE_RESULT);
  808. $tbl_attendance = Database::get_course_table(TABLE_ATTENDANCE);
  809. $course_id = api_get_course_int_id();
  810. $attendanceId = intval($attendanceId);
  811. // fill results about presence of students
  812. $attendance_calendar = $this->get_attendance_calendar(
  813. $attendanceId,
  814. 'all',
  815. null,
  816. null,
  817. true
  818. );
  819. $calendar_ids = [];
  820. // get all dates from calendar by current attendance
  821. foreach ($attendance_calendar as $cal) {
  822. $calendar_ids[] = $cal['id'];
  823. }
  824. // get count of presences by users inside current attendance and save like results
  825. if (count($user_ids) > 0) {
  826. foreach ($user_ids as $uid) {
  827. $uid = (int) $uid;
  828. $count_presences = 0;
  829. if (count($calendar_ids) > 0) {
  830. $sql = "SELECT count(presence) as count_presences
  831. FROM $tbl_attendance_sheet
  832. WHERE
  833. c_id = $course_id AND
  834. user_id = '$uid' AND
  835. attendance_calendar_id IN (".implode(',', $calendar_ids).") AND
  836. presence = 1";
  837. $rs_count = Database::query($sql);
  838. $row_count = Database::fetch_array($rs_count);
  839. $count_presences = $row_count['count_presences'];
  840. }
  841. // save results
  842. $sql = "SELECT id FROM $tbl_attendance_result
  843. WHERE
  844. c_id = $course_id AND
  845. user_id = '$uid' AND
  846. attendance_id = '$attendanceId' ";
  847. $rs_check_result = Database::query($sql);
  848. if (Database::num_rows($rs_check_result) > 0) {
  849. // update result
  850. $sql = "UPDATE $tbl_attendance_result SET
  851. score = '$count_presences'
  852. WHERE
  853. c_id = $course_id AND
  854. user_id='$uid' AND
  855. attendance_id='$attendanceId'";
  856. Database::query($sql);
  857. } else {
  858. // insert new result
  859. $sql = "INSERT INTO $tbl_attendance_result SET
  860. c_id = $course_id ,
  861. user_id = '$uid',
  862. attendance_id = '$attendanceId',
  863. score = '$count_presences'";
  864. Database::query($sql);
  865. $insertId = Database::insert_id();
  866. if ($insertId) {
  867. $sql = "UPDATE $tbl_attendance_result SET id = iid WHERE iid = $insertId";
  868. Database::query($sql);
  869. }
  870. }
  871. }
  872. }
  873. // update attendance qualify max
  874. $count_done_calendar = self::get_done_attendance_calendar($attendanceId);
  875. $sql = "UPDATE $tbl_attendance SET
  876. attendance_qualify_max = '$count_done_calendar'
  877. WHERE c_id = $course_id AND id = '$attendanceId'";
  878. Database::query($sql);
  879. }
  880. /**
  881. * update attendance_sheet_log table, is used as history of an attendance sheet.
  882. *
  883. * @param int Attendance id
  884. * @param string Last edit datetime
  885. * @param string Event type ('locked_attendance', 'done_attendance_sheet' ...)
  886. * @param int Last edit user id
  887. * @param string Calendar datetime value (optional, when event type is 'done_attendance_sheet')
  888. *
  889. * @return int Affected rows
  890. */
  891. public function saveAttendanceSheetLog(
  892. $attendanceId,
  893. $lastedit_date,
  894. $lastedit_type,
  895. $lastedit_user_id,
  896. $calendar_date_value = null
  897. ) {
  898. $course_id = api_get_course_int_id();
  899. // define table
  900. $tbl_attendance_sheet_log = Database::get_course_table(TABLE_ATTENDANCE_SHEET_LOG);
  901. // protect data
  902. $attendanceId = intval($attendanceId);
  903. $lastedit_user_id = intval($lastedit_user_id);
  904. if (isset($calendar_date_value)) {
  905. $calendar_date_value = $calendar_date_value;
  906. } else {
  907. $calendar_date_value = '';
  908. }
  909. // save data
  910. $params = [
  911. 'c_id' => $course_id,
  912. 'attendance_id' => $attendanceId,
  913. 'lastedit_date' => $lastedit_date,
  914. 'lastedit_type' => $lastedit_type,
  915. 'lastedit_user_id' => $lastedit_user_id,
  916. 'calendar_date_value' => $calendar_date_value,
  917. ];
  918. $insertId = Database::insert($tbl_attendance_sheet_log, $params);
  919. if ($insertId) {
  920. $sql = "UPDATE $tbl_attendance_sheet_log SET id = iid WHERE iid = $insertId";
  921. Database::query($sql);
  922. }
  923. return $insertId;
  924. }
  925. /**
  926. * Get number of done attendances inside current sheet.
  927. *
  928. * @param int attendance id
  929. *
  930. * @return int number of done attendances
  931. */
  932. public static function get_done_attendance_calendar($attendanceId)
  933. {
  934. $table = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  935. $attendanceId = intval($attendanceId);
  936. $course_id = api_get_course_int_id();
  937. $sql = "SELECT count(done_attendance) as count
  938. FROM $table
  939. WHERE
  940. c_id = $course_id AND
  941. attendance_id = '$attendanceId' AND
  942. done_attendance = 1
  943. ";
  944. $rs = Database::query($sql);
  945. $row = Database::fetch_array($rs);
  946. $count = $row['count'];
  947. return $count;
  948. }
  949. /**
  950. * Get results of faults (absents) by user.
  951. *
  952. * @param int $user_id
  953. * @param int $attendanceId
  954. * @param int $groupId
  955. *
  956. * @return array results containing number of faults, total done attendance,
  957. * percent of faults and color depend on result (red, orange)
  958. */
  959. public function get_faults_of_user($user_id, $attendanceId, $groupId = null)
  960. {
  961. $user_id = intval($user_id);
  962. $attendanceId = intval($attendanceId);
  963. $results = [];
  964. $calendar_count = self::get_number_of_attendance_calendar(
  965. $attendanceId,
  966. $groupId,
  967. null,
  968. $user_id
  969. );
  970. // $total_done_attendance = $attendance_data['attendance_qualify_max'];
  971. $total_done_attendance = self::get_number_of_attendance_calendar(
  972. $attendanceId,
  973. $groupId,
  974. true,
  975. $user_id
  976. );
  977. $attendance_user_score = $this->get_user_score(
  978. $user_id,
  979. $attendanceId,
  980. $groupId
  981. );
  982. //This is the main change of the BT#1381
  983. //$total_done_attendance = $calendar_count;
  984. // calculate results
  985. $faults = $total_done_attendance - $attendance_user_score;
  986. if (empty($calendar_count)) {
  987. $faults = 0;
  988. }
  989. $faults = $faults > 0 ? $faults : 0;
  990. $faults_porcent = $calendar_count > 0 ? round(($faults * 100) / $calendar_count, 0) : 0;
  991. $results['faults'] = $faults;
  992. $results['total'] = $calendar_count;
  993. $results['faults_porcent'] = $faults_porcent;
  994. $color_bar = '';
  995. if ($faults_porcent > 25) {
  996. $color_bar = '#f28989';
  997. } elseif ($faults_porcent > 10) {
  998. $color_bar = '#F90';
  999. }
  1000. $results['color_bar'] = $color_bar;
  1001. return $results;
  1002. }
  1003. /**
  1004. * Get results of faults average for all courses by user.
  1005. *
  1006. * @param int $user_id
  1007. *
  1008. * @return array results containing number of faults, total done attendance,
  1009. * percentage of faults and color depend on result (red, orange)
  1010. */
  1011. public function get_faults_average_inside_courses($user_id)
  1012. {
  1013. // get all courses of current user
  1014. $courses = CourseManager::get_courses_list_by_user_id($user_id, true);
  1015. $user_id = intval($user_id);
  1016. $results = [];
  1017. $total_faults = $total_weight = $porcent = 0;
  1018. foreach ($courses as $course) {
  1019. //$course_code = $course['code'];
  1020. //$course_info = api_get_course_info($course_code);
  1021. $course_id = $course['real_id'];
  1022. $tbl_attendance_result = Database::get_course_table(TABLE_ATTENDANCE_RESULT);
  1023. $attendances_by_course = $this->get_attendances_list($course_id);
  1024. foreach ($attendances_by_course as $attendance) {
  1025. // get total faults and total weight
  1026. $total_done_attendance = $attendance['attendance_qualify_max'];
  1027. $sql = "SELECT score
  1028. FROM $tbl_attendance_result
  1029. WHERE
  1030. c_id = $course_id AND
  1031. user_id = $user_id AND
  1032. attendance_id = ".$attendance['id'];
  1033. $rs = Database::query($sql);
  1034. $score = 0;
  1035. if (Database::num_rows($rs) > 0) {
  1036. $row = Database::fetch_array($rs);
  1037. $score = $row['score'];
  1038. }
  1039. $faults = $total_done_attendance - $score;
  1040. $faults = $faults > 0 ? $faults : 0;
  1041. $total_faults += $faults;
  1042. $total_weight += $total_done_attendance;
  1043. }
  1044. }
  1045. $porcent = $total_weight > 0 ? round(($total_faults * 100) / $total_weight, 0) : 0;
  1046. $results['faults'] = $total_faults;
  1047. $results['total'] = $total_weight;
  1048. $results['porcent'] = $porcent;
  1049. return $results;
  1050. }
  1051. /**
  1052. * Get results of faults average by course.
  1053. *
  1054. * @param int $user_id
  1055. * @param string $course_code
  1056. * @param int Session id (optional)
  1057. *
  1058. * @return array results containing number of faults,
  1059. * total done attendance, porcent of faults and color depend on result (red, orange)
  1060. */
  1061. public function get_faults_average_by_course(
  1062. $user_id,
  1063. $course_code,
  1064. $session_id = null
  1065. ) {
  1066. // Database tables and variables
  1067. $course_info = api_get_course_info($course_code);
  1068. $tbl_attendance_result = Database::get_course_table(TABLE_ATTENDANCE_RESULT);
  1069. $user_id = intval($user_id);
  1070. $results = [];
  1071. $total_faults = $total_weight = $porcent = 0;
  1072. $attendances_by_course = $this->get_attendances_list(
  1073. $course_info['real_id'],
  1074. $session_id
  1075. );
  1076. foreach ($attendances_by_course as $attendance) {
  1077. // Get total faults and total weight
  1078. $total_done_attendance = $attendance['attendance_qualify_max'];
  1079. $sql = "SELECT score FROM $tbl_attendance_result
  1080. WHERE
  1081. c_id = {$course_info['real_id']} AND
  1082. user_id = $user_id AND
  1083. attendance_id=".$attendance['id'];
  1084. $rs = Database::query($sql);
  1085. $score = 0;
  1086. if (Database::num_rows($rs) > 0) {
  1087. $row = Database::fetch_array($rs);
  1088. $score = $row['score'];
  1089. }
  1090. $faults = $total_done_attendance - $score;
  1091. $faults = $faults > 0 ? $faults : 0;
  1092. $total_faults += $faults;
  1093. $total_weight += $total_done_attendance;
  1094. }
  1095. $porcent = $total_weight > 0 ? round(($total_faults * 100) / $total_weight, 0) : 0;
  1096. $results['faults'] = $total_faults;
  1097. $results['total'] = $total_weight;
  1098. $results['porcent'] = $porcent;
  1099. return $results;
  1100. }
  1101. /**
  1102. * Get registered users' attendance sheet inside current course.
  1103. *
  1104. * @param int $attendanceId
  1105. * @param int $user_id for showing data for only one user (optional)
  1106. * @param int $groupId
  1107. *
  1108. * @return array users attendance sheet data
  1109. */
  1110. public function get_users_attendance_sheet(
  1111. $attendanceId,
  1112. $user_id = 0,
  1113. $groupId = 0
  1114. ) {
  1115. $tbl_attendance_sheet = Database::get_course_table(TABLE_ATTENDANCE_SHEET);
  1116. $tbl_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1117. $attendance_calendar = $this->get_attendance_calendar(
  1118. $attendanceId,
  1119. 'all',
  1120. null,
  1121. $groupId
  1122. );
  1123. $calendar_ids = [];
  1124. // get all dates from calendar by current attendance
  1125. foreach ($attendance_calendar as $cal) {
  1126. $calendar_ids[] = $cal['id'];
  1127. }
  1128. $course_id = api_get_course_int_id();
  1129. $data = [];
  1130. if (empty($user_id)) {
  1131. // get all registered users inside current course
  1132. $users = $this->get_users_rel_course();
  1133. $user_ids = array_keys($users);
  1134. if (count($calendar_ids) > 0 && count($user_ids) > 0) {
  1135. foreach ($user_ids as $uid) {
  1136. $uid = (int) $uid;
  1137. $sql = "SELECT * FROM $tbl_attendance_sheet
  1138. WHERE
  1139. c_id = $course_id AND
  1140. user_id = '$uid' AND
  1141. attendance_calendar_id IN(".implode(',', $calendar_ids).")
  1142. ";
  1143. $res = Database::query($sql);
  1144. if (Database::num_rows($res) > 0) {
  1145. while ($row = Database::fetch_array($res)) {
  1146. $data[$uid][$row['attendance_calendar_id']]['presence'] = $row['presence'];
  1147. }
  1148. }
  1149. }
  1150. }
  1151. } else {
  1152. // Get attendance for current user
  1153. $user_id = (int) $user_id;
  1154. if (count($calendar_ids) > 0) {
  1155. $sql = "SELECT cal.date_time, att.presence
  1156. FROM $tbl_attendance_sheet att
  1157. INNER JOIN $tbl_attendance_calendar cal
  1158. ON cal.id = att.attendance_calendar_id
  1159. WHERE
  1160. att.c_id = $course_id AND
  1161. cal.c_id = $course_id AND
  1162. att.user_id = '$user_id' AND
  1163. att.attendance_calendar_id IN (".implode(',', $calendar_ids).")
  1164. ORDER BY date_time";
  1165. $res = Database::query($sql);
  1166. if (Database::num_rows($res) > 0) {
  1167. while ($row = Database::fetch_array($res)) {
  1168. $row['date_time'] = api_convert_and_format_date($row['date_time'], null, date_default_timezone_get());
  1169. $data[$user_id][] = $row;
  1170. }
  1171. }
  1172. }
  1173. }
  1174. return $data;
  1175. }
  1176. /**
  1177. * Get next attendance calendar without presences (done attendances).
  1178. *
  1179. * @param int attendance id
  1180. *
  1181. * @return int attendance calendar id
  1182. */
  1183. public function get_next_attendance_calendar_id($attendanceId)
  1184. {
  1185. $table = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1186. $attendanceId = (int) $attendanceId;
  1187. $course_id = api_get_course_int_id();
  1188. $sql = "SELECT id FROM $table
  1189. WHERE
  1190. c_id = $course_id AND
  1191. attendance_id = '$attendanceId' AND
  1192. done_attendance = 0
  1193. ORDER BY date_time
  1194. LIMIT 1";
  1195. $rs = Database::query($sql);
  1196. $next_calendar_id = 0;
  1197. if (Database::num_rows($rs) > 0) {
  1198. $row = Database::fetch_array($rs);
  1199. $next_calendar_id = $row['id'];
  1200. }
  1201. return $next_calendar_id;
  1202. }
  1203. /**
  1204. * Get next attendance calendar datetime without presences (done attendances).
  1205. *
  1206. * @param int attendance id
  1207. *
  1208. * @return int UNIX time format datetime
  1209. */
  1210. public function getNextAttendanceCalendarDatetime($attendanceId)
  1211. {
  1212. $table = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1213. $course_id = api_get_course_int_id();
  1214. $attendanceId = (int) $attendanceId;
  1215. $sql = "SELECT id, date_time FROM $table
  1216. WHERE
  1217. c_id = $course_id AND
  1218. attendance_id = '$attendanceId' AND
  1219. done_attendance = 0
  1220. ORDER BY date_time
  1221. LIMIT 1";
  1222. $rs = Database::query($sql);
  1223. $next_calendar_datetime = 0;
  1224. if (Database::num_rows($rs) > 0) {
  1225. $row = Database::fetch_array($rs);
  1226. $next_calendar_datetime = api_get_local_time($row['date_time']);
  1227. }
  1228. return $next_calendar_datetime;
  1229. }
  1230. /**
  1231. * Get user's score from current attendance.
  1232. *
  1233. * @param int $user_id
  1234. * @param int $attendanceId
  1235. * @param int $groupId
  1236. *
  1237. * @return int score
  1238. */
  1239. public function get_user_score($user_id, $attendanceId, $groupId = 0)
  1240. {
  1241. $tbl_attendance_result = Database::get_course_table(TABLE_ATTENDANCE_RESULT);
  1242. $tbl_attendance_sheet = Database::get_course_table(TABLE_ATTENDANCE_SHEET);
  1243. $tbl_attendance_cal_rel_group = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR_REL_GROUP);
  1244. $tbl_attendance_cal = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1245. $user_id = intval($user_id);
  1246. $attendanceId = intval($attendanceId);
  1247. $groupId = (int) $groupId;
  1248. $course_id = api_get_course_int_id();
  1249. if (empty($groupId)) {
  1250. $sql = "SELECT score FROM $tbl_attendance_result
  1251. WHERE
  1252. c_id = $course_id AND
  1253. user_id='$user_id' AND
  1254. attendance_id='$attendanceId'";
  1255. } else {
  1256. $sql = "SELECT count(presence) as score FROM $tbl_attendance_sheet
  1257. WHERE
  1258. c_id = $course_id AND
  1259. user_id='$user_id' AND
  1260. presence = 1 AND
  1261. attendance_calendar_id IN (
  1262. SELECT calendar_id FROM $tbl_attendance_cal_rel_group crg
  1263. INNER JOIN $tbl_attendance_cal c
  1264. ON (crg.calendar_id = c.id)
  1265. WHERE
  1266. crg.c_id = $course_id AND
  1267. crg.group_id = $groupId AND
  1268. c.attendance_id = $attendanceId
  1269. )
  1270. ";
  1271. }
  1272. $rs = Database::query($sql);
  1273. $score = 0;
  1274. if (Database::num_rows($rs) > 0) {
  1275. $row = Database::fetch_array($rs);
  1276. $score = $row['score'];
  1277. }
  1278. return $score;
  1279. }
  1280. /**
  1281. * Get attendance calendar data by id.
  1282. *
  1283. * @param int attendance calendar id
  1284. *
  1285. * @return array attendance calendar data
  1286. */
  1287. public function get_attendance_calendar_by_id($calendar_id)
  1288. {
  1289. $table = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1290. $calendar_id = intval($calendar_id);
  1291. $course_id = api_get_course_int_id();
  1292. $sql = "SELECT * FROM $table
  1293. WHERE c_id = $course_id AND id = '$calendar_id' ";
  1294. $rs = Database::query($sql);
  1295. $data = [];
  1296. if (Database::num_rows($rs) > 0) {
  1297. while ($row = Database::fetch_array($rs)) {
  1298. $row['date_time'] = api_get_local_time($row['date_time']);
  1299. $data = $row;
  1300. }
  1301. }
  1302. return $data;
  1303. }
  1304. /**
  1305. * Get all attendance calendar data inside current attendance.
  1306. *
  1307. * @param int $attendanceId
  1308. * @param string $type
  1309. * @param int $calendar_id
  1310. * @param int $groupId
  1311. * @param bool $showAll = false show group calendar items or not
  1312. *
  1313. * @return array attendance calendar data
  1314. */
  1315. public function get_attendance_calendar(
  1316. $attendanceId,
  1317. $type = 'all',
  1318. $calendar_id = null,
  1319. $groupId = 0,
  1320. $showAll = false
  1321. ) {
  1322. $tbl_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1323. $tbl_acrg = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR_REL_GROUP);
  1324. $attendanceId = intval($attendanceId);
  1325. $course_id = api_get_course_int_id();
  1326. if ($showAll) {
  1327. $sql = "SELECT * FROM $tbl_attendance_calendar c
  1328. WHERE c_id = $course_id AND attendance_id = '$attendanceId'";
  1329. } else {
  1330. $sql = "SELECT * FROM $tbl_attendance_calendar c
  1331. WHERE
  1332. c_id = $course_id AND
  1333. attendance_id = '$attendanceId' AND
  1334. id NOT IN (
  1335. SELECT calendar_id FROM $tbl_acrg
  1336. WHERE c_id = $course_id AND group_id != 0 AND group_id IS NOT NULL
  1337. )
  1338. ";
  1339. }
  1340. if (!empty($groupId)) {
  1341. $groupId = intval($groupId);
  1342. $sql = "SELECT c.* FROM $tbl_attendance_calendar c
  1343. INNER JOIN $tbl_acrg g
  1344. ON c.c_id = g.c_id AND c.id = g.calendar_id
  1345. WHERE
  1346. c.c_id = $course_id AND
  1347. g.group_id = '$groupId' AND
  1348. c.attendance_id = '$attendanceId'
  1349. ";
  1350. }
  1351. if (!in_array($type, ['today', 'all', 'all_done', 'all_not_done', 'calendar_id'])) {
  1352. $type = 'all';
  1353. }
  1354. switch ($type) {
  1355. case 'calendar_id':
  1356. $calendar_id = intval($calendar_id);
  1357. if (!empty($calendar_id)) {
  1358. $sql .= " AND c.id = $calendar_id";
  1359. }
  1360. break;
  1361. case 'today':
  1362. //$sql .= ' AND DATE_FORMAT(date_time,"%d-%m-%Y") = DATE_FORMAT("'.api_get_utc_datetime().'", "%d-%m-%Y" )';
  1363. break;
  1364. case 'all_done':
  1365. $sql .= " AND done_attendance = 1 ";
  1366. break;
  1367. case 'all_not_done':
  1368. $sql .= " AND done_attendance = 0 ";
  1369. break;
  1370. case 'all':
  1371. default:
  1372. break;
  1373. }
  1374. $sql .= " ORDER BY date_time ";
  1375. $rs = Database::query($sql);
  1376. $data = [];
  1377. if (Database::num_rows($rs) > 0) {
  1378. while ($row = Database::fetch_array($rs, 'ASSOC')) {
  1379. $row['db_date_time'] = $row['date_time'];
  1380. $row['date_time'] = api_get_local_time($row['date_time']);
  1381. $row['date'] = api_format_date($row['date_time'], DATE_FORMAT_SHORT);
  1382. $row['time'] = api_format_date($row['date_time'], TIME_NO_SEC_FORMAT);
  1383. $row['groups'] = $this->getGroupListByAttendanceCalendar($row['id'], $course_id);
  1384. if ($type == 'today') {
  1385. if (date('d-m-Y', api_strtotime($row['date_time'], 'UTC')) == date('d-m-Y', time())) {
  1386. $data[] = $row;
  1387. }
  1388. } else {
  1389. $data[] = $row;
  1390. }
  1391. }
  1392. }
  1393. return $data;
  1394. }
  1395. /**
  1396. * Get number of attendance calendar inside current attendance.
  1397. *
  1398. * @param int $attendanceId
  1399. * @param int $groupId
  1400. * @param $done_attendance
  1401. * @param int $userId
  1402. *
  1403. * @return int number of dates in attendance calendar
  1404. */
  1405. public static function get_number_of_attendance_calendar(
  1406. $attendanceId,
  1407. $groupId = 0,
  1408. $done_attendance = null,
  1409. $userId = 0
  1410. ) {
  1411. $tbl_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1412. $calendarRelGroup = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR_REL_GROUP);
  1413. $tbl_groupRelUser = Database::get_course_table(TABLE_GROUP_USER);
  1414. $attendanceId = intval($attendanceId);
  1415. $groupId = intval($groupId);
  1416. $course_id = api_get_course_int_id();
  1417. $where_attendance = '';
  1418. if ($done_attendance) {
  1419. $where_attendance = ' done_attendance = 1 AND ';
  1420. }
  1421. if (empty($userId)) {
  1422. if (empty($groupId)) {
  1423. $sql = "SELECT count(a.id)
  1424. FROM $tbl_attendance_calendar a
  1425. WHERE
  1426. c_id = $course_id AND
  1427. $where_attendance
  1428. attendance_id = '$attendanceId' AND
  1429. id NOT IN (
  1430. SELECT calendar_id FROM $calendarRelGroup
  1431. WHERE
  1432. c_id = $course_id AND
  1433. group_id != 0 AND
  1434. group_id IS NOT NULL
  1435. )
  1436. ";
  1437. } else {
  1438. $sql = "SELECT count(a.id)
  1439. FROM $tbl_attendance_calendar a
  1440. INNER JOIN $calendarRelGroup g
  1441. ON (a.id = g.calendar_id AND a.c_id = g.c_id)
  1442. WHERE
  1443. a.c_id = $course_id AND
  1444. $where_attendance
  1445. attendance_id = '$attendanceId' AND
  1446. group_id = $groupId
  1447. ";
  1448. }
  1449. } else {
  1450. if (empty($groupId)) {
  1451. $sql = "SELECT count(a.id)
  1452. FROM $tbl_attendance_calendar a
  1453. WHERE
  1454. c_id = $course_id AND
  1455. $where_attendance
  1456. attendance_id = '$attendanceId' AND
  1457. id NOT IN (
  1458. SELECT calendar_id FROM $calendarRelGroup
  1459. WHERE
  1460. c_id = $course_id AND
  1461. group_id != 0 AND
  1462. group_id IS NOT NULL AND
  1463. group_id NOT IN (
  1464. SELECT group_id
  1465. FROM $tbl_groupRelUser
  1466. WHERE user_id = $userId
  1467. )
  1468. )
  1469. ";
  1470. } else {
  1471. $sql = "SELECT count(a.id)
  1472. FROM $tbl_attendance_calendar a
  1473. INNER JOIN $calendarRelGroup g
  1474. ON (a.id = g.calendar_id AND a.c_id = g.c_id)
  1475. WHERE
  1476. a.c_id = $course_id AND
  1477. $where_attendance
  1478. attendance_id = '$attendanceId' AND
  1479. group_id = $groupId
  1480. ";
  1481. }
  1482. }
  1483. $rs = Database::query($sql);
  1484. $row = Database::fetch_row($rs);
  1485. $count = $row[0];
  1486. return $count;
  1487. }
  1488. /**
  1489. * Get count dates inside attendance calendar by attendance id.
  1490. *
  1491. * @param int $attendanceId
  1492. *
  1493. * @return int count of dates
  1494. */
  1495. public static function get_count_dates_inside_attendance_calendar($attendanceId)
  1496. {
  1497. $tbl_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1498. $attendanceId = intval($attendanceId);
  1499. $course_id = api_get_course_int_id();
  1500. $sql = "SELECT count(id) FROM $tbl_attendance_calendar
  1501. WHERE
  1502. c_id = $course_id AND
  1503. attendance_id = '$attendanceId'";
  1504. $rs = Database::query($sql);
  1505. $count = 0;
  1506. if (Database::num_rows($rs) > 0) {
  1507. $row = Database::fetch_row($rs);
  1508. $count = $row[0];
  1509. }
  1510. return $count;
  1511. }
  1512. /**
  1513. * check if all calendar of an attendance is done.
  1514. *
  1515. * @param int $attendanceId
  1516. *
  1517. * @return bool True if all calendar is done, otherwise false
  1518. */
  1519. public static function is_all_attendance_calendar_done($attendanceId)
  1520. {
  1521. $attendanceId = (int) $attendanceId;
  1522. $done_calendar = self::get_done_attendance_calendar($attendanceId);
  1523. $count_dates_in_calendar = self::get_count_dates_inside_attendance_calendar($attendanceId);
  1524. $number_of_dates = self::get_number_of_attendance_calendar($attendanceId);
  1525. $result = false;
  1526. if ($number_of_dates && intval($count_dates_in_calendar) == intval($done_calendar)) {
  1527. $result = true;
  1528. }
  1529. return $result;
  1530. }
  1531. /**
  1532. * check if an attendance is locked.
  1533. *
  1534. * @param int $attendanceId
  1535. * @param bool
  1536. *
  1537. * @return bool
  1538. */
  1539. public static function is_locked_attendance($attendanceId)
  1540. {
  1541. // Use gradebook lock
  1542. $result = api_resource_is_locked_by_gradebook($attendanceId, LINK_ATTENDANCE);
  1543. return $result;
  1544. }
  1545. /**
  1546. * Add new datetime inside attendance calendar table.
  1547. *
  1548. * @param int $attendanceId
  1549. * @param array $groupList
  1550. *
  1551. * @return int affected rows
  1552. */
  1553. public function attendance_calendar_add($attendanceId, $groupList = [])
  1554. {
  1555. $tbl_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1556. $affected_rows = 0;
  1557. $attendanceId = intval($attendanceId);
  1558. $course_id = api_get_course_int_id();
  1559. // check if datetime already exists inside the table
  1560. /*$sql = "SELECT id FROM $tbl_attendance_calendar
  1561. WHERE
  1562. c_id = $course_id AND
  1563. date_time='".Database::escape_string($this->date_time)."' AND
  1564. attendance_id = '$attendanceId'";
  1565. $rs = Database::query($sql);
  1566. if (Database::num_rows($rs) == 0) {*/
  1567. $params = [
  1568. 'c_id' => $course_id,
  1569. 'date_time' => $this->date_time,
  1570. 'attendance_id' => $attendanceId,
  1571. 'done_attendance' => 0,
  1572. ];
  1573. $id = Database::insert($tbl_attendance_calendar, $params);
  1574. if ($id) {
  1575. $sql = "UPDATE $tbl_attendance_calendar SET id = iid WHERE iid = $id";
  1576. Database::query($sql);
  1577. $affected_rows++;
  1578. }
  1579. $this->addAttendanceCalendarToGroup($id, $course_id, $groupList);
  1580. //}
  1581. // update locked attendance
  1582. $is_all_calendar_done = self::is_all_attendance_calendar_done($attendanceId);
  1583. if (!$is_all_calendar_done) {
  1584. self::lock_attendance($attendanceId, false);
  1585. } else {
  1586. self::lock_attendance($attendanceId);
  1587. }
  1588. return $affected_rows;
  1589. }
  1590. /**
  1591. * @param int $calendarId
  1592. * @param int $courseId
  1593. * @param array $groupList
  1594. *
  1595. * @return bool
  1596. */
  1597. public function addAttendanceCalendarToGroup($calendarId, $courseId, $groupList)
  1598. {
  1599. if (empty($groupList)) {
  1600. return false;
  1601. }
  1602. $table = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR_REL_GROUP);
  1603. foreach ($groupList as $groupId) {
  1604. if (empty($groupId)) {
  1605. continue;
  1606. }
  1607. $result = $this->getAttendanceCalendarGroup(
  1608. $calendarId,
  1609. $courseId,
  1610. $groupId
  1611. );
  1612. if (empty($result)) {
  1613. $params = [
  1614. 'calendar_id' => $calendarId,
  1615. 'c_id' => $courseId,
  1616. 'group_id' => $groupId,
  1617. ];
  1618. Database::insert($table, $params);
  1619. }
  1620. }
  1621. return true;
  1622. }
  1623. /**
  1624. * @param int $calendarId
  1625. * @param int $courseId
  1626. *
  1627. * @return array
  1628. */
  1629. public function getGroupListByAttendanceCalendar($calendarId, $courseId)
  1630. {
  1631. $table = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR_REL_GROUP);
  1632. return Database::select(
  1633. '*',
  1634. $table,
  1635. [
  1636. 'where' => [
  1637. 'calendar_id = ? AND c_id = ?' => [$calendarId, $courseId],
  1638. ],
  1639. ]
  1640. );
  1641. }
  1642. /**
  1643. * @param int $calendarId
  1644. * @param int $courseId
  1645. * @param int $groupId
  1646. *
  1647. * @return array
  1648. */
  1649. public function getAttendanceCalendarGroup($calendarId, $courseId, $groupId)
  1650. {
  1651. $table = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR_REL_GROUP);
  1652. return Database::select(
  1653. '*',
  1654. $table,
  1655. [
  1656. 'where' => [
  1657. 'calendar_id = ? AND c_id = ? AND group_id = ?' => [$calendarId, $courseId, $groupId],
  1658. ],
  1659. ]
  1660. );
  1661. }
  1662. /**
  1663. * @param int $calendarId
  1664. * @param int $courseId
  1665. */
  1666. public function deleteAttendanceCalendarGroup($calendarId, $courseId)
  1667. {
  1668. $table = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR_REL_GROUP);
  1669. Database::delete(
  1670. $table,
  1671. [
  1672. 'calendar_id = ? AND c_id = ?' => [$calendarId, $courseId],
  1673. ]
  1674. );
  1675. }
  1676. /**
  1677. * save repeated date inside attendance calendar table.
  1678. *
  1679. * @param int $attendanceId
  1680. * @param int $start_date start date in tms
  1681. * @param int $end_date end date in tms
  1682. * @param string $repeat_type daily, weekly, monthlyByDate
  1683. * @param array $groupList
  1684. */
  1685. public function attendance_repeat_calendar_add(
  1686. $attendanceId,
  1687. $start_date,
  1688. $end_date,
  1689. $repeat_type,
  1690. $groupList = []
  1691. ) {
  1692. $attendanceId = intval($attendanceId);
  1693. // save start date
  1694. $datetimezone = api_get_utc_datetime($start_date);
  1695. $this->set_date_time($datetimezone);
  1696. $this->attendance_calendar_add($attendanceId, $groupList);
  1697. // 86400 = 24 hours in seconds
  1698. // 604800 = 1 week in seconds
  1699. // Saves repeated dates
  1700. switch ($repeat_type) {
  1701. case 'daily':
  1702. $j = 1;
  1703. for ($i = $start_date + 86400; ($i <= $end_date); $i += 86400) {
  1704. $datetimezone = api_get_utc_datetime($i);
  1705. $this->set_date_time($datetimezone);
  1706. $this->attendance_calendar_add($attendanceId, $groupList);
  1707. $j++;
  1708. }
  1709. break;
  1710. case 'weekly':
  1711. $j = 1;
  1712. for ($i = $start_date + 604800; ($i <= $end_date); $i += 604800) {
  1713. $datetimezone = api_get_utc_datetime($i);
  1714. $this->set_date_time($datetimezone);
  1715. $this->attendance_calendar_add($attendanceId, $groupList);
  1716. $j++;
  1717. }
  1718. break;
  1719. case 'monthlyByDate':
  1720. $j = 1;
  1721. //@todo fix bug with february
  1722. for ($i = $start_date + 2419200; ($i <= $end_date); $i += 2419200) {
  1723. $datetimezone = api_get_utc_datetime($i);
  1724. $this->set_date_time($datetimezone);
  1725. $this->attendance_calendar_add($attendanceId, $groupList);
  1726. $j++;
  1727. }
  1728. break;
  1729. }
  1730. }
  1731. /**
  1732. * edit a datetime inside attendance calendar table.
  1733. *
  1734. * @param int attendance calendar id
  1735. * @param int attendance id
  1736. *
  1737. * @return int affected rows
  1738. */
  1739. public function attendance_calendar_edit($calendar_id, $attendanceId)
  1740. {
  1741. $tbl_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1742. $affected_rows = 0;
  1743. $attendanceId = intval($attendanceId);
  1744. $course_id = api_get_course_int_id();
  1745. // check if datetime already exists inside the table
  1746. $sql = "SELECT id FROM $tbl_attendance_calendar
  1747. WHERE
  1748. c_id = $course_id AND
  1749. date_time = '".Database::escape_string($this->date_time)."' AND
  1750. attendance_id = '$attendanceId'";
  1751. $rs = Database::query($sql);
  1752. if (Database::num_rows($rs) == 0) {
  1753. $sql = "UPDATE $tbl_attendance_calendar
  1754. SET date_time='".Database::escape_string($this->date_time)."'
  1755. WHERE c_id = $course_id AND id = '".intval($calendar_id)."'";
  1756. Database::query($sql);
  1757. }
  1758. // update locked attendance
  1759. $is_all_calendar_done = self::is_all_attendance_calendar_done($attendanceId);
  1760. if (!$is_all_calendar_done) {
  1761. self::lock_attendance($attendanceId, false);
  1762. } else {
  1763. self::lock_attendance($attendanceId);
  1764. }
  1765. return $affected_rows;
  1766. }
  1767. /**
  1768. * delete a datetime from attendance calendar table.
  1769. *
  1770. * @param int attendance calendar id
  1771. * @param int attendance id
  1772. * @param bool true for removing all calendar inside current attendance, false for removing by calendar id
  1773. *
  1774. * @return int affected rows
  1775. */
  1776. public function attendance_calendar_delete(
  1777. $calendar_id,
  1778. $attendanceId,
  1779. $all_delete = false
  1780. ) {
  1781. $tbl_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
  1782. $tbl_attendance_sheet = Database::get_course_table(TABLE_ATTENDANCE_SHEET);
  1783. $attendanceId = intval($attendanceId);
  1784. $calendar_id = (int) $calendar_id;
  1785. // get all registered users inside current course
  1786. $users = $this->get_users_rel_course();
  1787. $user_ids = array_keys($users);
  1788. $course_id = api_get_course_int_id();
  1789. $affected_rows = 0;
  1790. if ($all_delete) {
  1791. $attendance_calendar = $this->get_attendance_calendar($attendanceId);
  1792. // get all dates from calendar by current attendance
  1793. if (!empty($attendance_calendar)) {
  1794. foreach ($attendance_calendar as $cal) {
  1795. // delete all data from attendance sheet
  1796. $sql = "DELETE FROM $tbl_attendance_sheet
  1797. WHERE c_id = $course_id AND attendance_calendar_id = '".intval($cal['id'])."'";
  1798. Database::query($sql);
  1799. // delete data from attendance calendar
  1800. $sql = "DELETE FROM $tbl_attendance_calendar
  1801. WHERE c_id = $course_id AND id = '".intval($cal['id'])."'";
  1802. Database::query($sql);
  1803. $this->deleteAttendanceCalendarGroup($cal['id'], $course_id);
  1804. $affected_rows++;
  1805. }
  1806. }
  1807. } else {
  1808. // delete just one row from attendance sheet by the calendar id
  1809. $sql = "DELETE FROM $tbl_attendance_sheet
  1810. WHERE c_id = $course_id AND attendance_calendar_id = '".$calendar_id."'";
  1811. Database::query($sql);
  1812. // delete data from attendance calendar
  1813. $sql = "DELETE FROM $tbl_attendance_calendar
  1814. WHERE c_id = $course_id AND id = '".$calendar_id."'";
  1815. Database::query($sql);
  1816. $this->deleteAttendanceCalendarGroup($calendar_id, $course_id);
  1817. $affected_rows++;
  1818. }
  1819. // update users' results
  1820. $this->updateUsersResults($user_ids, $attendanceId);
  1821. return $affected_rows;
  1822. }
  1823. public function set_session_id($sessionId)
  1824. {
  1825. $this->session_id = $sessionId;
  1826. }
  1827. public function set_course_id($course_id)
  1828. {
  1829. $this->course_id = $course_id;
  1830. }
  1831. public function set_date_time($datetime)
  1832. {
  1833. $this->date_time = $datetime;
  1834. }
  1835. public function set_name($name)
  1836. {
  1837. $this->name = $name;
  1838. }
  1839. public function set_description($description)
  1840. {
  1841. $this->description = $description;
  1842. }
  1843. public function set_attendance_qualify_title($attendance_qualify_title)
  1844. {
  1845. $this->attendance_qualify_title = $attendance_qualify_title;
  1846. }
  1847. public function set_attendance_weight($attendance_weight)
  1848. {
  1849. $this->attendance_weight = $attendance_weight;
  1850. }
  1851. /** Getters for fields of attendances tables */
  1852. public function get_session_id()
  1853. {
  1854. return $this->session_id;
  1855. }
  1856. public function get_course_id()
  1857. {
  1858. return $this->course_id;
  1859. }
  1860. public function get_date_time()
  1861. {
  1862. return $this->date_time;
  1863. }
  1864. public function get_name()
  1865. {
  1866. return $this->name;
  1867. }
  1868. public function get_description()
  1869. {
  1870. return $this->description;
  1871. }
  1872. public function get_attendance_qualify_title()
  1873. {
  1874. return $this->attendance_qualify_title;
  1875. }
  1876. public function get_attendance_weight()
  1877. {
  1878. return $this->attendance_weight;
  1879. }
  1880. /**
  1881. * @param string $startDate in UTC time
  1882. * @param string $endDate in UTC time
  1883. *
  1884. * @return array
  1885. */
  1886. public function getAttendanceLogin($startDate, $endDate)
  1887. {
  1888. if (empty($startDate) ||
  1889. $startDate == '0000-00-00' ||
  1890. $startDate == '0000-00-00 00:00:00' ||
  1891. empty($endDate) ||
  1892. $endDate == '0000-00-00' ||
  1893. $endDate == '0000-00-00 00:00:00'
  1894. ) {
  1895. return false;
  1896. }
  1897. $sessionId = api_get_session_id();
  1898. $courseCode = api_get_course_id();
  1899. $courseId = api_get_course_int_id();
  1900. if (!empty($sessionId)) {
  1901. $users = CourseManager::get_user_list_from_course_code(
  1902. $courseCode,
  1903. $sessionId,
  1904. '',
  1905. 'lastname',
  1906. 0
  1907. );
  1908. } else {
  1909. $users = CourseManager::get_user_list_from_course_code(
  1910. $courseCode,
  1911. 0,
  1912. '',
  1913. 'lastname',
  1914. STUDENT
  1915. );
  1916. }
  1917. $dateTimeStartOriginal = new DateTime($startDate);
  1918. $dateTimeStart = new DateTime($startDate);
  1919. $dateTimeEnd = new DateTime($endDate);
  1920. $interval = $dateTimeStart->diff($dateTimeEnd);
  1921. $days = intval($interval->format('%a'));
  1922. $dateList = [$dateTimeStart->format('Y-m-d')];
  1923. $headers = [
  1924. get_lang('User'),
  1925. $dateTimeStart->format('Y-m-d'),
  1926. ];
  1927. for ($i = 0; $i < $days; $i++) {
  1928. $dateTimeStart = $dateTimeStart->add(new DateInterval('P1D'));
  1929. $date = $dateTimeStart->format('Y-m-d');
  1930. $dateList[] = $date;
  1931. $headers[] = $date;
  1932. }
  1933. $accessData = CourseManager::getCourseAccessPerCourseAndSession(
  1934. $courseId,
  1935. $sessionId,
  1936. $dateTimeStartOriginal->format('Y-m-d H:i:s'),
  1937. $dateTimeEnd->format('Y-m-d H:i:s')
  1938. );
  1939. $results = [];
  1940. if (!empty($accessData)) {
  1941. foreach ($accessData as $data) {
  1942. $onlyDate = substr($data['login_course_date'], 0, 10);
  1943. $results[$data['user_id']][$onlyDate] = true;
  1944. }
  1945. }
  1946. return [
  1947. 'users' => $users,
  1948. 'dateList' => $dateList,
  1949. 'headers' => $headers,
  1950. 'results' => $results,
  1951. ];
  1952. }
  1953. /**
  1954. * @param string $startDate in UTC time
  1955. * @param string $endDate in UTC time
  1956. *
  1957. * @return string
  1958. */
  1959. public function getAttendanceLoginTable($startDate, $endDate)
  1960. {
  1961. $data = $this->getAttendanceLogin($startDate, $endDate);
  1962. if (!$data) {
  1963. return null;
  1964. }
  1965. $headers = $data['headers'];
  1966. $dateList = $data['dateList'];
  1967. $users = $data['users'];
  1968. $results = $data['results'];
  1969. $table = new HTML_Table(['class' => 'data_table']);
  1970. $row = 0;
  1971. $column = 0;
  1972. foreach ($headers as $header) {
  1973. $table->setHeaderContents($row, $column, $header);
  1974. $column++;
  1975. }
  1976. $row = 1;
  1977. foreach ($users as $user) {
  1978. $table->setCellContents(
  1979. $row,
  1980. 0,
  1981. $user['lastname'].' '.$user['firstname'].' ('.$user['username'].')'
  1982. );
  1983. $row++;
  1984. }
  1985. $column = 1;
  1986. $row = 1;
  1987. foreach ($users as $user) {
  1988. foreach ($dateList as $date) {
  1989. $status = null;
  1990. if (isset($results[$user['user_id']]) &&
  1991. isset($results[$user['user_id']][$date])
  1992. ) {
  1993. $status = 'X';
  1994. }
  1995. $table->setCellContents($row, $column, $status);
  1996. $column++;
  1997. }
  1998. $row++;
  1999. $column = 1;
  2000. }
  2001. return $table->toHtml();
  2002. }
  2003. /**
  2004. * @param string $startDate in UTC time
  2005. * @param string $endDate in UTC time
  2006. *
  2007. * @return string
  2008. */
  2009. public function exportAttendanceLogin($startDate, $endDate)
  2010. {
  2011. $data = $this->getAttendanceLogin($startDate, $endDate);
  2012. if (!$data) {
  2013. return null;
  2014. }
  2015. $users = $data['users'];
  2016. $results = $data['results'];
  2017. $table = new HTML_Table(['class' => 'data_table']);
  2018. $table->setHeaderContents(0, 0, get_lang('User'));
  2019. $table->setHeaderContents(0, 1, get_lang('Date'));
  2020. $row = 1;
  2021. foreach ($users as $user) {
  2022. $table->setCellContents(
  2023. $row,
  2024. 0,
  2025. $user['lastname'].' '.$user['firstname'].' ('.$user['username'].')'
  2026. );
  2027. $row++;
  2028. }
  2029. $table->setColAttributes(0, ['style' => 'width:28%']);
  2030. $row = 1;
  2031. foreach ($users as $user) {
  2032. if (isset($results[$user['user_id']]) &&
  2033. !empty($results[$user['user_id']])
  2034. ) {
  2035. $dates = implode(', ', array_keys($results[$user['user_id']]));
  2036. $table->setCellContents($row, 1, $dates);
  2037. }
  2038. $row++;
  2039. }
  2040. $tableToString = $table->toHtml();
  2041. $params = [
  2042. 'filename' => get_lang('Attendance').'_'.api_get_utc_datetime(),
  2043. 'pdf_title' => get_lang('Attendance'),
  2044. 'course_code' => api_get_course_id(),
  2045. 'show_real_course_teachers' => true,
  2046. ];
  2047. $pdf = new PDF('A4', null, $params);
  2048. $pdf->html_to_pdf_with_template($tableToString);
  2049. }
  2050. }