Commit e85055c9 authored by Nicolas Wavrant's avatar Nicolas Wavrant Committed by Eteri

erp5_payroll_l10n_fr: can create DSN reports for organisations paying quaterly

parent 2b5c705b
from Products.ERP5Type.DateUtils import getIntervalBetweenDates, getNumberOfDayInMonth from Products.ERP5Type.DateUtils import addToDate, getIntervalBetweenDates, getNumberOfDayInMonth
portal = context.getPortalObject() portal = context.getPortalObject()
portal_categories = context.portal_categories portal_categories = context.portal_categories
...@@ -159,27 +159,32 @@ if block_id == 'S21.G00.15': ...@@ -159,27 +159,32 @@ if block_id == 'S21.G00.15':
if block_id == 'S21.G00.20': if block_id == 'S21.G00.20':
payment_transaction = target payment_transaction = target
bank_account = target.getSourcePaymentValue() bank_account = target.getSourcePaymentValue()
payment_source_section = payment_transaction.getSourceSectionValue()
payment_source_trade = payment_transaction.getSourceTradeValue() payment_source_trade = payment_transaction.getSourceTradeValue()
amount = (kw['amount'] if 'amount' in kw else payment_transaction.AccountingTransactionLine_statSourceDebit())
if kw['establishment'] == payment_source_trade: if payment_source_trade == kw['payer'] == kw['establishment']:
# A main establishment is paying for this one payment_mode = payment_transaction.getPaymentModeValue()
rubric_value_dict['S21.G00.20.005'] = formatFloat(0.) assert payment_mode is not None, "No payment mode defined on %s" % payment_transaction.absolute_url()
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():
# Establishment pays for itself # Establishment pays for itself
rubric_value_dict['S21.G00.20.003'] = bank_account.getBicCode() rubric_value_dict['S21.G00.20.003'] = ''.join(bank_account.getBicCode().split(' '))
rubric_value_dict['S21.G00.20.004'] = bank_account.getIban() rubric_value_dict['S21.G00.20.004'] = ''.join(bank_account.getIban().split(' '))
rubric_value_dict['S21.G00.20.005'] = payment_transaction.AccountingTransactionLine_statSourceDebit() rubric_value_dict['S21.G00.20.005'] = amount
rubric_value_dict['S21.G00.20.010'] = payment_transaction.getPaymentModeValue().getCodification() rubric_value_dict['S21.G00.20.010'] = payment_mode.getCodification()
if payment_source_trade is not None: if payment_source_trade is not None and payment_source_trade != payment_source_section:
# Establishment pays also for another one # Establishment pays also for another one
rubric_value_dict['S21.G00.20.012'] = ''.join(kw['establishment'].getCorporateRegistrationCode().split(' ')) 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.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.002'] = ''.join(kw['establishment'].getCorporateRegistrationCode().split(' '))
rubric_value_dict['S21.G00.20.006'] = formatDate(payment_transaction.getStartDate()) # TODO: check simulation correctly sets it start_date = kw['first_date_of_month']
rubric_value_dict['S21.G00.20.007'] = formatDate(payment_transaction.getStopDate()) 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'] = '' rubric_value_dict['S21.G00.20.008'] = ''
# Bordereau de cotisation due # Bordereau de cotisation due
...@@ -189,7 +194,7 @@ if block_id == 'S21.G00.22': ...@@ -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.002'] = ''.join(kw['establishment'].getCorporateRegistrationCode().split(' '))
rubric_value_dict['S21.G00.22.003'] = formatDate(kw['start_date']) 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.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': if block_id == 'S21.G00.23':
rubric_value_dict['S21.G00.23.001'] = target['code'][:3] rubric_value_dict['S21.G00.23.001'] = target['code'][:3]
...@@ -197,16 +202,17 @@ if block_id == 'S21.G00.23': ...@@ -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'])) rubric_value_dict['S21.G00.23.003'] = ('' if not target['rate'] else formatFloat(target['rate']))
if target['quantity']: if target['quantity']:
assert target['quantity'] > 0 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: 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'] rubric_value_dict['S21.G00.23.006'] = target['zip_code']
# Individu # Individu
if block_id == 'S21.G00.30': if block_id == 'S21.G00.30':
birth_country_code = getCountryCode(target) birth_country_code = getCountryCode(target)
address = target.getDefaultAddressStreetAddress().strip().split('\n') 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.002"] = target.getLastName()
rubric_value_dict["S21.G00.30.003"] = '' rubric_value_dict["S21.G00.30.003"] = ''
rubric_value_dict["S21.G00.30.004"] = " ".join([target.getFirstName(), target.getMiddleName() or '']).strip() rubric_value_dict["S21.G00.30.004"] = " ".join([target.getFirstName(), target.getMiddleName() or '']).strip()
...@@ -248,7 +254,10 @@ if block_id == 'S21.G00.40': ...@@ -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.016"] = enrollment_record.getLocalScheme()
rubric_value_dict["S21.G00.40.017"] = target.getCollectiveAgreementTitle() 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.018"] = enrollment_record.getMedicalScheme()
try:
rubric_value_dict["S21.G00.40.019"] = ''.join(target.getDestinationValue().getCorporateRegistrationCode().split(' '))[-5:] 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.020"] = enrollment_record.getRetirementScheme()
rubric_value_dict["S21.G00.40.021"] = enrollment_record.getEnrollmentCausality() rubric_value_dict["S21.G00.40.021"] = enrollment_record.getEnrollmentCausality()
rubric_value_dict["S21.G00.40.022"] = '' rubric_value_dict["S21.G00.40.022"] = ''
...@@ -278,9 +287,9 @@ if block_id == 'S21.G00.40': ...@@ -278,9 +287,9 @@ if block_id == 'S21.G00.40':
if block_id == 'S21.G00.50': if block_id == 'S21.G00.50':
# target is a paysheet # target is a paysheet
rubric_value_dict['S21.G00.50.001'] = formatDate(context.getEffectiveDate()) 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.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': if block_id == 'S21.G00.52':
rubric_value_dict['S21.G00.52.001'] = target['code'] rubric_value_dict['S21.G00.52.001'] = target['code']
...@@ -304,14 +313,14 @@ if block_id == 'S21.G00.55': ...@@ -304,14 +313,14 @@ if block_id == 'S21.G00.55':
if corporate_registration_code not in ('ORGANISATION1', 'ORGANISATION2'): if corporate_registration_code not in ('ORGANISATION1', 'ORGANISATION2'):
return {} return {}
payment_source_trade = target.getSourceTradeValue() payment_source_trade = target.getSourceTradeValue()
if kw['establishment'] == payment_source_trade: if kw['establishment'] == target.getSourceSectionValue():
rubric_value_dict['S21.G00.55.001'] = formatFloat(0.)
elif kw['establishment'] == target.getSourceSectionValue():
rubric_value_dict['S21.G00.55.001'] = target.AccountingTransactionLine_statSourceDebit() 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.002'] = ''
rubric_value_dict['S21.G00.55.003'] = 'REF_CONTRACT' + corporate_registration_code[-1] 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 # Fin du contrat
if block_id == 'S21.G00.62': if block_id == 'S21.G00.62':
...@@ -341,20 +350,23 @@ if block_id == 'S21.G00.65': ...@@ -341,20 +350,23 @@ if block_id == 'S21.G00.65':
# Affiliation Prevoyance # Affiliation Prevoyance
if block_id == 'S21.G00.70': if block_id == 'S21.G00.70':
if enrollment_record.getContractType() == '29':
return rubric_value_dict
# XXX: Hack as some organisations may have several contracts # XXX: Hack as some organisations may have several contracts
return [ if kw['contract_id'] == '1':
{ return {
'S21.G00.70.004': 'Option1', 'S21.G00.70.004': 'Option1',
'S21.G00.70.005': '', 'S21.G00.70.005': '',
'S21.G00.70.012': '1', 'S21.G00.70.012': '1',
'S21.G00.70.013': '1', 'S21.G00.70.013': '1',
}, }
{ elif kw['contract_id'] == '2':
return {
'S21.G00.70.004': 'Option2', 'S21.G00.70.004': 'Option2',
'S21.G00.70.005': '1', 'S21.G00.70.005': '1',
'S21.G00.70.012': '2', 'S21.G00.70.012': '2',
'S21.G00.70.013': '2', 'S21.G00.70.013': '2',
}] }
# Retraite complementaire # Retraite complementaire
if block_id == 'S21.G00.71': if block_id == 'S21.G00.71':
...@@ -394,13 +406,13 @@ if block_id == 'S21.G00.86': ...@@ -394,13 +406,13 @@ if block_id == 'S21.G00.86':
seniority = getIntervalBetweenDates(career_start_date, DateTime()) seniority = getIntervalBetweenDates(career_start_date, DateTime())
if seniority['year'] != 0: if seniority['year'] != 0:
rubric_value_dict['S21.G00.86.002'] = '03' 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: elif seniority['month'] != 0:
rubric_value_dict['S21.G00.86.002'] = '02' 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: elif seniority['day'] != 0:
rubric_value_dict['S21.G00.86.002'] = '01' 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.001'] = '01'
rubric_value_dict['S21.G00.86.005'] = '00000' rubric_value_dict['S21.G00.86.005'] = '00000'
......
...@@ -13,16 +13,10 @@ result = portal.portal_catalog(portal_type="DSN Monthly Report", ...@@ -13,16 +13,10 @@ result = portal.portal_catalog(portal_type="DSN Monthly Report",
simulation_state="validated", simulation_state="validated",
sort_on=[("creation_date", "descending")]) sort_on=[("creation_date", "descending")])
if len(result) != 0: from_date = DateTime(effective_date.year(), effective_date.month(), 1)
# 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)
# We report leave periods which are not over yet ... # 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] leave_period_list = [period.getObject() for period in result]
# ... And leave periods which ended during last period # ... 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 ...@@ -34,9 +28,9 @@ leave_period_list.extend([period.getObject() for period in result if period.getE
def formatDate(datetime): def formatDate(datetime):
return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year()) return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year())
def getLeaveBlocAsDict(leave_period): def getLeaveBlocAsDict(leave_period, leave_category):
bloc = {} 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.002'] = formatDate(leave_period.getStartDate())
bloc['S21.G00.60.003'] = formatDate(leave_period.getStopDate()) bloc['S21.G00.60.003'] = formatDate(leave_period.getStopDate())
# employee left during this period # employee left during this period
...@@ -46,7 +40,6 @@ def getLeaveBlocAsDict(leave_period): ...@@ -46,7 +40,6 @@ def getLeaveBlocAsDict(leave_period):
bloc['S21.G00.60.005'] = formatDate(first_subrogation_day) bloc['S21.G00.60.005'] = formatDate(first_subrogation_day)
# 3 months of subrogation, as defined in the collective agreement # 3 months of subrogation, as defined in the collective agreement
bloc['S21.G00.60.006'] = formatDate(addToDate(first_subrogation_day, month=3, days=-1)) 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.007'] = bank_account.getIban()
bloc['S21.G00.60.008'] = bank_account.getBicCode() bloc['S21.G00.60.008'] = bank_account.getBicCode()
else: else:
...@@ -57,18 +50,22 @@ def getLeaveBlocAsDict(leave_period): ...@@ -57,18 +50,22 @@ def getLeaveBlocAsDict(leave_period):
bloc['S21.G00.60.011'] = '01' # Restart normally bloc['S21.G00.60.011'] = '01' # Restart normally
return bloc 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 # Create dict containing a DSN leave blocs, grouped by employee
leave_dict = {} leave_dict = {}
for period in leave_period_list: for period in leave_period_list:
# some leave periods don't have to be reported in DSN # 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 continue
# Let's make a DSN Bloc for this leave period # Let's make a DSN Bloc for this leave period
leave_category = leave_category.pop()
if period.getDestinationValue() in leave_dict.keys(): if period.getDestinationValue() in leave_dict.keys():
leave_dict[period.getDestination()].append(getLeaveBlocAsDict(period)) leave_dict[period.getDestination()].append(getLeaveBlocAsDict(period, leave_category))
else: else:
leave_dict[period.getDestination()] = [getLeaveBlocAsDict(period),] leave_dict[period.getDestination()] = [getLeaveBlocAsDict(period, leave_category),]
return leave_dict return leave_dict
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>payment_transaction</string> </value> <value> <string>bank_account</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
from Products.ERP5Type.DateUtils import getNumberOfDayInMonth from Products.ERP5Type.DateUtils import addToDate, getNumberOfDayInMonth
if context.getSourceAdministration() is None \ if context.getSourceAdministration() is None \
or context.getEffectiveDate() is None \ or context.getEffectiveDate() is None \
...@@ -18,6 +18,11 @@ def getLastDateOfMonth(date): ...@@ -18,6 +18,11 @@ def getLastDateOfMonth(date):
declared_month = context.getEffectiveDate().month() declared_month = context.getEffectiveDate().month()
declared_year = context.getEffectiveDate().year() 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 # Get all paysheets for requested month
related_accounting_transaction_list = context.getAggregateRelatedValueList() related_accounting_transaction_list = context.getAggregateRelatedValueList()
payment_transaction_list = sorted([transaction for transaction in related_accounting_transaction_list 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] ...@@ -29,19 +34,29 @@ paysheet_id_list = [transaction.getId() for transaction in paysheet_list]
change_block_dict = context.DSNMonthlyReport_getChangeBlockDict() change_block_dict = context.DSNMonthlyReport_getChangeBlockDict()
organisation_contact = context.getSourceAdministrationValue() 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(' ')) establishment_registration_code = ''.join(establishment.getCorporateRegistrationCode().split(' '))
# Finds the head office of the comany # 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 # Variable containing all the record of the DSN
dsn_file = [] 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 # XXX: for the moment just use one of the payment transactions to retrieve
# the bank account. Later, a special accounting document should be provided # 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 = [] employee_list = []
# DSN HEADERS # DSN HEADERS
...@@ -50,16 +65,12 @@ dsn_file.append(getDSNBlockDict(block_id='S10.G00.01', target=organisation)) ...@@ -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)) dsn_file.append(getDSNBlockDict(block_id='S10.G00.02', target=organisation_contact))
# Monthly DSN # 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.06', target=organisation))
dsn_file.append(getDSNBlockDict(block_id='S21.G00.11', target=establishment, manpower=len(paysheet_id_list))) dsn_file.append(getDSNBlockDict(block_id='S21.G00.11', target=establishment, manpower=len(paysheet_id_list)))
collective_contract = getDSNBlockDict(block_id='S21.G00.15') 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 # Print aggregated cotisations
employee_result_list = [ employee_result_list = [
...@@ -70,6 +81,14 @@ employee_result_list = [ ...@@ -70,6 +81,14 @@ employee_result_list = [
employee_data_list, paysheet_data_list = zip(*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 # Generate aggregated contributions
aggregated_social_contribution_dict = {} aggregated_social_contribution_dict = {}
social_contribution_organisation = None social_contribution_organisation = None
...@@ -85,32 +104,92 @@ for employee_result in paysheet_data_list: ...@@ -85,32 +104,92 @@ for employee_result in paysheet_data_list:
if ctp_code not in aggregated_social_contribution_dict: if ctp_code not in aggregated_social_contribution_dict:
aggregated_social_contribution_dict[ctp_code] = employee_ctp[ctp_code].copy() aggregated_social_contribution_dict[ctp_code] = employee_ctp[ctp_code].copy()
else: else:
aggregated_social_contribution_dict[ctp_code]['base'] = \ for summing_parameter in ('base', 'quantity'):
aggregated_social_contribution_dict[ctp_code]['base'] + employee_ctp[ctp_code]['base'] 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 # Find the payment transaction for the social contributions
for payment in payment_transaction_list: if len(payment_transaction_list):
if payment.getDestinationSectionValue().getCorporateRegistrationCode() == social_contribution_organisation: for payment in payment_transaction_list:
corporate_registration_code = payment.getDestinationSectionValue().getCorporateRegistrationCode()
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', dsn_file.append(getDSNBlockDict(block_id='S21.G00.20',
target=payment, target=payment,
corporate_registration_code=social_contribution_organisation, corporate_registration_code=social_contribution_organisation.getCorporateRegistrationCode(),
establishment=establishment)) first_date_of_month=start_date,
dsn_file.append(getDSNBlockDict(block_id='S21.G00.22', 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, target=payment,
corporate_registration_code=social_contribution_organisation, 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, establishment=establishment,
start_date=social_contribution_start_date, start_date=social_contribution_start_date,
stop_date=social_contribution_stop_date)) stop_date=social_contribution_stop_date,
amount=amount))
for ctp_code in aggregated_social_contribution_dict: for ctp_code in aggregated_social_contribution_dict:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.23', dsn_file.append(getDSNBlockDict(block_id='S21.G00.23',
target=aggregated_social_contribution_dict[ctp_code])) target=aggregated_social_contribution_dict[ctp_code]))
else: else:
corporate_registration_code = payment.getDestinationSectionValue().getCorporateRegistrationCode() 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', dsn_file.append(getDSNBlockDict(block_id='S21.G00.20',
target=payment, target=payment,
corporate_registration_code=corporate_registration_code, corporate_registration_code=corporate_registration_code,
establishment=establishment)) 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)) 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: for employee_data_dict, paysheet_data_dict in employee_result_list:
enrollment_record = employee_data_dict['enrollment_record'] enrollment_record = employee_data_dict['enrollment_record']
...@@ -146,11 +225,16 @@ for employee_data_dict, paysheet_data_dict in employee_result_list: ...@@ -146,11 +225,16 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
'S21.G00.60.012')} 'S21.G00.60.012')}
dsn_file.append(leave_block) dsn_file.append(leave_block)
death_insurance_contract = getDSNBlockDict(block_id='S21.G00.70', enrollment_record=enrollment_record) # All employees don't share all the insurance contract, so here we need to
if isinstance(death_insurance_contract, list): # know to which the employee contributes. Let's loop over the keys of
dsn_file.extend(death_insurance_contract) # paysheet_data_dict['taxable_base'],
else: # which are of the form : (contribution_category, contract_id)
dsn_file.append(death_insurance_contract) 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)) 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: ...@@ -180,9 +264,9 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
del paysheet_data_dict['individual_contribution'][('018', '')] del paysheet_data_dict['individual_contribution'][('018', '')]
if taxable_base_category['code'] == '03': # Assiette Brute deplafonnee if taxable_base_category['code'] == '03': # Assiette Brute deplafonnee
if ('03', '') in paysheet_data_dict['taxable_base_component']: 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'][('03', '')])) dsn_file.append(getDSNBlockDict(block_id='S21.G00.79', target=paysheet_data_dict['taxable_base_component'][('01', '')]))
del paysheet_data_dict['taxable_base_component'][('03', '')] del paysheet_data_dict['taxable_base_component'][('01', '')]
if ('064', '') in paysheet_data_dict['individual_contribution']: if ('064', '') in paysheet_data_dict['individual_contribution']:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.81', target=paysheet_data_dict['individual_contribution'][('064', '')])) dsn_file.append(getDSNBlockDict(block_id='S21.G00.81', target=paysheet_data_dict['individual_contribution'][('064', '')]))
del 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: ...@@ -213,23 +297,21 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
dsn_file.append(employee_data_dict['seniority']) dsn_file.append(employee_data_dict['seniority'])
# Add leave event DSN if needed # 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): if len(leave_period_dict):
for employee in leave_period_dict: for employee in leave_period_dict:
for period in leave_period_dict[employee]: for period in leave_period_dict[employee]:
leave_date_as_string = period['S21.G00.60.002'] #leave_date_as_string = period['S21.G00.60.002']
year = int(leave_date_as_string[4:]) #year = int(leave_date_as_string[4:])
month = int(leave_date_as_string[2:4]) #month = int(leave_date_as_string[2:4])
day = int(leave_date_as_string[:2]) #day = int(leave_date_as_string[:2])
leave_date = DateTime(year, month, day) #leave_date = DateTime(year, month, day)
if leave_date < first_date_of_month: #if leave_date < first_date_of_month:
continue # continue
if employee in employee_list: 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) 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.05', dsn_type='04', order=dsn_order)) #'04' is DSN Leave Event
dsn_file.append(getEventDSNBlockDict(block_id='S20.G00.07', target=organisation_contact)) dsn_file.append(getEventDSNBlockDict(block_id='S20.G00.07', target=organisation_contact))
...@@ -264,7 +346,7 @@ for block in dsn_file: ...@@ -264,7 +346,7 @@ for block in dsn_file:
dsn_report_string += "%s,'%s'\n" % (rubric, block[rubric]) dsn_report_string += "%s,'%s'\n" % (rubric, block[rubric])
# Footer block # 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()): for rubric in sorted(footer.keys()):
dsn_report_string += "%s,'%s'\n" % (rubric, footer[rubric]) dsn_report_string += "%s,'%s'\n" % (rubric, footer[rubric])
......
...@@ -24,6 +24,7 @@ all_taxable_base_set = set(portal_categories.getCategoryValue('base_amount/payro ...@@ -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_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_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')) 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): def formatDate(datetime):
return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year()) return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year())
...@@ -54,13 +55,16 @@ ZIP_CODE = context.getDestinationSectionValue().getDefaultAddressZipCode() ...@@ -54,13 +55,16 @@ ZIP_CODE = context.getDestinationSectionValue().getDefaultAddressZipCode()
INSEE_CODE = getINSEECode(ZIP_CODE) INSEE_CODE = getINSEECode(ZIP_CODE)
def makeCTPBlock(movement, category): def makeCTPBlock(movement, category):
quantity = 0.
if category[:3] in ('437', '671'):
quantity = getattr(movement, 'employer_total_price', 0.) + getattr(movement, 'employee_total_price', 0.)
return { return {
'code': category, 'code': category,
'corporate_registration_code': movement.getSourceSectionValue().getCorporateRegistrationCode(), 'corporate_registration_code': movement.getSourceSectionValue(),
'cap': ('921' if category[-1] == 'P' else '920'), 'cap': ('921' if category[-1] == 'P' else '920'),
'rate': (abs(getattr(movement, 'employer_price') * 100) if category in ('100A', '900D', '901D', '863A') else ''), 'rate': (abs(getattr(movement, 'employer_price') * 100) if category in ('100A', '900D', '901D', '863A') else ''),
'base': round(movement.base), 'base': movement.base,
'quantity': ((getattr(movement, 'employer_total_price', 0.) + getattr(movement, 'employee_total_price', 0.)) if category[:3] in ('437', '671') else ''), 'quantity': quantity,
'zip_code': (INSEE_CODE if category == '900T' else ''), 'zip_code': (INSEE_CODE if category == '900T' else ''),
'start_date': movement.getStartDate(), 'start_date': movement.getStartDate(),
'stop_date': movement.getStopDate(), 'stop_date': movement.getStopDate(),
...@@ -143,6 +147,7 @@ for movement in context.PaySheetTransaction_getMovementList(): ...@@ -143,6 +147,7 @@ for movement in context.PaySheetTransaction_getMovementList():
contribution_dict = makeCTPBlock(movement, category) contribution_dict = makeCTPBlock(movement, category)
if category in result["ctp"]: if category in result["ctp"]:
result['ctp'][category]['base'] = result['ctp'][category]['base'] + contribution_dict['base'] result['ctp'][category]['base'] = result['ctp'][category]['base'] + contribution_dict['base']
result['ctp'][category]['quantity'] = result['ctp'][category]['quantity'] + contribution_dict['quantity']
else: else:
result['ctp'][category] = contribution_dict result['ctp'][category] = contribution_dict
...@@ -178,8 +183,9 @@ for movement in context.PaySheetTransaction_getMovementList(): ...@@ -178,8 +183,9 @@ for movement in context.PaySheetTransaction_getMovementList():
for category in other_income_set: for category in other_income_set:
category = category.getCodification() category = category.getCodification()
contribution_dict = makeOtherIncomeBlock(movement, category) contribution_dict = makeOtherIncomeBlock(movement, category)
if contribution_dict['quantity']:
if category in result["other_income"]: if category in result["other_income"]:
result['other_income'][category]['base'] = result['other_income'][category]['base'] + contribution_dict['base'] result['other_income'][category]['quantity'] = result['other_income'][category]['quantity'] + contribution_dict['quantity']
else: else:
result['other_income'][category] = contribution_dict result['other_income'][category] = contribution_dict
...@@ -188,12 +194,56 @@ for movement in context.PaySheetTransaction_getMovementList(): ...@@ -188,12 +194,56 @@ for movement in context.PaySheetTransaction_getMovementList():
for category in other_bonus_set: for category in other_bonus_set:
category = category.getCodification() category = category.getCodification()
contribution_dict = makeOtherBonusBlock(movement, category) contribution_dict = makeOtherBonusBlock(movement, category)
if contribution_dict['quantity']:
if category in result["other_bonus"]: if category in result["other_bonus"]:
result['other_bonus'][category]['base'] = result['other_bonus'][category]['base'] + contribution_dict['base'] result['other_bonus'][category]['quantity'] = result['other_bonus'][category]['quantity'] + contribution_dict['quantity']
else: else:
result['other_bonus'][category] = contribution_dict result['other_bonus'][category] = contribution_dict
total_bonus += contribution_dict['quantity'] 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 # Remuneration and Activity
...@@ -210,6 +260,8 @@ def getRemunerationBlockAsDict(remuneration_type, amount): ...@@ -210,6 +260,8 @@ def getRemunerationBlockAsDict(remuneration_type, amount):
# Corporate executives and trainees don't contribute to unemployment fee # Corporate executives and trainees don't contribute to unemployment fee
if is_corporate_executive and remuneration_type == '002': if is_corporate_executive and remuneration_type == '002':
amount = 0. amount = 0.
elif is_trainee and remuneration_type == '001':
amount = trainee_bonus
elif is_trainee and remuneration_type == '002': elif is_trainee and remuneration_type == '002':
amount = 0. amount = 0.
# Nexedi trainees don't pay social fees # 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