timesheet source code
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

466 linhas
16KB

  1. <?php
  2. /**
  3. * Plugin Name: Acare Advanced Office
  4. * Plugin URI: http://biukop.com.au/acaresydney/timesheets
  5. * Description: Advanced Office system, timesheet, Payroll for AcareSydney
  6. * Version: 2.1
  7. * Author: Biukop Intelligence
  8. * Author URI: http://biukop.com.au/
  9. */
  10. namespace Biukop;
  11. require_once(dirname(__FILE__) . '/autoload.php');
  12. require_once (ABSPATH . 'wp-includes/pluggable.php');
  13. class AcareOffice{
  14. private $nonce; //for ajax verification
  15. private $pages = array('time-sheets', 'user-list');
  16. private $acaresydney_userid = 0;
  17. private $xero ;
  18. private $db;
  19. private $table_name;
  20. public function __construct() {
  21. add_option( "acare_ts_db_version", "1.0" );
  22. register_activation_hook( __FILE__, array($this, 'db_install') );
  23. add_action('init', array($this, 'class_loader'));
  24. add_action('wp', array($this, 'check_auth'));
  25. add_action('wp_enqueue_scripts', array($this, 'register_js_css'), 99);
  26. add_filter('show_admin_bar', '__return_false');
  27. //ts-xx for sync single user
  28. add_shortcode( 'ts-sync-users', array($this, 'sync_users'));
  29. //bts-xx for webpage
  30. add_shortcode( 'bts_staff_item', array($this, 'bts_staff_item'));
  31. add_shortcode( 'bts_client_item', array($this, 'bts_client_item'));
  32. add_shortcode( 'bts_job_item', array($this, 'bts_job_item'));
  33. add_shortcode( 'bts_rate_options', array($this, 'bts_rate_options'));
  34. add_shortcode( 'bts_select_staff', array($this, 'bts_select_staff'));
  35. add_shortcode( 'bts_select_client', array($this, 'bts_select_client'));
  36. add_shortcode( 'bts_type_of_service', array($this, 'bts_type_of_service'));
  37. add_action('wp_ajax_list_staff', array($this,'list_staff' ));
  38. add_action('wp_ajax_list_client', array($this,'list_client' ));
  39. add_action('wp_ajax_save_job', array($this,'save_job' ));
  40. add_action('wp_ajax_list_job', array($this,'list_job' ));
  41. add_action('wp_ajax_delete_job', array($this,'delete_job' ));
  42. add_action('wp_ajax_earnings_rate', array($this,'get_payitem_earnings_rate' ));
  43. add_action('wp_ajax_nopriv_earnings_rate', array($this,'get_payitem_earnings_rate' ));
  44. global $wpdb;
  45. $this->db = $wpdb;
  46. $this->table_name = $wpdb->prefix . 'acare_ts';
  47. }
  48. /**
  49. * Autoload the custom theme classes
  50. */
  51. public function class_loader()
  52. {
  53. // Create a new instance of the autoloader
  54. $loader = new \Psr4AutoloaderClass();
  55. // Register this instance
  56. $loader->register();
  57. // Add our namespace and the folder it maps to
  58. $loader->addNamespace('\XeroPHP', dirname(__FILE__) . '/xero-php-master/src/XeroPHP');
  59. $loader->addNamespace('\Biukop', dirname(__FILE__) . '/' );
  60. $this->xero = new Xero();
  61. $this->xero->init_wp();
  62. }
  63. //init database
  64. public function db_install () {
  65. global $wpdb;
  66. $charset_collate = $wpdb->get_charset_collate();
  67. //table name: broker transactions
  68. $table_name = $this->table_name;
  69. $sql = "CREATE TABLE $table_name (
  70. id INT NOT NULL AUTO_INCREMENT,
  71. tos VARCHAR(45) NULL,
  72. start DATETIME NULL,
  73. finish DATETIME NULL,
  74. rate VARCHAR(45) NULL,
  75. staff VARCHAR(45) NULL,
  76. client VARCHAR(45) NULL,
  77. ack TINYINT(4) NULL,
  78. rating INT NULL DEFAULT 0,
  79. PRIMARY KEY (id)
  80. ) $charset_collate;";
  81. // $sql = "CREATE TABLE $table_name (
  82. // id int(64) NOT NULL AUTO_INCREMENT,
  83. // paid tinyint(4) DEFAULT NULL,
  84. // referal varchar(45) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL,
  85. // clientid int(64) NOT NULL,
  86. // loanamount float DEFAULT NULL,
  87. // settledate date DEFAULT NULL,
  88. // loanterm mediumint(10) DEFAULT NULL,
  89. // commissionrate float DEFAULT NULL,
  90. // commission float DEFAULT NULL,
  91. // trailrate float DEFAULT NULL,
  92. // trail float DEFAULT NULL,
  93. // paydate date DEFAULT NULL,
  94. // brokerid int(64) NOT NULL,
  95. // status tinyint(4) NOT NULL,
  96. // notes varchar(255) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL,
  97. // PRIMARY KEY (id)
  98. // ) $charset_collate;";
  99. //create database
  100. require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
  101. dbDelta( $sql );
  102. }
  103. //
  104. //
  105. ///check auth
  106. public function check_auth(){
  107. global $pagename;
  108. //echo $pagename;
  109. }
  110. ///
  111. // enqueue / register css /js
  112. //
  113. public function register_js_css() {
  114. $this->nonce = wp_create_nonce('acaresydney');
  115. $this->acaresydney_userid = get_query_var( 'acaresydney_userid' ) ;
  116. $this->register_bts_js();
  117. $this->register_timesheet_js_css();
  118. }
  119. private function register_bts_js()
  120. {
  121. wp_enqueue_style( 'bts', plugins_url('css/ts.css', __FILE__));
  122. wp_enqueue_script('bts', plugins_url('js/ts.js', __FILE__), array('jquery', 'jquery-ui-core'));
  123. wp_localize_script( 'bts', 'bts1', array(
  124. 'ajax_url' => admin_url( 'admin-ajax.php' ),
  125. 'nonce' => $this->nonce, // It is common practice to comma after
  126. 'display_name' => wp_get_current_user()->display_name,
  127. 'anonymous' => !is_user_logged_in(),
  128. 'me'=> get_current_user_id(),
  129. 'userid'=> $this->acaresydney_userid,
  130. 'load_user_img'=> plugins_url('img/loading_user.gif', __FILE__),
  131. ) );
  132. }
  133. private function register_timesheet_js_css(){
  134. global $pagename;
  135. if ($pagename != 'time-sheets'){
  136. return;
  137. }
  138. wp_enqueue_style( 'bts_ts', plugins_url('css/bts_timesheet.css', __FILE__));
  139. wp_enqueue_script( 'bts_ts', plugins_url('js/bts_timesheet.js', __FILE__), array( 'jquery' , 'bts' ));
  140. wp_enqueue_script('mustache', plugins_url('js/mustache.min.js', __FILE__), array('jquery'));
  141. }
  142. public function sync_users()
  143. {
  144. //dummy sync
  145. return;
  146. }
  147. // Usage: `wp sync_users --mininterval=123
  148. public function sync_user_cli($args = array(), $assoc_args = array()){
  149. $arguments = wp_parse_args( $assoc_args, array(
  150. 'mininterval' => 600,
  151. ) );
  152. $this->xero->sync_users($arguments['mininterval']);
  153. return;
  154. }
  155. public function bts_staff_item($attr){
  156. return $this->template('staff_item', 'staff.html');
  157. }
  158. public function bts_client_item($attr){
  159. return $this->template('client_item', 'client.html');
  160. }
  161. public function bts_job_item($attr){
  162. $html =$this->template('job_item', 'job.html');
  163. //$html = str_replace('[bts-tos-options]', $this->bts_tos_options([]), $html);
  164. $html = do_shortcode($html);
  165. return $html;
  166. }
  167. public function bts_rate_options($attr){
  168. $result = "<select> \n";
  169. $options = get_option('bts_payitem_earnings_rate');
  170. foreach($options as $o){
  171. $result.=sprintf("<option value='%s'> $%3.2f-%s</option>",
  172. $o['EarningsRateID'], $o['RatePerUnit'], $o['Name']);
  173. }
  174. $result .="</select>";
  175. return $result;
  176. }
  177. public function bts_select_staff($attr){
  178. $result = "<select> \n";
  179. $staff = $this->get_people_by_role('staff');
  180. foreach ($staff as $u){
  181. $result .= sprintf("<option value=%s> %s</option>", $u->user_login, $u->first_name . " " . $u->last_name);
  182. }
  183. $result .="</select>";
  184. return $result;
  185. }
  186. public function bts_select_client($attr){
  187. $result = "<select> \n";
  188. $staff = $this->get_people_by_role('client');
  189. foreach ($staff as $u){
  190. $result .= sprintf("<option value=%s> %s</option>", $u->user_login, $u->first_name . " " . $u->last_name);
  191. }
  192. $result .="</select>";
  193. return $result;
  194. }
  195. public function bts_type_of_service($attr){
  196. $result = ' <select>
  197. <option value="personalcare">Personal Care (stanard)</option>
  198. <option value="personalcare_h">Personal Care(Complex)</option>
  199. <option value="lunch">Lunch (stanard)</option>
  200. <option value="lunch_h">Lunch(Complex)</option>
  201. <option value="community">Community(stanard)</option>
  202. <option value="community_h">Community(Complex)</option>
  203. <option value="turn">Turn(stanard)</option>
  204. <option value="turn_h">Turn(Complex)</option>
  205. </select>
  206. ';
  207. return $result;
  208. }
  209. //generate template based on html file
  210. private function template($id, $file)
  211. {
  212. $text = '<script id="' . $id .'" type="text/x-biukop-template">';
  213. $text .= file_get_contents(plugin_dir_path(__FILE__) . "/html/$file");
  214. $text .= '</script>';
  215. return $text;
  216. }
  217. function list_staff(){
  218. check_ajax_referer('acaresydney');
  219. // Handle the ajax request
  220. $response = array(
  221. 'status' =>'error',
  222. 'users' => [],
  223. );
  224. //search all users that are staff
  225. $staffq = new \WP_User_Query(array('role'=>'staff','meta_key'=>'first_name', 'orderby'=>'meta_value', order=>'ASC'));
  226. $staff = $staffq->get_results();
  227. if (! empty($staff)){
  228. $response['status'] = 'success';
  229. foreach( $staff as $s){
  230. $response['users'][] = array(
  231. 'login' => $s->user_login,
  232. 'firstname'=> $s->first_name,
  233. 'lastname'=> $s->last_name,
  234. 'mobile'=> get_user_meta($s->ID, 'mobile', true),
  235. 'email'=> $s->user_email,
  236. 'wages'=> 0,
  237. 'hour' => 0 ,
  238. 'OT' => 0 ,
  239. 'petrol'=> 0 ,
  240. 'rating'=> 0,
  241. 'unconfirmedjob'=> 0,
  242. );
  243. }
  244. }
  245. wp_send_json($response);
  246. wp_die();
  247. }
  248. function list_client(){
  249. check_ajax_referer('acaresydney');
  250. // Handle the ajax request
  251. $response = array(
  252. 'status' =>'error',
  253. 'users' => [],
  254. );
  255. //search all users that are staff
  256. $clientq = new \WP_User_Query(array('role'=>'client', 'meta_key'=>'first_name', 'orderby'=>'meta_value', order=>'ASC'));
  257. $client = $clientq->get_results();
  258. if (! empty($client)){
  259. $response['status'] = 'success';
  260. foreach( $client as $s){
  261. $response['users'][] = array(
  262. 'login' => $s->user_login,
  263. 'firstname'=> $s->first_name,
  264. 'lastname'=> $s->last_name,
  265. 'mobile'=> get_user_meta($s->ID, 'mobile', true),
  266. 'email'=> $s->user_email,
  267. 'account'=> get_user_meta($s->ID, 'account', true),
  268. 'address' => get_user_meta($s->ID, 'address', true),
  269. 'rating'=> 0,
  270. 'unconfirmedjob'=> 0,
  271. );
  272. }
  273. }
  274. wp_send_json($response);
  275. wp_die();
  276. }
  277. private function get_people_by_role($role){
  278. //search all users that are staff
  279. $staffq = new \WP_User_Query(array('role'=>$role, 'meta_key'=>'first_name', 'orderby'=>'meta_value', order=>'ASC'));
  280. $staff = $staffq->get_results();
  281. return $staff;
  282. }
  283. //ajax get earnings rates
  284. function get_payitem_earnings_rate()
  285. {
  286. $response= array(
  287. 'status' => 'success',
  288. 'options'=> get_option('bts_payitem_earnings_rate'),
  289. );
  290. wp_send_json($response);
  291. }
  292. //ajax job CRUD
  293. function save_job()
  294. {
  295. check_ajax_referer('acaresydney');
  296. $r = $_POST['record'];
  297. $response = array();
  298. $d = array(
  299. 'tos' => $r['tos'],
  300. 'start' => $r['start'],
  301. 'finish' => $r['finish'],
  302. 'rate' => $r['rate'],
  303. 'staff' => $r['staff'],
  304. 'client' => $r['client'],
  305. 'ack' => $r['ack']=='true'?1:0,
  306. );
  307. //this is an update
  308. if ( isset($r['id']) && trim($r['id']) !='' && is_numeric($r['id'])){
  309. $response['isNew'] = false; //add or update?
  310. $result = $this->db->update($this->table_name, $d, array('id' =>$r['id']));
  311. if ($result !== false && $this->db->last_error == ''){
  312. $d['id'] = $r['id'];
  313. $response['status'] = 'success';
  314. //do data type conversion, string to int
  315. $response['newdata'] = $this->get_ts_record($r['id']);
  316. $response['errors'] = array(); //empty array
  317. }else{
  318. $response['status'] = 'error';
  319. $repsonse['errors'] = array(
  320. 'db' => "network database error" . $this->db->last_error,
  321. );
  322. }
  323. }else{
  324. $response['isNew'] = true;
  325. $result = $this->db->insert($this->table_name, $d);
  326. $lastid = $this->db->insert_id;
  327. if ($result != false && $this->db->last_error == ''){
  328. $response['status'] = 'success';
  329. $response['newdata'] = $this->get_ts_record($lastid);
  330. }else{
  331. $response['status'] = 'error';
  332. $response['errors'] = array(
  333. 'db' => 'network database error ' . $this->db->last_error,
  334. );
  335. }
  336. }
  337. wp_send_json($response);
  338. wp_die();
  339. }
  340. private function get_ts_record($id){
  341. $sql = "SELECT * FROM $this->table_name WHERE id=%d";
  342. $row = $this->db->get_row($this->db->prepare ($sql, array($id)));
  343. $response = [];
  344. if ($row != null){
  345. $response = array(
  346. 'id' => (int)$row->id,
  347. 'tos' => $row->tos,
  348. 'start' => $row->start,
  349. 'finish' => $row->finish,
  350. 'rate' => $row->rate,
  351. 'staff' => $row->staff,
  352. 'client' => $row->client,
  353. 'ack' => (int)$row->ack,
  354. 'rating' =>(int) $row->rating,
  355. );
  356. }
  357. return $response;
  358. }
  359. //ajax delete job
  360. function delete_job(){
  361. check_ajax_referer('acaresydney');
  362. $id = $_POST['recordid'];
  363. $result = $this->db->delete($this->table_name, array('id'=> $id));
  364. $response=array(
  365. 'status' => 'success',
  366. 'id' => $id,
  367. 'action'=> 'delete',
  368. 'error' => '',
  369. );
  370. if ($result == 1){
  371. wp_send_json($response);
  372. }else{
  373. $response['status'] = 'error';
  374. $response['error'] = $this->db->last_error;
  375. wp_send_json($response);
  376. }
  377. wp_die();
  378. }
  379. //ajax browse job with different filters
  380. function list_job(){
  381. check_ajax_referer('acaresydney');
  382. $start = $_POST['start'];
  383. $finish = $_POST['finish'];
  384. $response = array(
  385. 'status'=>'success',
  386. 'jobs' => [],
  387. );
  388. $sql = "SELECT * FROM $this->table_name WHERE start>='%s' and start <='%s'";
  389. $jobs = $this->db->get_results($this->db->prepare ($sql, array($start, $finish)));
  390. if (! empty($jobs)){
  391. $response['status'] = 'success';
  392. foreach( $jobs as $s){
  393. $response['jobs'][] = array(
  394. 'id' => $s->id,
  395. 'tos' => $s->tos,
  396. 'start'=> $s->start,
  397. 'finish'=> $s->finish,
  398. 'rate'=> $s->rate,
  399. 'staff'=> $s->staff,
  400. 'client'=> $s->client,
  401. 'ack' => $s->ack,
  402. );
  403. }
  404. }
  405. wp_send_json($response);
  406. wp_die();
  407. }
  408. }
  409. $bb = new AcareOffice();
  410. if ( defined( 'WP_CLI' ) && WP_CLI ) {
  411. \WP_CLI::add_command( 'sync_users', array($bb, 'sync_user_cli'));
  412. }