diff --git a/.travis.yml b/.travis.yml
index 99cfdd4fa..a1bece4b8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,8 +20,12 @@ virtualenv:
install:
- git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
+ - pip install -U pip wheel
- pip install unidecode
- - pip install https://github.com/aricaldeira/pybrasil/archive/master.zip
+ - pip install python-dateutil
+ - pip install pytz
+ - pip install pyparsing
+ - pip install git+https://github.com/aricaldeira/pybrasil.git
- travis_install_nightly
script:
diff --git a/l10n_br_hr_holiday/i18n/pt_BR.po b/l10n_br_hr_holiday/i18n/pt_BR.po
index ed5c7ff26..830e0cb3b 100644
--- a/l10n_br_hr_holiday/i18n/pt_BR.po
+++ b/l10n_br_hr_holiday/i18n/pt_BR.po
@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-01-02 17:30+0000\n"
-"PO-Revision-Date: 2017-01-02 17:30+0000\n"
+"POT-Creation-Date: 2017-02-02 21:44+0000\n"
+"PO-Revision-Date: 2017-02-02 21:44+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -56,10 +56,10 @@ msgid "Alistamento Militar"
msgstr "Alistamento Militar"
#. module: l10n_br_hr_holiday
-#: code:addons/l10n_br_hr_holiday/models/hr_holidays.py:33
+#: code:addons/l10n_br_hr_holiday/models/hr_holidays.py:49
#, python-format
msgid "Atestado Obrigatório!"
-msgstr "Atestado Obrigatório!"
+msgstr "Favor anexar documento comprobatório"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_blood_donation
@@ -109,7 +109,13 @@ msgstr "Disposicao TRE"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_end_of_year_recess
msgid "End of year recess"
-msgstr "Recesso de final de ano"
+msgstr "Recesso"
+
+#. module: l10n_br_hr_holiday
+#: selection:hr.holidays,tipo:0
+#: selection:hr.holidays.status,tipo:0
+msgid "Férias"
+msgstr "Férias"
#. module: l10n_br_hr_holiday
#: field:hr.holidays,attachment_ids:0
@@ -124,7 +130,7 @@ msgstr "Folga"
#. module: l10n_br_hr_holiday
#: model:ir.model,name:l10n_br_hr_holiday.model_hr_holidays_status
msgid "Leave Type"
-msgstr "Tipo de falta"
+msgstr "Tipo de evento"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_Legal_adoption
@@ -144,7 +150,7 @@ msgstr "Limite de Horas"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_marriage
msgid "Marriage"
-msgstr "Casamento"
+msgstr "Licença Casamento"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_maternity_leave
@@ -169,23 +175,52 @@ msgid "Need attachment"
msgstr "Comprovante obrigatório"
#. module: l10n_br_hr_holiday
-#: code:addons/l10n_br_hr_holiday/models/hr_holidays.py:42
-#: code:addons/l10n_br_hr_holiday/models/hr_holidays.py:46
+#: code:addons/l10n_br_hr_holiday/models/hr_holidays.py:58
+#: code:addons/l10n_br_hr_holiday/models/hr_holidays.py:62
#, python-format
msgid "Number of days exceeded!"
msgstr "Quantidade de dias excedido!"
#. module: l10n_br_hr_holiday
-#: code:addons/l10n_br_hr_holiday/models/hr_holidays.py:52
+#: code:addons/l10n_br_hr_holiday/models/hr_holidays.py:68
#, python-format
msgid "Number of hours exceeded!"
msgstr "Quantidade de horas excedidas!"
+#. module: l10n_br_hr_holiday
+#: model:ir.ui.menu,name:l10n_br_hr_holiday.menu_ocorrencias
+msgid "Ocorrencias"
+msgstr "Evento"
+
+#. module: l10n_br_hr_holiday
+#: selection:hr.holidays,tipo:0
+#: selection:hr.holidays.status,tipo:0
+#: model:ir.actions.act_window,name:l10n_br_hr_holiday.l10n_br_hr_holiday_action_ocorrencias
+msgid "Ocorrências"
+msgstr "Evento"
+
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_paternity_leave
msgid "Paternity leave"
msgstr "Licença paternidade"
+#. module: l10n_br_hr_holiday
+#: field:hr.holidays,payroll_discount:0
+#: field:hr.holidays.status,payroll_discount:0
+msgid "Payroll Discount"
+msgstr "Payroll Discount"
+
+#. module: l10n_br_hr_holiday
+#: model:ir.model,name:l10n_br_hr_holiday.model_resource_calendar
+msgid "Resource Calendar"
+msgstr "Calendário de Recursos"
+
+#. module: l10n_br_hr_holiday
+#: field:hr.holidays,tipo:0
+#: field:hr.holidays.status,tipo:0
+msgid "Tipo"
+msgstr "Tipo"
+
#. module: l10n_br_hr_holiday
#: field:hr.holidays.status,type_day:0
msgid "Tipo de Dia"
@@ -194,4 +229,4 @@ msgstr "Tipo de Dia"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_yearly_leave_days
msgid "Yearly Leave Days"
-msgstr "Abono Pecuniário"
+msgstr "Abono"
diff --git a/l10n_br_hr_holiday/views/hr_holidays.xml b/l10n_br_hr_holiday/views/hr_holidays.xml
index 2eccb3b0b..9fbbf7637 100644
--- a/l10n_br_hr_holiday/views/hr_holidays.xml
+++ b/l10n_br_hr_holiday/views/hr_holidays.xml
@@ -13,6 +13,9 @@
+
+
+
@@ -27,7 +30,7 @@
id="l10n_br_hr_holiday_action_ocorrencias"
name="Ocorrências"
res_model="hr.holidays"
- view_mode="calendar"
+ view_mode="calendar,form"
context="{'default_tipo':'ocorrencias', 'default_type': 'remove',
'search_default_my_leaves':1 }"/>
@@ -39,5 +42,9 @@
groups="base.group_hr_manager"
sequence="6"/>
+
+ Evento
+
+
diff --git a/l10n_br_hr_payroll/__openerp__.py b/l10n_br_hr_payroll/__openerp__.py
index ecb68bbea..8a8ea9293 100644
--- a/l10n_br_hr_payroll/__openerp__.py
+++ b/l10n_br_hr_payroll/__openerp__.py
@@ -16,19 +16,22 @@
'l10n_br_hr_contract',
'hr_payroll',
],
+ 'external_dependencies': {
+ 'python': ['pybrasil'],
+ },
'data': [
'data/l10n_br_hr_income_tax.xml',
'data/l10n_br_hr_income_tax_deductable_amount_family.xml',
- 'views/hr_contract.xml',
- 'security/l10n_br_hr_contract.xml',
- 'views/l10n_br_hr_contract/l10n_br_hr_contract.xml',
- 'views/l10n_br_hr_contract/l10n_br_hr_contract_cargo_atividade.xml',
- 'views/l10n_br_hr_contract/l10n_br_hr_contract_filiacao_sindical.xml',
- 'views/l10n_br_hr_contract/l10n_br_hr_contract_jornada.xml',
- 'views/l10n_br_hr_contract/l10n_br_hr_contract_lotacao_local.xml',
- 'views/l10n_br_hr_contract/l10n_br_hr_contract_remuneracao.xml',
'data/l10n_br_hr_payroll_data_rubricas.xml',
'data/l10n_br_hr_payroll_data_tabela_INSS.xml',
+ 'views/hr_contract.xml',
+ 'security/l10n_br_hr_contract.xml',
+ 'views/l10n_br_hr_contract.xml',
+ 'views/l10n_br_hr_contract_cargo_atividade.xml',
+ 'views/l10n_br_hr_contract_filiacao_sindical.xml',
+ 'views/l10n_br_hr_contract_jornada.xml',
+ 'views/l10n_br_hr_contract_lotacao_local.xml',
+ 'views/l10n_br_hr_contract_remuneracao.xml',
'security/ir.model.access.csv',
'views/l10n_br_hr_child_benefit_view.xml',
'views/l10n_br_hr_income_tax_view.xml',
@@ -38,6 +41,11 @@
'views/l10n_br_hr_social_security_tax_view.xml',
'views/hr_payslip.xml',
'views/hr_salary_rule.xml',
+ 'views/hr_payroll_structure.xml',
+ 'views/hr_payslip_run.xml',
+ ],
+ 'demo': [
+ 'demo/hr_contract.xml',
],
'installable': True,
'auto_install': False,
diff --git a/l10n_br_hr_payroll/data/l10n_br_hr_income_tax.xml b/l10n_br_hr_payroll/data/l10n_br_hr_income_tax.xml
index e4b11a8ae..b8ee2d05e 100644
--- a/l10n_br_hr_payroll/data/l10n_br_hr_income_tax.xml
+++ b/l10n_br_hr_payroll/data/l10n_br_hr_income_tax.xml
@@ -5,6 +5,40 @@
+
+ 2016
+ 0
+ 0
+ 0
+
+
+
+ 2016
+ 1903.99
+ 7.5
+ 142.80
+
+
+
+ 2016
+ 2826.66
+ 15.00
+ 354.80
+
+
+
+ 2016
+ 3751.06
+ 22.50
+ 636.13
+
+
+
+ 2016
+ 4664.68
+ 27.5
+ 869.36
+
2017
diff --git a/l10n_br_hr_payroll/data/l10n_br_hr_payroll_data_rubricas.xml b/l10n_br_hr_payroll/data/l10n_br_hr_payroll_data_rubricas.xml
index b2e804805..679bd0aea 100644
--- a/l10n_br_hr_payroll/data/l10n_br_hr_payroll_data_rubricas.xml
+++ b/l10n_br_hr_payroll/data/l10n_br_hr_payroll_data_rubricas.xml
@@ -38,6 +38,14 @@
FGTS
FGTS
+
+ SEFIP
+ SEFIP
+
+
+ FERIAS
+ FERIAS
+
@@ -131,29 +139,121 @@
+
+
+ INSS_EMPRESA_BASE
+ INSS Empresa Base
+
+ code
+ result=BASE_INSS
+ if 'BASE_INSS_13' in locals():
+ result+=BASE_INSS_13
+
+
+
+
+ INSS_DEDUCAO_PREVIDENCIARIA
+ INSS Dedução Previdenciária
+
+ code
+ result=0
+ if 'SALARIO_FAMILIA' in locals():
+ result+=SALARIO_FAMILIA
+ if 'LICENCA_MATERNIDADE' in locals():
+ result+=LICENCA_MATERNIDADE
+
+
+
+
+ INSS_EMPRESA
+ INSS Empresa
+
+ code
+ result=INSS_EMPRESA_BASE
+ result_rate=RAT_FAP.total_rate
+
+
+
+
+ INSS_OUTRAS_ENTIDADES
+ INSS Outras Entidades
+
+ code
+ result=INSS_EMPRESA_BASE
+ result_rate=RAT_FAP.other_entities_rate
+
+
+
+
+ INSS_RAT_FAP
+ INSS RAT/FAP
+
+ code
+ result=INSS_EMPRESA_BASE
+ result_rate=RAT_FAP.rat_rate*RAT_FAP.fap_rate
+
+
+
+
+ INSS_EMPRESA_TOTAL
+ INSS Empresa Total
+
+ code
+ result=INSS_EMPRESA
+ if 'INSS_RAT_FAP' in locals():
+ result+=INSS_RAT_FAP
+ if 'INSS_OUTRAS_ENTIDADES' in locals():
+ result+=INSS_OUTRAS_ENTIDADES
+
+
+
+
+ INSS_EMPRESA_LIQUIDO
+ INSS Empresa Líquido
+
+ code
+ result=INSS_EMPRESA_TOTAL-INSS_DEDUCAO_PREVIDENCIARIA
+
+
+
+
+
+ BASE_FERIAS
+ Base FERIAS
+
+ code
+ none
+ result = MEDIAS.SALARIO.media/12.0
+result_qty = MEDIAS.SALARIO.meses
+
+
+
+
+
FERIAS
- Rubrica de FERIAS
-
+ FERIAS
+
code
- python
- result = worked_days.FERIAS.number_of_days > 0
- result = worked_days.FERIAS.number_of_days * contract.wage / 30
-
+ none
+ result = BASE_FERIAS / worked_days.SALDO_FERIAS.number_of_days
+result_qty = worked_days.FERIAS.number_of_days
+
+
1/3_FERIAS
- Rubrica de 1/3 FERIAS
-
+ 1/3 FERIAS
+
code
- python
- result = worked_days.FERIAS.number_of_days > 0
- result = FERIAS / 3
-
+ none
+ result = FERIAS / 3.0
+
+
@@ -191,7 +291,10 @@
code
none
- result = CALCULAR.get_specific_rubric_value(rubrica.id)
+ if MEDIAS:
+ result = CALCULAR.get_specific_rubric_value(rubrica.id, MEDIAS)
+else:
+ result = CALCULAR.get_specific_rubric_value(rubrica.id)
@@ -201,7 +304,46 @@
code
none
- result = worked_days.DIAS_BASE.number_of_days * contract.wage/30
+ result = worked_days.DIAS_TRABALHADOS.number_of_days * contract.wage/30
+
+
+
+
+
+
+
+ SALARIO
+ Honorario Presidente
+
+ code
+ none
+ result = worked_days.DIAS_TRABALHADOS.number_of_days * contract.wage/30
+
+
+
+
+
+
+
+ SALARIO
+ Honorario Diretoria
+
+ code
+ none
+ result = worked_days.DIAS_TRABALHADOS.number_of_days * contract.wage/30
+
+
+
+
+
+
+
+ SALARIO
+ Honorario Conselho
+
+ code
+ none
+ result = worked_days.DIAS_TRABALHADOS.number_of_days * contract.wage/30
@@ -235,18 +377,21 @@
code
none
- result = BASE_FGTS
+ result = BASE_FGTS/2
-
REMBOLSO_SAUDE
Reembolso Plano de Saude
code
none
- result = CALCULAR.get_specific_rubric_value(rubrica.id)
+ if MEDIAS:
+ result = CALCULAR.get_specific_rubric_value(rubrica.id, MEDIAS)
+else:
+ result = CALCULAR.get_specific_rubric_value(rubrica.id)
+
@@ -254,10 +399,10 @@
ADIANTAMENTO_13
Adiantamento 13 Salario
- percentage
- contract.wage
- 1.0
- 50.00
+ code
+ none
+ result = CALCULAR.BUSCAR_PRIMEIRA_PARCELA()
+
@@ -266,10 +411,11 @@
PRIMEIRA_PARCELA_13
Primeira parcela 13 Salario
- percentage
- contract.wage
- 1.0
- 50.00
+ code
+ none
+ result = MEDIAS.SALARIO.media/12.0
+result_qty = MEDIAS.SALARIO.meses
+
@@ -278,22 +424,25 @@
SEGUNDA_PARCELA_13
Segunda parcela 13 Salário
- percentage
- contract.wage
- 1.0
- 50.00
+ code
+ none
+ result = MEDIAS.SALARIO.media/12.0
+result_qty = MEDIAS.SALARIO.meses
+
+
+
FERIAS
- Estrutura de Salario de Férias
-
+ Férias
+
@@ -338,6 +487,30 @@
+
+ HONORARIO_PRESIDENTE
+ Honorario Presidente
+
+
+
+
+
+
+ HONORARIO_DIRETORIA
+ Honorario Diretoria
+
+
+
+
+
+
+ HONORARIO_CONSELHO
+ Honorario Conselho
+
+
+
+
+
PRIMEIRA_PARCELA_13
Primeira Parcela 13 Salário
diff --git a/l10n_br_hr_payroll/demo/hr_contract.xml b/l10n_br_hr_payroll/demo/hr_contract.xml
new file mode 100644
index 000000000..9b907a7a2
--- /dev/null
+++ b/l10n_br_hr_payroll/demo/hr_contract.xml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+ 2017
+ 1.5
+ 1.5
+ 3.0
+ 6.0
+
+
+
+
+ 2016
+ 1.5
+ 1.5
+ 3.0
+ 6.0
+
+
+
+
+
+
+
+
+ Tony Stark
+ user
+ +24242424
+
+
+
+
+
+ Contract For Tony Stark
+
+
+
+
+
+ This is Tony Stark's contract
+
+
+
+
+
+
+
+ 2017
+
+
+
+
+
+
+
+
+
+
+
+ Bruce Banner
+ user
+ +71717171
+
+
+
+
+
+
+
+ 1.0
+ 100
+ 400.00
+
+
+
+
+ Contract For Bruce Banner
+
+
+
+
+ This is Bruce Banner's contract
+
+
+
+
+
+
+
+
+ 2017
+ Holerite_01
+
+
+
+
+
+
+
+ Dias Base
+ 1
+ DIAS_BASE
+ 0.0
+ 30
+
+
+
+
+
+
diff --git a/l10n_br_hr_payroll/models/__init__.py b/l10n_br_hr_payroll/models/__init__.py
index 481cf73a1..40421af62 100644
--- a/l10n_br_hr_payroll/models/__init__.py
+++ b/l10n_br_hr_payroll/models/__init__.py
@@ -3,6 +3,7 @@
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from . import hr_payslip
+from . import hr_payslip_line
from . import l10n_br_hr_child_benefit
from . import l10n_br_hr_income_tax
from . import l10n_br_hr_income_tax_deductable_amount_family
@@ -15,3 +16,6 @@
from . import hr_contract
from . import hr_contract_salary_rule
from . import hr_employee
+from . import hr_payroll_structure
+from . import l10n_br_hr_medias
+from . import hr_payslip_run
diff --git a/l10n_br_hr_payroll/models/hr_contract.py b/l10n_br_hr_payroll/models/hr_contract.py
index a9dc5f68c..31851350e 100644
--- a/l10n_br_hr_payroll/models/hr_contract.py
+++ b/l10n_br_hr_payroll/models/hr_contract.py
@@ -3,28 +3,87 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import api, fields, models
+from datetime import datetime
class HrContract(models.Model):
_inherit = 'hr.contract'
+ _rec_name = 'nome_contrato'
+
+ @api.depends('employee_id', 'date_start')
+ def _nome_contrato(self):
+ for contrato in self:
+ nome = contrato.employee_id.name
+ inicio_contrato = contrato.date_start
+ fim_contrato = contrato.date_end
+
+ if inicio_contrato:
+ inicio_contrato = datetime.strptime(inicio_contrato,
+ '%Y-%m-%d')
+ inicio_contrato = inicio_contrato.strftime('%d/%m/%y')
+
+ if fim_contrato:
+ fim_contrato = datetime.strptime(fim_contrato, '%Y-%m-%d')
+ fim_contrato = fim_contrato.strftime('%d/%m/%y')
+ if fim_contrato > fields.Date.today():
+ fim_contrato = "- D. %s" % fim_contrato
+ else:
+ fim_contrato = "- %s" % fim_contrato
+ else:
+ fim_contrato = ''
+ matricula = contrato.name
+ nome_contrato = '[%s] %s - %s %s' % (matricula,
+ nome, inicio_contrato,
+ fim_contrato)
+ contrato.nome_contrato = nome_contrato
+
+ nome_contrato = fields.Char(default="[mat] nome - inicio - fim",
+ compute="_nome_contrato", store=True)
+
+ @api.multi
+ def _buscar_salario_vigente_periodo(self, data_inicio, data_fim):
+ contract_change_obj = self.env['l10n_br_hr.contract.change']
+ change = contract_change_obj.search(
+ [
+ ('change_date', '>=', data_inicio),
+ ('change_date', '<=', data_fim),
+ ('wage', '>', 0),
+ ],
+ order="change_date DESC",
+ limit=1,
+ )
+ return change.wage
@api.multi
def _salario_dia(self, data_inicio, data_fim):
- if data_inicio >= self.date_start and data_fim <= self.date_end:
+ if data_inicio >= self.date_start and \
+ (data_fim <= self.date_end or not self.date_end):
return self.wage/30
+ else:
+ return self._buscar_salario_vigente_periodo(
+ data_inicio, data_fim)/30
@api.multi
def _salario_hora(self, data_inicio, data_fim):
- if data_inicio >= self.date_start and data_fim <= self.date_end:
+ if data_inicio >= self.date_start and \
+ (data_fim <= self.date_end or not self.date_end):
return self.wage/(
220 if not self.monthly_hours else self.monthly_hours
)
+ else:
+ return self._buscar_salario_vigente_periodo(
+ data_inicio, data_fim)/(
+ 220 if not self.monthly_hours else self.monthly_hours
+ )
@api.multi
def _salario_mes(self, data_inicio, data_fim):
- if data_inicio >= self.date_start and data_fim <= self.date_end:
+ if data_inicio >= self.date_start and \
+ (data_fim <= self.date_end or not self.date_end):
return self.wage
+ else:
+ return self._buscar_salario_vigente_periodo(data_inicio, data_fim)
specific_rule_ids = fields.One2many(
comodel_name='hr.contract.salary.rule',
@@ -71,3 +130,274 @@ def _salario_mes(self, data_inicio, data_fim):
('change_type', '=', 'filiacao-sindical')
],
)
+ company_id = fields.Many2one(
+ comodel_name='res.company',
+ string='Empresa',
+ required=True,
+ )
+
+ # Admissão
+ tipo_do_contrato = fields.Selection(
+ selection=[],
+ string="Tipo do contrato"
+ )
+
+ tipo_de_admissao = fields.Selection(
+ selection=[],
+ string="Tipo de admissão"
+ )
+
+ indicativo_de_admissao = fields.Selection(
+ selection=[('transferencia', u'Trasferência'),
+ ('normal', u'Normal')],
+ string="Indicativo da admissão"
+ )
+
+ contrato_transferido = fields.Selection(
+ selection=[],
+ string="Contrato transferido"
+ )
+
+ data_da_transferencia = fields.Date(
+ string="Data da transferencia"
+ )
+
+ seguro_desemprego = fields.Boolean(
+ string="Em Seguro Desemprego?"
+ )
+
+ primeiro_emprego = fields.Boolean(
+ string="Primeiro emprego?"
+ )
+
+ primeira_experiencia = fields.Integer(
+ string="Tempo em dias do 1º período de experiência"
+ )
+
+ data_primeira_experiencia = fields.Date(
+ string="Início da primeira experiência"
+ )
+
+ segunda_experiencia = fields.Integer(
+ string="Tempo em dias do 2º período de experiência"
+ )
+
+ data_segunda_experiencia = fields.Date(
+ string="Início da segunda experiência"
+ )
+
+ # Lotação
+ departamento_lotacao = fields.Selection(
+ selection=[],
+ string="Departamento/lotação"
+ )
+
+ lotacao_cliente_fornecedor = fields.Selection(
+ selection=[],
+ string="Lotação/cliente/fornecedor"
+ )
+
+ # Jornada
+ tipo_de_jornada = fields.Selection(
+ selection=[],
+ string="Tipo de jornada de trabalho"
+ )
+
+ jornada_seg_sex = fields.Selection(
+ selection=[],
+ string="Jornada padrão de segunda a sexta-feira"
+ )
+
+ jornada_sab = fields.Selection(
+ selection=[],
+ string="Jornada no sábado"
+ )
+
+ # Aba Vínculos Anteriores e cedentes
+ # Vínculo anterior
+ cnpj_empregador_anterior = fields.Char(
+ string="CNPJ do empregador anterior"
+ )
+
+ matricula_anterior = fields.Char(
+ string="Matrícula anterior"
+ )
+
+ data_admissao_anterior = fields.Date(
+ string="Data de admissão no vínculo anterior"
+ )
+
+ observacoes_vinculo_anterior = fields.Text(
+ string="Observações do vínculo anterior"
+ )
+
+ # Vínculo cedente
+ cnpj_empregador_cedente = fields.Char(
+ string="CNPJ do empregador cedente"
+ )
+
+ matricula_cedente = fields.Char(
+ string="Matrícula cedente"
+ )
+
+ data_admissao_cedente = fields.Date(
+ string="Data de admissão no vínculo cedente"
+ )
+
+ onus_vinculo_cedente = fields.Selection(
+ selection=[],
+ string="Ônus para o cedente"
+ )
+
+ # Aba Saúde ocupacional
+ data_atestado_saude = fields.Date(
+ string="Data do atestado de saúde ocupacional"
+ )
+
+ numero_crm = fields.Integer(
+ string="CRM nº"
+ )
+
+ nome_medico_encarregado = fields.Char(
+ string="Nome do médico encarregado"
+ )
+
+ estado_crm = fields.Selection(
+ selection=[],
+ string="Estado do CRM"
+ )
+
+ # Tree Exames
+ exame_ids = fields.One2many(
+ comodel_name='hr.exame.medico',
+ inverse_name='contract_id',
+ string="Exames"
+ )
+
+ # Aba Processo judicial
+ numero_processo = fields.Integer(
+ string="Nº processo judicial"
+ )
+
+ nome_advogado_autor = fields.Char(
+ string="Advogado do autor do processo"
+ )
+
+ nome_advogado_empresa = fields.Char(
+ string="Advogado da empresa"
+ )
+
+ observacoes_processo = fields.Text(
+ string="Observações do processo judicial"
+ )
+
+ # Aba Cursos e treinamentos
+ curso_ids = fields.One2many(
+ comodel_name='hr.curso',
+ inverse_name='contract_id',
+ string="Cursos"
+ )
+
+ # Aba Afastamentos
+ afastamento_ids = fields.One2many(
+ comodel_name='hr.holidays',
+ inverse_name='contrato_id',
+ string="Afastamentos"
+ )
+
+
+class Exame(models.Model):
+ _name = 'hr.exame.medico'
+
+ name = fields.Char(
+ string="Exame"
+ )
+
+ data_do_exame = fields.Date(
+ string="Data do exame"
+ )
+
+ data_de_validade = fields.Date(
+ string="Data de validade"
+ )
+
+ contract_id = fields.Many2one(
+ comodel_name='hr.contract',
+ )
+
+
+class Curso(models.Model):
+ _name = 'hr.curso'
+
+ name = fields.Char(
+ string="Curso"
+ )
+
+ carga_horaria = fields.Integer(
+ string="Carga horária"
+ )
+
+ inicio_curso = fields.Date(
+ string="Início"
+ )
+
+ fim_curso = fields.Date(
+ string="Encerramento"
+ )
+
+ situacao = fields.Selection(
+ selection=[],
+ string="Situação"
+ )
+
+ contract_id = fields.Many2one(
+ comodel_name='hr.contract',
+ )
+
+
+class HrHoliday(models.Model):
+ _inherit = 'hr.holidays'
+
+ rubrica = fields.Char(
+ string="Rubrica"
+ )
+
+ periodo = fields.Char(
+ string="Data de afastamento"
+ )
+
+ valor_inss = fields.Float(
+ string="Valor INSS"
+ )
+
+ contrato_id = fields.Many2one(
+ comodel_name='hr.contract',
+ )
+
+
+class HrContractSalaryUnit(models.Model):
+ _inherit = 'hr.contract.salary.unit'
+
+ @api.multi
+ def name_get(self):
+ result = []
+ for record in self:
+ name = record['name']
+ if name == 'Monthly':
+ name = 'Por mês'
+ elif name == 'Biweekly':
+ name = 'Por 15 dias'
+ elif name == 'Weekly':
+ name = 'Por semana'
+ elif name == 'Daily':
+ name = 'Por dia'
+ elif name == 'Hourly':
+ name = 'Por hora'
+ elif name == 'Task':
+ name = 'Por tarefa'
+ elif name == 'Others':
+ name = 'Outros'
+ elif record['code']:
+ name = record['code'] + ' - ' + name
+ result.append((record['id'], name))
+ return result
diff --git a/l10n_br_hr_payroll/models/hr_payroll_structure.py b/l10n_br_hr_payroll/models/hr_payroll_structure.py
new file mode 100644
index 000000000..07537a78a
--- /dev/null
+++ b/l10n_br_hr_payroll/models/hr_payroll_structure.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2016 KMEE (http://www.kmee.com.br)
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+from openerp import fields, models
+
+
+class HrPayrollStructure(models.Model):
+ _inherit = 'hr.payroll.structure'
+
+ ferias = fields.Many2one(
+ comodel_name='hr.payroll.structure',
+ string='Férias',
+ domain=[('tipo_estrutura', '=', 'ferias')],
+ )
+
+ tipo_estrutura = fields.Selection(
+ selection=[
+ ('normal', 'Folha Normal'),
+ ('ferias', 'Fériass'),
+ ('adiantamento_13', 'Adiantamento do 13º'),
+ ('segunda_parcela_13', 'Segunda Parcela do 13º'),
+ ('recisao', 'Recisão'),
+ ],
+ string='Tipo de Estrutura de Salários',
+ )
diff --git a/l10n_br_hr_payroll/models/hr_payslip.py b/l10n_br_hr_payroll/models/hr_payslip.py
index 6e0d6f5c9..642a6344d 100644
--- a/l10n_br_hr_payroll/models/hr_payslip.py
+++ b/l10n_br_hr_payroll/models/hr_payslip.py
@@ -2,49 +2,166 @@
# Copyright (C) 2016 KMEE (http://www.kmee.com.br)
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
-from openerp import api, fields, models
+import logging
+from openerp import api, fields, models, exceptions, _
from datetime import datetime
+from dateutil.relativedelta import relativedelta
+from lxml import etree
+
+_logger = logging.getLogger(__name__)
+
+try:
+ from pybrasil import valor, data
+except ImportError:
+ _logger.info('Cannot import pybrasil')
MES_DO_ANO = [
- (1, u'Jan'),
- (2, u'Fev'),
- (3, u'Mar'),
- (4, u'Abr'),
- (5, u'Mai'),
- (6, u'Jun'),
- (7, u'Jul'),
- (8, u'Ago'),
- (9, u'Set'),
- (10, u'Out'),
- (11, u'Nov'),
- (12, u'Dez'),
+ (1, u'Janeiro'),
+ (2, u'Fevereiro'),
+ (3, u'Marco'),
+ (4, u'Abril'),
+ (5, u'Maio'),
+ (6, u'Junho'),
+ (7, u'Julho'),
+ (8, u'Agosto'),
+ (9, u'Setembro'),
+ (10, u'Outubro'),
+ (11, u'Novembro'),
+ (12, u'Dezembro'),
+]
+
+TIPO_DE_FOLHA = [
+ ('normal', u'Folha normal'),
+ ('rescisao', u'Rescisão'),
+ ('ferias', u'Férias'),
+ ('decimo_terceiro', u'Décimo terceiro (13º)'),
+ ('aviso_previo', u'Aviso Prévio'),
+ ('licenca_maternidade', u'Licença maternidade'),
+ ('auxilio_doenca', u'Auxílio doença'),
+ ('auxílio_acidente_trabalho', u'Auxílio acidente de trabalho'),
]
class HrPayslip(models.Model):
_inherit = 'hr.payslip'
+ @api.multi
+ def _buscar_dias_aviso_previo(self):
+ for payslip in self:
+ if payslip.tipo_de_folha == 'aviso_previo':
+ periodos_aquisitivos = self.env['hr.vacation.control'].search(
+ [
+ ('contract_id', '=', payslip.contract_id.id),
+ ('fim_aquisitivo', '<', payslip.date_to)
+ ]
+ )
+ if periodos_aquisitivos:
+ payslip.dias_aviso_previo = 30 + len(
+ periodos_aquisitivos) * 3
+ else:
+ payslip.dias_aviso_previo = 30
+
@api.multi
def _valor_total_folha(self):
- total = 0.00
- for line in self.line_ids:
- total += line.valor_provento - line.valor_deducao
- self.write({'total_folha': total})
+ for holerite in self:
+ total = 0.00
+ total_proventos = 0.00
+ total_descontos = 0.00
+ base_inss = 0.00
+ base_irpf = 0.00
+ base_fgts = 0.00
+ fgts = 0.00
+ inss = 0.00
+ irpf = 0.00
+ codigo = {}
+ codigo['BASE_FGTS'] = \
+ holerite.env\
+ .ref('l10n_br_hr_payroll.hr_salary_rule_BASE_FGTS').code
+ codigo['BASE_INSS'] = \
+ holerite.env\
+ .ref('l10n_br_hr_payroll.hr_salary_rule_BASE_INSS').code
+ codigo['BASE_IRPF'] = \
+ holerite.env\
+ .ref('l10n_br_hr_payroll.hr_salary_rule_BASE_IRPF').code
+ codigo['FGTS'] = \
+ holerite.env\
+ .ref('l10n_br_hr_payroll.hr_salary_rule_FGTS').code
+ codigo['INSS'] = \
+ holerite.env\
+ .ref('l10n_br_hr_payroll.hr_salary_rule_INSS').code
+ codigo['IRPF'] = \
+ holerite.env\
+ .ref('l10n_br_hr_payroll.hr_salary_rule_IRPF').code
+ for line in holerite.line_ids:
+ total += line.valor_provento - line.valor_deducao
+ total_proventos += line.valor_provento
+ total_descontos += line.valor_deducao
+ if codigo['BASE_FGTS']:
+ base_fgts = line.total
+ elif codigo['BASE_INSS']:
+ base_inss = line.total
+ elif codigo('BASE_IRPF'):
+ base_irpf = line.total
+ elif codigo['FGTS']:
+ fgts = line.total
+ elif codigo['INSS']:
+ inss = line.total
+ elif codigo['IRPF']:
+ irpf = line.total
+ holerite.total_folha = total
+ holerite.total_proventos = total_proventos
+ holerite.total_descontos = total_descontos
+ holerite.base_fgts = base_fgts
+ holerite.base_inss = base_inss
+ holerite.base_irpf = base_irpf
+ holerite.fgts = fgts
+ holerite.inss = inss
+ holerite.irpf = irpf
+ # Formato
+ holerite.data_admissao_fmt =\
+ data.formata_data(holerite.contract_id.date_start)
+ holerite.salario_base_fmt =\
+ valor.formata_valor(holerite.contract_id.wage)
+ holerite.total_folha_fmt =\
+ valor.formata_valor(holerite.total_folha)
+ holerite.total_proventos_fmt =\
+ valor.formata_valor(holerite.total_proventos)
+ holerite.total_descontos_fmt =\
+ valor.formata_valor(holerite.total_descontos)
+ holerite.base_fgts_fmt = valor.formata_valor(holerite.base_fgts)
+ holerite.base_inss_fmt = valor.formata_valor(holerite.base_inss)
+ holerite.base_irpf_fmt = valor.formata_valor(holerite.base_irpf)
+ holerite.fgts_fmt = valor.formata_valor(holerite.fgts)
+ holerite.inss_fmt = valor.formata_valor(holerite.inss)
+ holerite.irpf_fmt = valor.formata_valor(holerite.irpf)
employee_id_readonly = fields.Many2one(
string=u'Funcionário',
comodel_name='hr.employee',
compute='set_employee_id',
)
+ is_simulacao = fields.Boolean(
+ string=u"Simulação",
+ )
+ dias_aviso_previo = fields.Integer(
+ string="Dias de Aviso Prévio",
+ )
@api.depends('line_ids')
@api.model
def _buscar_payslip_line(self):
- lines = []
- for line in self.line_ids:
- if line.valor_provento or line.valor_deducao:
- lines.append(line.id)
- self.line_resume_ids = lines
+ for holerite in self:
+ lines = []
+ for line in holerite.line_ids:
+ if line.valor_provento or line.valor_deducao:
+ lines.append(line.id)
+ holerite.line_resume_ids = lines
+
+ tipo_de_folha = fields.Selection(
+ selection=TIPO_DE_FOLHA,
+ string=u'Tipo de folha',
+ default='normal',
+ )
struct_id_readonly = fields.Many2one(
string=u'Estrutura de Salário',
@@ -64,16 +181,158 @@ def _buscar_payslip_line(self):
default=datetime.now().year,
)
+ data_mes_ano = fields.Char(
+ string=u'Mês/Ano',
+ compute='computar_mes_ano',
+ )
+
total_folha = fields.Float(
- string="Total",
- default=0.00
+ string=u'Total',
+ default=0.00,
+ compute='_valor_total_folha'
+ )
+
+ total_folha_fmt = fields.Char(
+ string=u'Total',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ data_admissao_fmt = fields.Char(
+ string=u'Data de admissao',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ salario_base_fmt = fields.Char(
+ string=u'Salario Base',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ total_proventos = fields.Float(
+ string=u'Total Proventos',
+ default=0.00,
+ compute='_valor_total_folha'
+ )
+
+ total_proventos_fmt = fields.Char(
+ string=u'Total Proventos',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ total_descontos = fields.Float(
+ string=u'Total Descontos',
+ default=0.00,
+ compute='_valor_total_folha'
+ )
+
+ total_descontos_fmt = fields.Char(
+ string=u'Total Descontos',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ base_fgts = fields.Float(
+ string=u'Base do FGTS',
+ default=0.00,
+ compute='_valor_total_folha'
+ )
+
+ base_fgts_fmt = fields.Char(
+ string=u'Base do FGTS',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ base_inss = fields.Float(
+ string=u'Base do INSS',
+ default=0.00,
+ compute='_valor_total_folha'
+ )
+
+ base_inss_fmt = fields.Char(
+ string=u'Base do INSS',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ base_irpf = fields.Float(
+ string=u'Base do IRPF',
+ default=0.00,
+ compute='_valor_total_folha'
+ )
+
+ base_irpf_fmt = fields.Char(
+ string=u'Base do IRPF',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ fgts = fields.Float(
+ string=u'FGTS',
+ default=0.00,
+ compute='_valor_total_folha'
+ )
+
+ fgts_fmt = fields.Char(
+ string=u'FGTS',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ inss = fields.Float(
+ string=u'INSS',
+ default=0.00,
+ compute='_valor_total_folha'
+ )
+
+ inss_fmt = fields.Char(
+ string=u'INSS',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ irpf = fields.Float(
+ string=u'IRPF',
+ default=0.00,
+ compute='_valor_total_folha'
+ )
+
+ irpf_fmt = fields.Char(
+ string=u'IRPF',
+ default='0',
+ compute='_valor_total_folha'
+ )
+
+ medias_proventos = fields.One2many(
+ string=u'Linhas das medias dos proventos',
+ comodel_name='l10n_br.hr.medias',
+ inverse_name='holerite_id',
)
line_resume_ids = fields.One2many(
comodel_name='hr.payslip.line',
inverse_name='slip_id',
compute=_buscar_payslip_line,
- string="Holerite Resumo",
+ string=u"Holerite Resumo",
+ )
+
+ @api.depends('contract_id')
+ @api.model
+ def _get_periodo_aquisitivo(self):
+ if self.contract_id:
+ controles_ferias = self.contract_id.vacation_control_ids
+ if controles_ferias:
+ return controles_ferias[0]
+
+ periodo_aquisitivo = fields.Many2one(
+ comodel_name='hr.vacation.control',
+ default='_get_periodo_aquisitivo',
+ string="Período Aquisitivo",
+ domain="[('contract_id','=',contract_id)]",
+ store=True,
)
def get_attendances(self, nome, sequence, code, number_of_days,
@@ -89,14 +348,14 @@ def get_attendances(self, nome, sequence, code, number_of_days,
return attendance
@api.multi
- def get_worked_day_lines(self, date_from, date_to):
+ def get_worked_day_lines(self, contract_id, date_from, date_to):
"""
@param contract_ids: list of contract id
@return: returns a list of dict containing the input that should
be applied for the given contract between date_from and date_to
"""
result = []
- for contract_id in self:
+ for contract_id in self.env['hr.contract'].browse(contract_id):
# get dias Base para cálculo do mês
dias_mes = self.env['resource.calendar'].get_dias_base(
@@ -160,10 +419,21 @@ def get_worked_day_lines(self, date_from, date_to):
0.0, contract_id
)
]
+ if hr_contract.vacation_control_ids[0].saldo:
+ saldo_ferias = hr_contract.vacation_control_ids[0].saldo
+ else:
+ saldo_ferias = 0
+ result += [
+ self.get_attendances(
+ u'Saldo de dias máximo para Férias', 8,
+ u'SALDO_FERIAS', saldo_ferias,
+ 0.0, contract_id
+ )
+ ]
# get Dias Trabalhados
quantidade_dias_trabalhados = \
- dias_mes - leaves['quantidade_dias_faltas_nao_remuneradas'] - \
+ 30 - leaves['quantidade_dias_faltas_nao_remuneradas'] - \
quantity_DSR_discount - quantidade_dias_ferias
result += [self.get_attendances(u'Dias Trabalhados', 34,
u'DIAS_TRABALHADOS',
@@ -223,17 +493,18 @@ def IRRF(self, BASE_IR, BASE_INSS):
def get_contract_specific_rubrics(self, contract_id, rule_ids):
contract = self.env['hr.contract'].browse(contract_id.id)
for rule in contract.specific_rule_ids:
- if datetime.strftime(
- datetime.now(), '%Y-%m-%d') >= rule.date_start:
- if not rule.date_stop or datetime.strftime(
- datetime.now(), '%Y-%m-%d') <= rule.date_stop:
+ if self.date_from >= rule.date_start:
+ if not rule.date_stop or self.date_to <= rule.date_stop:
rule_ids.append((rule.rule_id.id, rule.rule_id.sequence))
return rule_ids
@api.model
- def get_specific_rubric_value(self, rubrica_id):
+ def get_specific_rubric_value(self, rubrica_id, medias_obj=False):
for rubrica in self.contract_id.specific_rule_ids:
if rubrica.rule_id.id == rubrica_id:
+ if medias_obj:
+ if rubrica.rule_id.code not in medias_obj.dict.keys():
+ return 0
return rubrica.specific_quantity * \
rubrica.specific_percentual/100 * \
rubrica.specific_amount
@@ -245,6 +516,75 @@ def _buscar_valor_salario(self, codigo):
return tipo_salario.amount
return 0.00
+ @api.multi
+ def _get_rat_fap_period_values(self, year):
+ rat_fap_obj = self.env['l10n_br.hr.rat.fap']
+ rat_fap = rat_fap_obj = rat_fap_obj.search(
+ [('year', '=', year), ('company_id', '=', self.company_id.id)]
+ )
+ if rat_fap:
+ return rat_fap
+ else:
+ raise exceptions.Warning(
+ _('Can\'t find this year values in Rat Fap Table')
+ )
+
+ @api.multi
+ def buscar_estruturas_salario(self):
+ if self.tipo_de_folha == "normal" \
+ or self.tipo_de_folha == "aviso_previo":
+ return self.contract_id.struct_id
+ elif self.tipo_de_folha == "decimo_terceiro":
+ if self.mes_do_ano < 12:
+ estrutura_decimo_terceiro = self.env.ref(
+ 'l10n_br_hr_payroll.'
+ 'hr_salary_structure_PRIMEIRA_PARCELA_13'
+ )
+ return estrutura_decimo_terceiro
+ else:
+ estrutura_decimo_terceiro = self.env.ref(
+ 'l10n_br_hr_payroll.'
+ 'hr_salary_structure_SEGUNDA_PARCELA_13'
+ )
+ return estrutura_decimo_terceiro
+ elif self.tipo_de_folha == "ferias":
+ estrutura_decimo_terceiro = self.env.ref(
+ 'l10n_br_hr_payroll.'
+ 'hr_salary_structure_FERIAS'
+ )
+ return estrutura_decimo_terceiro
+
+ # @api.multi
+ # def buscar_media_rubrica(self, rubrica_id):
+ # rubrica = self.env['hr.salary.rule'].browse(rubrica_id)
+ # for media in self.medias_proventos:
+ # if rubrica.name == media.nome_rubrica:
+ # return media.media
+
+ @api.multi
+ def BUSCAR_PRIMEIRA_PARCELA(self):
+ primeira_parcela_struct_id = self.env.ref(
+ 'l10n_br_hr_payroll.hr_salary_structure_PRIMEIRA_PARCELA_13'
+ )
+ primeira_parcela_id = self.env.ref(
+ 'l10n_br_hr_payroll.hr_salary_rule_PRIMEIRA_PARCELA_13'
+ )
+ payslip_id = self.env['hr.payslip'].search(
+ [
+ ('contract_id', '=', self.contract_id.id),
+ ('date_from', '>=', str(self.ano) + '-01-01'),
+ ('date_to', '<=', str(self.ano) + '-11-30'),
+ ('struct_id', '=', primeira_parcela_struct_id.id)
+ ]
+ )
+ if len(payslip_id) > 1:
+ raise exceptions.Warning(
+ _('Existe mais de um holerite da primeira parcela do 13º!')
+ )
+ for line in payslip_id.line_ids:
+ if line.salary_rule_id.id == primeira_parcela_id.id:
+ return line.total
+
@api.multi
def get_payslip_lines(self, payslip_id):
"""
@@ -341,40 +681,52 @@ def sum(self, code, from_date, to_date=None):
payslip = payslip_obj.browse(payslip_id)
worked_days = {}
for worked_days_line in payslip.worked_days_line_ids:
- worked_days[worked_days_line.code] = worked_days_line
+ if payslip.tipo_de_folha == "aviso_previo" \
+ and worked_days_line.code == u'DIAS_TRABALHADOS':
+ worked_days_line.number_of_days = payslip.dias_aviso_previo
+ worked_days[worked_days_line.code] = worked_days_line
+ else:
+ worked_days[worked_days_line.code] = worked_days_line
inputs = {}
for input_line in payslip.input_line_ids:
inputs[input_line.code] = input_line
-
+ medias = {}
+ for media in payslip.medias_proventos:
+ medias[media.rubrica_id.code] = media
input_obj = InputLine(payslip.employee_id.id, inputs)
worked_days_obj = WorkedDays(payslip.employee_id.id, worked_days)
payslip_obj = Payslips(payslip.employee_id.id, payslip)
rules_obj = BrowsableObject(payslip.employee_id.id, rules)
+ medias_obj = BrowsableObject(payslip.employee_id.id, medias) \
+ if payslip.tipo_de_folha in ["ferias", "decimo_terceiro"] \
+ else False
categories_obj = \
BrowsableObject(payslip.employee_id.id, categories_dict)
- salario_mes = self._buscar_valor_salario('SALARIO_MES')
- salario_dia = self._buscar_valor_salario('SALARIO_DIA')
- salario_hora = self._buscar_valor_salario('SALARIO_HORA')
-
+ salario_mes = payslip._buscar_valor_salario('SALARIO_MES')
+ salario_dia = payslip._buscar_valor_salario('SALARIO_DIA')
+ salario_hora = payslip._buscar_valor_salario('SALARIO_HORA')
+ rat_fap = payslip._get_rat_fap_period_values(payslip.ano)
baselocaldict = {
'CALCULAR': payslip, 'BASE_INSS': 0.0, 'BASE_FGTS': 0.0,
'BASE_IR': 0.0, 'categories': categories_obj, 'rules': rules_obj,
'payslip': payslip_obj, 'worked_days': worked_days_obj,
'inputs': input_obj, 'rubrica': None, 'SALARIO_MES': salario_mes,
'SALARIO_DIA': salario_dia, 'SALARIO_HORA': salario_hora,
+ 'RAT_FAP': rat_fap, 'MEDIAS': medias_obj,
}
for contract_ids in self:
# get the ids of the structures on the contracts
# and their parent id as well
- structure_ids = self.env['hr.contract'].browse(
- contract_ids.ids).get_all_structures()
+ # structure_ids = self.env['hr.contract'].browse(
+ # contract_ids.ids).get_all_structures()
+ structure_ids = payslip.struct_id._get_parent_structure()
# get the rules of the structure and thier children
rule_ids = self.env['hr.payroll.structure'].browse(
structure_ids).get_all_rules()
- rule_ids = self.get_contract_specific_rubrics(
+ rule_ids = payslip.get_contract_specific_rubrics(
contract_ids, rule_ids)
# run the rules by sequence
@@ -397,6 +749,12 @@ def sum(self, code, from_date, to_date=None):
# compute the amount of the rule
amount, qty, rate = \
obj_rule.compute_rule(rule.id, localdict)
+ # se ja tiver sido calculado a media dessa rubrica,
+ # utilizar valor da media e multiplicar pela reinciden.
+ if medias.get(rule.code):
+ amount = medias.get(rule.code).media/12
+ qty = medias.get(rule.code).meses
+
# check if there is already a rule computed
# with that code
previous_amount = \
@@ -429,7 +787,8 @@ def sum(self, code, from_date, to_date=None):
result_dict[key] = {
'salary_rule_id': rule.id,
'contract_id': contract.id,
- 'name': rule.name,
+ 'name': u'Média de ' + rule.name
+ if medias_obj else rule.name,
'code': rule.code,
'category_id': rule.category_id.id,
'sequence': rule.sequence,
@@ -460,82 +819,181 @@ def sum(self, code, from_date, to_date=None):
result = [value for code, value in result_dict.items()]
return result
- def _computar_ano(self):
- ano = datetime.now().year
- return ano
+ @api.multi
+ def onchange_employee_id(self, date_from, date_to, contract_id):
+ worked_days_obj = self.env['hr.payslip.worked_days']
+ input_obj = self.env['hr.payslip.input']
+
+ # delete old worked days lines
+ old_worked_days_ids = worked_days_obj.search(
+ [('payslip_id', '=', self.id)]
+ )
+ if old_worked_days_ids:
+ for worked_day_id in old_worked_days_ids:
+ worked_day_id.unlink()
+
+ # delete old input lines
+ old_input_ids = input_obj.search([('payslip_id', '=', self.id)])
+ if old_input_ids:
+ for input_id in old_input_ids:
+ input_id.unlink()
+
+ # defaults
+ res = {
+ 'value': {
+ 'line_ids': [],
+ 'input_line_ids': [],
+ 'worked_days_line_ids': [],
+ 'name': '',
+ }
+ }
+ # computation of the salary input
+ worked_days_line_ids = self.get_worked_day_lines(
+ contract_id, date_from, date_to
+ )
+ input_line_ids = self.get_inputs(contract_id, date_from, date_to)
+ res['value'].update(
+ {
+ 'worked_days_line_ids': worked_days_line_ids,
+ 'input_line_ids': input_line_ids,
+ }
+ )
+ return res
@api.multi
@api.onchange('contract_id')
def set_employee_id(self):
for record in self:
- record.employee_id = record.contract_id.employee_id
- record.struct_id = record.contract_id.struct_id
- record.employee_id_readonly = record.employee_id
+ record.struct_id = record.buscar_estruturas_salario()
record.struct_id_readonly = record.struct_id
+ record.set_dates()
+ if record.contract_id:
+ record.employee_id = record.contract_id.employee_id
+ record.employee_id_readonly = record.employee_id
+ record._get_periodo_aquisitivo()
- ultimo_dia_do_mes = self.env['resource.calendar'].\
- get_ultimo_dia_mes(self.mes_do_ano, self.ano)
+ @api.multi
+ @api.onchange('mes_do_ano', 'ano')
+ def buscar_datas_periodo(self):
+ for record in self:
+ record.set_dates()
+ if record.contract_id:
+ record.onchange_employee_id(
+ record.date_from, record.date_to, record.contract_id.id
+ )
- primeiro_dia_do_mes = \
- datetime.strptime(str(self.mes_do_ano) + '-' +
- str(self.ano), '%m-%Y')
+ def computar_mes_ano(self):
+ for record in self:
+ record.data_mes_ano = MES_DO_ANO[record.mes_do_ano-1][1][:3] + \
+ '/' + str(record.ano)
- if not record.contract_id.date_start:
- continue
+ def set_dates(self):
+ for record in self:
+ ultimo_dia_do_mes = str(
+ self.env['resource.calendar'].get_ultimo_dia_mes(
+ record.mes_do_ano, record.ano))
- date_start = record.contract_id.date_start
+ primeiro_dia_do_mes = str(
+ datetime.strptime(str(record.mes_do_ano) + '-' +
+ str(record.ano), '%m-%Y'))
- if str(primeiro_dia_do_mes) < date_start:
- date_from = record.contract_id.date_start
- else:
- date_from = str(primeiro_dia_do_mes)
+ record.date_from = primeiro_dia_do_mes
+ record.date_to = ultimo_dia_do_mes
- record.date_from = date_from
+ data_de_inicio = record.contract_id.date_start
+ data_final = record.contract_id.date_end
- date_end = record.contract_id.date_end
+ if data_de_inicio and primeiro_dia_do_mes < data_de_inicio:
+ record.date_from = record.contract_id.date_start
- if not date_end:
- record.date_to = str(ultimo_dia_do_mes)
- elif str(ultimo_dia_do_mes) > record.contract_id.date_end:
+ if data_final and ultimo_dia_do_mes > data_final:
record.date_to = record.contract_id.date_end
- else:
- record.date_to = str(ultimo_dia_do_mes)
@api.multi
def compute_sheet(self):
+ if self.tipo_de_folha in ["decimo_terceiro", "ferias", "aviso_previo"]:
+ hr_medias_ids, data_de_inicio, data_final = \
+ self.gerar_media_dos_proventos()
+
+ if not hr_medias_ids \
+ and self.tipo_de_folha in ["decimo_terceiro", "ferias"]:
+ raise exceptions.Warning(
+ _('Nenhum Holerite encontrado para médias nesse período!')
+ )
+
+ self.validacao_holerites_anteriores(
+ data_de_inicio, data_final, self.contract_id)
super(HrPayslip, self).compute_sheet()
self._valor_total_folha()
return True
+ def validacao_holerites_anteriores(self, data_inicio, data_fim, contrato):
+ """
+ VAlida se existe todos os holerites calculados e confirmados em
+ determinado período.
+ :param date_from:
+ :param date_to:
+ :return:
+ """
+ folha_obj = self.env['hr.payslip']
+ domain = [
+ ('date_from', '>=', data_inicio),
+ ('date_to', '<=', data_fim),
+ ('contract_id', '=', contrato.id),
+ ('state', '=', 'done'),
+ ]
+ folhas_periodo = folha_obj.search(domain)
+
+ folhas_sorted = folhas_periodo.sorted(key=lambda r: r.date_from)
+ mes = fields.Date.from_string(data_inicio) + relativedelta(months=-1)
+
+ for folha in folhas_sorted:
+ mes = mes + relativedelta(months=1)
+ if folha.mes_do_ano != mes.month:
+ raise exceptions.ValidationError(_(
+ "Faltando Holerite confirmado do mês de %s"
+ ) % MES_DO_ANO[mes.month-1][1])
+
+ if mes.month != fields.Date.from_string(data_fim).month:
+ raise exceptions.ValidationError(_(
+ "Não foi encontrado holerite confirmado do mês de %s"
+ ) % MES_DO_ANO[mes.month-1][1])
-class HrPayslipeLine(models.Model):
- _inherit = "hr.payslip.line"
-
- @api.model
- def _valor_provento(self):
- for record in self:
- if record.salary_rule_id.category_id.code == "PROVENTO":
- record.valor_provento = record.total
+ @api.multi
+ def gerar_media_dos_proventos(self):
+ medias_obj = self.env['l10n_br.hr.medias']
+ if self.tipo_de_folha == 'ferias' \
+ or self.tipo_de_folha == 'aviso_previo':
+ periodo_aquisitivo = self.periodo_aquisitivo
+ data_de_inicio = str(fields.Date.from_string(
+ periodo_aquisitivo.inicio_aquisitivo))
+ data_final = str(fields.Date.from_string(
+ periodo_aquisitivo.fim_aquisitivo))
+ elif self.tipo_de_folha == 'decimo_terceiro':
+ if self.contract_id.date_start > str(self.ano) + '-01-01':
+ data_de_inicio = self.contract_id.date_start
else:
- record.valor_provento = 0.00
+ data_de_inicio = str(self.ano) + '-01-01'
+ data_final = self.date_to
+ hr_medias_ids = medias_obj.gerar_media_dos_proventos(
+ data_de_inicio, data_final, self)
+ return hr_medias_ids, data_de_inicio, data_final
@api.model
- def _valor_deducao(self):
- for record in self:
- if record.salary_rule_id.category_id.code in ["DEDUCAO"] \
- or record.salary_rule_id.code == "INSS" \
- or record.salary_rule_id.code == "IRPF":
- record.valor_deducao = record.total
- else:
- record.valor_deducao = 0.00
-
- valor_provento = fields.Float(
- string="Provento",
- compute=_valor_provento,
- default=0.00,
- )
- valor_deducao = fields.Float(
- string="Dedução",
- compute=_valor_deducao,
- default=0.00,
- )
+ def fields_view_get(self, view_id=None, view_type='form',
+ toolbar=False, submenu=False):
+ res = super(HrPayslip, self).fields_view_get(
+ view_id=view_id, view_type=view_type, toolbar=toolbar,
+ submenu=submenu
+ )
+ if view_type == 'form':
+ doc = etree.XML(res['arch'])
+ for sheet in doc.xpath("//sheet"):
+ parent = sheet.getparent()
+ index = parent.index(sheet)
+ for child in sheet:
+ parent.insert(index, child)
+ index += 1
+ parent.remove(sheet)
+ res['arch'] = etree.tostring(doc)
+ return res
diff --git a/l10n_br_hr_payroll/models/hr_payslip_line.py b/l10n_br_hr_payroll/models/hr_payslip_line.py
new file mode 100644
index 000000000..3ec3f70c8
--- /dev/null
+++ b/l10n_br_hr_payroll/models/hr_payslip_line.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2016 KMEE (http://www.kmee.com.br)
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+import logging
+from openerp import api, fields, models
+
+_logger = logging.getLogger(__name__)
+
+try:
+ from pybrasil import valor
+except ImportError:
+ _logger.info('Cannot import pybrasil')
+
+
+class HrPayslipeLine(models.Model):
+ _inherit = "hr.payslip.line"
+
+ @api.model
+ def _valor_provento(self):
+ for record in self:
+ record.quantity_fmt = valor.formata_valor(record.quantity)
+ if record.salary_rule_id.category_id.code == "PROVENTO":
+ record.valor_provento = record.total
+ record.valor_provento_fmt = \
+ valor.formata_valor(record.valor_provento)
+ else:
+ record.valor_provento = 0.00
+ record.valor_provento_fmt = ''
+
+ @api.model
+ def _valor_deducao(self):
+ for record in self:
+ if record.salary_rule_id.category_id.code in ["DEDUCAO"] \
+ or record.salary_rule_id.code == "INSS" \
+ or record.salary_rule_id.code == "IRPF":
+ record.valor_deducao = record.total
+ record.valor_deducao_fmt = \
+ valor.formata_valor(record.valor_deducao)
+ else:
+ record.valor_deducao = 0.00
+ record.valor_deducao_fmt = ''
+
+ quantity_fmt = fields.Char(
+ string=u'Quantidade',
+ compute=_valor_provento,
+ default='',
+ )
+
+ valor_provento = fields.Float(
+ string=u'Provento',
+ compute=_valor_provento,
+ default=0.00,
+ )
+
+ valor_provento_fmt = fields.Char(
+ string=u'Provento',
+ compute=_valor_provento,
+ default='',
+ )
+ valor_deducao = fields.Float(
+ string=u'Dedução',
+ compute=_valor_deducao,
+ default=0.00,
+ )
+
+ valor_deducao_fmt = fields.Char(
+ string=u'Dedução',
+ compute=_valor_deducao,
+ default='',
+ )
diff --git a/l10n_br_hr_payroll/models/hr_payslip_run.py b/l10n_br_hr_payroll/models/hr_payslip_run.py
new file mode 100644
index 000000000..a8f0f090b
--- /dev/null
+++ b/l10n_br_hr_payroll/models/hr_payslip_run.py
@@ -0,0 +1,161 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2016 KMEE (http://www.kmee.com.br)
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+from datetime import datetime
+
+from openerp import api, fields, models
+
+MES_DO_ANO = [
+ (1, u'Jan'),
+ (2, u'Fev'),
+ (3, u'Mar'),
+ (4, u'Abr'),
+ (5, u'Mai'),
+ (6, u'Jun'),
+ (7, u'Jul'),
+ (8, u'Ago'),
+ (9, u'Set'),
+ (10, u'Out'),
+ (11, u'Nov'),
+ (12, u'Dez'),
+]
+
+TIPO_DE_FOLHA = [
+ ('normal', u'Folha normal'),
+ ('decimo_terceiro', u'Décimo terceiro (13º)'),
+]
+
+
+class HrPayslipRun(models.Model):
+ _inherit = "hr.payslip.run"
+
+ mes_do_ano = fields.Selection(
+ selection=MES_DO_ANO,
+ string=u'Mês',
+ required=True,
+ default=datetime.now().month,
+ )
+ ano = fields.Integer(
+ string=u'Ano',
+ default=datetime.now().year,
+ )
+ tipo_de_folha = fields.Selection(
+ selection=TIPO_DE_FOLHA,
+ string=u'Tipo de folha',
+ default='normal',
+ )
+ contract_id = fields.Many2many(
+ comodel_name='hr.contract',
+ string='Contratos',
+ )
+ contract_id_readonly = fields.Many2many(
+ comodel_name='hr.contract',
+ string='Contratos',
+ )
+ departamento_id = fields.Many2one(
+ comodel_name='hr.department',
+ string='Departamento',
+ )
+ company_id = fields.Many2one(
+ comodel_name='res.company',
+ string='Empresa',
+ )
+
+ @api.multi
+ @api.onchange('mes_do_ano')
+ def buscar_datas_periodo(self):
+ for record in self:
+ record.set_dates()
+
+ def set_dates(self):
+ for record in self:
+ ultimo_dia_do_mes = str(
+ self.env['resource.calendar'].get_ultimo_dia_mes(
+ record.mes_do_ano, record.ano))
+
+ primeiro_dia_do_mes = str(
+ datetime.strptime(str(record.mes_do_ano) + '-' +
+ str(record.ano), '%m-%Y'))
+
+ record.date_start = primeiro_dia_do_mes
+ record.date_end = ultimo_dia_do_mes
+
+ @api.multi
+ def verificar_holerites_gerados(self):
+ contract_id = self.env['hr.contract'].search(
+ [
+ ('company_id', '=', self.company_id.id)
+ ]
+ )
+ contratos = [contrato.id for contrato in contract_id]
+ payslip_obj = self.env['hr.payslip']
+ payslips = payslip_obj.search(
+ [
+ ('tipo_de_folha', '=', self.tipo_de_folha),
+ ('date_from', '>=', self.date_start),
+ ('date_to', '<=', self.date_end),
+ ('contract_id', 'in', contratos)
+ ]
+ )
+ contratos_holerites_gerados = []
+ for payslip in payslips:
+ if payslip.contract_id.id not in contratos_holerites_gerados:
+ contratos_holerites_gerados.append(payslip.contract_id.id)
+ contratos_sem_holerite = [
+ contrato.id for contrato in contract_id
+ if contrato.id not in contratos_holerites_gerados
+ ]
+ if self.id:
+ self.write(
+ {
+ 'contract_id': [(6, 0, contratos_sem_holerite)],
+ 'contract_id_readonly': [(6, 0, contratos_sem_holerite)],
+ }
+ )
+ else:
+ self.contract_id = contratos_sem_holerite
+ self.contract_id_readonly = contratos_sem_holerite
+
+ @api.multi
+ def gerar_holerites(self):
+ for contrato in self.contract_id:
+ try:
+ payslip_obj = self.env['hr.payslip']
+ payslip = payslip_obj.create(
+ {
+ 'contract_id': contrato.id,
+ 'mes_do_ano': self.mes_do_ano,
+ 'ano': self.ano,
+ 'date_from': self.date_start,
+ 'date_to': self.date_end,
+ 'employee_id': contrato.employee_id.id,
+ 'tipo_de_folha': self.tipo_de_folha,
+ 'payslip_run_id': self.id,
+ }
+ )
+ payslip.set_employee_id()
+ payslip.onchange_employee_id(
+ self.date_start,
+ self.date_end,
+ contrato.id
+ )
+ worked_days_line_ids = payslip.get_worked_day_lines(
+ contrato.id, self.date_start, self.date_end
+ )
+ input_line_ids = payslip.get_inputs(
+ contrato.id, self.date_start, self.date_end
+ )
+ worked_days_obj = self.env['hr.payslip.worked_days']
+ input_obj = self.env['hr.payslip.input']
+ for worked_day in worked_days_line_ids:
+ worked_day.update({'payslip_id': payslip.id})
+ worked_days_obj.create(worked_day)
+ for input_id in input_line_ids:
+ input_id.update({'payslip_id': payslip.id})
+ input_obj.create(input_id)
+ payslip.compute_sheet()
+ except:
+ self._cr.rollback()
+ pass
+ self.verificar_holerites_gerados()
diff --git a/l10n_br_hr_payroll/models/hr_salary_rule.py b/l10n_br_hr_payroll/models/hr_salary_rule.py
index 8c31992a9..9bed00117 100644
--- a/l10n_br_hr_payroll/models/hr_salary_rule.py
+++ b/l10n_br_hr_payroll/models/hr_salary_rule.py
@@ -2,20 +2,103 @@
# Copyright (C) 2016 KMEE (http://www.kmee.com.br)
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
-from openerp import fields, models
+import logging
+
+from openerp import fields, models, exceptions, _
+from openerp.tools.safe_eval import safe_eval
+
+_logger = logging.getLogger(__name__)
+
+try:
+ from pybrasil.python_pt_BR import python_pt_BR
+ # from pybrasil.valor.decimal import Decimal
+
+except ImportError:
+ _logger.info('Cannot import pybrasil')
+
+
+CALCULO_FOLHA_PT_BR = {
+ u'resultado': 'result',
+ u'valor': 'result',
+ u'taxa': 'result_rate',
+ u'aliquota': 'result_rate',
+ u'alíquota': 'result_rate',
+ u'quantidade': 'result_qty',
+ u'quant': 'result_qty',
+ u'qtd': 'result_qty',
+ u'qtde': 'result_qty',
+}
class HrSalaryRule(models.Model):
_inherit = 'hr.salary.rule'
compoe_base_INSS = fields.Boolean(
- string=u'Compõe Base INSS'
+ string=u'Compõe Base INSS',
)
compoe_base_IR = fields.Boolean(
- string=u'Compõe Base IR'
+ string=u'Compõe Base IR',
)
compoe_base_FGTS = fields.Boolean(
- string=u'Compõe Base FGTS'
+ string=u'Compõe Base FGTS',
+ )
+
+ def compute_rule(self, cr, uid, rule_id, localdict, context=None):
+ rule = self.browse(cr, uid, rule_id, context=context)
+
+ if rule.amount_select != 'code':
+ return super(HrSalaryRule, self).compute_rule(cr, uid, rule_id,
+ localdict,
+ context=context)
+
+ codigo_python = python_pt_BR(rule.amount_python_compute or '',
+ CALCULO_FOLHA_PT_BR)
+
+ try:
+ safe_eval(codigo_python, localdict, mode='exec', nocopy=True)
+ result = localdict['result']
+
+ if 'result_qty' in localdict:
+ result_qty = localdict['result_qty']
+ else:
+ result_qty = 1
+
+ if 'result_rate' in localdict:
+ result_rate = localdict['result_rate']
+ else:
+ result_rate = 100
+
+ return result, result_qty, result_rate
+
+ except:
+ msg = _('Wrong python code defined for salary rule %s (%s).')
+ raise exceptions.ValidationError(msg % (rule.name, rule.code))
+
+ def satisfy_condition(self, cr, uid, rule_id, localdict, context=None):
+ rule = self.browse(cr, uid, rule_id, context=context)
+
+ if rule.condition_select != 'python':
+ return super(HrSalaryRule, self).satisfy_condition(
+ cr, uid, rule_id, localdict, context=context
+ )
+
+ codigo_python = python_pt_BR(rule.condition_python or '',
+ CALCULO_FOLHA_PT_BR)
+
+ try:
+ safe_eval(codigo_python, localdict, mode='exec', nocopy=True)
+ return 'result' in localdict and localdict['result'] or False
+
+ except:
+ msg = _('Wrong python condition defined for salary rule %s (%s).')
+ raise exceptions.UserError(msg % (rule.name, rule.code))
+
+ tipo_media = fields.Selection(
+ selection=[
+ ('valor', 'Valor'),
+ ('quantidade', 'Quantidade'),
+ ],
+ string='Tipo de Média da Rubrica',
)
diff --git a/l10n_br_hr_payroll/models/l10n_br_hr_contract.py b/l10n_br_hr_payroll/models/l10n_br_hr_contract.py
index 80aeddf57..f5a5327f1 100644
--- a/l10n_br_hr_payroll/models/l10n_br_hr_contract.py
+++ b/l10n_br_hr_payroll/models/l10n_br_hr_contract.py
@@ -3,12 +3,16 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import api, fields, models
+from openerp.exceptions import Warning as UserError
+
+STATES = [('draft', 'Rascunho'),
+ ('applied', 'Aplicada')]
class HrContractChangeReason(models.Model):
_name = 'l10n_br_hr.contract.change_reason'
- _description = u"Motivo de alteração contatual"
+ _description = u"Motivo de alteração contratual"
name = fields.Char(u"Motivo")
@@ -16,7 +20,7 @@ class HrContractChangeReason(models.Model):
class HrContractChange(models.Model):
_name = 'l10n_br_hr.contract.change'
- _description = u"Alteração contatual"
+ _description = u"Alteração contratual"
_inherit = 'hr.contract'
def _get_default_type(self):
@@ -24,7 +28,16 @@ def _get_default_type(self):
if change_type:
return change_type
else:
- raise UserWarning(u'Sem tipo de alteração definido!')
+ raise UserError(u'Sem tipo de alteração definido!')
+
+ @api.depends('contract_id', 'change_history_ids')
+ def _get_change_history(self):
+ change_type = self._context.get('change_type', False)
+ full_history = self.search(
+ [('contract_id', '=', self.contract_id.id),
+ ('change_type', '=', change_type),
+ ('state', '=', 'applied')])
+ self.change_history_ids = full_history
contract_id = fields.Many2one(
'hr.contract',
@@ -37,20 +50,20 @@ def _get_default_type(self):
('cargo-atividade', u'Cargo/Atividade'),
('filiacao-sindical', u'Filiação Sindical'),
('lotacao-local', u'Lotação/Local de trabalho'),
- # ('curso-treinamento', u'Curso/Treinamento'),
],
string=u"Tipo de alteração contratual",
default=_get_default_type
)
change_reason_id = fields.Many2one(
comodel_name='l10n_br_hr.contract.change_reason',
- string=u"Motivo",
+ string=u"Motivo", required=True,
)
change_date = fields.Date(u'Data da alteração')
- change_history = fields.One2many(
+ change_history_ids = fields.Many2many(
comodel_name='l10n_br_hr.contract.change',
inverse_name='contract_id',
string=u"Histórico",
+ compute=_get_change_history,
)
name = fields.Char(string='Contract Reference', required=False)
employee_id = fields.Many2one(string='Employee',
@@ -59,7 +72,129 @@ def _get_default_type(self):
type_id = fields.Many2one(string='Contract Type',
comodel_name='hr.contract.type',
required=False)
+ state = fields.Selection(string=u'Alteração aplicada', selection=STATES,
+ default='draft')
+ user_id = fields.Many2one(
+ comodel_name='res.users',
+ string='Alterado por',
+ )
@api.onchange('contract_id')
def _onchange_contract_id(self):
- pass
+ contract = self.contract_id
+ self.change_date = fields.datetime.now()
+ self.notes = contract.notes
+ if self.change_type == 'remuneracao':
+ self.wage = contract.wage
+ self.salary_unit = contract.salary_unit
+ self.struct_id = contract.struct_id
+ elif self.change_type == 'jornada':
+ self.wage = contract.wage
+ self.working_hours = contract.working_hours
+ self.schedule_pay = contract.schedule_pay
+ self.monthly_hours = contract.monthly_hours
+ self.weekly_hours = contract.weekly_hours
+ elif self.change_type == 'cargo-atividade':
+ self.wage = contract.wage
+ self.job_id = contract.job_id
+ self.type_id = contract.type_id
+ self.admission_type_id = contract.admission_type_id
+ self.labor_bond_type_id = contract.labor_bond_type_id
+ self.labor_regime_id = contract.labor_regime_id
+ elif self.change_type == 'filiacao-sindical':
+ self.wage = contract.wage
+ self.union = contract.union
+ self.union_cnpj = contract.union_cnpj
+ self.union_entity_code = contract.union_entity_code
+ self.discount_union_contribution = \
+ contract.discount_union_contribution
+ self.month_base_date = contract.month_base_date
+
+ @api.multi
+ def apply_contract_changes(self):
+ for change in self:
+ contract = change.contract_id
+ if self.change_type == 'remuneracao':
+ if not self.env['l10n_br_hr.contract.change'].search(
+ [('wage', '>', 0),
+ ('change_date', '<', change.change_date)]):
+ vals = {
+ 'contract_id': contract.id,
+ 'change_date': contract.date_start,
+ 'change_reason_id': change.change_reason_id.id,
+ 'wage': contract.wage,
+ 'struct_id': change.struct_id.id,
+ }
+ self.env['l10n_br_hr.contract.change'].create(vals)
+ contract.wage = self.wage
+ contract.salary_unit = self.salary_unit
+ contract.struct_id = self.struct_id
+ elif self.change_type == 'jornada':
+ if not self.env['l10n_br_hr.contract.change'].search(
+ [('working_hours', '!=', False),
+ ('change_date', '<', change.change_date)]):
+ vals = {
+ 'contract_id': contract.id,
+ 'change_date': contract.date_start,
+ 'change_reason_id': change.change_reason_id.id,
+ 'wage': contract.wage,
+ 'working_hours': contract.working_hours.id,
+ 'struct_id': change.struct_id.id,
+ }
+ self.env['l10n_br_hr.contract.change'].create(vals)
+ contract.working_hours = self.working_hours
+ contract.schedule_pay = self.schedule_pay
+ contract.monthly_hours = self.monthly_hours
+ contract.weekly_hours = self.weekly_hours
+ elif self.change_type == 'cargo-atividade':
+ if not self.env['l10n_br_hr.contract.change'].search(
+ [('job_id', '!=', False),
+ ('change_date', '<', change.change_date)]):
+ vals = {
+ 'contract_id': contract.id,
+ 'change_date': contract.date_start,
+ 'change_reason_id': change.change_reason_id.id,
+ 'wage': contract.wage,
+ 'job_id': contract.job_id.id,
+ 'type_id': contract.type_id.id,
+ 'adminission_type_id': contract.admission_type_id.id,
+ 'labor_bond_type_id': contract.labor_bond_type_id.id,
+ 'labor_regime_id': contract.labor_regime_id.id,
+ 'struct_id': change.struct_id.id,
+ }
+ self.env['l10n_br_hr.contract.change'].create(vals)
+ contract.job_id = self.job_id
+ contract.type_id = self.type_id
+ contract.admission_type_id = self.admission_type_id
+ contract.labor_bond_type_id = self.labor_bond_type_id
+ contract.labor_regime_id = self.labor_regime_id
+ elif self.change_type == 'filiacao-sindical':
+ if not self.env['l10n_br_hr.contract.change'].search(
+ [('union', '!=', False),
+ ('change_date', '<', change.change_date)]):
+ vals = {
+ 'contract_id': contract.id,
+ 'change_date': contract.date_start,
+ 'change_reason_id': change.change_reason_id.id,
+ 'wage': contract.wage,
+ 'union': contract.union,
+ 'union_cnpj': contract.union_cnpj,
+ 'union_entity_code': contract.union_entity_code,
+ 'discount_union_contribution':
+ contract.discount_union_contribution,
+ 'month_base_date': contract.month_base_date,
+ 'struct_id': change.struct_id.id,
+ }
+ self.env['l10n_br_hr.contract.change'].create(vals)
+ contract.union = self.union
+ contract.union_cnpj = self.union_cnpj
+ contract.union_entity_code = self.union_entity_code
+ contract.discount_union_contribution = \
+ self.discount_union_contribution
+ contract.month_base_date = self.month_base_date
+ self.state = 'applied'
+
+ @api.model
+ def create(self, vals):
+ vals.update({'user_id': self.env.user.id})
+ return super(HrContractChange, self).create(vals)
diff --git a/l10n_br_hr_payroll/models/l10n_br_hr_medias.py b/l10n_br_hr_payroll/models/l10n_br_hr_medias.py
new file mode 100644
index 000000000..6aecac966
--- /dev/null
+++ b/l10n_br_hr_payroll/models/l10n_br_hr_medias.py
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2016 KMEE (http://www.kmee.com.br)
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+from openerp import api, fields, models
+
+MES_DO_ANO = [
+ (1, u'Janeiro'),
+ (2, u'Fevereiro'),
+ (3, u'Marco'),
+ (4, u'Abril'),
+ (5, u'Maio'),
+ (6, u'Junho'),
+ (7, u'Julho'),
+ (8, u'Agosto'),
+ (9, u'Setembro'),
+ (10, u'Outubro'),
+ (11, u'Novembro'),
+ (12, u'Dezembro'),
+]
+
+
+class L10nBrHrMedias(models.Model):
+ _name = 'l10n_br.hr.medias'
+ _description = 'Brazilian HR - Medias dos Proventos'
+ # _order = 'year desc'
+
+ holerite_id = fields.Many2one(
+ string=u'Holerite',
+ comodel_name='hr.payslip',
+ )
+ rubrica_id = fields.Many2one(
+ comodel_name="hr.salary.rule",
+ string="Id da rubrica"
+ )
+ nome_rubrica = fields.Char(
+ string=u'Nome da Rubrica',
+ )
+ mes_1 = fields.Char(
+ string=u'1º Mes',
+ )
+ mes_2 = fields.Char(
+ string=u'2º Mes',
+ )
+ mes_3 = fields.Char(
+ string=u'3º Mes',
+ )
+ mes_4 = fields.Char(
+ string=u'4º Mes',
+ )
+ mes_5 = fields.Char(
+ string=u'5º Mes',
+ )
+ mes_6 = fields.Char(
+ string=u'6º Mes',
+ )
+ mes_7 = fields.Char(
+ string=u'7º Mes',
+ )
+ mes_8 = fields.Char(
+ string=u'8º Mes',
+ )
+ mes_9 = fields.Char(
+ string=u'9º Mes',
+ )
+ mes_10 = fields.Char(
+ string=u'10º Mes',
+ )
+ mes_11 = fields.Char(
+ string=u'11º Mes',
+ )
+ mes_12 = fields.Char(
+ string=u'12º Mes',
+ )
+ soma = fields.Float(
+ string=u'Total dos Meses',
+ compute='calcular_soma'
+ )
+ meses = fields.Float(
+ string=u'Meses do periodo',
+ )
+ media = fields.Float(
+ string=u'Média',
+ compute='calcular_media',
+ )
+ media_texto = fields.Char(
+ string=u'Média'
+ )
+ linha_de_titulo = fields.Boolean(
+ string=u'Linha do Titulo',
+ help='Indica se é a linha construida para compor o título',
+ default=False,
+ )
+
+ def calcular_soma(self):
+ for linha in self:
+ if not linha.linha_de_titulo:
+ linha.soma = \
+ float(linha.mes_1) + float(linha.mes_2) + \
+ float(linha.mes_3) + float(linha.mes_4) + \
+ float(linha.mes_5) + float(linha.mes_6) + \
+ float(linha.mes_7) + float(linha.mes_8) + \
+ float(linha.mes_9) + float(linha.mes_10) + \
+ float(linha.mes_11) + float(linha.mes_12)
+
+ def calcular_media(self):
+ for linha in self:
+ if not linha.linha_de_titulo:
+ if linha.meses == 0:
+ linha.media = 123
+ else:
+ linha.media = linha.soma/linha.meses
+
+ @api.multi
+ def gerar_media_dos_proventos(self, data_inicio, data_fim, holerite_id):
+ """
+ Recuperar os proventos do periodo e retornar média
+ :param data_inicio:
+ :param data_fim:
+ :param holerite_id:
+ :return:
+ """
+ for linha in holerite_id.medias_proventos:
+ linha.unlink()
+
+ folha_obj = self.env['hr.payslip']
+ domain = [
+ ('date_from', '>=', data_inicio),
+ ('date_to', '<=', data_fim),
+ ('contract_id', '=', holerite_id.contract_id.id),
+ ('state', '=', 'done'),
+ ]
+ folhas_periodo = folha_obj.search(domain)
+ folhas_periodo = folhas_periodo.sorted(key=lambda r: r.date_from)
+ medias = {}
+ for folha in folhas_periodo:
+ for linha in folha.line_ids:
+ if linha.salary_rule_id.category_id.code == "PROVENTO" \
+ and linha.salary_rule_id.tipo_media:
+ if not medias.get(linha.salary_rule_id.id):
+ medias.update({
+ linha.salary_rule_id.id:
+ [{
+ 'mes': MES_DO_ANO[folha.mes_do_ano-1][1],
+ 'valor': linha.total,
+ 'rubrica_id': linha.salary_rule_id.id,
+ }]
+ })
+ else:
+ medias[linha.salary_rule_id.id].append({
+ 'mes': MES_DO_ANO[folha.mes_do_ano-1][1],
+ 'valor': linha.total,
+ 'rubrica_id': linha.salary_rule_id.id,
+ })
+
+ linha_obj = self.env['l10n_br.hr.medias']
+ hr_medias_ids = []
+ titulo = {}
+ meses_titulos = []
+
+ # definindo titulo da visao tree
+ for rubrica in medias:
+ mes_cont = 1
+ titulo.update({'meses': len(medias[rubrica])})
+ titulo.update({'holerite_id': holerite_id.id})
+ titulo.update({'linha_de_titulo': True})
+ for mes in medias[rubrica]:
+ titulo.update({'mes_' + str(mes_cont): str(mes['mes']), })
+ if str(mes['mes']) in meses_titulos:
+ meses_titulos.remove(str(mes['mes']))
+ meses_titulos.append(str(mes['mes']))
+ mes_cont += 1
+ linha_obj.create(titulo)
+
+ # definindo a linha
+ for rubrica in medias:
+ vals = {}
+ nome_rubrica = self.env['hr.salary.rule'].\
+ browse(rubrica).display_name
+ vals.update({'nome_rubrica': nome_rubrica})
+ vals.update({'meses': len(medias[rubrica])})
+ vals.update({'holerite_id': holerite_id.id})
+ vals.update({'rubrica_id': rubrica})
+
+ for mes in medias[rubrica]:
+ mes_cont = 1
+ for mes_titulo in meses_titulos:
+ # se o mes em questão for igual mes do titulo
+ if mes_titulo == mes['mes']:
+ vals.update({
+ 'mes_' + str(mes_cont): str(mes['valor']),
+ })
+ break
+ mes_cont += 1
+ hr_medias_ids.append(linha_obj.create(vals))
+
+ return hr_medias_ids
diff --git a/l10n_br_hr_payroll/security/ir.model.access.csv b/l10n_br_hr_payroll/security/ir.model.access.csv
index 20e0f93fb..7b71254f2 100644
--- a/l10n_br_hr_payroll/security/ir.model.access.csv
+++ b/l10n_br_hr_payroll/security/ir.model.access.csv
@@ -8,3 +8,6 @@
"access_l10n_br_hr_contract_change_reason","access_l10n_br_hr_contract_change_reason","model_l10n_br_hr_contract_change_reason","",1,0,0,0
"access_l10n_br_hr_contract_change","access_l10n_br_hr_contract_change","model_l10n_br_hr_contract_change","",1,0,0,0
"access_hr_contract_salary_rule","access_hr_contract_salary_rule","model_hr_contract_salary_rule","",1,0,0,0
+"access_l10n_br_hr_medias","access_l10n_br_hr_medias","model_l10n_br_hr_medias","",1,0,0,0
+"access_hr_exame_medico","access_hr_exame_medico","model_hr_exame_medico","",1,0,0,0
+"access_hr_curso","access_hr_curso","model_hr_curso","",1,0,0,0
\ No newline at end of file
diff --git a/l10n_br_hr_payroll/views/hr_contract.xml b/l10n_br_hr_payroll/views/hr_contract.xml
index 5ec97482f..97b8da154 100644
--- a/l10n_br_hr_payroll/views/hr_contract.xml
+++ b/l10n_br_hr_payroll/views/hr_contract.xml
@@ -10,6 +10,9 @@
hr.contract
+
+
+
@@ -43,6 +46,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payroll/views/hr_payroll_structure.xml b/l10n_br_hr_payroll/views/hr_payroll_structure.xml
new file mode 100644
index 000000000..e3a02abf9
--- /dev/null
+++ b/l10n_br_hr_payroll/views/hr_payroll_structure.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+ hr.payroll.structure.form (in l10n_br_hr_payroll)
+ hr.payroll.structure
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payroll/views/hr_payslip.xml b/l10n_br_hr_payroll/views/hr_payslip.xml
index 6ed6f9f9b..bd975f81d 100644
--- a/l10n_br_hr_payroll/views/hr_payslip.xml
+++ b/l10n_br_hr_payroll/views/hr_payslip.xml
@@ -5,11 +5,41 @@
+
+
+
+ hr.payslip.tree
+ hr.payslip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Holerites do Funcionário
+ hr.payslip
+ form
+
+
+ {'default_tipo_de_folha': 'normal'}
+ [('tipo_de_folha','=','normal')]
+
+
hr.payslip.form (in l10n_br_hr_payroll)
hr.payslip
+
@@ -103,13 +133,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
@@ -124,12 +183,20 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -137,9 +204,108 @@
+
+
+
+
+
+
+
+
+
+ hr.ferias.tree
+ hr.payslip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Férias
+ hr.payslip
+ form
+
+
+ {'default_tipo_de_folha': 'ferias'}
+ [('tipo_de_folha','=','ferias')]
+
+
+
+
+
+
+ hr.decimo.terceiro.tree
+ hr.payslip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 13º Salário
+ hr.payslip
+ form
+
+ {'default_tipo_de_folha': 'decimo_terceiro'}
+ [('tipo_de_folha','=','decimo_terceiro')]
+
+
+
+
+
+
+ hr.aviso.previo.tree
+ hr.payslip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Aviso Prévio
+ hr.payslip
+ form
+
+ {'default_tipo_de_folha': 'aviso_previo', 'default_is_simulacao':True}
+ [('tipo_de_folha','=','aviso_previo'),('is_simulacao','=',True)]
+
+
+
diff --git a/l10n_br_hr_payroll/views/hr_payslip_run.xml b/l10n_br_hr_payroll/views/hr_payslip_run.xml
new file mode 100644
index 000000000..f5f6faa83
--- /dev/null
+++ b/l10n_br_hr_payroll/views/hr_payslip_run.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+ hr.payslip.run.form
+ hr.payslip.run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payroll/views/hr_salary_rule.xml b/l10n_br_hr_payroll/views/hr_salary_rule.xml
index b7f6621e5..ae261ae60 100644
--- a/l10n_br_hr_payroll/views/hr_salary_rule.xml
+++ b/l10n_br_hr_payroll/views/hr_salary_rule.xml
@@ -15,6 +15,7 @@
+
diff --git a/l10n_br_hr_payroll/views/l10n_br_hr_contract/l10n_br_hr_contract.xml b/l10n_br_hr_payroll/views/l10n_br_hr_contract.xml
similarity index 100%
rename from l10n_br_hr_payroll/views/l10n_br_hr_contract/l10n_br_hr_contract.xml
rename to l10n_br_hr_payroll/views/l10n_br_hr_contract.xml
diff --git a/l10n_br_hr_payroll/views/l10n_br_hr_contract/l10n_br_hr_contract_cargo_atividade.xml b/l10n_br_hr_payroll/views/l10n_br_hr_contract/l10n_br_hr_contract_cargo_atividade.xml
deleted file mode 100644
index d869c6136..000000000
--- a/l10n_br_hr_payroll/views/l10n_br_hr_contract/l10n_br_hr_contract_cargo_atividade.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
-
-
- l10n_br_hr.contract.change.form (cargo/atividade)
- l10n_br_hr.contract.change
-
-
-
-
-
-
- l10n_br_hr.contract.change.tree (cargo/atividade)
- l10n_br_hr.contract.change
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Cargo/Atividade
- l10n_br_hr.contract.change
- tree,form
- [('change_type','=','cargo-atividade')]
- {'search_default_current':1, 'change_type': 'cargo-atividade'}
-
-
-
-
-
-
- tree
-
-
-
-
-
- form
-
-
-
-
-
-
diff --git a/l10n_br_hr_payroll/views/l10n_br_hr_contract_cargo_atividade.xml b/l10n_br_hr_payroll/views/l10n_br_hr_contract_cargo_atividade.xml
new file mode 100644
index 000000000..49afcde2f
--- /dev/null
+++ b/l10n_br_hr_payroll/views/l10n_br_hr_contract_cargo_atividade.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+ l10n_br_hr.contract.change.form (cargo/atividade)
+ l10n_br_hr.contract.change
+
+
+
+
+
+
+ l10n_br_hr.contract.change.tree (cargo/atividade)
+ l10n_br_hr.contract.change
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cargo/Atividade
+ l10n_br_hr.contract.change
+ tree,form
+ [('change_type','=','cargo-atividade')]
+ {'search_default_current':1, 'change_type': 'cargo-atividade'}
+
+
+
+
+
+
+ tree
+
+
+
+
+
+
+ form
+
+
+
+
+
+
diff --git a/l10n_br_hr_payroll/views/l10n_br_hr_contract/l10n_br_hr_contract_filiacao_sindical.xml b/l10n_br_hr_payroll/views/l10n_br_hr_contract_filiacao_sindical.xml
similarity index 74%
rename from l10n_br_hr_payroll/views/l10n_br_hr_contract/l10n_br_hr_contract_filiacao_sindical.xml
rename to l10n_br_hr_payroll/views/l10n_br_hr_contract_filiacao_sindical.xml
index e2915fc37..aa7b9e61a 100644
--- a/l10n_br_hr_payroll/views/l10n_br_hr_contract/l10n_br_hr_contract_filiacao_sindical.xml
+++ b/l10n_br_hr_payroll/views/l10n_br_hr_contract_filiacao_sindical.xml
@@ -10,18 +10,24 @@
l10n_br_hr.contract.change