-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: read Sage Payroll pdf and compare
That's useful to understand if the data of the Payroll does match the data available in kitamanager.
- Loading branch information
Showing
9 changed files
with
225 additions
and
3 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from dataclasses import dataclass | ||
from dateparser import parse | ||
from pypdf import PdfReader | ||
from decimal import Decimal | ||
|
||
|
||
@dataclass | ||
class PayrollPerson: | ||
""" | ||
A Person from a Payroll | ||
""" | ||
|
||
first_name: str | ||
last_name: str | ||
hours: int | ||
pay_group: int | ||
pay_level: int | ||
|
||
|
||
class SagePayrolls: | ||
""" | ||
Parse a Sage Payroll (Lohn/Gehaltsabrechnung) PDF file with multiple pages. Each page contains a single person | ||
The file is expected to be in German and currently very eenemeene specific | ||
""" | ||
|
||
def __init__(self, lohnscheine_path: str): | ||
self._lohnscheine_path = lohnscheine_path | ||
self._reader = PdfReader(self._lohnscheine_path) | ||
self._date = None | ||
|
||
def _get_date(self, text_split): | ||
for count, line in enumerate(text_split): | ||
if line.endswith("Abrechnungsmonat:"): | ||
date_str = text_split[count + 1].split("#")[0] | ||
date = parse(date_str).replace(day=1) | ||
return date | ||
return None | ||
|
||
def _get_person(self, text_split): | ||
for count, line in enumerate(text_split): | ||
# FIXME: very eenemeene specific | ||
if line.startswith("TV-EM"): | ||
parts = line.split(" ") | ||
assert parts[0] == "TV-EM" | ||
pay_group = int(parts[1].replace("S", "")) | ||
assert pay_group >= 3 and pay_group <= 10 | ||
pay_level = int(parts[2].replace("(", "").replace(")", "")) | ||
assert pay_level >= 1 and pay_level <= 6 | ||
hours = Decimal(parts[4]) | ||
assert hours >= 0 and hours <= 40 | ||
first_name = parts[5][1:] | ||
last_name = " ".join(parts[6:]) | ||
return PayrollPerson( | ||
first_name=first_name, last_name=last_name, hours=hours, pay_group=pay_group, pay_level=pay_level | ||
) | ||
return None | ||
|
||
@property | ||
def date(self): | ||
# cache the date | ||
if not self._date: | ||
# just use the first page and assume that all pages are for the same date | ||
page = self._reader.pages[0] | ||
text = page.extract_text() | ||
text_split = text.splitlines() | ||
self._date = self._get_date(text_split) | ||
return self._date | ||
|
||
@property | ||
def persons(self): | ||
""" | ||
Parse the different PDF pages and return a list of persons | ||
""" | ||
persons = [] | ||
for page_number, page in enumerate(self._reader.pages): | ||
text = page.extract_text() | ||
text_split = text.splitlines() | ||
person = self._get_person(text_split) | ||
if person: | ||
persons.append(person) | ||
return persons |
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
57 changes: 57 additions & 0 deletions
57
django-kitamanager/kitamanager/templates/kitamanager/employee_check_sage_payroll.html
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
{% extends "kitamanager/base.html" %} | ||
{% load i18n %} | ||
{% block content %} | ||
|
||
<div class="box"> | ||
<h5 class="title"> | ||
{% translate "check Sage payroll" %} | ||
</h5> | ||
<div class="notification is-info is-light"> | ||
{% blocktranslate trimmed %} | ||
The payroll check can be used to compare a Sage payroll (usually sent from Daks) | ||
with the data available in Kitamanager | ||
{% endblocktranslate %} | ||
</div> | ||
<form enctype="multipart/form-data" action="{% url 'kitamanager:employee-check-sage-payroll' %}" method="POST"> | ||
{% csrf_token %} | ||
{{ form.as_div }} | ||
<input type="submit" value={% translate "check" %}> | ||
</form> | ||
</div> | ||
{% if data %} | ||
<div class="box"> | ||
<h5 class="title"> | ||
{% translate "Compare for " %}{{ payroll_date|date:"M Y" }} | ||
</h5> | ||
<div class="table-container"> | ||
<table class="table is-striped is-hoverable"> | ||
<thead> | ||
<tr> | ||
<th>{% translate "name" %}</th> | ||
<th>{% translate "payroll" %}</th> | ||
<th>{% translate "kitamanager" %}</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{% for person, d in data.items %} | ||
<tr {% if d.payroll != d.kitamanager %}class="has-text-danger"{% endif %}> | ||
<td>{{ person }}</td> | ||
{% if d.payroll %} | ||
<td>{% translate "hours" %}: {{ d.payroll.hours|floatformat:2 }}, {% translate "pay group" %}: {{ d.payroll.pay_group }}, {% translate "pay level" %}: {{ d.payroll.pay_level }}</td> | ||
{% else %} | ||
<td>-</td> | ||
{% endif %} | ||
{% if d.kitamanager %} | ||
<td>{% translate "hours" %}: {{ d.kitamanager.hours|floatformat:2 }}, {% translate "pay group" %}: {{ d.kitamanager.pay_group }}, {% translate "pay level" %}: {{ d.kitamanager.pay_level }}</td> | ||
{% else %} | ||
<td>-</td> | ||
{% endif %} | ||
</tr> | ||
{% endfor %} | ||
<tbody> | ||
</table> | ||
</div> | ||
</div> | ||
{% endif %} | ||
|
||
{% endblock %} |
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
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
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
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
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