[PYTHON] Ich möchte einen Slack-Bot, der das Gehalt eines Teilzeitjobs aus dem Zeitplan von Google Kalender berechnet und anzeigt!

Einführung

Google Kalender ist sehr praktisch, nicht wahr? Es kann mit Google Mail verknüpft werden, kann von einem PC aus geöffnet werden und ist einfach. Es gibt jedoch einige Unzufriedenheitspunkte. Das heißt, es wird nicht das Gehalt des Teilzeitjobs berechnet. Ich wünschte, es würde mit der Schichtmanagement-App funktionieren. .. .. Trotzdem habe ich versucht, es mit verschiedenen APIs und AWS zu schaffen, an denen ich als Anfänger interessiert war.

Was ich benutzt habe

Überblick über die Architektur

Ich habe einen Bot mit der folgenden Konfiguration erstellt.

仕組み

Verfahren

  1. Erstellen Sie eine App zum Erstellen eines Bots auf der Slack API-Site
  2. Erstellen Sie in AWS einen Endpunkt, der Slack-Ereignisse empfängt
  3. Erstellen Sie ein Programm zur Berechnung des Byte-Gehalts aus dem Google-Kalender mithilfe der Google-API
  4. Einführung in AWS Lambda

[Prozedur 1] [Prozedur 2] Erstellen Sie einen Slack-Bot und einen Endpunkt in AWS

Dieses Verfahren war für den folgenden Artikel sehr hilfreich. Wenn Sie dem Artikel folgen, können Sie dies ohne Probleme tun. Auch AWS-Anfänger können verstehen! Im Browser abgeschlossen! Super Einführung in Slack Bot mit AWS + Slack Event API

[Prozedur 3] Erstellen Sie ein Programm zur Berechnung des Gehalts von Bytes aus Google Kalender

Ich habe im folgenden Artikel beschrieben, wie Sie den Zeitplan des Google-Kalenders mit Python abrufen können. Google Kalendertermine von Python 3 abrufen

Lesen Sie als Nächstes Offizielles Beispiel und Offizielle Referenz. , Wir werden ein Programm zur Berechnung des Gehalts erstellen.

Das Programm ist grob in Folgendes unterteilt.

Den vollständigen Code finden Sie unter github.

handle_slack_event()

Dies ist der Einstiegspunkt. Es analysiert den vom Benutzer gesendeten Text und sendet eine darauf basierende Nachricht.

# -----Einstiegspunkt-----
def handle_slack_event(slack_event, context):

    #Geben Sie empfangene Ereignisinformationen in das Cloud Watch-Protokoll aus
    logging.info(json.dumps(slack_event))

    #Ereignis-API-Authentifizierung
    if "challenge" in slack_event:
        return slack_event.get("challenge")

    #Andere als Bot-Ereignisse oder Nachrichtenposting-Ereignisse
    #Kehre zurück, wie es ist, nicht zu reagieren
    #Ich muss eine Antwort an Slack zurückgeben, damit ich OK zurückschicke
    #(Wenn es nicht zurückgegeben wird, wird es als Fehler betrachtet und dieselbe Anfrage wird mehrmals gesendet.)
    if is_bot(slack_event) or not is_message_event(slack_event):
        return "OK"

    #Nachrichtentext vom Benutzer extrahieren
    text = slack_event.get("event").get("text")

    #Erklärung der Gehaltsklasse
    pay_msg = MakePayMsg()
    
    #Verfassen Sie eine Nachricht, indem Sie den Text des Benutzers analysieren
    if 'help' in text:
        msg = 'Geben Sie die Nummer ein, die den Informationen entspricht, die Sie wissen möchten!\n'
        msg += '(1)Gehalt für nächsten Monat\n'
        msg += '(2)Das diesjährige Gehalt\n'
        msg += '(3)Gehaltsliste\n'
    elif text == '1':
        msg = 'Das Gehalt für den nächsten Monat beträgt ¥{}ist!'.format(pay_msg.monthpay())
    elif text == '2':
        msg = '{}'.format(pay_msg.yearpay())
    elif text == '3':
        msg = 'Gehaltsliste\n{}'.format(pay_msg.paylog())
    else:
        msg = '\\Kai/'
    
    #Eine Nachricht posten
    post_message_to_slack_channel(msg, slack_event.get("event").get("channel"))

    #Als Ergebnis einer Anforderung durch die Ereignis-API, abgesehen von der Veröffentlichung der Nachricht
    #Ich muss eine Antwort an Slack zurückgeben, damit ich OK zurückschicke
    #(Wenn es nicht zurückgegeben wird, wird es als Fehler betrachtet und dieselbe Anfrage wird mehrmals gesendet.)
    return "OK"

MakePayMsg() Berechnen Sie das Gehalt entsprechend dem Benutzertext und erstellen Sie eine Nachricht.

# -----Berechnen Sie das Gehalt und verfassen Sie eine Nachricht-----
class MakePayMsg():
    def __init__(self):
    
        self.SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
        self.now = datetime.datetime.now()
        self.events = self.get_event() #Aus Google Kalender abgerufene Ereignisse
        self.pay_log = self.make_paylog() #Das diesjährige Gehaltsprotokoll

    # ---Ereignisse aus Google Kalender abrufen---
    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)

        #Wählen Sie den Kalender aus, in dem die Byte-Verschiebung registriert ist
        calender_id = os.environ['CALENDER_ID']

        page_token = None
        events = service.events().list(calendarId=calender_id, pageToken=page_token).execute()
        return events

    # ---Erstellen Sie ein Gehaltsprotokoll für dieses Jahr---
    def make_paylog(self):
        pay_log = []
        cal = CalculatePay(1013, 1063, 1.25, 22) #Geben Sie die Stundenlohninformationen ein
        
        #Extrahieren Sie die Start- und Endzeit des Bytes aus dem Ereignis und berechnen Sie das Gehalt
        for event in self.events['items']:
            #Transformieren Sie Startzeit und Endzeit in Datum / Uhrzeit
            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]))
            
            #Zeitraum für die Lohn- und Gehaltsabrechnung
            # (x-1)Dezember~Der Arbeitsaufwand im November x entspricht dem Gehalt von 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)

            #Notieren Sie ein Jahresgehalt als Protokoll
            if (stime.date() >= sdate) and (etime.date() <= edate):
                #Gehaltsberechnung für einen Tag ab Start- und Endzeit
                daypay = cal.calculate(stime, etime)
                #Stellen Sie so ein, dass der Arbeitsaufwand dem Gehalt des nächsten Monats entspricht
                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
            
    # ---Erstellen Sie eine Nachricht, um das Gehalt des nächsten Monats anzuzeigen---
    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

    # ---Erstellen Sie eine Nachricht, um das Gehalt für ein Jahr anzuzeigen---
    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 += '{}Monat ¥{:,}\n'.format(i+1, mpay)
        msg += '\n insgesamt ¥{}'.format(sum(mpay_list))
        return msg

    # ---Erstellen Sie eine Nachricht, um das Jahresprotokoll anzuzeigen---
    def paylog(self):
        msg = ''
        month = 0
        for i in self.pay_log:
            while i['month'] != month:
                msg += '\n{}Mond\n'.format(month+1)
                month += 1
            msg += '{} ¥{:,}\n'.format(i['date'], i['pay'])
        return msg

Beachten Sie, dass Lambda nur in Dateien unter / tmp schreiben kann. Daher kann beim Schreiben in eine bestimmte Datei gesagt werden, dass bei Ausführung mit Lambda "[Errno 30] Schreibgeschütztes Dateisystem" auftritt, obwohl bei lokaler Ausführung kein Fehler aufgetreten ist. Da auch in diesem Programm ein Fehler aufgetreten ist, habe ich ihn wie folgt geändert.

Vorher ändern


with open('token.pickle', 'wb') as token:
    pickle.dump(creds, token)

Nach der veränderung


with open('/tmp/token.pickle', 'wb') as token:
    pickle.dump(creds, token)

CalculatePay() Berechnen Sie das Tagesgehalt.


# -----Tageslohn berechnen-----
class CalculatePay():
    def __init__(
        self, basic_pay, irregular_pay, night_rate, night_time):

        self.basic_pay = basic_pay #Wochentagsstundenlohn
        self.irregular_pay = irregular_pay #Stundenlohn an Samstagen, Sonntagen und Feiertagen
        self.night_rate = night_rate #Late-Night-Gehaltserhöhungsrate
        self.night_time = night_time #Zeit, Mitternachtsgehalt zu bekommen

    # ---Tagesgehalt berechnen---
    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)

    # ---Konvertieren Sie von x Stunden y Minuten in h Zeitanzeige---
    def get_h(self, delta_time):
        h = delta_time.seconds / 3600
        return h

[Verfahren 4] Einführung in AWS Lambda

Ich habe einige Module installiert, um ein Programm zur Berechnung des Gehalts aus Google Kalender zu schreiben. Wenn ich dieses Programm unter AWS Lambda ausführe, ohne etwas zu tun, erhalte ich einen ModuleNotFoundError. Erstellen Sie ein AWS Lambda-Bereitstellungspaket für Python, damit die verschiedenen Module auch in AWS Lambda verwendet werden können. Einfach ausgedrückt, installieren Sie alle abhängigen Module in Ihrem Projektverzeichnis und komprimieren Sie sie mit Ihrer ausführbaren Datei. Dies kann gemäß der folgenden Site erfolgen. [Python] Verwenden eines externen Moduls mit AWS Lambda

Ausführungsergebnis

Ich habe kürzlich damit begonnen, Byte-Verschiebungen in Google Kalender aufzuzeichnen, daher gibt es nicht viele Daten. Seit ich diesen Bot eingeführt habe, möchte ich in Zukunft Schichten mit Google Kalender verwalten. (Es ist ein leicht verständliches Symbol, in dem sich das Byte-Ziel befindet.)

Zeig Hilfe

スクリーンショット 2019-11-28 0.37.29.png

Anzeige des Gehalts des nächsten Monats

スクリーンショット 2019-11-28 0.36.52.png

Das diesjährige Gehalt

スクリーンショット 2019-11-28 0.37.05.png

Gehaltsliste

スクリーンショット 2019-11-28 0.42.47.png

Andere

スクリーンショット 2019-11-28 0.45.04.png

Recommended Posts

Ich möchte einen Slack-Bot, der das Gehalt eines Teilzeitjobs aus dem Zeitplan von Google Kalender berechnet und anzeigt!
Ich habe einen schlaffen Bot gemacht, der mich über die Temperatur informiert
[Bot dekodieren] Ich habe versucht, einen Bot zu erstellen, der mir den Rassenwert von Pokemon angibt
Ich habe einen Kalender erstellt, der den Verteilungsplan von Vtuber automatisch aktualisiert (Google Kalender Edition).
Ich habe einen Kalender erstellt, der den Verteilungsplan von Vtuber automatisch aktualisiert
Ich habe mit Heroku + Flask + PostgreSQL (Heroku Postgres) einen LINE-Bot erstellt, der mir den Typ und die Stärke von Pokemon in der Garal-Region angibt.
Die Geschichte, einen Line Bot zu erstellen, der uns den Zeitplan für die Wettbewerbsprogrammierung erzählt
Erstellt einen Slack-Bot, der AWS Lambda über das Ablaufdatum eines SSL-Zertifikats bestätigt und benachrichtigt
Verschrotten Sie den Zeitplan von Hinatazaka 46 und spiegeln Sie ihn in Google Kalender wider
Eine Formel, die einfach das Alter ab dem Geburtsdatum berechnet
Da ich zu verschiedenen Zeiten anfing zu arbeiten, machte ich einen Bot, der mir die Zeit sagt, die Arbeit zu verlassen
Holen Sie sich das durchschnittliche Gehalt eines Jobs mit bestimmten Bedingungen von Indeed.com
Die Geschichte der IPv6-Adresse, die ich auf ein Minimum beschränken möchte
[Python] Ein Programm, das die Anzahl der Aktualisierungen der höchsten und niedrigsten Datensätze berechnet
Importieren Sie den von "Schedule-kun" erhaltenen Zeitplan in Google Kalender
Erstellen Sie einen BOT, der die Discord-URL verkürzt
Ich möchte den Schnittpunkt einer Bezier-Kurve und einer geraden Linie finden (Bezier-Clipping-Methode)
Ich möchte viele Prozesse von Python aus starten
Ich möchte eine Nachricht von Python an LINE Bot senden
Ich möchte die Natur von Python und Pip kennenlernen
Ich möchte Informationen von fstab am ssh-Verbindungsziel abrufen und den Befehl ausführen
Ich habe versucht, das Bild des Bogenschießen-Bewertungsbuchs (eine Broschüre, in der die Ergebnisse von Treffern aufgezeichnet werden) zu analysieren. (Google Colaboratory)
Ich möchte die Frage nach der Methode "__init__" und dem Argument "self" der Python-Klasse klären.
[Google Photo & Slack Photo Bot] Eine Geschichte über das Erstellen eines Bots, der ein Foto in Google Photo erfasst und an Slack sendet.
Ich möchte Tag-Informationen (Titel und Künstler) einer Musikdatei (flac, wav) extrahieren.
Die Geschichte des Erstellens eines Bots, der aktive Mitglieder in einem bestimmten Slack-Kanal mit Python anzeigt