Google Calendar is very convenient, isn't it? It can be linked with Gmail, can be opened from a PC, and is simple. However, there are some dissatisfaction points. That is that it does not calculate the salary of the part-time job. I wish it would work with the shift management app. .. .. With that said, I tried to make it while using various APIs and AWS that I was interested in as a beginner.
I created a bot with the following configuration.
This procedure was very helpful to the following article. If you follow the article, you can do it without any problems. Even AWS beginners can understand! Completed on the browser! Super Introduction to Slack Bot Using AWS + Slack Event API
I referred to the following article for how to get the schedule of Google Calendar using Python. Get Google Calender appointments from Python 3
Next, refer to Official Sample and Official Reference. , We will make a program to calculate salary.
The program is roughly divided into the following.
The full code can be found on github, so please refer to that.
handle_slack_event()
This is the entry point. It parses the text sent by the user and posts a message based on it.
# -----Entry point-----
def handle_slack_event(slack_event, context):
#Output received event information to Cloud Watch log
logging.info(json.dumps(slack_event))
#Event API authentication
if "challenge" in slack_event:
return slack_event.get("challenge")
#Other than bot events or message posting events
#Return as it is to not react
#I need to return some response to Slack, so I return OK
#(If not returned, it will be considered a failure and the same request will be sent several times)
if is_bot(slack_event) or not is_message_event(slack_event):
return "OK"
#Extract message text from user
text = slack_event.get("event").get("text")
#Payroll Class Declaration
pay_msg = MakePayMsg()
#Compose a message by parsing text from the user
if 'help' in text:
msg = 'Enter the number corresponding to the information you want to know!\n'
msg += '(1)Next month's salary\n'
msg += '(2)This year's salary\n'
msg += '(3)Salary log\n'
elif text == '1':
msg = 'Next month's salary is ¥{}is!'.format(pay_msg.monthpay())
elif text == '2':
msg = '{}'.format(pay_msg.yearpay())
elif text == '3':
msg = 'Salary log\n{}'.format(pay_msg.paylog())
else:
msg = '\\Quay/'
#Posting a message
post_message_to_slack_channel(msg, slack_event.get("event").get("channel"))
#As a result of a request by the Event API, apart from posting the message
#I need to return some response to Slack, so I return OK
#(If not returned, it will be considered a failure and the same request will be sent several times)
return "OK"
MakePayMsg() Calculate the salary corresponding to the user text and create a message.
# -----Calculate salary and compose a message-----
class MakePayMsg():
def __init__(self):
self.SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
self.now = datetime.datetime.now()
self.events = self.get_event() #Events retrieved from Google Calendar
self.pay_log = self.make_paylog() #This year's salary log
# ---Retrieving events from Google Calendar---
def get_event(self):
creds = None
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', self.SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('/tmp/token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('calendar', 'v3', credentials=creds)
#Select the calendar that has the byte shift registered
calender_id = os.environ['CALENDER_ID']
page_token = None
events = service.events().list(calendarId=calender_id, pageToken=page_token).execute()
return events
# ---Create a salary log for this year---
def make_paylog(self):
pay_log = []
cal = CalculatePay(1013, 1063, 1.25, 22) #Enter hourly wage information
#Extract the start time and end time of the byte from event and calculate the salary
for event in self.events['items']:
#Transform start time and end time into datetime
stime = event['start']['dateTime']
stime = datetime.datetime(
int(stime[0:4]), int(stime[5:7]), int(stime[8:10]),
int(stime[11:13]), int(stime[14:16]))
etime = event['end']['dateTime']
etime = datetime.datetime(
int(etime[0:4]), int(etime[5:7]), int(etime[8:10]),
int(etime[11:13]), int(etime[14:16]))
#Period to calculate salary
# (x-1)December~The salary for x years is the amount worked in November x
if self.now.month != 12:
sdate = datetime.date(self.now.year-1, 12, 1)
edate = datetime.date(self.now.year, 11, 30)
else:
sdate = datetime.date(self.now.year, 12, 1)
edate = datetime.date(self.now.year+1, 11, 30)
#Record one year's salary as a log
if (stime.date() >= sdate) and (etime.date() <= edate):
#One day salary calculation from start time and end time
daypay = cal.calculate(stime, etime)
#Adjust so that the amount of work is the salary of the next month
if stime.month==12:
daypay_dir = {'date':stime.date(), 'month':1, 'pay':daypay}
else:
daypay_dir = {'date':stime.date(), 'month':stime.month+1, 'pay':daypay}
pay_log += [daypay_dir]
pay_log = sorted(pay_log, key=lambda x:x['date'])
return pay_log
# ---Create a message to show your salary for next month---
def monthpay(self):
mpay = 0
for i in self.pay_log:
if self.now.month!=12:
if i['month'] == (self.now.month+1):
mpay += i['pay']
else:
if i['month'] == 1:
mpay += i['pay']
return mpay
# ---Create a message to show your salary for one year---
def yearpay(self):
mpay_list = [0] * 12
for i in self.pay_log:
mpay_list[i['month']-1] += i['pay']
msg = ''
for i, mpay in enumerate(mpay_list):
msg += '{}Month ¥{:,}\n'.format(i+1, mpay)
msg += '\n total ¥{}'.format(sum(mpay_list))
return msg
# ---Create a message to display one year's log---
def paylog(self):
msg = ''
month = 0
for i in self.pay_log:
while i['month'] != month:
msg += '\n{}Month\n'.format(month+1)
month += 1
msg += '{} ¥{:,}\n'.format(i['date'], i['pay'])
return msg
Please note that Lambda can only write files under / tmp
.
Therefore, when writing to a certain file, it may be said that [Errno 30] Read-only file system
occurs when executed with Lambda, even though no error occurred when executed locally.
Since an error occurred in this program as well, I changed it as follows.
Change before
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
After change
with open('/tmp/token.pickle', 'wb') as token:
pickle.dump(creds, token)
CalculatePay() Calculate the daily salary.
# -----Calculate daily wage-----
class CalculatePay():
def __init__(
self, basic_pay, irregular_pay, night_rate, night_time):
self.basic_pay = basic_pay #Weekday hourly wage
self.irregular_pay = irregular_pay #Hourly wages on Saturdays, Sundays, and holidays
self.night_rate = night_rate #Late night salary increase rate
self.night_time = night_time #Time to get midnight salary
# ---Calculate daily wage---
def calculate(self, stime, etime):
night_time = datetime.datetime(stime.year, stime.month, stime.day, self.night_time)
if stime.weekday() >= 5 or jpholiday.is_holiday(stime.date()):
pay = self.irregular_pay
else:
pay = self.basic_pay
if etime >= night_time:
normal_time = self.get_h(night_time - stime)
night_time = self.get_h(etime - night_time)
daypay = normal_time * pay + night_time * (pay * self.night_rate)
else:
normal_time = self.get_h(etime - stime)
daypay = normal_time * pay
return round(daypay)
# ---Convert from x hours y minutes to h hours display---
def get_h(self, delta_time):
h = delta_time.seconds / 3600
return h
I have installed some modules to write a program to calculate salary from Google Calendar. If you run this program on AWS Lambda without doing anything, you will get a ModuleNotFoundError. Create an AWS Lambda deployment package for Python so that various modules can be used on AWS Lambda. Simply put, install all the dependent modules in your project directory and zip them up with the executable. This can be done according to the following site. [Python] Using an external module with AWS Lambda
I recently started recording byte shifts in Google Calendar, so there isn't much data. Since I introduced this bot, I would like to manage shifts with Google Calendar in the future. (It's an easy-to-understand icon where the byte destination is)
Recommended Posts