Commit 9fdf65c0 authored by Jérome Perrin's avatar Jérome Perrin

payroll_l10n_fr: Python3 compatibility

This fixes compatibility for python3, especially with hash randomization
(PYTHONHASHSEED) turned on.

This also enables coding style test that was not running for this bt,
after fixing everything flagged by coding style test.

See merge request nexedi/erp5!1892
parents 4b0b00a0 746a8734
Pipeline #33150 failed with stage
in 0 seconds
......@@ -60,7 +60,7 @@
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Print DSN report</string> </value>
<value> <string>Print DSN</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
......@@ -77,7 +77,7 @@
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/DSNReport_printAsFile</string> </value>
<value> <string>string:${object_url}/DSNMonthlyReport_viewFilePrintDialog</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -77,7 +77,7 @@
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/DSNReport_viewEditor</string> </value>
<value> <string>string:${object_url}/DSNMonthlyReport_viewEditor</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -60,7 +60,7 @@
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Print DSN report</string> </value>
<value> <string>Print DSN</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
......@@ -77,7 +77,7 @@
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/DSNReport_printAsFile</string> </value>
<value> <string>string:${object_url}/DSNMonthlyReport_viewFilePrintDialog</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -77,7 +77,7 @@
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/DSNReport_viewEditor</string> </value>
<value> <string>string:${object_url}/DSNMonthlyReport_viewEditor</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -60,7 +60,7 @@
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Print DSN Report</string> </value>
<value> <string>Print DSN</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
......@@ -77,7 +77,7 @@
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/DSNReport_viewFilePrintDialog</string> </value>
<value> <string>string:${object_url}/DSNMonthlyReport_viewFilePrintDialog</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -77,7 +77,7 @@
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/DSNReport_viewEditor</string> </value>
<value> <string>string:${object_url}/DSNMonthlyReport_viewEditor</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -85,7 +85,7 @@
<value>
<list>
<string>my_notice_type</string>
<string>my_validation_state_title</string>
<string>my_translated_validation_state_title</string>
</list>
</value>
</item>
......
......@@ -8,7 +8,7 @@
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_validation_state_title</string> </value>
<value> <string>my_translated_validation_state_title</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......
portal = context.getPortalObject()
portal_categories = context.portal_categories
rubric_value_dict = {}
france_territory_code = ('FR' ,'GP', 'BL', 'MF', 'MQ', 'GF', 'RE', 'PM', 'YT', 'WF', 'PF', 'NC', 'MC')
def getCountryCode(target):
region = portal_categories.getCategoryValue(target.getDefaultAddressRegion(), base_category="region")
if region is None:
raise ValueError("Country should be defined in address field of %s" % target.getRelativeUrl())
codification = region.getCodification()
if codification is None:
raise ValueError("Region %s doesn't have codification" % region.getRelativeUrl())
return codification
def formatDate(datetime):
return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year())
def formatFloat(number):
return "{:.2f}".format(float(number))
# Bloc Declaration
if block_id == 'S20.G00.05':
......@@ -44,7 +29,6 @@ if block_id == 'S21.G00.06':
# Etablissement
elif block_id == 'S21.G00.11':
establishment_country_code = getCountryCode(target)
rubric_value_dict['S21.G00.11.001'] = target.getCorporateRegistrationCode()[-5:]
rubric_value_dict['S21.G00.11.003'] = target.getDefaultAddressStreetAddress()
rubric_value_dict['S21.G00.11.004'] = target.getDefaultAddressZipCode()
......
portal = context.getPortalObject()
portal_categories = context.portal_categories
rubric_value_dict = {}
france_territory_code = ('FR' ,'GP', 'BL', 'MF', 'MQ', 'GF', 'RE', 'PM', 'YT', 'WF', 'PF', 'NC', 'MC')
def getCountryCode(target):
region = portal_categories.getCategoryValue(target.getDefaultAddressRegion(), base_category="region")
if region is None:
raise ValueError("Country should be defined in address field of %s" % target.getRelativeUrl())
codification = region.getCodification()
if codification is None:
raise ValueError("Region %s doesn't have codification" % region.getRelativeUrl())
return codification
def formatDate(datetime):
return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year())
def formatFloat(number):
return "{:.2f}".format(float(number))
# Bloc Declaration
if block_id == 'S20.G00.05':
......@@ -44,7 +29,6 @@ if block_id == 'S21.G00.06':
# Etablissement
elif block_id == 'S21.G00.11':
establishment_country_code = getCountryCode(target)
rubric_value_dict['S21.G00.11.001'] = target.getCorporateRegistrationCode()[-5:]
rubric_value_dict['S21.G00.11.003'] = target.getDefaultAddressStreetAddress()
rubric_value_dict['S21.G00.11.004'] = target.getDefaultAddressZipCode()
......
from erp5.component.module.DateUtils import addToDate
from Products.ERP5Type.Message import translateString
if context.getSourceAdministration() is None \
or context.getEffectiveDate() is None \
or context.getFormat() is None \
or len(context.getAggregateRelatedIdList()) <= 0:
return context.REQUEST.response.redirect("%s?portal_status_message=%s" % (context.absolute_url(), "DSN can't be built if some fields are empty"))
return context.Base_redirect(form_id, keep_items={
'portal_status_message': translateString("DSN can't be built if some fields are empty"),
'portal_status_level': 'error',
})
getDSNblockDict = context.DSNMonthlyReport_getDataDictPhaseTwo
getEventDSNblockDict = context.DSNEarlyRecoveryReport_getDataDictPhaseTwo
......@@ -56,7 +59,10 @@ if leave_period.getExpirationDate() <= leave_period.getStopDate():
else:
if batch_mode:
return
context.REQUEST.response.redirect("%s?portal_status_message=%s" % (context.absolute_url(), "No need to create this DSN event report : return date is not previous to last leaved date."))
return context.Base_redirect(form_id, keep_items={
'portal_status_message': translateString("No need to create this DSN event report : return date is not previous to last leaved date."),
'portal_status_level': 'error',
})
# Print DSN
dsn_report_string = ""
......@@ -76,4 +82,7 @@ context.setTextContent(dsn_report_string.strip())
if batch_mode:
return
context.REQUEST.response.redirect("%s?portal_status_message=%s" % (context.absolute_url(), "Event DSN Record Created."))
return context.Base_redirect(form_id, keep_items={
'portal_status_message': translateString( "Event DSN Record Created."),
'portal_status_level': 'success',
})
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>batch_mode=False</string> </value>
<value> <string>form_id=\'\', batch_mode=False</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
portal = context.getPortalObject()
portal_categories = context.portal_categories
rubric_value_dict = {}
france_territory_code = ('FR' ,'GP', 'BL', 'MF', 'MQ', 'GF', 'RE', 'PM', 'YT', 'WF', 'PF', 'NC', 'MC')
def getCountryCode(target):
region = portal_categories.getCategoryValue(target.getDefaultAddressRegion(), base_category="region")
if region is None:
raise ValueError("Country should be defined in address field of %s" % target.getRelativeUrl())
codification = region.getCodification()
if codification is None:
raise ValueError("Region %s doesn't have codification" % region.getRelativeUrl())
return codification
def formatDate(datetime):
return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year())
def formatFloat(number):
return "{:.2f}".format(float(number))
# Declaration
if block_id == 'S20.G00.05':
......
from erp5.component.module.DateUtils import getNumberOfDayInMonth
import six
def getLastDateOfMonth(date):
return DateTime(date.year(), date.month(), getNumberOfDayInMonth(date))
......@@ -80,10 +81,10 @@ for remuneration_block in paysheet_data_dict['remuneration']:
continue
dsn_file.append(remuneration_block)
for bonus_category in paysheet_data_dict['other_bonus'].itervalues():
for bonus_category in six.itervalues(paysheet_data_dict['other_bonus']):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.52', target=bonus_category))
for bonus_category in paysheet_data_dict['other_income'].itervalues():
for bonus_category in six.itervalues(paysheet_data_dict['other_income']):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.54', target=bonus_category))
# Print DSN Record
......
portal = context.getPortalObject()
def formatDate(datetime):
return "%02d%02d%04d" % (datetime.day(), datetime.month(), datetime.year())
def formatFloat(number):
return "{:.02f}".format(float(number))
# Get the DSN Header and make modifications
is_monthly_dsn = False
header_bloc = [] # list of 2-item tuples
header_line_number = 0
header_length = 0
previous_date = None
previous_order = 0
data = context.getTextContent()
dsn_file_as_list = data.split('\n')
......@@ -28,10 +22,8 @@ for line_number, line in enumerate(dsn_file_as_list):
if is_monthly_dsn and rubric == 'S20.G00.05.002':
value = "03"
elif is_monthly_dsn and rubric == 'S20.G00.05.004':
previous_order = value
value = "%d" % (int(value) + 1)
elif is_monthly_dsn and rubric == 'S20.G00.05.007':
previous_date = value
value = "%s" % formatDate(DateTime())
header_bloc.append((rubric, "'%s'" % value))
......
from erp5.component.module.DateUtils import addToDate, getIntervalBetweenDates, getNumberOfDayInMonth
from erp5.component.module.DateUtils import getIntervalBetweenDates, getNumberOfDayInMonth
import six
portal = context.getPortalObject()
portal_categories = context.portal_categories
......@@ -43,7 +44,7 @@ if block_id in ('S21.G00.31', 'S21.G00.41', 'S21.G00.72'):
change_block = kw['change_block']
change_date = kw['change_date']
rubric_value_dict[block_id + ".001"] = change_date
for rubric, value in change_block.iteritems():
for rubric, value in six.iteritems(change_block):
rubric_value_dict[rubric] = value
# Envoi
......@@ -127,7 +128,7 @@ if block_id == 'S21.G00.06':
total_manpower = 0
for _, employee_quantity in manpower_dict.items():
total_manpower += sum(employee_quantity)
return total_manpower / len(manpower_dict.keys()) # Divide by number of months
return total_manpower // len(list(manpower_dict.keys())) # Divide by number of months.
average_manpower = ''
if context.getEffectiveDate().month() == 12 and target.getRelativeUrl() == getDSNOrganisation(context):
......@@ -163,7 +164,7 @@ elif block_id == 'S21.G00.11':
if block_id == 'S21.G00.15':
# XXX: Hack as some organisations may have several contracts
return [
return [
{
'S21.G00.15.001': 'REF_CONTRACT1',
'S21.G00.15.002': 'ORGANISATION1',
......
from erp5.component.module.DateUtils import getNumberOfDayInMonth
import six
portal = context.getPortalObject()
portal_categories = context.portal_categories
......@@ -30,7 +31,7 @@ if block_id in ('S21.G00.31', 'S21.G00.41', 'S21.G00.72'):
change_bloc = kw['change_bloc']
change_date = kw['change_date']
rubric_value_dict[block_id + ".001"] = change_date
for rubric, value in change_bloc.iteritems():
for rubric, value in six.iteritems(change_bloc):
rubric_value_dict[rubric] = value
# Envoi
......@@ -265,7 +266,7 @@ if block_id == 'S21.G00.70':
start_date = enrollment_record.getCareerStartDate()
if start_date.year() == context.getEffectiveDate().year() \
and start_date.month() == context.getEffectiveDate().month():
just_hired = True
just_hired = True
else:
just_hired = False
rubric_value_dict['S21.G00.70.001'] = 'ReferenceAdhesionPSC'
......
from erp5.component.module.DateUtils import getNumberOfDayInMonth
portal = context.getPortalObject()
paysheet = portal.accounting_module[paysheet_id]
remuneration_bloc = {}
bonus_result = []
result = []
is_trainee = (True if enrollment_record.getContractType() == '29' else False)
......
......@@ -4,9 +4,7 @@ from Products.ZSQLCatalog.SQLCatalog import Query
portal = context.getPortalObject()
portal_categories = portal.portal_categories
now = DateTime()
effective_date = context.getEffectiveDate()
previous_pay_day = addToDate(effective_date, month=-1)
# Get period dates
result = portal.portal_catalog(portal_type="DSN Monthly Report",
......@@ -50,7 +48,7 @@ leave_period_type_set = set(portal_categories.use.social_declaration.l10n.fr.lea
# Create dict containing a DSN leave blocs, grouped by employee
leave_dict = {}
for period in leave_period_list:
for period in sorted(leave_period_list, key=lambda lp: lp.getCreationDate()):
# some leave periods don't have to be reported in DSN
period_resource = period.getResourceValue()
assert period_resource is not None, 'No type set on Leave Request %s' % period.absolute_url()
......@@ -59,7 +57,7 @@ for period in leave_period_list:
continue
# 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:
leave_dict[period.getDestination()].append(getLeaveBlocAsDict(period, leave_category))
else:
leave_dict[period.getDestination()] = [getLeaveBlocAsDict(period, leave_category),]
......
from erp5.component.module.DateUtils import addToDate
portal = context.getPortalObject()
# record base and rate for each ctp for an Establishment
......@@ -17,8 +15,6 @@ fillon_relative_min_salary = {}
fillon_individual_reduction = {}
# Social Entity corporate registration code
SOCIAL_ENTITY = ''
# establishment paysheets belong to
current_establishement_code = portal.accounting_module[paysheet_list[0]].getDestinationSectionValue().getCorporateRegistrationCode()[-5:]
# Rate to apply to bases to calculate the final amount of fees
standard_rate_mapping = {'012D': 0.28, '027D': 0.00016, '100D': 0.1954, '100P': 0.1545,
......@@ -139,32 +135,6 @@ for paysheet_id in paysheet_list:
done_ctp_set.update(current_ctp_set)
def getFeeFromDate(ctp_code, date):
'''
Return a list of the previous contributions for
a specific CTP code in the older DSN
'''
amount_list = []
aggregated_fee_list = context.DSNReport_getGroupedOlderValues(searched_bloc='S21.G00.23',
grouping_rubric='S21.G00.11.001',
from_date=date)
for dsn_record in aggregated_fee_list:
for establishment in aggregated_fee_list[dsn_record].keys():
if establishment != current_establishement_code:
continue
for bloc in aggregated_fee_list[dsn_record][establishment]:
bloc_found = 0
for rubric, value in bloc:
value = value.strip('\'')
if rubric == 'S21.G00.23.001' and value == ctp_code:
bloc_found = 1
if rubric == 'S21.G00.23.001' and value != ctp_code:
bloc_found = 0
if bloc_found and rubric == 'S21.G00.23.004':
amount_list.append(float(value))
return (amount_list if len(amount_list) > 0 else [0])
def getFeeBlocAsDict(ctp, ctp_dict):
""""
Write a S21.G00.23 bloc for each ctp, helped by a record from the dict "fee_per_ctp_dict"
......
from Products.ERP5Type.Message import translateString
from erp5.component.module.DateUtils import getNumberOfDayInMonth
if context.getSourceAdministration() is None \
......@@ -5,7 +6,10 @@ if context.getSourceAdministration() is None \
or context.getFormat() is None \
or context.getQuantity() is None \
or len(context.getAggregateRelatedIdList()) <= 0:
return context.REQUEST.response.redirect("%s?portal_status_message=%s" % (context.absolute_url(), "DSN can't be built if some fields are empty"))
return context.Base_redirect(form_id, keep_items={
'portal_status_message': translateString("DSN can't be built if some fields are empty"),
'portal_status_level': 'error',
})
portal = context.getPortalObject()
accounting_module = portal.getDefaultModuleValue("Pay Sheet Transaction")
......@@ -240,8 +244,6 @@ for paysheet_id in paysheet_id_list:
social_entity=transport_individual_fee[1],
insee_code=transport_individual_fee[3]))
errors = []
# Add leave event DSN if needed
if len(leave_period_dict):
for employee in leave_period_dict:
......@@ -264,11 +266,11 @@ if len(leave_period_dict):
dsn_file.append(period)
# Print DSN Record
last_block = ''
rubric_counter = 0
# DEBUG MODE
#
# errors = []
# last_block = ''
# def checkformat(rubric, value):
# rubric_desc = rubric_dict[rubric]
# if len(str(value)) < rubric_desc.min_length:
......@@ -317,4 +319,7 @@ if batch_mode:
context.REQUEST.response.setHeader("Content-Type", "text/plain; charset=iso-8859-1")
return
context.REQUEST.response.redirect("%s?portal_status_message=%s" % (context.absolute_url(), "Monthly DSN Record Created."))
return context.Base_redirect(form_id, keep_items={
'portal_status_message': translateString("Monthly DSN Record Created."),
'portal_status_level': 'error',
})
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>batch_mode=False</string> </value>
<value> <string>form_id=\'\', batch_mode=False</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
from Products.ERP5Type.Message import translateString
from erp5.component.module.DateUtils import addToDate, getNumberOfDayInMonth
import six
if context.getSourceAdministration() is None \
or context.getEffectiveDate() is None \
or context.getQuantity() is None:
return context.REQUEST.response.redirect("%s?portal_status_message=%s" % (context.absolute_url(), "DSN can't be built if some fields are empty"))
return context.Base_redirect(form_id, keep_items={
'portal_status_message': translateString("DSN can't be built if some fields are empty"),
'portal_status_level': 'error',
})
portal = context.getPortalObject()
accounting_module = portal.getDefaultModuleValue("Pay Sheet Transaction")
......@@ -39,7 +44,7 @@ else:
establishment = context.getSourceTradeValue()
establishment_registration_code = ''.join(establishment.getCorporateRegistrationCode().split(' '))
# Finds the head office of the comany
# Finds the head office of the company
if len(payment_transaction_list):
organisation = payment_transaction_list[0].getSourceSectionValue()
elif len(paysheet_list):
......@@ -90,9 +95,9 @@ employee_result_list = [
]
if len(employee_result_list):
employee_data_list, paysheet_data_list = zip(*employee_result_list)
_, paysheet_data_list = zip(*employee_result_list)
else:
employee_data_list, paysheet_data_list = [], []
_, paysheet_data_list = [], []
insurance_contract_id_list = set()
for employee_data_dict, paysheet_data_dict in employee_result_list:
......@@ -168,7 +173,7 @@ if len(payment_transaction_list):
start_date=social_contribution_start_date,
stop_date=social_contribution_stop_date,
amount=amount))
for ctp_code in aggregated_social_contribution_dict:
for ctp_code in sorted(aggregated_social_contribution_dict):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.23',
target=aggregated_social_contribution_dict[ctp_code]))
else:
......@@ -201,7 +206,7 @@ elif len(paysheet_list):
start_date=first_date_of_month,
stop_date=last_date_of_month,
amount=amount))
for ctp_code in aggregated_social_contribution_dict:
for ctp_code in sorted(aggregated_social_contribution_dict):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.23',
target=aggregated_social_contribution_dict[ctp_code]))
......@@ -223,12 +228,12 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
contract_change_block_list = []
if employee in change_block_dict:
for rubric_root, change_date_block in change_block_dict[employee].iteritems():
for rubric_root, change_date_block in sorted(six.iteritems(change_block_dict[employee])):
if rubric_root == 'S21.G00.31':
for date, change_block in change_date_block.iteritems():
for date, change_block in sorted(six.iteritems(change_date_block)):
dsn_file.append(getDSNBlockDict(block_id=rubric_root, change_block=change_block, change_date=date))
elif rubric_root == 'S21.G00.41':
for date, change_block in change_date_block.iteritems():
for date, change_block in sorted(six.iteritems(change_date_block)):
contract_change_block_list.append(getDSNBlockDict(block_id=rubric_root, change_block=change_block, change_date=date))
employee_data_dict['contract']['S21.G00.40.019'] = establishment_registration_code
......@@ -236,7 +241,7 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
dsn_file.extend(contract_change_block_list)
if employee in leave_period_dict:
for leave_period in leave_period_dict[employee]:
for leave_period in sorted(leave_period_dict[employee]):
leave_block = {rubric: leave_period.get(rubric, None)
for rubric in ('S21.G00.60.001',
'S21.G00.60.002',
......@@ -252,7 +257,7 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
leaving_employee_list.append(employee)
disenrollment_record = portal.restrictedTraverse(employee).Person_getCareerRecord('DSN Disenrollment Record')
dsn_file.append({rubric: value
for rubric, value in getDSNBlockDict("S21.G00.62", enrollment_record=enrollment_record, disenrollment_record=disenrollment_record).items()
for rubric, value in sorted(getDSNBlockDict("S21.G00.62", enrollment_record=enrollment_record, disenrollment_record=disenrollment_record).items())
if rubric in ('S21.G00.62.001',
'S21.G00.62.002',
'S21.G00.62.006',
......@@ -265,7 +270,7 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
# 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:
for insurance_contract_id in sorted(insurance_contract_id_list):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.70',
enrollment_record=enrollment_record,
contract_id=insurance_contract_id))
......@@ -279,13 +284,13 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
for remuneration_block in paysheet_data_dict['remuneration']:
dsn_file.append(remuneration_block)
for bonus_category in paysheet_data_dict['other_bonus'].itervalues():
for bonus_category in sorted(six.itervalues(paysheet_data_dict['other_bonus'])):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.52', target=bonus_category))
for bonus_category in paysheet_data_dict['other_income'].itervalues():
for bonus_category in sorted(six.itervalues(paysheet_data_dict['other_income'])):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.54', target=bonus_category))
for taxable_base_category in paysheet_data_dict['taxable_base'].itervalues():
for taxable_base_category in sorted(six.itervalues(paysheet_data_dict['taxable_base'])):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.78', target=taxable_base_category))
if taxable_base_category['code'] == '02': # Assiette Brute plafonnee
if ('063', '') in paysheet_data_dict['individual_contribution']:
......@@ -319,21 +324,21 @@ for employee_data_dict, paysheet_data_dict in employee_result_list:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.81', target=paysheet_data_dict['individual_contribution'][('059', taxable_base_category['contract_id'])]))
del paysheet_data_dict['individual_contribution'][('059', taxable_base_category['contract_id'])]
for taxable_base_component_category in paysheet_data_dict['taxable_base_component'].itervalues():
for taxable_base_component_category in sorted(six.itervalues(paysheet_data_dict['taxable_base_component'])):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.79', target=taxable_base_component_category))
if ('03', '') in taxable_base_component_category:
dsn_file.append(getDSNBlockDict(block_id='S21.G00.81', target=paysheet_data_dict['individual_contribution'][('064', '')]))
del paysheet_data_dict['individual_contribution'][('064', '')]
for individual_contribution_category in paysheet_data_dict['individual_contribution'].itervalues():
for individual_contribution_category in sorted(six.itervalues(paysheet_data_dict['individual_contribution'])):
dsn_file.append(getDSNBlockDict(block_id='S21.G00.81', target=individual_contribution_category))
dsn_file.append(employee_data_dict['seniority'])
# Add leave event DSN if needed
if len(leave_period_dict):
for employee in leave_period_dict:
for period in leave_period_dict[employee]:
for employee in sorted(leave_period_dict):
for period in sorted(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])
......@@ -403,11 +408,10 @@ if len(leave_period_dict):
# Print DSN Record
last_block = ''
rubric_counter = 0
# DEBUG MODE
#
# last_block = ''
# for block in dsn_file:
# for rubric in sorted(block.keys()):
# if block[rubric]:
......@@ -438,4 +442,7 @@ if batch_mode:
context.REQUEST.response.setHeader("Content-Type", "text/plain; charset=iso-8859-1")
return
context.REQUEST.response.redirect("%s?portal_status_message=%s" % (context.absolute_url(), "Monthly DSN Record Created."))
return context.Base_redirect(form_id, keep_items={
'portal_status_message': translateString("Monthly DSN Record Created."),
'portal_status_level': 'success',
})
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>batch_mode=False</string> </value>
<value> <string>form_id=\'\', batch_mode=False</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -3,12 +3,12 @@ import unicodedata
data = unicodedata.normalize('NFKD', context.getTextContent().decode('utf-8')).encode('iso-8859-1', 'ignore')
# Update sending mode "on the fly"
dsn_line_list = data.split('\n')
dsn_line_list = data.split(b'\n')
for line_number, dsn_line in enumerate(dsn_line_list):
if dsn_line.split(',', 1)[0] == 'S10.G00.00.005':
dsn_line_list[line_number] = 'S10.G00.00.005,\'%s\'' % sending_mode
if dsn_line.split(b',', 1)[0] == b'S10.G00.00.005':
dsn_line_list[line_number] = b'S10.G00.00.005,\'%s\'' % sending_mode.encode()
data = '\n'.join(dsn_line_list)
data = b'\n'.join(dsn_line_list)
filename = context.getTitle()
......
......@@ -54,7 +54,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>DSNReport_printAsFile</string> </value>
<value> <string>DSNMonthlyReport_printAsFile</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -87,7 +87,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>DSNReport_viewEditor</string> </value>
<value> <string>DSNMonthlyReport_viewEditor</string> </value>
</item>
<item>
<key> <string>method</string> </key>
......
......@@ -14,7 +14,7 @@
</item>
<item>
<key> <string>action</string> </key>
<value> <string>DSNReport_printAsFile</string> </value>
<value> <string>DSNMonthlyReport_printAsFile</string> </value>
</item>
<item>
<key> <string>description</string> </key>
......@@ -87,7 +87,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>DSNReport_viewFilePrintDialog</string> </value>
<value> <string>DSNMonthlyReport_viewFilePrintDialog</string> </value>
</item>
<item>
<key> <string>method</string> </key>
......@@ -95,7 +95,7 @@
</item>
<item>
<key> <string>name</string> </key>
<value> <string>DSNReport_viewFilePrintDialog</string> </value>
<value> <string>DSNMonthlyReport_viewFilePrintDialog</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
......
"""
Return a list of values of a given rubric from one or more DSN Records.
Rubrics will be grouped on a given parent's bloc. This bloc must be made unique
by a given rubrique's code.
Values will be returned as a list in a dictionnary, whose keys are the values of
the unique rubrique's code use to group them.
"""
portal = context.getPortalObject()
if not searched_block:
searched_block = 'S21.G00.23'
if not grouping_rubric:
grouping_rubric = 'S21.G00.11.001'
dsn_files = portal.dsn_module.searchFolder(effective_date=">%s" % from_date,
simulation_state='validated',
**kw)
result_dict = {}
for dsn_file in dsn_files:
# Exclude current and future DSNs
if dsn_file.getEffectiveDate() >= context.getEffectiveDate():
continue
dsn_file = dsn_file.getObject()
result_dict[dsn_file] = {}
found_parent = False
dsn_data = dsn_file.getTextContent()
is_monthly_dsn = False
result_bloc = []
last_rubric = ''
for line in dsn_data.split('\n'):
rubric, value = line.split(',', 1)
value = value.strip('\'')
# Let's exclude events DSN
if rubric == 'S20.G00.05.001':
is_monthly_dsn = (True if value == '01' else False)
# We found a parent node
if grouping_rubric == rubric and is_monthly_dsn:
found_parent = value
result_dict[dsn_file][value] = []
# If we have finished a bloc, we add it to the returned dict,
# and we look for another bloc under the same parent node
if rubric < last_rubric and found_parent and len(result_bloc):
result_dict[dsn_file][found_parent].append(result_bloc)
result_bloc = []
# The bloc we are looking for has been found. We add it to
# the corresponding gathering rubric
if found_parent and searched_block in rubric and is_monthly_dsn:
result_bloc.append((rubric, value))
last_rubric = rubric
return result_dict
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<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>_params</string> </key>
<value> <string>searched_block=\'\', grouping_rubric=\'\', from_date=None, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>DSNReport_getGroupedOlderValueDict</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -105,7 +105,7 @@
<string>my_civil_servant_status</string>
<string>my_occupational_accident_risk_code</string>
<string>my_occupational_accident_risk_rate</string>
<string>my_validation_state_title</string>
<string>my_translated_validation_state_title</string>
</list>
</value>
</item>
......
......@@ -8,7 +8,7 @@
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_validation_state_title</string> </value>
<value> <string>my_translated_validation_state_title</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......
......@@ -92,34 +92,6 @@
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_context</string> </key>
<value> <string></string> </value>
......@@ -132,14 +104,6 @@
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
......
import six
from Products.ZSQLCatalog.SQLCatalog import ComplexQuery, SimpleQuery
kw["report_data"] = context.PaySheetTransaction_getPayslipData()
......@@ -59,7 +60,7 @@ if batch:
rep_content = context.PaySheetTransaction_generatePayslipReportContent(**kw)
if isinstance(rep_content, unicode):
if six.PY2 and isinstance(rep_content, six.text_type):
rep_content = rep_content.encode("utf8")
return rep_content,"",""
portal = context.getPortalObject()
translateString = portal.Base_translateString
request = context.REQUEST
quantity_renderer = portal.Base_viewFieldLibrary.my_view_mode_money_quantity.render_pdf
paysheet = context
def getFieldAsString(field):
return ', '.join(getFieldAsLineList(field))
def getFieldAsLineList(field):
"""Returns the text as a list of lines."""
field = field or ''
......
from DateTime import DateTime
import six
line_dict_list = context.PaySheetTransaction_getLineListAsDict()
non_subject_amount = 'base_amount/payroll/report_section/l10n/fr/amount_non_subject_to_contribution'
......@@ -59,7 +60,7 @@ def groupSameReportSectionLine(line_to_group_list):
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)
# Check if can group by same rate
for _, value in tmp_base_dict.iteritems():
for value in six.itervalues(tmp_base_dict):
new_key = (value['employer_price'], value['employee_price'])
if new_key not in tmp2_base_dict:
tmp2_base_dict[new_key] = value
......
......@@ -31,11 +31,11 @@ for paysheet in paysheet_list:
start_date=paysheet.getStartDate(),
stop_date=paysheet.getStopDate())
if model is not None:
slice = model.getCell(slice_path)
if slice is None:
slice_cell = model.getCell(slice_path)
if slice_cell is None:
return 0.0
plafond_max = slice.getQuantityRangeMax()
plafond_min = slice.getQuantityRangeMin()
plafond_max = slice_cell.getQuantityRangeMax()
plafond_min = slice_cell.getQuantityRangeMin()
yearly_slice_amount += min(salary, plafond_max) - plafond_min
return yearly_slice_amount
# pylint:disable=redefined-builtin
from Products.ERP5Type.Message import translateString
if dialog_id is not None:
request = container.REQUEST
......
......@@ -24,13 +24,12 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
import difflib
import os
import time
import six
from DateTime import DateTime
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
class TestDSNSocialDeclarationReport(ERP5TypeTestCase):
"""
Test Suite for the generation of the French Social Declaration Report,
......@@ -60,8 +59,26 @@ class TestDSNSocialDeclarationReport(ERP5TypeTestCase):
"""
test_dsn = self.dsn_module['test_model']
test_dsn.DSNMonthlyReport_makeReport()
reference_DSN = getattr(self.portal.portal_skins.erp5_payroll_l10n_fr_test, "test_model.dsn").data
diff_list = []
for unit_diff in difflib.unified_diff(reference_DSN.split('\n'), test_dsn.getTextContent().split('\n')):
diff_list.append(unit_diff)
self.assertEqual(reference_DSN, test_dsn.getTextContent(), msg='\n'.join(diff_list))
reference_DSN = bytes(
getattr(self.portal.portal_skins.erp5_payroll_l10n_fr_test, "test_model.dsn").data
)
if six.PY3:
reference_DSN = reference_DSN.decode('utf-8')
self.maxDiff = None
self.assertEqual(
test_dsn.getTextContent().splitlines(),
reference_DSN.splitlines(),
)
# the export is latin1 encoded by spec, but we remove accents
ret = self.publish(
'%s/DSNMonthlyReport_printAsFile' % test_dsn.getPath(),
user='ERP5TypeTestCase')
self.assertEqual(ret.getHeader('Content-Type'), 'text/plain; charset=iso-8859-1')
self.assertIn('Clemenceau', ret.getBody().decode('iso-8859-1'))
# when exporting, we can choose another mode, there's a field in the report dialog
ret = self.publish(
'%s/DSNMonthlyReport_printAsFile?sending_mode=02' % test_dsn.getPath(),
user='ERP5TypeTestCase')
self.assertIn("S10.G00.00.005,'02'", ret.getBody().decode('iso-8859-1'))
......@@ -32,6 +32,7 @@ import cStringIO
import math
import os.path
from Products.Localizer.itools.i18n.accept import AcceptLanguage
import six
class TestSimplifiedPayslipReport(ERP5TypeTestCase):
......@@ -107,7 +108,7 @@ class TestSimplifiedPayslipReport(ERP5TypeTestCase):
"total_contribution_relief": 468.88
}
payslip_content = test_pay_sheet_transaction.PaySheetTransaction_getPayslipData()
for key, value in expected_payslip_content.iteritems():
for key, value in six.iteritems(expected_payslip_content):
self.assertAlmostEqual(value, payslip_content[key])
expected_non_contribution_dict_list= [
......@@ -124,7 +125,7 @@ class TestSimplifiedPayslipReport(ERP5TypeTestCase):
for index in range(len(expected_non_contribution_dict_list)):
expected_value_dict = expected_non_contribution_dict_list[index]
value_dict = non_contribution_dict_list[index]
for key, value in expected_value_dict.iteritems():
for key, value in six.iteritems(expected_value_dict):
self.assertEqual(value_dict[key], value)
expected_contribution_dict_list = [
......@@ -163,7 +164,7 @@ class TestSimplifiedPayslipReport(ERP5TypeTestCase):
for index in range(len(expected_contribution_dict_list)):
expected_value_dict = expected_contribution_dict_list[index]
value_dict = contribution_dict_list[index]
for key, value in expected_value_dict.iteritems():
for key, value in six.iteritems(expected_value_dict):
self.assertAlmostEqual(value_dict[key], value)
test_pay_sheet_transaction.setStartDate(DateTime("2020/01/01"))
......
......@@ -6,18 +6,18 @@
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple/>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
......
......@@ -6,18 +6,18 @@
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple/>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
......
......@@ -85,39 +85,39 @@ S21.G00.22.002,'44004750400020'
S21.G00.22.003,'01012015'
S21.G00.22.004,'31012015'
S21.G00.22.005,'5158.42'
S21.G00.23.001,'260'
S21.G00.23.002,'920'
S21.G00.23.004,'10278.00'
S21.G00.23.001,'479'
S21.G00.23.002,'920'
S21.G00.23.004,'275.00'
S21.G00.23.001,'772'
S21.G00.23.002,'920'
S21.G00.23.004,'9163.00'
S21.G00.23.001,'100'
S21.G00.23.002,'920'
S21.G00.23.003,'1.10'
S21.G00.23.004,'9163.00'
S21.G00.23.001,'100'
S21.G00.23.002,'921'
S21.G00.23.004,'8505.00'
S21.G00.23.001,'260'
S21.G00.23.002,'920'
S21.G00.23.004,'10278.00'
S21.G00.23.001,'332'
S21.G00.23.002,'921'
S21.G00.23.004,'8505.00'
S21.G00.23.001,'900'
S21.G00.23.001,'400'
S21.G00.23.002,'920'
S21.G00.23.003,'2.00'
S21.G00.23.004,'9163.00'
S21.G00.23.006,'59378'
S21.G00.23.004,'5335.00'
S21.G00.23.001,'430'
S21.G00.23.002,'920'
S21.G00.23.004,'6913.00'
S21.G00.23.001,'400'
S21.G00.23.001,'479'
S21.G00.23.002,'920'
S21.G00.23.004,'5335.00'
S21.G00.23.004,'275.00'
S21.G00.23.001,'671'
S21.G00.23.002,'921'
S21.G00.23.005,'32.00'
S21.G00.23.001,'100'
S21.G00.23.002,'921'
S21.G00.23.004,'8505.00'
S21.G00.23.001,'772'
S21.G00.23.002,'920'
S21.G00.23.004,'9163.00'
S21.G00.23.001,'900'
S21.G00.23.002,'920'
S21.G00.23.003,'2.00'
S21.G00.23.004,'9163.00'
S21.G00.23.006,'59378'
S21.G00.30.001,'1930259017323'
S21.G00.30.002,'Beginner'
S21.G00.30.004,'Usertest'
......@@ -197,20 +197,14 @@ S21.G00.51.002,'31012015'
S21.G00.51.010,'00000'
S21.G00.51.011,'010'
S21.G00.51.013,'2250.00'
S21.G00.54.001,'18'
S21.G00.54.002,'23.00'
S21.G00.54.003,'01012015'
S21.G00.54.004,'31012015'
S21.G00.54.001,'17'
S21.G00.54.002,'100.80'
S21.G00.54.003,'01012015'
S21.G00.54.004,'31012015'
S21.G00.78.001,'02'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'2250.00'
S21.G00.81.001,'063'
S21.G00.81.004,'219.38'
S21.G00.54.001,'18'
S21.G00.54.002,'23.00'
S21.G00.54.003,'01012015'
S21.G00.54.004,'31012015'
S21.G00.78.001,'31'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
......@@ -220,27 +214,16 @@ S21.G00.79.001,'20'
S21.G00.79.004,'97.16'
S21.G00.81.001,'059'
S21.G00.81.004,'97.16'
S21.G00.78.001,'31'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'0.00'
S21.G00.78.005,'2'
S21.G00.79.001,'11'
S21.G00.79.004,'2250.00'
S21.G00.81.001,'059'
S21.G00.81.004,'15.75'
S21.G00.78.001,'04'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'2305.53'
S21.G00.78.001,'13'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'94.91'
S21.G00.78.001,'07'
S21.G00.78.001,'02'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'2250.00'
S21.G00.81.001,'063'
S21.G00.81.004,'219.38'
S21.G00.78.001,'03'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
......@@ -253,6 +236,23 @@ S21.G00.81.001,'226'
S21.G00.81.002,'75367340900011'
S21.G00.81.003,'2250.00'
S21.G00.81.005,'59378'
S21.G00.78.001,'07'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'2250.00'
S21.G00.78.001,'31'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'0.00'
S21.G00.78.005,'2'
S21.G00.79.001,'11'
S21.G00.79.004,'2250.00'
S21.G00.81.001,'059'
S21.G00.81.004,'15.75'
S21.G00.78.001,'04'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'2305.53'
S21.G00.81.001,'018'
S21.G00.81.002,'75367340900011'
S21.G00.81.003,'2250.00'
......@@ -335,12 +335,6 @@ S21.G00.54.001,'17'
S21.G00.54.002,'62.40'
S21.G00.54.003,'01012015'
S21.G00.54.004,'31012015'
S21.G00.78.001,'02'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'3085.28'
S21.G00.81.001,'063'
S21.G00.81.004,'300.81'
S21.G00.78.001,'31'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
......@@ -350,27 +344,16 @@ S21.G00.79.001,'20'
S21.G00.79.004,'97.16'
S21.G00.81.001,'059'
S21.G00.81.004,'97.16'
S21.G00.78.001,'31'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'0.00'
S21.G00.78.005,'2'
S21.G00.79.001,'11'
S21.G00.79.004,'3085.28'
S21.G00.81.001,'059'
S21.G00.81.004,'21.60'
S21.G00.78.001,'04'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'4125.36'
S21.G00.78.001,'13'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'94.07'
S21.G00.78.001,'07'
S21.G00.78.001,'02'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'3085.28'
S21.G00.81.001,'063'
S21.G00.81.004,'300.81'
S21.G00.78.001,'03'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
......@@ -381,6 +364,23 @@ S21.G00.81.001,'226'
S21.G00.81.002,'75367340900011'
S21.G00.81.003,'3085.28'
S21.G00.81.005,'59378'
S21.G00.78.001,'07'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'3085.28'
S21.G00.78.001,'31'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'0.00'
S21.G00.78.005,'2'
S21.G00.79.001,'11'
S21.G00.79.004,'3085.28'
S21.G00.81.001,'059'
S21.G00.81.004,'21.60'
S21.G00.78.001,'04'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'4125.36'
S21.G00.86.001,'01'
S21.G00.86.002,'02'
S21.G00.86.003,'11'
......@@ -459,12 +459,6 @@ S21.G00.54.001,'17'
S21.G00.54.002,'67.20'
S21.G00.54.003,'01012015'
S21.G00.54.004,'31012015'
S21.G00.78.001,'02'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'3170.00'
S21.G00.81.001,'063'
S21.G00.81.004,'323.55'
S21.G00.78.001,'31'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
......@@ -474,6 +468,16 @@ S21.G00.79.001,'20'
S21.G00.79.004,'97.16'
S21.G00.81.001,'059'
S21.G00.81.004,'97.16'
S21.G00.78.001,'13'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'86.36'
S21.G00.78.001,'02'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'3170.00'
S21.G00.81.001,'063'
S21.G00.81.004,'323.55'
S21.G00.78.001,'31'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
......@@ -485,18 +489,6 @@ S21.G00.79.001,'13'
S21.G00.79.004,'657.86'
S21.G00.81.001,'059'
S21.G00.81.004,'29.29'
S21.G00.78.001,'04'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'3847.23'
S21.G00.78.001,'13'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'86.36'
S21.G00.78.001,'07'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'3827.86'
S21.G00.78.001,'03'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
......@@ -507,6 +499,14 @@ S21.G00.81.001,'226'
S21.G00.81.002,'75367340900011'
S21.G00.81.003,'3827.86'
S21.G00.81.005,'59378'
S21.G00.78.001,'07'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'3827.86'
S21.G00.78.001,'04'
S21.G00.78.002,'01012015'
S21.G00.78.003,'31012015'
S21.G00.78.004,'3847.23'
S21.G00.86.001,'01'
S21.G00.86.002,'02'
S21.G00.86.003,'11'
......
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