Last active
November 30, 2018 15:19
-
-
Save toofusan/44579c8e09c057b948b032e39a72dc41 to your computer and use it in GitHub Desktop.
freee APIを使ったVR勤怠打刻の実装例
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEngine; | |
using Freee; | |
public class FreeeEventHandler : MonoBehaviour { | |
Freee.Client client; | |
[SerializeField] private string appID; | |
[SerializeField] private string secret; | |
[SerializeField] private string redirectURL; | |
[SerializeField] private string authorization_code; | |
[SerializeField] private string company_name; | |
[SerializeField] private string employee_name; | |
private int company_id; | |
private int employee_id; | |
[SerializeField] private SystemMessageController _SystemMessageController; | |
[SerializeField] private TimeClocksController m_TimeClocksController; | |
private void Start () { | |
string refresh_token = PlayerPrefs.GetString("refresh_token", ""); | |
client = new Freee.Client(appID, secret, redirectURL); | |
if (string.IsNullOrEmpty(refresh_token)) { | |
Debug.Log("authorization_code"); | |
client.authorizationCode = authorization_code; | |
} else { | |
Debug.Log("refresh_token"); | |
client.refreshToken = refresh_token; | |
} | |
StartCoroutine(client.GenerateAccessToken(OnGenerateAccessToken)); | |
} | |
private void OnGenerateAccessToken(bool success, string response) { | |
if (!success) { | |
_SystemMessageController.ShowMessageWithSad(response); | |
return; | |
} | |
GetCompanies(); | |
} | |
void GetCompanies() { | |
StartCoroutine(client.Get("https://api.freee.co.jp/api/1/companies", new Dictionary<string, string>(), OnGetCompanies)); | |
} | |
void OnGetCompanies(bool success, string response) { | |
if (!success) { | |
string msg = JsonUtility.FromJson<Message>(response).message; | |
_SystemMessageController.ShowMessageWithSad(msg); | |
return; | |
} | |
Company[] companies = JsonUtility.FromJson<Companies>(response).companies; | |
var company = companies.First(c => c.display_name == company_name); | |
company_id = company.id; | |
GetLoginUser(); | |
} | |
void GetLoginUser() { | |
string employee_endpoint = "https://api.freee.co.jp/hr/api/v1/users/me"; | |
StartCoroutine(client.Get(employee_endpoint, new Dictionary<string, string>(), OnGetLoginUser)); | |
} | |
private void OnGetLoginUser(bool success, string response) { | |
if (!success) { | |
string msg = JsonUtility.FromJson<Message>(response).message; | |
_SystemMessageController.ShowMessageWithSad(msg); | |
return; | |
} | |
LoginUserCompany[] companies = JsonUtility.FromJson<LoginUser>(response).companies; | |
var company = companies.First(e => e.id == company_id); | |
employee_id = company.employee_id; | |
GetTimeClocksAvailableTypes(); | |
} | |
private void GetTimeClocksAvailableTypes() { | |
string endpoint = "https://api.freee.co.jp/hr/api/v1/employees/" + employee_id + "/time_clocks/available_types"; | |
Dictionary<string, string> parameter = new Dictionary<string, string> { | |
{"company_id", company_id.ToString()} | |
}; | |
StartCoroutine(client.Get(endpoint, parameter, OnGetTimeClocksAvailableTypes)); | |
} | |
void OnGetTimeClocksAvailableTypes(bool success, string response) { | |
if (!success) { | |
string msg = JsonUtility.FromJson<Message>(response).message; | |
_SystemMessageController.ShowMessageWithSad(msg); | |
return; | |
} | |
string[] available_types = JsonUtility.FromJson<TimeClocksAvailableTypes>(response).available_types; | |
m_TimeClocksController.SetAvailableTypes(available_types); | |
GetTimeClocks(); | |
} | |
private void GetTimeClocks() { | |
string endpoint = "https://api.freee.co.jp/hr/api/v1/employees/" + employee_id + "/time_clocks"; | |
Dictionary<string, string> parameter = new Dictionary<string, string> { | |
{"company_id", company_id.ToString()}, | |
{"from_date", DateTime.Now.ToString("yyyy-MM-dd")}, | |
{"to_date", DateTime.Now.ToString("yyyy-MM-dd")} | |
}; | |
StartCoroutine(client.Get(endpoint, parameter, OnGetTimeClocks)); | |
} | |
private void OnGetTimeClocks(bool success, string response) { | |
if (!success) { | |
string msg = JsonUtility.FromJson<Message>(response).message; | |
_SystemMessageController.ShowMessageWithSad(msg); | |
return; | |
} | |
TimeClock[] timeClocks = JsonUtility.FromJson<TimeClocksResponse>(response).items; | |
m_TimeClocksController.SetTimeClocksInfo(timeClocks); | |
} | |
public void PostTimeClocks(string type) { | |
string endpoint = "https://api.freee.co.jp/hr/api/v1/employees/" + employee_id + "/time_clocks"; | |
string p = TimeClockRequestJson(type, DateTime.Now); | |
StartCoroutine(client.Post(endpoint, p, OnPostTimeClocks)); | |
} | |
void OnPostTimeClocks(bool success, string response) { | |
if (!success) { | |
string msg = JsonUtility.FromJson<Message>(response).message; | |
_SystemMessageController.ShowMessageWithSad(msg); | |
return; | |
} | |
TimeClock tc = JsonUtility.FromJson<PostTimeClocksResponse>(response).employee_time_clock; | |
switch(tc.type) { | |
case "clock_in": | |
_SystemMessageController.ShowMessageWithSmile("出勤しました\n今日も一日頑張ろう!"); | |
break; | |
case "break_begin": | |
_SystemMessageController.ShowMessageWithSmile("休憩を開始したよ\nゆっくり休んでね"); | |
break; | |
case "break_end": | |
_SystemMessageController.ShowMessageWithSmile("休憩は終わりだよ\nもう一息がんばろう!"); | |
break; | |
case "clock_out": | |
_SystemMessageController.ShowMessageWithSmile("退勤しました\nおつかれさま!", true); | |
break; | |
} | |
GetTimeClocksAvailableTypes(); | |
} | |
private string TimeClockRequestJson(string type, DateTime dt) | |
{ | |
TimeClockRequest r = new TimeClockRequest(); | |
r.company_id = company_id; | |
r.type = type; | |
r.base_date = dt.ToString("yyyy-MM-dd"); | |
return JsonUtility.ToJson(r); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class Gazable : MonoBehaviour { | |
protected bool m_IsGazed {get; set;} | |
virtual public void GazeBegin() | |
{ | |
m_IsGazed = true; | |
} | |
virtual public void GazeComplete() | |
{ | |
} | |
virtual public void GazeEnd() | |
{ | |
m_IsGazed = false; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.UI; | |
public class GazableUnitychan : Gazable { | |
[SerializeField] private TimeClocksController m_TimeClockController; | |
[SerializeField] private SphereCollider m_Collider; | |
[SerializeField] private Slider m_Slider; | |
private CanvasGroup m_SliderCanvasGroup; | |
private RectTransform m_SliderRectTransform; | |
private bool gazeCompleted; | |
private void Awake() { | |
m_SliderCanvasGroup = m_Slider.gameObject.GetComponent<CanvasGroup>(); | |
m_SliderRectTransform = m_Slider.GetComponent<RectTransform>(); | |
} | |
void Update() | |
{ | |
if (m_IsGazed) | |
{ | |
m_Slider.value += 0.008f; | |
if (m_Slider.value >= 1f && !gazeCompleted) | |
{ | |
gazeCompleted = true; | |
GazeComplete(); | |
} | |
} | |
if (m_SliderRectTransform != null) { | |
m_SliderRectTransform.LookAt(Camera.main.transform); | |
m_SliderRectTransform.Rotate(new Vector3(0f, 180f, 0f)); | |
} | |
} | |
public override void GazeBegin() { | |
base.GazeBegin(); | |
if (m_SliderCanvasGroup != null) m_SliderCanvasGroup.alpha = 1f; | |
} | |
public override void GazeComplete() { | |
m_TimeClockController.PostSimpleTimeClocks(); | |
} | |
public override void GazeEnd() | |
{ | |
base.GazeEnd(); | |
gazeCompleted = false; | |
m_Slider.value = 0f; | |
if (m_SliderCanvasGroup != null) m_SliderCanvasGroup.alpha = 0f; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class GazePointer : MonoBehaviour { | |
[SerializeField] private Transform m_Camera; | |
[SerializeField] private LayerMask m_ExclusionLayers; | |
[SerializeField] private float m_RayLength = 500f; | |
private Gazable m_GazeTarget; | |
void Start () { | |
m_GazeTarget = null; | |
} | |
void Update () { | |
if (m_Camera == null) return; | |
Ray ray = new Ray(m_Camera.position, m_Camera.forward); | |
RaycastHit hit; | |
if (Physics.Raycast(ray, out hit, m_RayLength, ~m_ExclusionLayers)) { | |
GameObject target = hit.collider.gameObject; | |
Gazable gazable = target.GetComponent<Gazable>(); | |
if (gazable != null) { | |
m_GazeTarget = gazable; | |
m_GazeTarget.GazeBegin(); | |
} else { | |
ReleaseGazeTarget(); | |
} | |
} else { | |
ReleaseGazeTarget(); | |
} | |
} | |
void ReleaseGazeTarget() { | |
if (m_GazeTarget != null) { | |
m_GazeTarget.GazeEnd(); | |
} | |
m_GazeTarget = null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using DG.Tweening; | |
public class SystemMessageController : MonoBehaviour { | |
[SerializeField] private Transform m_MessagePanel; | |
[SerializeField] private float messagePanelSize = 0.0006f; | |
[SerializeField] private float messagePanelDuration = 0.6f; | |
[SerializeField] private Animator m_UnitychanAnimator; | |
private AnimatorStateInfo currentState; | |
[SerializeField] private UnityChan.FaceUpdate m_UnitychanFaceUpdate; | |
[SerializeField] private float animSpeed = 0.5f; | |
private void Start () { | |
currentState = m_UnitychanAnimator.GetCurrentAnimatorStateInfo(0); | |
} | |
private void Update() { | |
if (m_UnitychanAnimator.GetBool("Jump")) { | |
currentState = m_UnitychanAnimator.GetCurrentAnimatorStateInfo(0); | |
if (currentState.fullPathHash != Animator.StringToHash("Custom Layer.Jumping@loop")) return; | |
m_UnitychanAnimator.SetBool("Jump", false); | |
} | |
} | |
public void ShowMessageWithSmile(string message, bool Jumping = false, float remainTime = 5f) { | |
if (Jumping) m_UnitychanAnimator.SetBool("Jump", true); | |
ShowMessage(message, "smile@sd_hmd", 5f); | |
} | |
public void ShowMessageWithSad(string message, float remainTime = 5f) { | |
ShowMessage(message, "sad@sd_hmd", 5f); | |
} | |
private void ShowMessage(string msg, string face, float remainTime) { | |
m_UnitychanFaceUpdate.OnCallChangeFace(face); | |
SetMessagePanel( | |
msg, | |
remainTime, | |
(() => m_UnitychanFaceUpdate.OnCallChangeFace("default@sd_hmd")) | |
); | |
} | |
private void SetMessagePanel(string message, float remainTime, TweenCallback callback = null) { | |
m_MessagePanel.Find("Panel/Text").GetComponent<Text>().text = message; | |
m_MessagePanel.GetComponent<RectTransform>().localScale = new Vector3(0f, 0f, 0f); | |
Sequence seq = DOTween.Sequence(); | |
seq.Append( | |
m_MessagePanel.GetComponent<RectTransform>().DOScale(messagePanelSize, messagePanelDuration).SetEase(Ease.InOutQuart) | |
); | |
seq.Append( | |
m_MessagePanel.GetComponent<RectTransform>().DOScale(0f, messagePanelDuration).SetEase(Ease.InOutQuart).SetDelay(remainTime).OnComplete(callback) | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using TMPro; | |
using Freee; | |
public class TimeClocksController : MonoBehaviour | |
{ | |
[SerializeField] private FreeeEventHandler _FreeeEventHandler; | |
[SerializeField] private TextMeshProUGUI _Datetime; | |
[SerializeField] private TextMeshProUGUI _Status; | |
[SerializeField] private GazableButton _ClockInButton; | |
[SerializeField] private GazableButton _BreakBeginButton; | |
[SerializeField] private GazableButton _BreakEndButton; | |
[SerializeField] private GazableButton _ClockOutButton; | |
[SerializeField] private GazableButton _TestClockInButton; | |
[SerializeField] private GazableButton _TestClockOutButton; | |
CultureInfo culture = System.Globalization.CultureInfo.GetCultureInfo("ja-JP"); | |
private string[] m_AvailableTypes; | |
public void Awake() { | |
_ClockInButton.GazeCompleteAction += PostTimeClocks; | |
_ClockInButton.Init(); | |
_TestClockInButton.GazeCompleteAction += PostTimeClocks; | |
_TestClockInButton.Init(); | |
_BreakBeginButton.GazeCompleteAction += PostTimeClocks; | |
_BreakBeginButton.Init(); | |
_BreakEndButton.GazeCompleteAction += PostTimeClocks; | |
_BreakEndButton.Init(); | |
_ClockOutButton.GazeCompleteAction += PostTimeClocks; | |
_ClockOutButton.Init(); | |
_TestClockOutButton.GazeCompleteAction += PostTimeClocks; | |
_TestClockOutButton.Init(); | |
} | |
private void Update() { | |
if (_Datetime != null) { | |
_Datetime.text = DateTime.Now.ToString("yyyy年MM月dd日 HH:mm:ss"); | |
} | |
} | |
public void SetAvailableTypes(string[] types) { | |
m_AvailableTypes = types; | |
SetButtons(types); | |
_Status.text = statusText(types); | |
} | |
public void SetTimeClocksInfo(TimeClock[] tcs) { | |
string s = DateTime.Now.ToString("yyyy年MM月dd日(ddd)", culture) + "\n"; | |
if (tcs.Length >= 1) { | |
foreach (TimeClock tc in tcs) { | |
s += typeString(tc.type) + ":" + DateTime.Parse(tc.datetime).ToString("HH:mm") + "\n"; | |
} | |
} else { | |
s += "打刻履歴なし"; | |
} | |
transform.Find("TimeClocksInfo/Info").GetComponent<TextMeshProUGUI>().text = s; | |
} | |
public void PostSimpleTimeClocks() { | |
_FreeeEventHandler.PostTimeClocks(simpleAvailableType(m_AvailableTypes)); | |
} | |
void SetButtons(string[] types) { | |
_ClockInButton.gameObject.SetActive(Array.IndexOf(types, "clock_in") >= 0); | |
_BreakBeginButton.gameObject.SetActive(Array.IndexOf(types, "break_begin") >= 0); | |
_BreakEndButton.gameObject.SetActive(Array.IndexOf(types, "break_end") >= 0); | |
_ClockOutButton.gameObject.SetActive(Array.IndexOf(types, "clock_out") >= 0); | |
} | |
private string statusText(string[] types) { | |
if (Array.IndexOf(types, "clock_in") >= 0) { | |
return "出勤しましょう"; | |
} else if (Array.IndexOf(types, "break_begin") >= 0) { | |
return "出勤中です"; | |
} else if (Array.IndexOf(types, "break_end") >= 0) { | |
return "休憩中です"; | |
} else { | |
return "退勤しました"; | |
} | |
} | |
private string typeString(string type) { | |
if (type == "clock_in") { | |
return "出勤 "; | |
} else if (type == "break_begin") { | |
return "休憩開始"; | |
} else if (type == "break_end") { | |
return "休憩終了"; | |
} else if (type == "clock_out") { | |
return "退勤 "; | |
} else { | |
return ""; | |
} | |
} | |
private string simpleAvailableType(string[] types) { | |
if (Array.IndexOf(types, "clock_in") >= 0) { | |
return "clock_in"; | |
} else if (Array.IndexOf(types, "clock_out") >= 0) { | |
return "clock_out"; | |
} else { | |
return ""; | |
} | |
} | |
void PostTimeClocks(string s) | |
{ | |
string type = ""; | |
switch (s) { | |
case "出勤": | |
type = "clock_in"; | |
break; | |
case "休憩開始": | |
type = "break_begin"; | |
break; | |
case "休憩終了": | |
type = "break_end"; | |
break; | |
case "退勤": | |
type = "clock_out"; | |
break; | |
} | |
_FreeeEventHandler.PostTimeClocks(type); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment