Commit c48ce799 authored by Xiaowu Zhang's avatar Xiaowu Zhang

erp5_payroll: payslip draft verison

parent e04b05cf
kwargs["report_data"] = context.PaySheetTransaction_getPayslipData()
rep_content = context.PaySheetTransaction_generatePayslipReportContent(*args, **kwargs)
kw["report_data"] = context.PaySheetTransaction_getPayslipData()
rep_content = context.PaySheetTransaction_generatePayslipReportContent(**kw)
if isinstance(rep_content, unicode):
rep_content = rep_content.encode("utf8")
......
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>*args, **kwargs</string> </value>
<value> <string>**kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaySheetTransaction_generatePayslipReportFooter</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<p>Dans votre intérêt et pour vous aider à faire valoir vos droits, conservez ce bulletin de paie sans limitation de durée.</p>
<p>Generated with ERP5 – Open Source ERP suite (www.erp5.org)</p>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaySheetTransaction_generatePayslipReportHeader</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<tal:block tal:define="data_dict here/PaySheetTransaction_getODTDataDict;
other_data_dict here/PaySheetTransaction_getOtherInformationsDataDict;
language python: options.get('language');
date_renderer nocall:here/Base_viewFieldLibrary/my_date_time_field/render_pdf;
">
<div class="ci-book-report-content-header-wrapper">
<span tal:content='python: here.Base_translateString("Payslip", lang=language)'></span>
<span tal:content='python: here.Base_translateString("From ${start_date} to ${stop_date}",
lang=language,
mapping={
"start_date": date_renderer(here.getStartDate()),
"stop_date": date_renderer(here.getStopDate())})'></span>
<table class="ci-book-table">
<tbody>
<tr>
<td style="background:#fff">
<div class="ci-book-report-content-card">
<span class='ci-book-report-emphasis ci-book-report-headline' tal:content='python:data_dict["destination_section_title"]'>destination_section</span>
<span tal:content='python:data_dict["destination_section_address"]'>address</span>
<span tal:condition='data_dict/destination_section_corporate_registration_codeid' tal:content='python:data_dict["destination_section_corporate_registration_codeid"]'>SIRET</span>
<span tal:condition='data_dict/destination_section_activity_codeid' tal:content='python:data_dict["destination_section_activity_codeid"]'>APE</span>
</div>
<td style="background:#fff">
<div class="ci-book-report-content-card">
<div class="ci-book-report-content-card">
<span class='ci-book-report-emphasis ci-book-report-headline' tal:content='python:data_dict["source_section_title"]'>source_section</span>
<span tal:content='python:data_dict["source_section_address"]'>address</span>
<span tal:condition='other_data_dict/source_section_default_career_social_code' tal:content='python:other_data_dict["source_section_default_career_social_code"]'>185897778270987</span>
<span tal:condition='other_data_dict/source_section_default_career_start_date' tal:content='python:other_data_dict["source_section_default_career_start_date"]'>12/09/2005</span>
<span tal:condition='other_data_dict/source_section_career_title' tal:content='python:other_data_dict["source_section_career_title"]'>Réceptionniste</span>
<span tal:condition='other_data_dict/source_section_default_career_coefficient' tal:content='python:other_data_dict["source_section_default_career_coefficient"]'>100</span>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</tal:block>
\ No newline at end of file
......@@ -25,6 +25,9 @@ for line in line_list:
if line.getResourceId() == 'total_employee_contributions':
continue
line_dict = {
'report_section': line.getReportSection(),
'group_by_report_section': line.getGroupByReportSection(),
'resource_title': line.getResourceTitle(),
'group' : line.getSourceSectionTitle(),
'source_section_title': line.getSourceSectionTitle(),
'title' : line.getTitle(),
......
"""
================================================================================
Get data to build a payslip report based on a person's paysheet transaction
================================================================================
"""
#
# parameters
# ------------------------------------------------------------------------------
# start_date start date of the report
# stop_date stop date of the report
#
# returns:
# {
# "general_data_dict": {
# "year": 2017,
# "net_salary": "2 300.93",
# "gross_salary": "3 085.28"
# },
# "cumulative_title_list": [
# {"value": "Gross Salary", "is_header": True},
# ...
# ],
# "cumulative_info_list":[
# {"value": "3 085.28", "is_header": True},
# ...
# ],
# 'destination_address_line_list': [
# {"value": "USERTEST Slicea", "is_header": True},
# {"value": "2 rue unerue"},
# ...
# ],
# 'destination_hiring_info_list': [
# {"value": "Hiring Date: 1990/10/10"},
# ...
# ],
# 'destination_attendance_info_list': [
# {"value": "Normal Working Hours": 151.67"},
# ...
# ]
# 'destination_vacation_info_list': [
# {"value": "Earned this period: "},
# ...
# ],
# 'destination_taxation_info_list': [
# {"value": "Price Currency: EUR"},
# ],
# 'source_address_line_list: [
# {"value": "Nexedi SA", "is_header": True},
# {"value": "147 Rue du Ballon"}
# ...
# ],
# source_corporate_info_line_list: [
# {"value": "Corporate Registration Code: 440047504 00020"},
# {"value": "Activity Code: 5829C"},
# ...
# ],
# "payslip_section_list": [
# [
# {"value": "Usertest Slicea", "is_header": True, "value_base": "", "value_employee_share_rate": "", "value_employee_share": "", "value_employer_share_rate": "", "value_employer_share": ""},
# {"value": "Salarie de Base", "value_base": "2 805.28", "value_employee_share_rate": "", "value_employee_share": "", "value_employer_share_rate": "", "value_employer_share": ""}
# ], [
# ...
# ]
# ]
#}
response = {
"general_data_dict": {
"year": "",
"net_salary": "",
"gross_salary": ""
},
"cumulative_title_list": [],
"cumulative_info_list": [],
"destination_address_line_list": [],
"destination_hiring_info_list": [],
"destination_attendance_info_list": [],
"destination_vacation_info_list": [],
"destination_taxation_info_list": [],
"source_address_line_list": [],
"source_corporate_info_line_list": [],
"payslip_section_list": []
from DateTime import DateTime
line_dict_list = context.PaySheetTransaction_getLineListAsDict()
new_line_dict_list = []
previous_line_dict = None
previous_report_section = None
gross_category = 'base_amount/payroll/report/salary/gross'
line_to_group_list = []
exception_line = True
def getReportSectionTitle(title):
if title.startswith('report_section'):
return context.portal_categories.restrictedTraverse(title).getTitle()
return title
def getFakeLineDictForNewSection(title, base=0, employer_price=0, employer_total_price=0, employee_price=0, employee_total_price=0):
return {
'title': title.upper(),
'base': base,
'employer_price': employer_price,
'employer_total_price': employer_total_price,
'employee_price': employee_price,
'employee_total_price': employee_total_price
}
def groupSameReportSectionLine(line_to_group_list):
tmp_base_dict = {}
title = getReportSectionTitle(line_to_group_list[0]['report_section'])
for line_dict in line_to_group_list:
base = line_dict['base']
if base not in tmp_base_dict:
tmp_base_dict[base] = getFakeLineDictForNewSection(title,base)
tmp_base_dict[base]['employer_price'] = tmp_base_dict[base]['employer_price'] + (line_dict['employer_price'] or 0)
tmp_base_dict[base]['employer_total_price'] = tmp_base_dict[base]['employer_total_price'] + (line_dict['employer_total_price'] or 0)
tmp_base_dict[base]['employee_price'] = tmp_base_dict[base]['employee_price'] + (line_dict['employee_price'] or 0)
tmp_base_dict[base]['employee_total_price'] = tmp_base_dict[base]['employee_total_price'] + (line_dict['employee_total_price'] or 0)
new_value_list = []
for _, value in tmp_base_dict.iteritems():
new_value_list.append(value)
return new_value_list
employer_total_price = 0
employee_total_price = 0
for current_line_dict in line_dict_list:
if current_line_dict['resource_title'].startswith('CSG'):
csg_base = current_line_dict['base']
current_report_section = current_line_dict['report_section'] or current_line_dict['group']
# New section
if previous_report_section != current_report_section:
if len(line_to_group_list):
new_line_dict_list += groupSameReportSectionLine(line_to_group_list)
exception_line = True
line_to_group_list = []
if current_report_section == 'report_section/payroll/fr/amount_not_subject_to_contribution':
new_line_dict_list.append(
getFakeLineDictForNewSection(
context.Base_translateString("TOTAL FEES AND CONTRIBUTIONS"),
employer_total_price=employer_total_price,
employee_total_price=employee_total_price))
employer_total_price = 0
employee_total_price = 0
# add one line for gross salary
if previous_line_dict is not None and gross_category in previous_line_dict['base_contribution_list'] and gross_category not in current_line_dict['base_contribution_list']:
new_line_dict_list.append(
getFakeLineDictForNewSection(
context.Base_translateString("Gross Salary"),
base=context.PaySheetTransaction_getMovementTotalPriceFromCategory(base_contribution="base_contribution/%s"%gross_category)))
if current_line_dict['group_by_report_section']:
line_to_group_list.append(current_line_dict)
else:
if previous_report_section != current_report_section:
new_line_dict_list.append(getFakeLineDictForNewSection(getReportSectionTitle(current_report_section)))
if len(line_to_group_list) and exception_line:
exception_line = False
new_line_dict_list.append(getFakeLineDictForNewSection(getReportSectionTitle(current_report_section)))
new_line_dict_list.append(current_line_dict)
employer_total_price += (current_line_dict['employer_total_price'] or 0)
employee_total_price += (current_line_dict['employee_total_price'] or 0)
previous_report_section = current_report_section
previous_line_dict = current_line_dict
new_line_dict_list.append(
getFakeLineDictForNewSection(
context.Base_translateString("TOTAL AMOUNTS NOT SUBJECT TO CONTRIBUTIONS"),
employer_total_price=employer_total_price,
employee_total_price=employee_total_price))
gross_salary = context.PaySheetTransaction_getMovementTotalPriceFromCategory(base_contribution="base_contribution/%s"%gross_category)
net_salary = context.PaySheetTransaction_getMovementTotalPriceFromCategory(
base_contribution='base_contribution/base_amount/payroll/report/salary/net',
contribution_share='contribution_share/employee')
currency = context.getPriceCurrencyValue() is not None and context.getPriceCurrencyValue().getShortTitle() or context.getPriceCurrencyReference() or ''
start_date = context.getStartDate()
amount_benefit = 0
if DateTime('2018/01/01') <= start_date <= DateTime('2018/09/30'):
amount_benefit = gross_salary * 0.022 - csg_base * 0.017
elif start_date >= DateTime('2018/10/01'):
amount_benefit = gross_salary * 0.0315 - csg_base * 0.017
return {
"payslip_line_list": new_line_dict_list,
"gross_salary": gross_salary,
"net_salary": net_salary,
"currency": currency,
"amount_benefit": amount_benefit
}
return response
......@@ -11,12 +11,12 @@ Wire PaySheetTransaction through to erp5_corporate_identity Report
# format: output in html*, pdf
# international_form translate terms
# language target_language
return context.Base_printAsReport(
format=format,
report_title="Payslip",
report_header = "PaySheetTransaction_generatePayslipReportHeader",
report_name = "PaySheetTransaction_generatePayslipReport",
language=target_language,
report_footer = "PaySheetTransaction_generatePayslipReportFooter",
document_language=target_language,
start_date=context.getStartDate() or None,
stop_date=context.getStopDate() or None,
**kw
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment