Commit 62f2af80 authored by Nicolas Wavrant's avatar Nicolas Wavrant

erp5_payroll_l10n_fr: can create DSN reports for organisations paying quaterly

parent 0926dc6f
from Products.ERP5Type.DateUtils import getIntervalBetweenDates, getNumberOfDayInMonth
from Products.ERP5Type.DateUtils import addToDate, getIntervalBetweenDates, getNumberOfDayInMonth
portal = context.getPortalObject()
portal_categories = context.portal_categories
......@@ -159,27 +159,32 @@ if block_id == 'S21.G00.15':
if block_id == 'S21.G00.20':
payment_transaction = target
bank_account = target.getSourcePaymentValue()
payment_source_section = payment_transaction.getSourceSectionValue()
payment_source_trade = payment_transaction.getSourceTradeValue()
amount = (kw['amount'] if 'amount' in kw else payment_transaction.AccountingTransactionLine_statSourceDebit())
if kw['establishment'] == payment_source_trade:
# A main establishment is paying for this one
rubric_value_dict['S21.G00.20.005'] = formatFloat(0.)
rubric_value_dict['S21.G00.20.010'] = '06'
rubric_value_dict['S21.G00.20.012'] = ''.join(payment_transaction.getSourceSectionValue().getCorporateRegistrationCode().split(' '))
elif kw['establishment'] == payment_transaction.getSourceSectionValue():
if payment_source_trade == kw['payer'] == kw['establishment']:
payment_mode = payment_transaction.getPaymentModeValue()
assert payment_mode is not None, "No payment mode defined on %s" % payment_transaction.absolute_url()
# Establishment pays for itself
rubric_value_dict['S21.G00.20.003'] = bank_account.getBicCode()
rubric_value_dict['S21.G00.20.004'] = bank_account.getIban()
rubric_value_dict['S21.G00.20.005'] = payment_transaction.AccountingTransactionLine_statSourceDebit()
rubric_value_dict['S21.G00.20.010'] = payment_transaction.getPaymentModeValue().getCodification()
if payment_source_trade is not None:
rubric_value_dict['S21.G00.20.003'] = ''.join(bank_account.getBicCode().split(' '))
rubric_value_dict['S21.G00.20.004'] = ''.join(bank_account.getIban().split(' '))
rubric_value_dict['S21.G00.20.005'] = amount
rubric_value_dict['S21.G00.20.010'] = payment_mode.getCodification()
if payment_source_trade is not None and payment_source_trade != payment_source_section:
# Establishment pays also for another one
rubric_value_dict['S21.G00.20.012'] = ''.join(kw['establishment'].getCorporateRegistrationCode().split(' '))
else:
# A main establishment is paying for this one
rubric_value_dict['S21.G00.20.005'] = formatFloat(0.)
rubric_value_dict['S21.G00.20.010'] = '06'
rubric_value_dict['S21.G00.20.012'] = ''.join(payment_source_section.getCorporateRegistrationCode().split(' '))
rubric_value_dict['S21.G00.20.001'] = kw['corporate_registration_code']
rubric_value_dict['S21.G00.20.002'] = ''.join(kw['establishment'].getCorporateRegistrationCode().split(' ')) # TODO: Check if it is always needed
rubric_value_dict['S21.G00.20.006'] = formatDate(payment_transaction.getStartDate()) # TODO: check simulation correctly sets it
rubric_value_dict['S21.G00.20.007'] = formatDate(payment_transaction.getStopDate())
rubric_value_dict['S21.G00.20.002'] = ''.join(kw['establishment'].getCorporateRegistrationCode().split(' '))
start_date = kw['first_date_of_month']
rubric_value_dict['S21.G00.20.006'] = formatDate(start_date)
rubric_value_dict['S21.G00.20.007'] = formatDate(kw['last_date_of_month'])
rubric_value_dict['S21.G00.20.008'] = ''
# Bordereau de cotisation due
......@@ -189,7 +194,7 @@ if block_id == 'S21.G00.22':
rubric_value_dict['S21.G00.22.002'] = ''.join(kw['establishment'].getCorporateRegistrationCode().split(' '))
rubric_value_dict['S21.G00.22.003'] = formatDate(kw['start_date'])
rubric_value_dict['S21.G00.22.004'] = formatDate(kw['stop_date'])
rubric_value_dict['S21.G00.22.005'] = payment_transaction.AccountingTransactionLine_statSourceDebit()
rubric_value_dict['S21.G00.22.005'] = formatFloat(kw['amount'])
if block_id == 'S21.G00.23':
rubric_value_dict['S21.G00.23.001'] = target['code'][:3]
......@@ -197,16 +202,17 @@ if block_id == 'S21.G00.23':
rubric_value_dict['S21.G00.23.003'] = ('' if not target['rate'] else formatFloat(target['rate']))
if target['quantity']:
assert target['quantity'] > 0
rubric_value_dict['S21.G00.23.005'] = formatFloat(target['quantity'])
rubric_value_dict['S21.G00.23.005'] = formatFloat(round(target['quantity']))
else:
rubric_value_dict['S21.G00.23.004'] = formatFloat(target['base'])
rubric_value_dict['S21.G00.23.004'] = formatFloat(round(target['base']))
rubric_value_dict['S21.G00.23.006'] = target['zip_code']
# Individu
if block_id == 'S21.G00.30':
birth_country_code = getCountryCode(target)
address = target.getDefaultAddressStreetAddress().strip().split('\n')
rubric_value_dict["S21.G00.30.001"] = "".join(target.getSocialCode('').split(' '))[:13]
social_code = target.getSocialCode('')
rubric_value_dict["S21.G00.30.001"] = ("" if not social_code else "".join(social_code.split(' '))[:13])
rubric_value_dict["S21.G00.30.002"] = target.getLastName()
rubric_value_dict["S21.G00.30.003"] = ''
rubric_value_dict["S21.G00.30.004"] = " ".join([target.getFirstName(), target.getMiddleName() or '']).strip()
......@@ -248,7 +254,10 @@ if block_id == 'S21.G00.40':
rubric_value_dict["S21.G00.40.016"] = enrollment_record.getLocalScheme()
rubric_value_dict["S21.G00.40.017"] = target.getCollectiveAgreementTitle()
rubric_value_dict["S21.G00.40.018"] = enrollment_record.getMedicalScheme()
rubric_value_dict["S21.G00.40.019"] = ''.join(target.getDestinationValue().getCorporateRegistrationCode().split(' '))[-5:]
try:
rubric_value_dict["S21.G00.40.019"] = ''.join(target.getDestinationValue().getCorporateRegistrationCode().split(' '))[-5:]
except AttributeError:
raise AttributeError(target, target.getDestinationValue())
rubric_value_dict["S21.G00.40.020"] = enrollment_record.getRetirementScheme()
rubric_value_dict["S21.G00.40.021"] = enrollment_record.getEnrollmentCausality()
rubric_value_dict["S21.G00.40.022"] = ''
......@@ -278,9 +287,9 @@ if block_id == 'S21.G00.40':
if block_id == 'S21.G00.50':
# target is a paysheet
rubric_value_dict['S21.G00.50.001'] = formatDate(context.getEffectiveDate())
rubric_value_dict['S21.G00.50.002'] = kw['net_taxable_salary']
rubric_value_dict['S21.G00.50.002'] = formatFloat(kw['net_taxable_salary'])
rubric_value_dict['S21.G00.50.003'] = ''
rubric_value_dict['S21.G00.50.004'] = kw['net_salary']
rubric_value_dict['S21.G00.50.004'] = formatFloat(kw['net_salary'])
if block_id == 'S21.G00.52':
rubric_value_dict['S21.G00.52.001'] = target['code']
......@@ -304,14 +313,14 @@ if block_id == 'S21.G00.55':
if corporate_registration_code not in ('ORGANISATION1', 'ORGANISATION2'):
return {}
payment_source_trade = target.getSourceTradeValue()
if kw['establishment'] == payment_source_trade:
rubric_value_dict['S21.G00.55.001'] = formatFloat(0.)
elif kw['establishment'] == target.getSourceSectionValue():
if kw['establishment'] == target.getSourceSectionValue():
rubric_value_dict['S21.G00.55.001'] = target.AccountingTransactionLine_statSourceDebit()
else:
rubric_value_dict['S21.G00.55.001'] = formatFloat(0.)
rubric_value_dict['S21.G00.55.002'] = ''
rubric_value_dict['S21.G00.55.003'] = 'REF_CONTRACT' + corporate_registration_code[-1]
rubric_value_dict['S21.G00.55.004'] = getPaymentPeriod(target.getStopDate(), 'M')
rubric_value_dict['S21.G00.55.004'] = getPaymentPeriod(context.getEffectiveDate(), 'M')
# Fin du contrat
if block_id == 'S21.G00.62':
......@@ -341,20 +350,23 @@ if block_id == 'S21.G00.65':
# Affiliation Prevoyance
if block_id == 'S21.G00.70':
if enrollment_record.getContractType() == '29':
return rubric_value_dict
# XXX: Hack as some organisations may have several contracts
return [
{
if kw['contract_id'] == '1':
return {
'S21.G00.70.004': 'Option1',
'S21.G00.70.005': '',
'S21.G00.70.012': '1',
'S21.G00.70.013': '1',
},
{
}
elif kw['contract_id'] == '2':
return {
'S21.G00.70.004': 'Option2',
'S21.G00.70.005': '1',
'S21.G00.70.012': '2',
'S21.G00.70.013': '2',
}]
}
# Retraite complementaire
if block_id == 'S21.G00.71':
......@@ -394,13 +406,13 @@ if block_id == 'S21.G00.86':
seniority = getIntervalBetweenDates(career_start_date, DateTime())
if seniority['year'] != 0:
rubric_value_dict['S21.G00.86.002'] = '03'
rubric_value_dict['S21.G00.86.003'] = seniority['year']
rubric_value_dict['S21.G00.86.003'] = int(seniority['year'])
elif seniority['month'] != 0:
rubric_value_dict['S21.G00.86.002'] = '02'
rubric_value_dict['S21.G00.86.003'] = seniority['month']
rubric_value_dict['S21.G00.86.003'] = int(seniority['month'])
elif seniority['day'] != 0:
rubric_value_dict['S21.G00.86.002'] = '01'
rubric_value_dict['S21.G00.86.003'] = seniority['day']
rubric_value_dict['S21.G00.86.003'] = int(seniority['day'])
rubric_value_dict['S21.G00.86.001'] = '01'
rubric_value_dict['S21.G00.86.005'] = '00000'
......
......@@ -13,16 +13,10 @@ result = portal.portal_catalog(portal_type="DSN Monthly Report",
simulation_state="validated",
sort_on=[("creation_date", "descending")])
if len(result) != 0:
# if there is a previous DSN, we report leave requests from last end-of-pay date
last_dsn = result[0].getObject()
from_date = last_dsn.getEffectiveDate()
else:
# else we get 1st day of current month
from_date = DateTime(effective_date.year(), effective_date.month(), 1)
from_date = DateTime(effective_date.year(), effective_date.month(), 1)
# We report leave periods which are not over yet ...
result = portal.portal_catalog(query=SimpleQuery(expiration_date=None), portal_type='Leave Request Period')
result = portal.portal_catalog(SimpleQuery(expiration_date=None), portal_type='Leave Request Period')
leave_period_list = [period.getObject() for period in result]
# ... And leave periods which ended during last period
......@@ -34,9 +28,9 @@ leave_period_list.extend([period.getObject() for period in result if period.getE
def formatDate(datetime):
return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year())
def getLeaveBlocAsDict(leave_period):
def getLeaveBlocAsDict(leave_period, leave_category):
bloc = {}
bloc['S21.G00.60.001'] = leave_period.getResourceValue().getCodification()
bloc['S21.G00.60.001'] = leave_category.getCodification()
bloc['S21.G00.60.002'] = formatDate(leave_period.getStartDate())
bloc['S21.G00.60.003'] = formatDate(leave_period.getStopDate())
# employee left during this period
......@@ -46,7 +40,6 @@ def getLeaveBlocAsDict(leave_period):
bloc['S21.G00.60.005'] = formatDate(first_subrogation_day)
# 3 months of subrogation, as defined in the collective agreement
bloc['S21.G00.60.006'] = formatDate(addToDate(first_subrogation_day, month=3, days=-1))
bank_account = payment_transaction.getSourcePaymentValue()
bloc['S21.G00.60.007'] = bank_account.getIban()
bloc['S21.G00.60.008'] = bank_account.getBicCode()
else:
......@@ -57,18 +50,22 @@ def getLeaveBlocAsDict(leave_period):
bloc['S21.G00.60.011'] = '01' # Restart normally
return bloc
leave_period_type_list = portal_categories.calendar_period_type.social_declaration.l10n.fr.getCategoryChildValueList()
leave_period_type_set = set(portal_categories.use.social_declaration.l10n.fr.leave.getCategoryChildValueList())
# Create dict containing a DSN leave blocs, grouped by employee
leave_dict = {}
for period in leave_period_list:
# some leave periods don't have to be reported in DSN
if period.getResourceValue() not in leave_period_type_list:
period_resource = period.getResourceValue()
assert period_resource is not None, 'No type set on Leave Request %s' % period.absolute_url()
leave_category = set(period.getResourceValue().getUseValueList()).intersection(leave_period_type_set)
if not leave_category:
continue
# Let's make a DSN Bloc for this leave period
leave_category = leave_category.pop()
if period.getDestinationValue() in leave_dict.keys():
leave_dict[period.getDestination()].append(getLeaveBlocAsDict(period))
leave_dict[period.getDestination()].append(getLeaveBlocAsDict(period, leave_category))
else:
leave_dict[period.getDestination()] = [getLeaveBlocAsDict(period),]
leave_dict[period.getDestination()] = [getLeaveBlocAsDict(period, leave_category),]
return leave_dict
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>payment_transaction</string> </value>
<value> <string>bank_account</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
from Products.ERP5Type.DateUtils import getNumberOfDayInMonth
from Products.ERP5Type.DateUtils import addToDate, getNumberOfDayInMonth
if context.getSourceAdministration() is None \
or context.getEffectiveDate() is None \
......@@ -18,6 +18,11 @@ def getLastDateOfMonth(date):
declared_month = context.getEffectiveDate().month()
declared_year = context.getEffectiveDate().year()
last_date_of_month = getLastDateOfMonth(context.getEffectiveDate())
first_date_of_month = DateTime(context.getEffectiveDate().year(),
context.getEffectiveDate().month(),
1)
# Get all paysheets for requested month
related_accounting_transaction_list = context.getAggregateRelatedValueList()
payment_transaction_list = sorted([transaction for transaction in related_accounting_transaction_list
......@@ -29,19 +34,29 @@ paysheet_id_list = [transaction.getId() for transaction in paysheet_list]
change_block_dict = context.DSNMonthlyReport_getChangeBlockDict()
organisation_contact = context.getSourceAdministrationValue()
establishment = accounting_module.restrictedTraverse(paysheet_id_list[0]).getDestinationSectionValue()
establishment = accounting_module.restrictedTraverse(paysheet_id_list[0]).getDestinationTradeValue()
establishment_registration_code = ''.join(establishment.getCorporateRegistrationCode().split(' '))
# Finds the head office of the comany
organisation = payment_transaction_list[0].getSourceSectionValue()
if len(payment_transaction_list):
organisation = payment_transaction_list[0].getSourceSectionValue()
else:
organisation = paysheet_list[0].getDestinationSectionValue()
# Variable containing all the record of the DSN
dsn_file = []
dsn_order = 1 # Increment for each DSN
nb_dsn = 1 # Increment for each DSN
# XXX: for the moment just use one of the payment transactions to retrieve
# the bank account. Later, a special accounting document should be provided
leave_period_dict = context.DSNMonthlyReport_getLeavePeriodDict(payment_transaction_list[0])
if len(payment_transaction_list):
bank_account = payment_transaction_list[0].getSourcePaymentValue()
else:
bank_account, = [bank_account for bank_account
in organisation.objectValues(portal_type='Bank Account')
if bank_account.getValidationState() == 'validated']
leave_period_dict = context.DSNMonthlyReport_getLeavePeriodDict(bank_account)
employee_list = []
# DSN HEADERS
......@@ -50,16 +65,12 @@ dsn_file.append(getDSNBlockDict(block_id='S10.G00.01', target=organisation))
dsn_file.append(getDSNBlockDict(block_id='S10.G00.02', target=organisation_contact))
# Monthly DSN
dsn_file.append(getDSNBlockDict(block_id='S20.G00.05', year=declared_year, month=declared_month, order=dsn_order))
dsn_file.append(getDSNBlockDict(block_id='S20.G00.05', year=declared_year, month=declared_month, order=nb_dsn))
dsn_file.append(getDSNBlockDict(block_id='S21.G00.06', target=organisation))
dsn_file.append(getDSNBlockDict(block_id='S21.G00.11', target=establishment, manpower=len(paysheet_id_list)))
collective_contract = getDSNBlockDict(block_id='S21.G00.15')
if isinstance(collective_contract, list):
dsn_file.extend(collective_contract)
else:
dsn_file.append(collective_contract)
# Print aggregated cotisations
employee_result_list = [
......@@ -70,6 +81,14 @@ employee_result_list = [
employee_data_list, paysheet_data_list = zip(*employee_result_list)
for employee_data_dict, paysheet_data_dict in employee_result_list:
insurance_contract_id_list = set([x[1] for x in paysheet_data_dict['taxable_base']])
collective_contract_list = getDSNBlockDict(block_id='S21.G00.15')
for collective_contract in collective_contract_list:
if collective_contract['S21.G00.15.005'] in insurance_contract_id_list:
dsn_file.append(collective_contract)
# Generate aggregated contributions
aggregated_social_contribution_dict = {}
social_contribution_organisation = None
......@@ -85,32 +104,92 @@ for employee_result in paysheet_data_list:
if ctp_code not in aggregated_social_contribution_dict:
aggregated_social_contribution_dict[ctp_code] = employee_ctp[ctp_code].copy()
else:
aggregated_social_contribution_dict[ctp_code]['base'] = \
aggregated_social_contribution_dict[ctp_code]['base'] + employee_ctp[ctp_code]['base']
for summing_parameter in ('base', 'quantity'):
aggregated_social_contribution_dict[ctp_code][summing_parameter] = \
aggregated_social_contribution_dict[ctp_code][summing_parameter] + employee_ctp[ctp_code][summing_parameter]
# Find the payment transaction for the social contributions
for payment in payment_transaction_list:
if payment.getDestinationSectionValue().getCorporateRegistrationCode() == social_contribution_organisation:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.20',
target=payment,
corporate_registration_code=social_contribution_organisation,
establishment=establishment))
dsn_file.append(getDSNBlockDict(block_id='S21.G00.22',
target=payment,
corporate_registration_code=social_contribution_organisation,
establishment=establishment,
start_date=social_contribution_start_date,
stop_date=social_contribution_stop_date))
for ctp_code in aggregated_social_contribution_dict:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.23',
target=aggregated_social_contribution_dict[ctp_code]))
else:
if len(payment_transaction_list):
for payment in payment_transaction_list:
corporate_registration_code = payment.getDestinationSectionValue().getCorporateRegistrationCode()
dsn_file.append(getDSNBlockDict(block_id='S21.G00.20',
target=payment,
corporate_registration_code=corporate_registration_code,
establishment=establishment))
dsn_file.append(getDSNBlockDict(block_id='S21.G00.55', target=payment, establishment=establishment))
if corporate_registration_code == social_contribution_organisation.getCorporateRegistrationCode():
if establishment.isQuaterlyPayment():
amount_list = []
for i in range(3):
start_date = addToDate(first_date_of_month, month=-i)
stop_date = addToDate(last_date_of_month, month=-i) + 1
amount = -1. * portal.portal_simulation.getInventory(
from_date=start_date,
to_date=stop_date,
section_uid=organisation.getUid(),
mirror_section_uid=social_contribution_organisation.getUid(),
node_uid=portal.account_module['securite_sociale'].getUid(),
ledger_uid=portal.portal_categories.ledger.accounting.general.getUid(),
parent_portal_type='Accounting Transaction',
)
amount_list.append(amount)
dsn_file.append(getDSNBlockDict(block_id='S21.G00.20',
target=payment,
corporate_registration_code=social_contribution_organisation.getCorporateRegistrationCode(),
first_date_of_month=start_date,
last_date_of_month=getLastDateOfMonth(start_date),
establishment=establishment,
payer=establishment,
amount=amount_list[-1]))
# Let's check that difference is < 1 cts
assert sum(amount_list) - payment.AccountingTransactionLine_statSourceDebit() * 100 < 1, 'Error, URSSAF Amount to Pay for each month is different for URSSAF Amount to pay in total'
amount = amount_list[0]
else:
amount = payment.AccountingTransactionLine_statSourceDebit()
dsn_file.append(getDSNBlockDict(block_id='S21.G00.20',
target=payment,
corporate_registration_code=social_contribution_organisation.getCorporateRegistrationCode(),
first_date_of_month=first_date_of_month,
last_date_of_month=last_date_of_month,
establishment=establishment,
payer=establishment))
dsn_file.append(getDSNBlockDict(block_id='S21.G00.22',
corporate_registration_code=corporate_registration_code,
establishment=establishment,
start_date=social_contribution_start_date,
stop_date=social_contribution_stop_date,
amount=amount))
for ctp_code in aggregated_social_contribution_dict:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.23',
target=aggregated_social_contribution_dict[ctp_code]))
else:
if organisation.isQuaterlyPayment():
start_date = addToDate(first_date_of_month, month=-2)
else:
start_date = first_date_of_month
dsn_file.append(getDSNBlockDict(block_id='S21.G00.20',
target=payment,
corporate_registration_code=corporate_registration_code,
first_date_of_month=start_date,
last_date_of_month=last_date_of_month,
establishment=establishment,
payer=organisation))
dsn_file.append(getDSNBlockDict(block_id='S21.G00.55', target=payment, establishment=establishment))
else:
# If there is no Payment Transaction, then the organisation pays quaterly
amount = -1. * portal.portal_simulation.getInventory(
from_date=first_date_of_month,
to_date=last_date_of_month + 1,
section_uid=establishment.getUid(),
mirror_section_uid=social_contribution_organisation.getUid(),
node_uid=portal.account_module['securite_sociale'].getUid(),
ledger_uid=portal.portal_categories.ledger.accounting.general.getUid(),
parent_portal_type='Accounting Transaction',
)
dsn_file.append(getDSNBlockDict(block_id='S21.G00.22',
corporate_registration_code=social_contribution_organisation.getCorporateRegistrationCode(),
establishment=establishment,
start_date=first_date_of_month,
stop_date=last_date_of_month,
amount=amount))
for ctp_code in aggregated_social_contribution_dict:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.23',
target=aggregated_social_contribution_dict[ctp_code]))
for employee_data_dict, paysheet_data_dict in employee_result_list:
enrollment_record = employee_data_dict['enrollment_record']
......@@ -146,11 +225,16 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
'S21.G00.60.012')}
dsn_file.append(leave_block)
death_insurance_contract = getDSNBlockDict(block_id='S21.G00.70', enrollment_record=enrollment_record)
if isinstance(death_insurance_contract, list):
dsn_file.extend(death_insurance_contract)
else:
dsn_file.append(death_insurance_contract)
# All employees don't share all the insurance contract, so here we need to
# know to which the employee contributes. Let's loop over the keys of
# paysheet_data_dict['taxable_base'],
# which are of the form : (contribution_category, contract_id)
insurance_contract_id_list = set([x[1] for x in paysheet_data_dict['taxable_base']])
for insurance_contract_id in insurance_contract_id_list:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.70',
enrollment_record=enrollment_record,
contract_id=insurance_contract_id))
dsn_file.append(getDSNBlockDict(block_id='S21.G00.71', enrollment_record=enrollment_record))
......@@ -180,9 +264,9 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
del paysheet_data_dict['individual_contribution'][('018', '')]
if taxable_base_category['code'] == '03': # Assiette Brute deplafonnee
if ('03', '') in paysheet_data_dict['taxable_base_component']:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.79', target=paysheet_data_dict['taxable_base_component'][('03', '')]))
del paysheet_data_dict['taxable_base_component'][('03', '')]
if ('01', '') in paysheet_data_dict['taxable_base_component']:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.79', target=paysheet_data_dict['taxable_base_component'][('01', '')]))
del paysheet_data_dict['taxable_base_component'][('01', '')]
if ('064', '') in paysheet_data_dict['individual_contribution']:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.81', target=paysheet_data_dict['individual_contribution'][('064', '')]))
del paysheet_data_dict['individual_contribution'][('064', '')]
......@@ -213,23 +297,21 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
dsn_file.append(employee_data_dict['seniority'])
# Add leave event DSN if needed
last_date_of_month = getLastDateOfMonth(context.getEffectiveDate())
first_date_of_month = DateTime(context.getEffectiveDate().year(),
context.getEffectiveDate().month(),
1)
if len(leave_period_dict):
for employee in leave_period_dict:
for period in leave_period_dict[employee]:
leave_date_as_string = period['S21.G00.60.002']
year = int(leave_date_as_string[4:])
month = int(leave_date_as_string[2:4])
day = int(leave_date_as_string[:2])
leave_date = DateTime(year, month, day)
if leave_date < first_date_of_month:
continue
#leave_date_as_string = period['S21.G00.60.002']
#year = int(leave_date_as_string[4:])
#month = int(leave_date_as_string[2:4])
#day = int(leave_date_as_string[:2])
#leave_date = DateTime(year, month, day)
#if leave_date < first_date_of_month:
# continue
if employee in employee_list:
dsn_order += 1
nb_dsn += 1
dsn_order = portal.portal_ids.generateNewId(
id_generator='continuous_integer_increasing',
id_group='dsn_event_counter')
employee = portal.restrictedTraverse(employee)
dsn_file.append(getEventDSNBlockDict(block_id='S20.G00.05', dsn_type='04', order=dsn_order)) #'04' is DSN Leave Event
dsn_file.append(getEventDSNBlockDict(block_id='S20.G00.07', target=organisation_contact))
......@@ -264,7 +346,7 @@ for block in dsn_file:
dsn_report_string += "%s,'%s'\n" % (rubric, block[rubric])
# Footer block
footer = getDSNBlockDict(block_id='S90.G00.90', length=rubric_counter, dsn_record_counter=dsn_order)
footer = getDSNBlockDict(block_id='S90.G00.90', length=rubric_counter, dsn_record_counter=nb_dsn)
for rubric in sorted(footer.keys()):
dsn_report_string += "%s,'%s'\n" % (rubric, footer[rubric])
......
......@@ -24,6 +24,7 @@ all_taxable_base_set = set(portal_categories.getCategoryValue('base_amount/payro
all_taxable_base_component_set = set(portal_categories.getCategoryValue('base_amount/payroll/l10n/fr/taxable_base_component').objectValues(portal_type='Category'))
all_other_income_set = set(portal_categories.getCategoryValue('base_amount/payroll/l10n/fr/other_income').objectValues(portal_type='Category'))
all_other_bonus_set = set(portal_categories.getCategoryValue('base_amount/payroll/l10n/fr/other_bonus').objectValues(portal_type='Category'))
trainee_base_contribution = portal_categories.getCategoryValue('base_amount/payroll/l10n/fr/base/gratification_stage')
def formatDate(datetime):
return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year())
......@@ -54,17 +55,20 @@ ZIP_CODE = context.getDestinationSectionValue().getDefaultAddressZipCode()
INSEE_CODE = getINSEECode(ZIP_CODE)
def makeCTPBlock(movement, category):
return {
'code': category,
'corporate_registration_code': movement.getSourceSectionValue().getCorporateRegistrationCode(),
'cap': ('921' if category[-1] == 'P' else '920'),
'rate': (abs(getattr(movement, 'employer_price') * 100) if category in ('100A', '900D', '901D', '863A') else ''),
'base': round(movement.base),
'quantity': ((getattr(movement, 'employer_total_price', 0.) + getattr(movement, 'employee_total_price', 0.)) if category[:3] in ('437', '671') else ''),
'zip_code': (INSEE_CODE if category == '900T' else ''),
'start_date': movement.getStartDate(),
'stop_date': movement.getStopDate(),
}
quantity = 0.
if category[:3] in ('437', '671'):
quantity = getattr(movement, 'employer_total_price', 0.) + getattr(movement, 'employee_total_price', 0.)
return {
'code': category,
'corporate_registration_code': movement.getSourceSectionValue(),
'cap': ('921' if category[-1] == 'P' else '920'),
'rate': (abs(getattr(movement, 'employer_price') * 100) if category in ('100A', '900D', '901D', '863A') else ''),
'base': movement.base,
'quantity': quantity,
'zip_code': (INSEE_CODE if category == '900T' else ''),
'start_date': movement.getStartDate(),
'stop_date': movement.getStopDate(),
}
def makeTaxableBaseBlock(movement, category):
return {
......@@ -143,6 +147,7 @@ for movement in context.PaySheetTransaction_getMovementList():
contribution_dict = makeCTPBlock(movement, category)
if category in result["ctp"]:
result['ctp'][category]['base'] = result['ctp'][category]['base'] + contribution_dict['base']
result['ctp'][category]['quantity'] = result['ctp'][category]['quantity'] + contribution_dict['quantity']
else:
result['ctp'][category] = contribution_dict
......@@ -178,22 +183,67 @@ for movement in context.PaySheetTransaction_getMovementList():
for category in other_income_set:
category = category.getCodification()
contribution_dict = makeOtherIncomeBlock(movement, category)
if category in result["other_income"]:
result['other_income'][category]['base'] = result['other_income'][category]['base'] + contribution_dict['base']
else:
result['other_income'][category] = contribution_dict
if contribution_dict['quantity']:
if category in result["other_income"]:
result['other_income'][category]['quantity'] = result['other_income'][category]['quantity'] + contribution_dict['quantity']
else:
result['other_income'][category] = contribution_dict
other_bonus_set = all_other_bonus_set.intersection(contribution_set)
total_bonus = 0.0
for category in other_bonus_set:
category = category.getCodification()
contribution_dict = makeOtherBonusBlock(movement, category)
if category in result["other_bonus"]:
result['other_bonus'][category]['base'] = result['other_bonus'][category]['base'] + contribution_dict['base']
else:
result['other_bonus'][category] = contribution_dict
total_bonus += contribution_dict['quantity']
if contribution_dict['quantity']:
if category in result["other_bonus"]:
result['other_bonus'][category]['quantity'] = result['other_bonus'][category]['quantity'] + contribution_dict['quantity']
else:
result['other_bonus'][category] = contribution_dict
total_bonus += contribution_dict['quantity']
if trainee_base_contribution in contribution_set:
trainee_bonus = movement.base
result['taxable_base'][('02', '')] = {
'code': '02',
'start_date': '',
'stop_date': '',
'base': 0.,
'contract_id': ''
}
result['taxable_base'][('03', '')] = {
'code': '03',
'start_date': '',
'stop_date': '',
'base': 0.,
'contract_id': ''
}
result['individual_contribution'][('022', '')] = {
'code': '022',
'corporate_registration_code': '',
'base': trainee_bonus,
'quantity': 0.,
'zip_code': '',
'contract_id': '',
}
# Let's try to calculate CTP 400D, which doesn't appear in the paysheet
if len(result['ctp']):
year_to_date_gross_salary = float(other_information_data_dict['year_to_date_gross_salary'])
try:
minimum_salary = float(context.getRatioQuantityFromReference('salaire_minimum_mensuel'))
except:
raise AttributeError(context.getUrl())
if year_to_date_gross_salary < 2.5 * minimum_salary * int(context.getStopDate().month()):
category = '400D'
result['ctp'][category] = {
'code': category,
'cap': ('921' if category[-1] == 'P' else '920'),
'rate': '',
'base': year_to_date_gross_salary,
'quantity': 0,
'zip_code': ''
}
######################################################################
# Remuneration and Activity
......@@ -210,6 +260,8 @@ def getRemunerationBlockAsDict(remuneration_type, amount):
# Corporate executives and trainees don't contribute to unemployment fee
if is_corporate_executive and remuneration_type == '002':
amount = 0.
elif is_trainee and remuneration_type == '001':
amount = trainee_bonus
elif is_trainee and remuneration_type == '002':
amount = 0.
# Nexedi trainees don't pay social fees
......
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