mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-09-30 07:53:11 +00:00
Email weekly pay summary to payroll via SES on Mondays
Sends an HTML pay summary email to configured payroll recipients alongside the existing Slack post. Uses SES with noreply@seahaven.com as sender. Recipients configured via PAYROLL_RECIPIENTS env var (set to adam@seahaven.com for testing, switch to payroll@seahaven.com for production). Closes #3
This commit is contained in:
parent
093bb43e71
commit
9deb8bf251
2 changed files with 72 additions and 2 deletions
|
|
@ -1,5 +1,5 @@
|
|||
"""Lambda handler — posts the weekly on-call schedule and previous week's pay summary
|
||||
to Slack every Monday at 7am ET."""
|
||||
to Slack every Monday at 7am ET, and emails the pay summary to payroll."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
|
@ -74,6 +74,66 @@ def _calculate_weekly_pay(schedule: ShiftSchedule, week_start: datetime) -> dict
|
|||
}
|
||||
|
||||
|
||||
def _build_pay_email_html(week_label: str, pay_record: dict) -> str:
|
||||
"""Build an HTML email body for the weekly pay summary."""
|
||||
rows = ""
|
||||
for entry in pay_record["breakdown"]:
|
||||
rows += (
|
||||
f"<tr><td>{entry['day']}</td><td>{entry['date_label']}</td>"
|
||||
f"<td>{entry['name']}</td><td>Ext {entry['extension']}</td>"
|
||||
f"<td>${entry['rate']:.2f}</td></tr>\n"
|
||||
)
|
||||
|
||||
totals_rows = ""
|
||||
for name, info in sorted(pay_record["totals"].items()):
|
||||
totals_rows += (
|
||||
f"<tr><td>{name}</td><td>{info['shifts']}</td>"
|
||||
f"<td>${info.get('rate', 0):.2f}</td><td><strong>${info['total']:.2f}</strong></td></tr>\n"
|
||||
)
|
||||
|
||||
return f"""<html>
|
||||
<body style="font-family: Arial, sans-serif; color: #333;">
|
||||
<h2>After-Hours Pay Summary — {week_label}</h2>
|
||||
|
||||
<h3>Shift Breakdown</h3>
|
||||
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse;">
|
||||
<tr style="background: #f0f0f0;"><th>Day</th><th>Date</th><th>Name</th><th>Extension</th><th>Rate</th></tr>
|
||||
{rows}</table>
|
||||
|
||||
<h3>Totals by Person</h3>
|
||||
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse;">
|
||||
<tr style="background: #f0f0f0;"><th>Name</th><th>Shifts</th><th>Rate</th><th>Total</th></tr>
|
||||
{totals_rows}</table>
|
||||
|
||||
<p style="color: #888; font-size: 12px;">This is an automated report from the After-Hours Shift Manager.</p>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
def _send_pay_email(week_label: str, pay_record: dict) -> None:
|
||||
"""Send the weekly pay summary email via SES."""
|
||||
sender = os.environ.get("SES_SENDER", "noreply@seahaven.com")
|
||||
recipients = os.environ.get("PAYROLL_RECIPIENTS", "").split(",")
|
||||
recipients = [r.strip() for r in recipients if r.strip()]
|
||||
|
||||
if not recipients:
|
||||
logger.warning("No PAYROLL_RECIPIENTS configured — skipping email")
|
||||
return
|
||||
|
||||
ses = boto3.client("ses")
|
||||
html_body = _build_pay_email_html(week_label, pay_record)
|
||||
|
||||
ses.send_email(
|
||||
Source=sender,
|
||||
Destination={"ToAddresses": recipients},
|
||||
Message={
|
||||
"Subject": {"Data": f"After-Hours Pay Summary — {week_label}"},
|
||||
"Body": {"Html": {"Data": html_body}},
|
||||
},
|
||||
)
|
||||
logger.info("Sent pay email to %s", recipients)
|
||||
|
||||
|
||||
def handler(event, context):
|
||||
now = datetime.now(EASTERN)
|
||||
|
||||
|
|
@ -114,6 +174,9 @@ def handler(event, context):
|
|||
)
|
||||
logger.info("Posted pay summary for week of %s", week_key)
|
||||
|
||||
# Email pay summary to payroll
|
||||
_send_pay_email(week_label, pay_record)
|
||||
|
||||
# --- Two-week schedule ---
|
||||
blocks = build_week_schedule(schedule, start_date=now)
|
||||
|
||||
|
|
|
|||
|
|
@ -89,9 +89,11 @@ Resources:
|
|||
SHIFT_TABLE: !Ref ShiftTable
|
||||
SLACK_BOT_TOKEN_PARAM: /afterhours-shift-manager/slack-bot-token
|
||||
SHIFT_CHANNEL_PARAM: /afterhours-shift-manager/channel-id
|
||||
SES_SENDER: noreply@seahaven.com
|
||||
PAYROLL_RECIPIENTS: adam@seahaven.com
|
||||
TZ: !Ref Timezone
|
||||
Policies:
|
||||
- DynamoDBReadPolicy:
|
||||
- DynamoDBCrudPolicy:
|
||||
TableName: !Ref ShiftTable
|
||||
- Statement:
|
||||
- Effect: Allow
|
||||
|
|
@ -106,6 +108,11 @@ Resources:
|
|||
Condition:
|
||||
StringEquals:
|
||||
"kms:ViaService": !Sub "ssm.${AWS::Region}.amazonaws.com"
|
||||
- Effect: Allow
|
||||
Action:
|
||||
- ses:SendEmail
|
||||
Resource:
|
||||
- !Sub "arn:aws:ses:${AWS::Region}:${AWS::AccountId}:identity/seahaven.com"
|
||||
Events:
|
||||
# EST: 7am ET = 12:00 UTC (Nov-Mar)
|
||||
WeeklyPostEST:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue