diff --git a/.travis.yml b/.travis.yml
index a1bece4b8..db829f14b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,7 +25,9 @@ install:
- pip install python-dateutil
- pip install pytz
- pip install pyparsing
- - pip install git+https://github.com/aricaldeira/pybrasil.git
+ - pip install git+https://github.com/aricaldeira/pybrasil.git@bb8d47a415a973bb2a823e1f7a480d77f3e22ef8
+ - pip install git+https://github.com/kmee/cnab240.git@feature/pagamento
+ - pip install pyboleto
- travis_install_nightly
script:
diff --git a/l10n_br_hr_allowance/models/hr_holidays.py b/l10n_br_hr_allowance/models/hr_holidays.py
new file mode 100644
index 000000000..8b7b6610a
--- /dev/null
+++ b/l10n_br_hr_allowance/models/hr_holidays.py
@@ -0,0 +1,19 @@
+from openerp import api, fields, models
+
+
+class HrHolidays(models.Model):
+ _inherit = 'hr.holidays'
+
+ ano = fields.Integer(
+ string=u'Ano referencia',
+ )
+
+ contrato_id = fields.Many2one(
+ comodel_name='hr.contract',
+ string=u'Contrato associado',
+ )
+
+ @api.onchange('contrato_id')
+ def onchange_contrato(self):
+ for holiday in self:
+ holiday.employee_id = holiday.contrato_id.employee_id
diff --git a/l10n_br_hr_allowance/views/hr_holidays.xml b/l10n_br_hr_allowance/views/hr_holidays.xml
new file mode 100644
index 000000000..35f46eff9
--- /dev/null
+++ b/l10n_br_hr_allowance/views/hr_holidays.xml
@@ -0,0 +1,15 @@
+
+
+
+ hr.holidays.form (in abono)
+ hr.holidays
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/l10n_br_hr_arquivos_governo/README.rst b/l10n_br_hr_arquivos_governo/README.rst
new file mode 100644
index 000000000..34f9a1f52
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/README.rst
@@ -0,0 +1,89 @@
+.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+===============================================================
+Modulo gerador de arquivos TXT da Folha de Pagamento Brasileira
+===============================================================
+
+This module extends the functionality of l10n_br_hr_payroll to support a geração
+de arquivos txt de dados dos recursos humanos em geral
+and to allow you to envie às autoridades regulamentadoras brasileiras.
+
+Installation
+============
+
+To install this module, you need to:
+
+#. Do this ...
+
+Configuration
+=============
+
+To configure this module, you need to:
+
+#. Go to ...
+
+.. figure:: path/to/local/image.png
+ :alt: alternative description
+ :width: 600 px
+
+Usage
+=====
+
+To use this module, you need to:
+
+#. Go to ...
+
+.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt
+.. branch is "8.0" for example
+
+Known issues / Roadmap
+======================
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues
+`_. In case of trouble, please
+check there if your issue has already been reported. If you spotted it first,
+help us smashing it by providing a detailed and welcomed feedback.
+
+Credits
+=======
+
+Images
+------
+
+* Odoo Community Association: `Icon `_.
+
+Contributors
+------------
+
+* Luis Felipe Miléo
+* Matheus Felix
+* Rafael da Silva Lima
+* Aristides Caldeira
+
+Funders
+-------
+
+The development of this module has been financially supported by:
+
+* Company 1 name
+* Company 2 name
+
+Maintainer
+----------
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+This module is maintained by the OCA.
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+To contribute to this module, please visit https://odoo-community.org.
diff --git a/l10n_br_hr_arquivos_governo/__init__.py b/l10n_br_hr_arquivos_governo/__init__.py
new file mode 100644
index 000000000..0650744f6
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/l10n_br_hr_arquivos_governo/__openerp__.py b/l10n_br_hr_arquivos_governo/__openerp__.py
new file mode 100644
index 000000000..167aa81cc
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/__openerp__.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ 'name': 'l10n br hr Arquivos Governo',
+ 'version': '8.0.0.0.1',
+ 'license': 'AGPL-3',
+ 'author': 'KMEE, Odoo Community Association (OCA)',
+ 'maintainer': 'KMEE',
+ 'website': 'http://www.kmee.com.br',
+ 'depends': [
+ 'document',
+ 'l10n_br_hr_payroll',
+ 'l10n_br_account',
+ 'l10n_br_financial_payment_order',
+ ],
+ 'external_dependencies': {
+ 'python': ['pybrasil'],
+ },
+ 'data': [
+ 'data/l10n_br_hr_contract_type.xml',
+ 'security/hr_payslip.xml',
+ 'security/ir.model.access.csv',
+ 'views/hr_payslip.xml',
+ 'views/hr_contract_type.xml',
+ 'views/l10n_br_hr_caged.xml',
+ 'views/l10n_br_hr_contract.xml',
+ 'views/l10n_br_hr_employee.xml',
+ 'views/l10n_br_hr_sefip.xml',
+ 'views/res_company.xml',
+ 'views/inherited_hr_salary_rule_view.xml'
+ ],
+}
diff --git a/l10n_br_hr_arquivos_governo/constantes_rh.py b/l10n_br_hr_arquivos_governo/constantes_rh.py
new file mode 100644
index 000000000..4f2c6f8ba
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/constantes_rh.py
@@ -0,0 +1,202 @@
+# -*- encoding: utf-8 -*-
+
+CATEGORIA_TRABALHADOR = (
+ ('101', u'101 - Empregado – Geral'),
+ ('102', u'102 - Empregado – Trabalhador Rural por Pequeno Prazo da Lei '
+ u'11.718/2008'),
+ ('103', u'103 - Empregado – Aprendiz'),
+ ('104', u'104 - Empregado – Doméstico'),
+ ('105', u'105 - Empregado – contrato a termo firmado nos termos da'
+ u' Lei 9601/98'),
+ ('106', u'106 - Empregado – contrato por prazo determinado nos termos da '
+ u'Lei 6019/74'),
+ ('107', u'107 - Trabalhador não vinculado ao RGPS com direito ao FGTS'),
+ ('201', u'201 - Trabalhador Avulso – Portuário'),
+ ('202', u'202 - Trabalhador Avulso – Não Portuário '
+ u'(Informação do Sindicato)'),
+ ('203', u'203 - Trabalhador Avulso – Não Portuário '
+ u'(Informação do Contratante)'),
+ ('301', u'301 - Servidor Público – Titular de Cargo Efetivo'),
+ ('302', u'302 - Servidor Público – '
+ u'Ocupante de Cargo exclusivo em comissão'),
+ ('303', u'303 - Servidor Público – Exercente de Mandato Eletivo'),
+ ('304', u'304 - Servidor Público – Agente Público'),
+ ('305', u'305 - Servidor Público vinculado a RPPS indicado para conselho '
+ u'ou órgão representativo, na condição de representante do govern'
+ u'o, órgão ou entidade da administração pública'),
+ ('401', u'401 - Dirigente Sindical – Em relação a Remuneração Recebida no'
+ u' Sindicato'),
+ ('701', u'701 - Contrib. Individual – Autônomo contratado por Empresas em'
+ u' geral'),
+ ('702', u'702 - Contrib. Individual – Autônomo contratado por Contrib. '
+ u'Individual, por pessoa física em geral, ou por missão '
+ u'diplomática e repartição consular de carreira estrangeiras'),
+ ('703', u'703 - Contrib. Individual – Autônomo contratado por Entidade '
+ u'Beneficente de Assistência Social isenta da cota patronal'),
+ ('704', u'704 - Excluído.'),
+ ('711', u'711 - Contrib. Individual – Transportador autônomo contratado'
+ u' por Empresas em geral'),
+ ('712', u'712 - Contrib. Individual – Transportador autônomo contratado'
+ u' por Contrib. Individual, por pessoa física em geral, ou por mis'
+ u'são diplomática e repartição consular de carreira estrangeiras'),
+ ('713', u'713 - Contrib. Individual – Transportador autônomo contratado'
+ u' por Entidade Beneficente de Assistência Social isenta da cota '
+ u'patronal'),
+ ('721', u'721 - Contrib. Individual – Diretor não empregado com FGTS'),
+ ('722', u'722 - Contrib. Individual – Diretor não empregado sem FGTS'),
+ ('731', u'731 - Contrib. Individual – Cooperado que presta serviços a '
+ u'empresa por intermédio de cooperativa de trabalho'),
+ ('732', u'732 - Contrib. Individual – Cooperado que presta serviços a '
+ u'Entidade Beneficente de Assistência Social isenta da cota '
+ u'patronal ou para pessoa física'),
+ ('733', u'733 - Contrib. Individual – Cooperado eleito para direção da '
+ u'Cooperativa'),
+ ('734', u'734 - Contrib. Individual – Transportador Cooperado que presta'
+ u' serviços a empresa por intermédio de cooperativa de trabalho'),
+ ('735', u'735 - Contrib. Individual – Transportador Cooperado que presta'
+ u' serviços a Entidade Beneficente de Assistência Social isenta '
+ u'da cota patronal ou para pessoa física'),
+ ('736', u'736 - Contrib. Individual – Transportador Cooperado eleito '
+ u'para direção da Cooperativa'),
+ ('741', u'741 - Contrib. Individual – Cooperado filiado a cooperativa '
+ u'de produção'),
+ ('751', u'751 - Contrib. Individual – Micro Empreendedor Individual, '
+ u'quando contratado por PJ'),
+ ('901', u'901 - Estagiário'),
+)
+CATEGORIA_TRABALHADOR_DIC = dict(CATEGORIA_TRABALHADOR)
+
+SEFIP_CATEGORIA_TRABALHADOR = {
+ '701': '13',
+ '702': '13',
+ '703': '13',
+ '721': '11',
+ '722': '11',
+ '103': '07'
+}
+
+MESES = [
+ ('01', u'Janeiro'),
+ ('02', u'Fevereiro'),
+ ('03', u'Março'),
+ ('04', u'Abril'),
+ ('05', u'Maio'),
+ ('06', u'Junho'),
+ ('07', u'Julho'),
+ ('08', u'Agosto'),
+ ('09', u'Setembro'),
+ ('10', u'Outubro'),
+ ('11', u'Novembro'),
+ ('12', u'Dezembro'),
+ ('13', u'13º Salário'),
+]
+
+MODALIDADE_ARQUIVO = [
+ (' ', u'Recolhimento ao FGTS e Declaração à Previdência'),
+ ('1', u'Declaração ao FGTS e à Previdência'),
+ ('9', u'Confirmação Informações anteriores – Rec/Decl ao FGTS e'
+ u' Decl à Previdência'),
+]
+
+CODIGO_RECOLHIMENTO = [
+ ('115', u'115 - Recolhimento ao FGTS e informações à Previdência Social'),
+ ('130', u'130 - Recolhimento ao FGTS e informações à Previdência Social '
+ u'relativas ao trabalhador avulso portuário'),
+ ('135', u'135 - Recolhimento e/ou declaração ao FGTS e informações à '
+ u'Previdência Social relativas ao trabalhador avulso não '
+ u'portuário'),
+ ('145', u'145 - Recolhimento ao FGTS de diferenças apuradas pela CAIXA'),
+ ('150', u'150 - Recolhimento ao FGTS e informações à Previdência Social '
+ u'de empresa prestadora de serviços com cessão de mâo-de-obra e '
+ u'empresa de trabalho temporário Lei nº 6.019/74, em relação aos '
+ u'empregados cedidos, ou de obra de construção civil '
+ u'- empreitada parcial'),
+ ('155', u'155 - Recolhimento ao FGTS e informações à Previdência Social '
+ u'de obra de construção civil - empreitada total ou obra própria'),
+ ('211', u'211 - Declaração para a Previdência Social de Cooperativa de '
+ u'Trabalho relativa aos contribuintes individuais cooperados que '
+ u'prestam serviçõs a tomadores'),
+ ('307', u'307 - Recolhimento de Parcelamento de débito com o FGTS'),
+ ('317', u'317 - Recolhimento de Parcelamento de débito com o FGTS de '
+ u'empresa com tomador de serviços'),
+ ('327', u'327 - Recolhimento de Parcelamento de débito com o FGTS '
+ u'priorizando os valores devidos aos trabalhores'),
+ ('337', u'337 - Recolhimento de Parcelamento de débito com o FGTS de '
+ u'empresas com tomador de serviços, priorizando os valores devidos'
+ u' aos trabalhadores'),
+ ('345', u'345 - Recolhimento de parcelamento de débito com o FGTS relativo'
+ u' a diferença de recolhimento, priorizando os valores devidos '
+ u'aos trabalhadores'),
+ ('418', u'418 - Recolhimento recursal para o FGTS'),
+ ('604', u'604 - Recolhimento ao FGTS de entidades com fins filantrópicos '
+ u'- Decreto-Lei nº194, de 24/02/1967 (competências anteriores '
+ u'a 10/1989'),
+ ('608', u'608 - Recolhimento ao FGTS e informações à Previdência Social '
+ u'relativo a dirigente sindical'),
+ ('640', u'640 - Recolhimento ao FGTS para empregado não optante '
+ u'(competência anterior a 10/1988)'),
+ ('650', u'650 - Recolhimento ao FGTS e Informações à Previdência Social'
+ u' relativo a Anistiados, Reclamatória Trabalhista, Reclamatória '
+ u'Trabalhista com reconhecimento de vínculo, Acordo ou Dissídio '
+ u'ou Convenção Coletiva, Comissão Conciliação Prévia ou Núcleo'
+ u' Intersindical Conciliação Trabalhista'),
+ ('660', u'660 - Recolhimento exclusivo ao FGTS relativo a Anistiados,'
+ u' Conversão Licença Saúde em Acidente Trabalho, Reclamatória '
+ u'Trabalhista, Acordo ou Dissídio ou Convenção Coletiva, '
+ u'Comissão Conciliação Prévia ou Núcleo Intersindical '
+ u'Conciliação Trabalhista'),
+]
+RECOLHIMENTO_FGTS = [
+ ('1', u'1-GRF no prazo'),
+ ('2', u'2-GRF em atraso'),
+ ('3', u'3-GRF em atraso - Ação Fiscal'),
+ ('5', u'5-Individualização'),
+ ('6', u'6-Individualização - Ação Fiscal'),
+ (' ', u'Em branco'),
+]
+RECOLHIMENTO_GPS = [
+ ('1', u'1-GPF no prazo'),
+ ('2', u'2-GPF em atraso'),
+ ('3', u'3-Não gera GPS'),
+]
+CENTRALIZADORA = [
+ ('0', u'0 - Não centraliza'),
+ ('1', u'1 - Centralizadora'),
+ ('2', u'2 - Centralizada'),
+]
+
+
+OCORRENCIA_SEFIP = [
+ ('01', u'01 - Não exposição a agente nocivo'),
+ ('02', u'Exposição a agente nocivo (aposentadoria especial aos '
+ u'15 anos de trabalho)'),
+ ('03', u'Exposição a agente nocivo (aposentadoria especial aos '
+ u'20 anos de trabalho)'),
+ ('04', u'Exposição a agente nocivo (aposentadoria especial aos '
+ u'25 anos de trabalho)'),
+ ('05', u'Mais de um vínculo empregatício (ou fonte pagadora) - '
+ u'Não exposição a agente nocivo'),
+ ('06', u'Mais de um vínculo empregatício (ou fonte pagadora) - '
+ u'Exposição a agente nocivo (aposentadoria especial aos '
+ u'15 anos de trabalho)'),
+ ('07', u'Mais de um vínculo empregatício (ou fonte pagadora) - '
+ u'Exposição a agente nocivo (aposentadoria especial aos '
+ u'20 anos de trabalho)'),
+ ('08', u'Mais de um vínculo empregatício (ou fonte pagadora) - '
+ u'Exposição a agente nocivo (aposentadoria especial aos '
+ u'25 anos de trabalho)'),
+]
+
+
+CATEGORIA_TRABALHADOR_SEFIP = [
+ ('01', u'01 - Empregado'),
+ ('05', u'05 - Contribuinte individual - Diretor não empregado com FGTS – '
+ u'Lei nº 8.036/90, art. 16'),
+ ('07', u'07 - Menor aprendiz - Lei n°10.097/2000.'),
+ ('11', u'11 - Contribuinte Individual - Diretor não empregado e demais '
+ u'empresários sem FGTS.'),
+ ('13', u'13 - Contribuinte individual – Trabalhador autônomo ou a este '
+ u'equiparado, inclusive o operador de máquina, com contribuição '
+ u'sobre remuneração; trabalhador associado à cooperativa de '
+ u'produção.'),
+]
diff --git a/l10n_br_hr_arquivos_governo/data/l10n_br_hr_contract_type.xml b/l10n_br_hr_arquivos_governo/data/l10n_br_hr_contract_type.xml
new file mode 100644
index 000000000..306b029a1
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/data/l10n_br_hr_contract_type.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ Prazo Indeterminado
+ 1
+
+
+
+ Prazo Determinado
+ 2
+
+
+
+
diff --git a/l10n_br_hr_arquivos_governo/models/__init__.py b/l10n_br_hr_arquivos_governo/models/__init__.py
new file mode 100644
index 000000000..6cce1a483
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/__init__.py
@@ -0,0 +1,14 @@
+from . import abstract_workflow
+from . import abstract_arquivos_governo
+from . import arquivo_caged
+from . import arquivo_grrf
+from . import arquivo_seguro_desemprego
+from . import hr_contract_type
+from . import hr_payslip
+from . import financial_move
+from . import l10n_br_hr_caged
+from . import l10n_br_hr_contract
+from . import l10n_br_hr_payslip
+from . import res_company
+from . import l10n_br_hr_sefip
+from . import inherited_hr_salary_rule
diff --git a/l10n_br_hr_arquivos_governo/models/abstract_arquivos_governo.py b/l10n_br_hr_arquivos_governo/models/abstract_arquivos_governo.py
new file mode 100644
index 000000000..654c19811
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/abstract_arquivos_governo.py
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+# (c) 2017 KMEE- Hendrix Costa
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+import logging
+import re
+
+_logger = logging.getLogger(__name__)
+
+try:
+ from pybrasil.base import tira_acentos
+ from pybrasil import data
+except ImportError:
+ _logger.info('Cannot import pybrasil')
+
+
+class AbstractArquivosGoverno(object):
+
+ def _gerar_arquivo_temp(self, text, tipo):
+ """
+ Dado um texto, criar um arquivo temporario, escrever nesse arquivo
+ fechar o arquivo e retornar o path do arquivo criado
+ :param text:
+ :param tipo:
+ :return:
+ """
+ arq = open('/tmp/' + tipo, 'w')
+ arq.write(text.encode('utf-8'))
+ arq.close()
+ return '/tmp/' + tipo
+
+ def _validar(self, word, tam, tipo='AN'):
+ """
+ Função Genérica utilizada para validação de campos que são gerados
+ nos arquivos TXT's
+ :param tipo: str - Tipo de palavras validadas:
+ - A -> Alfabéticas -> Apenas letras do alfabeto
+ - D -> Data -> Apenas numeral
+ - V -> Valor -> Valores decimais, retirando a virgula
+ - N -> Numerico -> Apenas numeros preechidos com zero a esq.
+ - AN -> Alfanumericos -> Aceita nuemros e caracateres sem acentos
+ :param word: str - palavra a ser validada
+ :param tam: int - Tamanho que a palavra deve ser
+ :return: str - Palavra formatada de acordo com tipo e tamanho
+ """
+ if not word:
+ word = u''
+
+ if tipo == 'A': # Alfabetico
+ word = tira_acentos(word)
+ # tirar tudo que nao for letra do alfabeto
+ word = re.sub('[^a-zA-Z]', ' ', word)
+ # Retirar 2 espaços seguidos
+ word = re.sub('[ ]+', ' ', word)
+ return unicode.ljust(unicode(word), tam)[:tam]
+
+ elif tipo == 'D': # Data
+ # Retira tudo que nao for numeral
+ word = data.formata_data(word)
+ word = re.sub(u'[^0-9]', '', str(word))
+ return unicode.ljust(unicode(word), tam)[:tam]
+
+ elif tipo == 'V': # Valor
+ # Pega a parte decimal como inteiro e nas duas ultimas casas
+ word = int(word * 100) if word else 0
+ # Preenche com zeros a esquerda
+ word = str(word).zfill(tam)
+ return word[:tam]
+
+ elif tipo == 'N': # Numerico
+ # Preenche com zeros a esquerda
+ word = re.sub('[^0-9]', '', str(word))
+ word = str(word).zfill(tam)
+ return word[:tam]
+
+ elif tipo == 'AN': # Alfanumerico
+ # Tira acentos da palavras
+ word = tira_acentos(word)
+ # Preenche com espaço vazio a esquerda
+ return unicode.ljust(unicode(word), tam)[:tam]
diff --git a/l10n_br_hr_arquivos_governo/models/abstract_workflow.py b/l10n_br_hr_arquivos_governo/models/abstract_workflow.py
new file mode 100644
index 000000000..0e34023f5
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/abstract_workflow.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# (c) 2017 KMEE INFORMATICA LTDA - Daniel Sadamo
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+from __future__ import (
+ division, print_function, unicode_literals, absolute_import
+)
+
+from openerp import api, fields, models, _
+from openerp.exceptions import Warning as UserError
+
+STATE = [
+ ('draft', u'Rascunho'),
+ ('open', u'Confirmada'),
+ ('sent', u'Enviado'),
+]
+
+
+class AbstractArquivosGovernoWorkflow(models.AbstractModel):
+ _name = b'abstract.arquivos.governo.workflow'
+
+ state = fields.Selection(
+ selection=STATE, index=True,
+ readonly=True, default='draft',
+ track_visibility='onchange', copy=False
+ )
+
+ @api.model
+ def _avaliable_transition(self, old_state, new_state):
+ allowed = [
+ ('draft', 'open'),
+ ('open', 'draft'),
+ ('open', 'sent'),
+ ]
+ return (old_state, new_state) in allowed
+
+ @api.multi
+ def change_state(self, new_state):
+ for record in self:
+ if record._avaliable_transition(record.state, new_state):
+ record.state = new_state
+ else:
+ raise UserError(_("This state transition is not allowed"))
+
+ @api.multi
+ def action_draft(self):
+ for record in self:
+ record.change_state('draft')
+
+ @api.multi
+ def action_open(self):
+ for record in self:
+ record.change_state('open')
+
+ @api.multi
+ def action_sent(self):
+ for record in self:
+ record.change_state('sent')
+
+ @api.multi
+ def unlink(self):
+ for record in self:
+ if record.state not in ['draft']:
+ raise UserError(
+ _('You cannot delete a record which is not '
+ 'draft or cancelled state!')
+ )
+ return super(AbstractArquivosGovernoWorkflow, self).unlink()
diff --git a/l10n_br_hr_arquivos_governo/models/arquivo_caged.py b/l10n_br_hr_arquivos_governo/models/arquivo_caged.py
new file mode 100644
index 000000000..7ac90d2f7
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/arquivo_caged.py
@@ -0,0 +1,262 @@
+# -*- coding: utf-8 -*-
+# (c) 2017 KMEE- Hendrix Costa
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+from datetime import datetime
+
+from .abstract_arquivos_governo import AbstractArquivosGoverno
+
+
+class Caged(AbstractArquivosGoverno):
+ # Registro do estabelecimento responsável pela informação no
+ # meio magnético (autorizado).
+
+ def _registro_A(self):
+ registro_A = self.A_tipo_de_registro
+ registro_A += self.A_tipo_layout
+ registro_A += str.ljust('', 3)
+ registro_A += self._validar(self.A_competencia, 6, 'N')
+ registro_A += self._validar(self.A_alteracao, 1, 'N')
+ registro_A += self._validar(self.A_sequencia, 5, 'N')
+ registro_A += self._validar(self.A_tipo_identificador, 1, 'N')
+ registro_A += self._validar(self.A_identificador_autorizado, 14, 'N')
+ registro_A += self._validar(self.A_razao_social, 35, 'AN')
+ registro_A += self._validar(self.A_endereco, 40, 'AN')
+ registro_A += self._validar(self.A_cep, 8, 'N')
+ registro_A += self._validar(self.A_uf, 2, 'A')
+ registro_A += self._validar(self.A_ddd, 4, 'N')
+ registro_A += self._validar(self.A_telefone, 8, 'N')
+ registro_A += self._validar(self.A_ramal, 5, 'N')
+ registro_A += \
+ self._validar(self.A_total_estabelecimento_informados, 5, 'N')
+ registro_A += \
+ self._validar(self.A_total_movimentacoes_informados, 5, 'N')
+ registro_A += str.ljust('', 92)
+ registro_A += '\n'
+ return registro_A
+
+ # Informações da Empresa
+ def _registro_B(self):
+ registro_B = self.B_tipo_de_registro
+ registro_B += self._validar(self.B_tipo_identificador, 1, 'N')
+ registro_B += \
+ self._validar(self.B_identificador_estabelecimento, 14, 'N')
+ registro_B += self._validar(self.B_sequencia, 5, 'N')
+ registro_B += self._validar(self.B_primeira_declaracao, 1, 'N')
+ registro_B += self._validar(self.B_alteracao, 1, 'N')
+ registro_B += self._validar(self.B_cep, 8, 'N')
+ registro_B += str.ljust('', 5)
+ registro_B += self._validar(self.B_razao_social, 40, 'A')
+ registro_B += self._validar(self.B_endereco, 40, 'AN')
+ registro_B += self._validar(self.B_bairro, 20, 'A')
+ registro_B += self._validar(self.B_uf, 2, 'A')
+ registro_B += self._validar(self.B_total_empregados_existentes, 5, 'N')
+ registro_B += self._validar(self.B_porte_estabelecimento, 1, 'N')
+ registro_B += self._validar(self.B_CNAE, 7, 'N')
+ registro_B += self._validar(self.B_ddd, 4, 'N')
+ registro_B += self._validar(self.B_telefone, 8, 'N')
+ registro_B += self._validar(self.B_email, 50, 'AN')
+ registro_B += str.ljust('', 27)
+ registro_B += '\n'
+ return registro_B
+
+ # Informações do trabalhador
+ def _registro_C(self):
+ registro_C = self.C_tipo_de_registro
+ registro_C += self._validar(self.C_tipo_identificador, 1, 'N')
+ registro_C += \
+ self._validar(self.C_identificador_estabelecimento, 14, 'N')
+ registro_C += self._validar(self.C_sequencia, 5, 'N')
+ registro_C += self._validar(self.C_PIS_PASEP, 11, 'N')
+ registro_C += self._validar(self.C_sexo, 1, 'N')
+ registro_C += self._validar(self.C_nascimento, 8, 'D')
+ registro_C += self._validar(self.C_grau_instrucao, 2, 'N')
+ registro_C += str.ljust('', 4)
+ registro_C += self._validar(self.C_salario_mensal, 8, 'V')
+ registro_C += self._validar(self.C_horas_trabalhadas, 2, 'N')
+ registro_C += self._validar(self.C_admissao, 8, 'D')
+ registro_C += self._validar(self.C_tipo_de_movimento, 2, 'N')
+ registro_C += self._validar(self.C_dia_desligamento, 2, 'N')
+ registro_C += self._validar(self.C_nome_empregado, 40, 'A')
+ registro_C += self._validar(self.C_numero_ctps, 8, 'N')
+ registro_C += self._validar(self.C_serie_ctps, 4, 'N')
+ registro_C += str.ljust('', 7)
+ registro_C += self._validar(self.C_raca_cor, 1, 'N')
+ registro_C += self._validar(self.C_pessoas_com_deficiencia, 1, 'N')
+ registro_C += self._validar(self.C_cbo2000, 6, 'N')
+ registro_C += self._validar(self.C_aprendiz, 1, 'N')
+ registro_C += self._validar(self.C_uf_ctps, 2, 'A')
+ registro_C += self._validar(self.C_tipo_deficiencia, 1, 'AN')
+ registro_C += self._validar(self.C_CPF, 11, 'N')
+ registro_C += self._validar(self.C_cep_residencia, 8, 'N')
+ registro_C += str.ljust('', 81)
+ registro_C += '\n'
+ return registro_C
+
+ def _registro_X(self):
+ registro_X = self.X_tipo_de_registro
+ registro_X += self._validar(self.X_tipo_identificador, 1, 'N')
+ registro_X += self.\
+ _validar(self.X_identificador_estabelecimento, 14, 'N')
+ registro_X += self._validar(self.X_sequencia, 5, 'N')
+ registro_X += self._validar(self.X_PIS_PASEP, 11, 'N')
+ registro_X += self._validar(self.X_sexo, 1, 'N')
+ registro_X += self._validar(self.X_nascimento, 8, 'N')
+ registro_X += self._validar(self.X_grau_instrucao, 2, 'N')
+ registro_X += str.ljust('', 4)
+ registro_X += self._validar(self.X_salario_mensal, 8, 'V')
+ registro_X += self._validar(self.X_horas_trabalhadas, 2, 'N')
+ registro_X += self._validar(self.X_admissao, 8, 'D')
+ registro_X += self._validar(self.X_tipo_de_movimento, 2, 'N')
+ registro_X += self._validar(self.X_dia_desligamento, 2, 'N')
+ registro_X += self._validar(self.X_nome_empregado, 40, 'A')
+ registro_X += self._validar(self.X_numero_ctps, 8, 'N')
+ registro_X += self._validar(self.X_serie_ctps, 4, 'N')
+ registro_X += self._validar(self.X_uf_ctps, 2, 'A')
+ registro_X += self._validar(self.X_atualizacao, 1, 'N')
+ registro_X += self._validar(self.X_competencia, 6, 'N')
+ registro_X += self._validar(self.X_raca_cor, 1, 'N')
+ registro_X += self._validar(self.X_pessoas_com_deficiencia, 1, 'N')
+ registro_X += self._validar(self.X_cbo2000, 6, 'N')
+ registro_X += self._validar(self.X_aprendiz, 1, 'N')
+ registro_X += self._validar(self.X_tipo_deficiencia, 1, 'A')
+ registro_X += self._validar(self.X_CPF, 11, 'N')
+ registro_X += self._validar(self.X_cep_residencia, 8, 'AN')
+ registro_X += str.ljust('', 81)
+ registro_X += '\n'
+ return registro_X
+
+ def _registro_Z(self):
+ registro_Z = self.Z_tipo_de_registro
+ registro_Z += self._validar(self.Z_responsavel, 40, 'AN')
+ registro_Z += self._validar(self.Z_email_responsavel, 50, 'AN')
+ registro_Z += ''.rjust(7, '0')
+ registro_Z += self._validar(self.Z_cpf_responsavel, 11, 'N')
+ registro_Z += str.ljust('', 122)
+ registro_Z += ''.rjust(9, '0')
+ registro_Z += '\n'
+ return registro_Z
+
+ def _gerar_grrf(self):
+ return \
+ self._registro_A() + \
+ self._registro_B() + \
+ self._registro_C() + \
+ self._registro_X() + \
+ self._registro_Z()
+
+ def __init__(self, *args, **kwargs):
+
+ # campos do Registro A (AUTORIZADO) -----------------------------------
+ # Registro do estabelecimento responsável pela informação (Autorizado)
+ self.A_tipo_de_registro = 'A'
+ self.A_tipo_layout = 'L2009'
+ self.A_competencia = ''
+ self.A_alteracao = ''
+ self.A_sequencia = ''
+ self.A_tipo_identificador = ''
+ self.A_identificador_autorizado = ''
+ self.A_razao_social = ''
+ self.A_endereco = ''
+ self.A_cep = ''
+ self.A_uf = ''
+ self.A_ddd = ''
+ self.A_telefone = ''
+ self.A_ramal = ''
+ self.A_total_estabelecimento_informados = ''
+ self.A_total_movimentacoes_informados = ''
+ # ---------------------------------------------------------------------
+
+ # campos do REGISTRO B (ESTABELECIMENTO) ------------------------------
+ # dados cadastrais do estabelecimento que teve movimentação
+ self.B_tipo_de_registro = 'B'
+ self.B_tipo_identificador = ''
+ self.B_identificador_estabelecimento = ''
+ self.B_sequencia = ''
+ self.B_primeira_declaracao = ''
+ self.B_alteracao = ''
+ self.B_cep = ''
+ self.B_razao_social = ''
+ self.B_endereco = ''
+ self.B_bairro = ''
+ self.B_uf = ''
+ self.B_total_empregados_existentes = ''
+ self.B_porte_estabelecimento = ''
+ self.B_CNAE = ''
+ self.B_ddd = ''
+ self.B_telefone = ''
+ self.B_email = ''
+ # ---------------------------------------------------------------------
+
+ # campos do REGISTRO C (MOVIMENTAÇÃO) ---------------------------------
+ self.C_tipo_de_registro = 'C'
+ self.C_tipo_identificador = ''
+ self.C_identificador_estabelecimento = ''
+ self.C_sequencia = ''
+ self.C_PIS_PASEP = ''
+ self.C_sexo = ''
+ self.C_nascimento = ''
+ self.C_grau_instrucao = ''
+ self.C_salario_mensal = ''
+ self.C_horas_trabalhadas = ''
+ self.C_admissao = ''
+ self.C_tipo_de_movimento = ''
+ self.C_dia_desligamento = ''
+ self.C_nome_empregado = ''
+ self.C_numero_ctps = ''
+ self.C_serie_ctps = ''
+ self.C_uf_ctps = ''
+ self.C_raca_cor = ''
+ self.C_pessoas_com_deficiencia = ''
+ self.C_cbo2000 = ''
+ self.C_aprendiz = ''
+ self.C_tipo_deficiencia = ''
+ self.C_CPF = ''
+ self.C_cep_residencia = ''
+ # ---------------------------------------------------------------------
+
+ # campos do REGISTRO X (ACERTO) ---------------------------------------
+ self.X_tipo_de_registro = 'X'
+ self.X_tipo_identificador = ''
+ self.X_identificador_estabelecimento = ''
+ self.X_sequencia = ''
+ self.X_PIS_PASEP = ''
+ self.X_sexo = ''
+ self.X_nascimento = ''
+ self.X_grau_instrucao = ''
+ self.X_salario_mensal = ''
+ self.X_horas_trabalhadas = ''
+ self.X_admissao = ''
+ self.X_tipo_de_movimento = ''
+ self.X_dia_desligamento = ''
+ self.X_nome_empregado = ''
+ self.X_numero_ctps = ''
+ self.X_serie_ctps = ''
+ self.X_uf_ctps = ''
+ self.X_atualizacao = ''
+ self.X_competencia = ''
+ self.X_raca_cor = ''
+ self.X_pessoas_com_deficiencia = ''
+ self.X_cbo2000 = ''
+ self.X_aprendiz = ''
+ self.X_tipo_deficiencia = ''
+ self.X_CPF = ''
+ self.X_cep_residencia = ''
+ # ---------------------------------------------------------------------
+
+ # campos do REGISTRO Z (Responsavel preenchimento) --------------------
+ self.Z_tipo_de_registro = 'Z'
+ self.Z_responsavel = ''
+ self.Z_email_responsavel = ''
+ self.Z_cpf_responsavel = ''
+
+ def _validar(self, word, tam, tipo='AN'):
+ """
+ Sobrescrever a função de validacao de palavras da classe abstrata para
+ obter todas as palavras do caged em maiusculas.
+ """
+ if tipo in ['AN', 'A'] and word:
+ word = word.upper()
+ if tipo in ['D'] and not word:
+ word = datetime.now().strftime("%Y-%m-%d")
+ return super(Caged, self)._validar(word, tam, tipo)
diff --git a/l10n_br_hr_arquivos_governo/models/arquivo_grrf.py b/l10n_br_hr_arquivos_governo/models/arquivo_grrf.py
new file mode 100644
index 000000000..54ba0f909
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/arquivo_grrf.py
@@ -0,0 +1,209 @@
+# -*- coding: utf-8 -*-
+# (c) 2017 KMEE- Hendrix Costa
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+from .abstract_arquivos_governo import AbstractArquivosGoverno
+
+
+class Grrf(AbstractArquivosGoverno):
+
+ # Informações do Responsavel
+ def _registro_00(self):
+ registro_00 = self.tipo_de_registro_00
+ registro_00 += str.ljust('', 51)
+ registro_00 += self._validar(self.tipo_de_remessa, 1, 'N')
+ registro_00 += \
+ self._validar(self.tipo_inscricao_responsavel, 1, 'N') \
+ if self.tipo_inscricao_responsavel \
+ else self._validar(self.self.tipo_de_inscricao_empresa, 1, 'N')
+ registro_00 += self._validar(self.inscricao_do_responsavel, 14, 'N') \
+ if self.inscricao_do_responsavel \
+ else self._validar(self.inscricao_da_empresa, 14, 'N')
+ registro_00 += self._validar(self.razao_social_responsavel, 30, 'AN') \
+ if self.razao_social_responsavel \
+ else self._validar(self.razao_social_empresa, 30, 'AN')
+ registro_00 += self._validar(self.nome_do_contato_responsavel, 20, 'A')
+ registro_00 += self._validar(self.endereco_responsavel, 50) \
+ if self.endereco_responsavel \
+ else self._validar(self.endereco_empresa, 50)
+ registro_00 += self._validar(self.bairro_responsavel, 20) \
+ if self.bairro_responsavel \
+ else self._validar(self.bairro_empresa, 20)
+ registro_00 += self._validar(self.cep_responsavel, 8, 'N') \
+ if self.cep_responsavel \
+ else self._validar(self.cep_empresa, 8, 'N')
+ registro_00 += self._validar(self.cidade_responsavel, 20, 'AN') \
+ if self.cidade_responsavel \
+ else self._validar(self.cidade_empresa, 20, 'AN')
+ registro_00 += \
+ self._validar(self.unidade_federacao_responsavel, 2, 'A') \
+ if self.unidade_federacao_responsavel \
+ else self._validar(self.unidade_federacao_empresa, 2, 'A')
+ registro_00 += \
+ self._validar(self.telefone_contato_responsavel, 12, 'N')
+ registro_00 += self._validar(self.endereco_internet_responsavel, 60)
+ registro_00 += self._validar(self.data_recolhimento_grrf, 8, 'D')
+ registro_00 += str.ljust('', 60)
+ registro_00 += self.final_de_linha
+ return registro_00
+
+ # Informações da Empresa
+ def _registro_10(self):
+ registro_10 = self.tipo_de_registro_10
+ registro_10 += self._validar(self.tipo_de_inscricao_empresa, 1, 'N')
+ registro_10 += self._validar(self.inscricao_da_empresa, 14, 'N')
+ registro_10 += ''.rjust(36, '0')
+ registro_10 += self._validar(self.razao_social_empresa, 40, 'AN')
+ registro_10 += self._validar(self.endereco_empresa, 50, 'AN')
+ registro_10 += self._validar(self.bairro_empresa, 20, 'AN')
+ registro_10 += self._validar(self.cep_empresa, 8, 'N')
+ registro_10 += self._validar(self.cidade_empresa, 20, 'AN')
+ registro_10 += self._validar(self.unidade_federacao_empresa, 2, 'A')
+ registro_10 += self._validar(self.telefone_empresa, 12, 'N')
+ registro_10 += self._validar(self.CNAE_fiscal, 7, 'N')
+ registro_10 += self._validar(self.simples, 1, 'N')
+ registro_10 += self._validar(self.fpas, 3, 'N')
+ registro_10 += str.ljust('', 143)
+ registro_10 += self.final_de_linha
+ return registro_10
+
+ # Informações do trabalhador
+ def _registro_40(self):
+ registro_40 = self.tipo_de_registro_40
+ registro_40 += \
+ self._validar(self.tipo_de_inscricao_trabalhador, 1, 'N') \
+ if self.tipo_de_inscricao_trabalhador \
+ else self._validar(self.tipo_de_inscricao_empresa, 1, 'N')
+ registro_40 += self._validar(self.inscricao_do_trabalhador, 14, 'N') \
+ if self.inscricao_do_trabalhador \
+ else self._validar(self.inscricao_da_empresa, 14, 'N')
+ registro_40 += self._validar(self.tipo_inscricao_tomador, 1, 'N')
+ registro_40 += self._validar(self.inscricao_tomador, 14, 'N')
+ registro_40 += self._validar(self.PIS_PASEP, 11, 'N')
+ registro_40 += self._validar(self.data_admissao, 8, 'D')
+ registro_40 += self._validar(self.categoria_trabalhador, 2, 'N')
+ registro_40 += self._validar(self.nome_do_trabalhador, 70, 'A')
+ registro_40 += self._validar(self.numero_ctps, 7, 'N')
+ registro_40 += self._validar(self.serie_ctps, 5, 'N')
+ registro_40 += self._validar(self.sexo, 1, 'N')
+ registro_40 += self._validar(self.grau_de_instrucao, 2, 'N')
+ registro_40 += self._validar(self.data_nascimento, 8, 'D')
+ registro_40 += self._validar(self.qtd_horas_trabalhadas_semana, 2, 'N')
+ registro_40 += self._validar(self.CBO, 6, 'AN')
+ registro_40 += self._validar(self.data_opcao, 8, 'D')
+ registro_40 += self._validar(self.codigo_da_movimentacao, 2, 'AN')
+ registro_40 += self._validar(self.data_movimentacao, 8, 'D')
+ registro_40 += self._validar(self.codigo_de_saque, 3, 'AN')
+ registro_40 += self._validar(self.aviso_previo, 1, 'N')
+ registro_40 += self._validar(self.data_inicio_aviso_previo, 8, 'D')
+ registro_40 += self._validar(self.reposicao_de_vaga, 1, 'A')
+ registro_40 += self._validar(self.data_homologacao_dissidio, 8, 'D')
+ registro_40 += self._validar(self.valor_dissidio, 15, 'V')
+ registro_40 += self._validar(self.remuneracao_mes_aterior, 15, 'V')
+ registro_40 += self._validar(self.remuneracao_mes_rescisao, 15, 'V')
+ registro_40 += self._validar(self.aviso_previo_indenizado, 15, 'V')
+ registro_40 += \
+ self._validar(self.indicativo_pensao_alimenticia, 1, 'A')
+ registro_40 += \
+ self._validar(self.percentual_pensao_alimenticia, 5, 'V')
+ registro_40 += self._validar(self.valor_pensao_alimenticia, 15, 'V')
+ registro_40 += self._validar(self.CPF, 11, 'N')
+ registro_40 += self._validar(self.banco_conta_trabalhador, 3, 'N')
+ registro_40 += self._validar(self.agencia_trabalhador, 4, 'N')
+ registro_40 += self._validar(self.conta_trabalhador, 13, 'N')
+ registro_40 += self._validar(self.saldo_para_fins_rescisorios, 15, 'N')
+ registro_40 += str.ljust('', 39)
+ registro_40 += self.final_de_linha
+ return registro_40
+
+ def _registro_90(self):
+ registro_90 = self.tipo_de_registro_90
+ registro_90 += self.marca_final_de_registro
+ registro_90 += str.ljust('', 306)
+ registro_90 += self.final_de_linha
+ return registro_90
+
+ def _gerar_grrf(self):
+ return \
+ self._registro_00() + \
+ self._registro_10() + \
+ self._registro_40() + \
+ self._registro_90()
+
+ # campos do registro 00 ---------------------------------------------------
+ tipo_de_registro_00 = u'00' # sempre '00'
+ tipo_de_remessa = u'2' # 2 - GRRF | 4 - Comunicar movimentação
+ tipo_inscricao_responsavel = u'1' # 1 - CNPJ | 2 - CEI
+ inscricao_do_responsavel = '' # CNPJ | CEI
+ razao_social_responsavel = ''
+ nome_do_contato_responsavel = ''
+ endereco_responsavel = ''
+ bairro_responsavel = ''
+ cep_responsavel = ''
+ cidade_responsavel = ''
+ unidade_federacao_responsavel = ''
+ telefone_contato_responsavel = ''
+ endereco_internet_responsavel = ''
+ data_recolhimento_grrf = ''
+ final_de_linha = u'*'
+ # -------------------------------------------------------------------------
+
+ # campos do registro 10 ---------------------------------------------------
+ tipo_de_registro_10 = u'10' # sempre '10'
+ tipo_de_inscricao_empresa = u'1'
+ inscricao_da_empresa = '' # CNPJ | CEI
+ razao_social_empresa = ''
+ endereco_empresa = ''
+ bairro_empresa = ''
+ cep_empresa = ''
+ cidade_empresa = ''
+ unidade_federacao_empresa = ''
+ telefone_empresa = ''
+ CNAE_fiscal = ''
+ simples = ''
+ fpas = ''
+ # ------------------------------------------------------------------------
+
+ # campos do registro 40 ---------------------------------------------------
+ tipo_de_registro_40 = u'40' # sempre '40'
+ tipo_de_inscricao_trabalhador = u'1'
+ inscricao_do_trabalhador = ''
+ tipo_inscricao_tomador = ''
+ inscricao_tomador = ''
+ PIS_PASEP = ''
+ data_admissao = '' # DDMMAAAA
+ categoria_trabalhador = u'01'
+ nome_do_trabalhador = ''
+ numero_ctps = ''
+ serie_ctps = ''
+ sexo = ''
+ grau_de_instrucao = ''
+ data_nascimento = ''
+ qtd_horas_trabalhadas_semana = ''
+ CBO = ''
+ data_opcao = ''
+ codigo_da_movimentacao = ''
+ data_movimentacao = ''
+ codigo_de_saque = ''
+ aviso_previo = ''
+ data_inicio_aviso_previo = ''
+ reposicao_de_vaga = ''
+ data_homologacao_dissidio = ''
+ valor_dissidio = ''
+ remuneracao_mes_aterior = ''
+ remuneracao_mes_rescisao = ''
+ aviso_previo_indenizado = ''
+ indicativo_pensao_alimenticia = ''
+ percentual_pensao_alimenticia = ''
+ valor_pensao_alimenticia = ''
+ CPF = ''
+ banco_conta_trabalhador = ''
+ agencia_trabalhador = ''
+ conta_trabalhador = ''
+ saldo_para_fins_rescisorios = ''
+ # ------------------------------------------------------------------------
+
+ # campos do registro 90 ---------------------------------------------------
+ tipo_de_registro_90 = u'90' # sempre '90'
+ marca_final_de_registro = ''.rjust(51, '9')
+ # ------------------------------------------------------------------------
diff --git a/l10n_br_hr_arquivos_governo/models/arquivo_sefip.py b/l10n_br_hr_arquivos_governo/models/arquivo_sefip.py
new file mode 100644
index 000000000..0341f2436
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/arquivo_sefip.py
@@ -0,0 +1,498 @@
+# -*- coding: utf-8 -*-
+# (c) 2017 KMEE INFORMATICA LTDA - Daniel Sadamo
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+import logging
+from .abstract_arquivos_governo import AbstractArquivosGoverno
+import re
+
+_logger = logging.getLogger(__name__)
+
+try:
+ from pybrasil.base import tira_acentos
+except ImportError:
+ _logger.info('Cannot import pybrasil')
+
+
+class SEFIP(AbstractArquivosGoverno):
+
+ def _registro_00_informacoes_responsavel(self):
+ registro_00 = self.tipo_de_registro_00
+ registro_00 += self._validar(self.preenche_brancos, 51, 'AN')
+ registro_00 += self._validar(self.tipo_remessa, 1, 'N')
+ registro_00 += self._validar(self.tipo_inscr_resp, 1, 'N')
+ registro_00 += self._validar(self.inscr_resp, 14, 'N')
+ registro_00 += self._validar(self.nome_resp, 30, 'AN')
+ registro_00 += self._validar(self.nome_contato, 20, 'A')
+ registro_00 += self._validar(self.arq_logradouro, 50, 'AN')
+ registro_00 += self._validar(self.arq_bairro, 20, 'AN')
+ registro_00 += self._validar(self.arq_cep, 8, 'N')
+ registro_00 += self._validar(self.arq_cidade, 20, 'AN')
+ registro_00 += self._validar(self.arq_uf, 2, 'A')
+ registro_00 += self._validar(self.tel_contato, 12, 'N')
+ registro_00 += self._validar(self.internet_contato, 60, 'AN')
+ registro_00 += self._validar(self.competencia, 6, 'D')
+ registro_00 += self._validar(self.cod_recolhimento, 3, 'N')
+ registro_00 += self._validar(self.indic_recolhimento_fgts, 1, 'N')
+ registro_00 += self._validar(self.modalidade_arq, 1, 'N')
+ if self.indic_recolhimento_fgts in ['2', '3', '5', '6']:
+ registro_00 += self._validar(self.data_recolhimento_fgts, 8, 'D')
+ else:
+ registro_00 += self._validar(False, 8, 'D')
+ registro_00 += self._validar(self.indic_recolh_ps, 1, 'N')
+ if self.indic_recolh_ps == '2':
+ registro_00 += self._validar(self.data_recolh_ps, 8, 'D')
+ else:
+ registro_00 += self._validar(False, 8, 'D')
+ registro_00 += self._validar(self.indice_recolh_atraso_ps, 7, 'N')
+ registro_00 += self._validar(self.tipo_inscr_fornec, 1, 'N')
+ registro_00 += self._validar(self.inscr_fornec, 14, 'N')
+ registro_00 += self._validar(self.preenche_brancos, 18, 'AN')
+ registro_00 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_00
+
+ def _registro_10_informacoes_empresa(self):
+ registro_10 = self.tipo_de_registro_10
+ registro_10 += self._validar(self.tipo_inscr_empresa, 1, 'N')
+ registro_10 += self._validar(self.inscr_empresa, 14, 'N')
+ registro_10 += self._validar(self.preenche_zeros, 36, 'V')
+ registro_10 += self._validar(self.emp_nome_razao_social, 40, 'AN')
+ registro_10 += self._validar(self.emp_logradouro, 50, 'AN')
+ registro_10 += self._validar(self.emp_bairro, 20, 'AN')
+ registro_10 += self._validar(self.emp_cep, 8, 'N')
+ registro_10 += self._validar(self.emp_cidade, 20, 'AN')
+ registro_10 += self._validar(self.emp_uf, 2, 'A')
+ registro_10 += self._validar(self.emp_tel, 12, 'N')
+ registro_10 += self._validar(self.emp_indic_alteracao_endereco, 1, 'A')
+ registro_10 += self._validar(self.emp_cnae, 7, 'N')
+ registro_10 += self._validar(self.emp_indic_alteracao_cnae, 1, 'A')
+ registro_10 += self._validar(self.emp_aliquota_RAT, 2, 'N')
+ registro_10 += self._validar(self.emp_cod_centralizacao, 1, 'N')
+ registro_10 += self._validar(self.emp_simples, 1, 'N')
+ registro_10 += self._validar(self.emp_FPAS, 3, 'N')
+ registro_10 += self._validar(self.emp_cod_outras_entidades, 4, 'N')
+ registro_10 += self._validar(self.emp_cod_pagamento_GPS, 4, 'N')
+ registro_10 += self._validar(
+ self.emp_percent_isencao_filantropia, 5, 'N')
+ registro_10 += self._validar(self.emp_salario_familia, 15, 'V')
+ registro_10 += self._validar(self.emp_salario_maternidade, 15, 'V')
+ registro_10 += self._validar(
+ self.emp_contrib_descont_empregados, 15, 'V')
+ registro_10 += self._validar(self.emp_indic_valor_pos_neg, 1, 'V')
+ registro_10 += self._validar(
+ self.emp_valor_devido_ps_referente, 14, 'V')
+ registro_10 += self._validar(self.emp_banco, 3, 'N')
+ registro_10 += self._validar(self.emp_ag, 4, 'N')
+ registro_10 += self._validar(self.emp_cc, 9, 'AN')
+ registro_10 += self._validar(self.preenche_zeros, 45, 'V')
+ registro_10 += self._validar(self.preenche_brancos, 4, 'AN')
+ registro_10 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_10
+
+ def _registro_12_inf_adic_recolhimento_empresa(self):
+ registro_12 = self.tipo_de_registro_12
+ registro_12 += self._validar(self.tipo_inscr_empresa, 1, 'N')
+ registro_12 += self._validar(self.inscr_empresa, 14, 'N')
+ registro_12 += self._validar(self.preenche_zeros, 36, 'V')
+ registro_12 += self._validar(self.ded_13_lic_maternidade, 15, 'V')
+ registro_12 += self._validar(self.receita_evento_desp_patroc, 15, 'V')
+ registro_12 += self._validar(self.indic_orig_receita, 1, 'AN')
+ registro_12 += self._validar(self.comercializacao_producao_pf, 15, 'V')
+ registro_12 += self._validar(self.comercializacao_producao_pj, 15, 'V')
+ registro_12 += self._validar(self.rec_outras_info_processo, 11, 'N')
+ registro_12 += self._validar(self.rec_outras_info_processo_ano, 4, 'N')
+ registro_12 += self._validar(self.rec_outras_info_vara_JCJ, 5, 'N')
+ registro_12 += self._validar(
+ self.rec_outras_info_periodo_inicio, 6, 'D')
+ registro_12 += self._validar(self.rec_outras_info_periodo_fim, 6, 'D')
+ registro_12 += self._validar(self.compensacao_valor_corrigido, 15, 'V')
+ registro_12 += self._validar(self.compensacao_periodo_inicio, 6, 'D')
+ registro_12 += self._validar(self.compensacao_periodo_fim, 6, 'D')
+ registro_12 += self._validar(
+ self.recolh_competencias_ant_folha_inss, 15, 'V')
+ registro_12 += self._validar(
+ self.recolh_competencias_ant_folha_outras_ent, 15, 'V')
+ registro_12 += self._validar(
+ self.recolh_competencias_ant_comerc_prod_inss, 15, 'V')
+ registro_12 += self._validar(
+ self.recolh_competencias_ant_comerc_prod_outras_ent, 15, 'V')
+ registro_12 += self._validar(
+ self.recolh_competencias_ant_eventos_desport_inss, 15, 'V')
+ registro_12 += self._validar(
+ self.inf_adic_tomador_parc_fgts_cat_01_02_03_05_06, 15, 'V')
+ registro_12 += self._validar(
+ self.inf_adic_tomador_parc_fgts_cat_04_07, 15, 'V')
+ registro_12 += self._validar(self.parc_fgts_valor_recolhido, 15, 'V')
+ registro_12 += self._validar(
+ self.vlr_pago_cooperativas_trabalho, 15, 'V')
+ registro_12 += self._validar(self.preenche_zeros, 45, 'V')
+ registro_12 += self._validar(self.preenche_brancos, 6, 'AN')
+ registro_12 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_12
+
+ def _registro_13_alteracao_cadastral_trabalhador(self):
+ registro_13 = self.tipo_de_registro_13
+ registro_13 += self._validar(self.tipo_inscr_empresa, 1, 'N')
+ registro_13 += self._validar(self.inscr_empresa, 14, 'N')
+ registro_13 += self._validar(self.preenche_zeros, 36, 'V')
+ registro_13 += self._validar(self.pis_pasep_ci, 11, 'N')
+ registro_13 += self._validar(self.data_admissao, 8, 'D')
+ registro_13 += self._validar(self.categoria_trabalhador, 2, 'N')
+ registro_13 += self._validar(self.matricula_trabalhador, 11, 'N')
+ registro_13 += self._validar(self.num_ctps, 7, 'E')
+ registro_13 += self._validar(self.serie_ctps, 5, 'E')
+ registro_13 += self._validar(self.nome_trabalhador, 70, 'A')
+ registro_13 += self._validar(self.codigo_empresa_caixa, 14, 'N')
+ registro_13 += self._validar(self.codigo_trabalhador_caixa, 11, 'N')
+ registro_13 += self._validar(self.codigo_alteracao_cadastral, 3, 'N')
+ registro_13 += self._validar(self.novo_conteudo_campo, 70, 'AN')
+ registro_13 += self._validar(self.preenche_brancos, 94, 'AN')
+ registro_13 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_13
+
+ def _registro_14_inclusao_alteracao_endereco_trabalhador(self):
+ registro_14 = self.tipo_de_registro_14
+ registro_14 += self._validar(self.tipo_inscr_empresa, 2, 'N')
+ registro_14 += self._validar(self.inscr_empresa, 14, 'N')
+ registro_14 += self._validar(self.preenche_zeros, 36, 'V')
+ registro_14 += self._validar(self.pis_pasep_ci, 11, 'N')
+ registro_14 += self._validar(self.data_admissao, 8, 'D')
+ registro_14 += self._validar(self.categoria_trabalhador, 2, 'N')
+ registro_14 += self._validar(self.nome_trabalhador, 70, 'A')
+ registro_14 += self._validar(self.num_ctps, 7, 'E')
+ registro_14 += self._validar(self.serie_ctps, 5, 'E')
+ registro_14 += self._validar(self.trabalhador_logradouro, 50, 'AN')
+ registro_14 += self._validar(self.trabalhador_bairro, 20, 'AN')
+ registro_14 += self._validar(self.trabalhador_cep, 8, 'N')
+ registro_14 += self._validar(self.trabalhador_cidade, 20, 'AN')
+ registro_14 += self._validar(self.trabalhador_uf, 2, 'A')
+ registro_14 += self._validar(self.preenche_brancos, 103, 'AN')
+ registro_14 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_14
+
+ def _registro_20_tomador_de_servico_ou_obra_contrucao_civil(self):
+ registro_20 = self.tipo_de_registro_20
+ registro_20 += self._validar(self.tipo_inscr_empresa, 1, 'N')
+ registro_20 += self._validar(self.inscr_empresa, 14, 'N')
+ registro_20 += self._validar(self.tipo_inscr_tomador, 1, 'N')
+ registro_20 += self._validar(self.inscr_tomador, 14, 'N')
+ registro_20 += self._validar(self.preenche_zeros, 21, 'V')
+ registro_20 += self._validar(self.nome_tomador, 40, 'AN')
+ registro_20 += self._validar(self.tomador_logradouro, 50, 'AN')
+ registro_20 += self._validar(self.tomador_bairro, 20, 'AN')
+ registro_20 += self._validar(self.tomador_cep, 8, 'N')
+ registro_20 += self._validar(self.tomador_cidade, 20, 'AN')
+ registro_20 += self._validar(self.tomador_uf, 2, 'A')
+ registro_20 += self._validar(self.tomador_cod_gps, 4, 'N')
+ registro_20 += self._validar(self.tomador_salario_familia, 15, 'V')
+ registro_20 += self._validar(
+ self.preenche_zeros, 15, 'V')
+ registro_20 += self._validar(self.preenche_zeros, 1, 'V')
+ registro_20 += self._validar(self.preenche_zeros, 14, 'V')
+ registro_20 += self._validar(self.tomador_valor_retencao, 15, 'V')
+ registro_20 += self._validar(self.tomador_faturas_emitidas, 15, 'V')
+ registro_20 += self._validar(self.preenche_zeros, 45, 'V')
+ registro_20 += self._validar(self.preenche_brancos, 42, 'AN')
+ registro_20 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_20
+
+ def _registro_21_informacoes_adicionais_tomador_de_servico(self):
+ registro_21 = self.tipo_de_registro_21
+ registro_21 += self._validar(self.tipo_inscr_empresa, 1, 'N')
+ registro_21 += self._validar(self.inscr_empresa, 14, 'N')
+ registro_21 += self._validar(self.tipo_inscr_tomador, 1, 'N')
+ registro_21 += self._validar(self.inscr_tomador, 14, 'N')
+ registro_21 += self._validar(self.preenche_zeros, 21, 'V')
+ registro_21 += self._validar(
+ self.inf_adic_tomador_compensacao_corrigido, 15, 'V')
+ registro_21 += self._validar(
+ self.inf_adic_tomador_compensacao_periodo_inicio, 6, 'D')
+ registro_21 += self._validar(
+ self.inf_adic_tomador_compensacao_periodo_fim, 6, 'D')
+ registro_21 += self._validar(
+ self.inf_adic_tomador_recolh_compet_ant_inss, 15, 'V')
+ registro_21 += self._validar(
+ self.inf_adic_tomador_recolh_compet_ant_outras_ent, 15, 'V')
+ registro_21 += self._validar(
+ self.inf_adic_tomador_parc_fgts_cat_01_02_03_05_06, 15, 'V')
+ registro_21 += self._validar(
+ self.inf_adic_tomador_parc_fgts_cat_04_07, 15, 'V')
+ registro_21 += self._validar(
+ self.inf_adic_tomador_parc_fgts_vlr_recolhido, 15, 'V')
+ registro_21 += self._validar(self.preenche_brancos, 204, 'AN')
+ registro_21 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_21
+
+ def _registro_30_registro_do_trabalhador(self):
+ registro_30 = self.tipo_de_registro_30
+ registro_30 += self._validar(self.tipo_inscr_empresa, 1, 'N')
+ registro_30 += self._validar(self.inscr_empresa, 14, 'N')
+ registro_30 += self._validar(self.tipo_inscr_tomador, 1, 'N')
+ registro_30 += self._validar(self.inscr_tomador, 14, 'N')
+ registro_30 += self._validar(self.pis_pasep_ci, 11, 'N')
+ registro_30 += self._validar(self.data_admissao, 8, 'D')
+ registro_30 += self._validar(self.categoria_trabalhador, 2, 'N')
+ registro_30 += self._validar(self.nome_trabalhador, 70, 'A')
+ registro_30 += self._validar(self.matricula_trabalhador, 11, 'N')
+ registro_30 += self._validar(self.num_ctps, 7, 'E')
+ registro_30 += self._validar(self.serie_ctps, 5, 'E')
+ registro_30 += self._validar(self.data_de_opcao, 8, 'D')
+ registro_30 += self._validar(self.data_de_nascimento, 8, 'D')
+ registro_30 += self._validar(self.trabalhador_cbo, 5, 'AN')
+ registro_30 += self._validar(self.trabalhador_remun_sem_13, 15, 'V')
+ registro_30 += self._validar(self.trabalhador_remun_13, 15, 'V')
+ registro_30 += self._validar(self.trabalhador_classe_contrib, 2, 'N')
+ registro_30 += self._validar(self.trabalhador_ocorrencia, 2, 'N')
+ registro_30 += self._validar(
+ self.trabalhador_valor_desc_segurado, 15, 'V')
+ registro_30 += self._validar(
+ self.trabalhador_remun_base_calc_contribuicao_previdenciaria,
+ 15, 'V')
+ registro_30 += self._validar(
+ self.trabalhador_base_calc_13_previdencia_competencia, 15, 'V')
+ registro_30 += self._validar(
+ self.trabalhador_base_calc_13_previdencia_GPS, 15, 'V')
+ registro_30 += self._validar(self.preenche_brancos, 98, 'AN')
+ registro_30 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_30
+
+ def _registro_32_movimentacao_do_trabalhador(self):
+ registro_32 = self.tipo_de_registro_32
+ registro_32 += self._validar(self.tipo_inscr_empresa, 1, 'N')
+ registro_32 += self._validar(self.inscr_empresa, 14, 'N')
+ registro_32 += self._validar(self.tipo_inscr_tomador, 1, 'N')
+ registro_32 += self._validar(self.inscr_tomador, 14, 'N')
+ registro_32 += self._validar(self.pis_pasep_ci, 11, 'N')
+ registro_32 += self._validar(self.data_admissao, 8, 'D')
+ registro_32 += self._validar(self.categoria_trabalhador, 2, 'N')
+ registro_32 += self._validar(self.nome_trabalhador, 70, 'A')
+ registro_32 += self._validar(
+ self.trabalhador_codigo_movimentacao, 2, 'AN')
+ registro_32 += self._validar(
+ self.trabalhador_data_movimentacao, 8, 'D')
+ registro_32 += self._validar(
+ self.trabalhador_indic_recolhimento_fgts, 1, 'AN')
+ registro_32 += self._validar(self.preenche_brancos, 225, 'AN')
+ registro_32 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_32
+
+ # PARA IMPLEMENTAÇAO FUTURA
+ # def _registro_50_(self):
+ # pass
+ #
+ # def _registro_51_(self):
+ # pass
+
+ def _registro_90_totalizador_do_arquivo(self):
+ registro_90 = self.tipo_de_registro_90
+ registro_90 += self._validar(self.marca_de_final_registro, 51, 'AN')
+ registro_90 += self._validar(self.preenche_brancos, 306, 'AN')
+ registro_90 += self._validar(self.fim_linha, 1, 'AN')
+ return registro_90
+
+ def __init__(self, *args, **kwargs):
+ # campos gerais--------------------------------------------------------
+ self.preenche_zeros = '0' # DEVE SER SEMPRE PASSADO COM TIPO 'V'
+ self.preenche_brancos = ''
+ self.fim_linha = '*'
+ self.tipo_inscr_empresa = '1'
+ self.inscr_empresa = ''
+ # campos do HEADER ARQUIVO--------------------------------------------
+ self.tipo_de_registro_00 = '00'
+ self.tipo_remessa = '1'
+ self.tipo_inscr_resp = '1'
+ self.inscr_resp = ''
+ self.nome_resp = ''
+ self.nome_contato = ''
+ self.arq_logradouro = ''
+ self.arq_bairro = ''
+ self.arq_cep = ''
+ self.arq_cidade = ''
+ self.arq_uf = ''
+ self.tel_contato = ''
+ self.internet_contato = ''
+ self.competencia = ''
+ self.cod_recolhimento = ''
+ self.indic_recolhimento_fgts = ''
+ self.modalidade_arq = ''
+ self.data_recolhimento_fgts = ' '
+ self.indic_recolh_ps = ''
+ self.data_recolh_ps = ' '
+ self.indice_recolh_atraso_ps = ''
+ self.tipo_inscr_fornec = ''
+ self.inscr_fornec = ''
+ # campos HEADER EMPRESA------------------------------------------------
+ self.tipo_de_registro_10 = '10'
+ self.emp_nome_razao_social = ''
+ self.emp_logradouro = ''
+ self.emp_bairro = ''
+ self.emp_cep = ''
+ self.emp_cidade = ''
+ self.emp_uf = ''
+ self.emp_tel = ''
+ self.emp_indic_alteracao_endereco = 'N'
+ self.emp_cnae = ''
+ self.emp_indic_alteracao_cnae = 'N'
+ self.emp_aliquota_RAT = ''
+ self.emp_cod_centralizacao = ''
+ self.emp_simples = '1'
+ self.emp_FPAS = ''
+ self.emp_cod_outras_entidades = ''
+ self.emp_cod_pagamento_GPS = ''
+ self.emp_percent_isencao_filantropia = ''
+ self.emp_salario_familia = ''
+ self.emp_salario_maternidade = ''
+ self.emp_contrib_descont_empregados = ''
+ self.emp_indic_valor_pos_neg = ''
+ self.emp_valor_devido_ps_referente = ''
+ self.emp_banco = ''
+ self.emp_ag = ''
+ self.emp_cc = ''
+ # campos do RECOLHIMENTO DA EMPRESA -----------------------------------
+ self.tipo_de_registro_12 = '12'
+ self.ded_13_lic_maternidade = ''
+ self.receita_evento_desp_patroc = ''
+ self.indic_orig_receita = ''
+ self.comercializacao_producao_pf = ''
+ self.comercializacao_producao_pj = ''
+ self.rec_outras_info_processo = ''
+ self.rec_outras_info_processo_ano = ''
+ self.rec_outras_info_vara_JCJ = ''
+ self.rec_outras_info_periodo_inicio = ''
+ self.rec_outras_info_periodo_fim = ''
+ self.compensacao_valor_corrigido = ''
+ self.compensacao_periodo_inicio = ''
+ self.compensacao_periodo_fim = ''
+ self.recolh_competencias_ant_folha_inss = ''
+ self.recolh_competencias_ant_folha_outras_ent = ''
+ self.recolh_competencias_ant_comerc_prod_inss = ''
+ self.recolh_competencias_ant_comerc_prod_outras_ent = ''
+ self.recolh_competencias_ant_eventos_desport_inss = ''
+ self.parc_fgts_soma_remuneracao = ''
+ self.parc_fgts_valor_recolhido = ''
+ self.vlr_pago_cooperativas_trabalho = ''
+ # campos gerais do TRABALHADOR ----------------------------------------
+ self.pis_pasep_ci = ''
+ self.data_admissao = ' '
+ self.categoria_trabalhador = ''
+ self.num_ctps = '' * 7
+ self.serie_ctps = '' * 5
+ self.nome_trabalhador = ''
+ self.matricula_trabalhador = ''
+ # campos ALTERACAO CADASTRAL TRABALHADOR ------------------------------
+ self.tipo_de_registro_13 = '13'
+ self.codigo_empresa_caixa = ''
+ self.codigo_trabalhador_caixa = ''
+ self.codigo_alteracao_cadastral = ''
+ self.novo_conteudo_campo = ''
+ # campos INCLUSAO/ALTERACAO ENDERECO TRABALHADOR ----------------------
+ self.tipo_de_registro_14 = '14'
+ self.trabalhador_logradouro = ''
+ self.trabalhador_bairro = ''
+ self.trabalhador_cep = ''
+ self.trabalhador_cidade = ''
+ self.trabalhador_uf = ''
+ # campos gerais TOMADOR DE SERVICO/OBRA DE CONSTRUCAO CIVIL------------
+ self.tipo_inscr_tomador = ''
+ self.inscr_tomador = ''
+ # campos TOMADOR DE SERVICO/OBRA DE CONSTRUCAO CIVIL ------------------
+ self.tipo_de_registro_20 = '20'
+ self.nome_tomador = ''
+ self.tomador_logradouro = ''
+ self.tomador_bairro = ''
+ self.tomador_cep = ''
+ self.tomador_cidade = ''
+ self.tomador_uf = ''
+ self.tomador_cod_gps = ''
+ self.tomador_salario_familia = ''
+ self.tomador_contrib_desc_empregado_13 = ''
+ self.tomador_valor_retencao = ''
+ self.tomador_faturas_emitidas = ''
+ # campos INFORMACOES ADICIONAIS TOMADOR DE SERVICO/OBRA DE CONST-------
+ self.tipo_de_registro_21 = '21'
+ self.inf_adic_tomador_compensacao_corrigido = ''
+ self.inf_adic_tomador_compensacao_periodo_inicio = ''
+ self.inf_adic_tomador_compensacao_periodo_fim = ''
+ self.inf_adic_tomador_recolh_compet_ant_inss = ''
+ self.inf_adic_tomador_recolh_compet_ant_outras_ent = ''
+ self.inf_adic_tomador_parc_fgts_cat_01_02_03_05_06 = ''
+ self.inf_adic_tomador_parc_fgts_cat_04_07 = ''
+ self.inf_adic_tomador_parc_fgts_vlr_recolhido = ''
+ # campos REGISTRO DO TRABALHADOR --------------------------------------
+ self.tipo_de_registro_30 = '30'
+ self.data_de_opcao = ' '
+ self.data_de_nascimento = ' '
+ self.trabalhador_cbo = ''
+ self.trabalhador_remun_sem_13 = ''
+ self.trabalhador_remun_13 = ''
+ self.trabalhador_classe_contrib = ''
+ self.trabalhador_ocorrencia = ''
+ self.trabalhador_valor_desc_segurado = ''
+ self.trabalhador_remun_base_calc_contribuicao_previdenciaria = ''
+ self.trabalhador_base_calc_13_previdencia_competencia = ''
+ self.trabalhador_base_calc_13_previdencia_GPS = ''
+ # campos MOVIMENTACAO DO TRABALHADOR
+ self.tipo_de_registro_32 = '32'
+ self.trabalhador_codigo_movimentacao = ''
+ self.trabalhador_data_movimentacao = ' '
+ self.trabalhador_indic_recolhimento_fgts = ''
+ # campos registro 50 - IMPLEMENTACAO FUTURA
+ # campos registro 51 - IMPLEMENTACAO FUTURA
+
+ # campos REGISTRO TOTALIZADOR DO ARQUIVO
+ self.tipo_de_registro_90 = '90'
+ self.marca_de_final_registro = '9' * 51
+
+ def _validar(self, word, tam, tipo='AN'):
+ """
+ Função Genérica utilizada para validação de campos que são gerados
+ nos arquivos TXT's
+ :param word:
+ :param tam:
+ :param tipo:
+ :return:
+ """
+ if not word:
+ word = u''
+
+ if tipo == 'A': # Alfabetico
+ word = tira_acentos(unicode(word))
+ # tirar tudo que nao for letra do alfabeto
+ word = re.sub('[^a-zA-Z]', ' ', word)
+ # Retirar 2 espaços seguidos
+ word = re.sub('[ ]+', ' ', word)
+ return unicode.ljust(unicode(word), tam)[:tam]
+
+ elif tipo == 'D': # Data
+ # Retira tudo que nao for numeral
+ data_calculo = re.sub(u'[^0-9]', '', str(word))
+ return unicode.ljust(unicode(data_calculo), tam)[:tam]
+
+ elif tipo == 'V': # Valor
+ # Pega a parte decimal como inteiro e nas duas ultimas casas
+ word = int(word * 100) if word else 0
+ # Preenche com zeros a esquerda
+ word = str(word).zfill(tam)
+ return word[:tam]
+
+ elif tipo == 'N': # Numerico
+ # Preenche com brancos a esquerda
+ word = re.sub('[^0-9]', '', str(word))
+ # word = str(word).zfill(tam)
+ # return word[:tam]
+ return unicode.rjust(unicode(word), tam)[:tam]
+
+ elif tipo == 'AN': # Alfanumerico
+ # Tira acentos da palavras
+ word = tira_acentos(unicode(word))
+ # Preenche com espaço vazio a direita
+ return unicode.ljust(unicode(word), tam)[:tam]
+
+ elif tipo == 'E': # Valor
+ if ' ' in word:
+ return word
+ # Pega a parte decimal como inteiro e nas duas ultimas casas
+ word = int(word * 100) if word else 0
+ # Preenche com zeros a esquerda
+ word = str(word).zfill(tam)
+ return word[:tam]
diff --git a/l10n_br_hr_arquivos_governo/models/arquivo_seguro_desemprego.py b/l10n_br_hr_arquivos_governo/models/arquivo_seguro_desemprego.py
new file mode 100644
index 000000000..a3a6e6bea
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/arquivo_seguro_desemprego.py
@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+# (c) 2017 KMEE- Hendrix Costa
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+import logging
+from .abstract_arquivos_governo import AbstractArquivosGoverno
+
+_logger = logging.getLogger(__name__)
+
+try:
+ from pybrasil.data import hoje
+except ImportError:
+ _logger.info('Cannot import pybrasil')
+
+
+class SeguroDesemprego(AbstractArquivosGoverno):
+
+ # HEADER
+ def _registro_header(self):
+ registro_header = self.tipo_de_registro_00
+ registro_header += self._validar(self.tipo_identificador, 1, 'N')
+ registro_header += self._validar(self.cnpj_empresa, 14, 'N')
+ registro_header += self._validar(self.versao_layout, 3, 'N')
+ registro_header += ''.ljust(280)
+ registro_header += '\r\n'
+ return registro_header
+
+ # REQUERIMENTO
+ def _registro_requerimento(self):
+ registro01 = self.tipo_de_registro_01
+ registro01 += self._validar(self.cpf, 11, 'N')
+ registro01 += self._validar(self.nome, 40, 'AN')
+ registro01 += self._validar(self.endereco, 40, 'AN')
+ registro01 += self._validar(self.complemento, 16, 'AN')
+ registro01 += self._validar(self.cep, 8, 'N')
+ registro01 += self._validar(self.uf, 2, 'A')
+ registro01 += self._validar(self.ddd, 2, 'N')
+ registro01 += self._validar(self.telefone, 8, 'N')
+ registro01 += self._validar(self.nome_mae, 40, 'A')
+ registro01 += self._validar(self.pis, 11, 'N')
+ registro01 += self._validar(self.carteira_trabalho_numero, 8, 'N')
+ registro01 += self._validar(self.carteira_trabalho_serie, 5, 'AN')
+ registro01 += self._validar(self.carteira_trabalho_estado, 2, 'A')
+ registro01 += self._validar(self.cbo, 6, 'N')
+ registro01 += self._validar(self.data_admissao, 8, 'D')
+ registro01 += self._validar(self.data_demissao, 8, 'D')
+ registro01 += self._validar(self.sexo, 1, 'N')
+ registro01 += self._validar(self.grau_instrucao, 2, 'N')
+ registro01 += self._validar(self.data_nascimento, 8, 'D')
+ registro01 += self._validar(self.horas_trabalhadas_semana, 2, 'N')
+ registro01 += \
+ self._validar(self.remuneracao_antepenultimo_salario, 10, 'N')
+ registro01 += \
+ self._validar(self.remuneracao_penultimo_salario, 10, 'N')
+ registro01 += self._validar(self.ultimo_salario, 10, 'N')
+ registro01 += self._validar(self.numero_meses_trabalhados, 2, 'N')
+ registro01 += self._validar(self.recebeu_6_salario, 1, 'N')
+ registro01 += self._validar(self.aviso_previo_indenizado, 1, 'N')
+ registro01 += self._validar(self.codigo_banco, 3, 'N')
+ registro01 += self._validar(self.codigo_agencia, 4, 'N')
+ registro01 += self._validar(self.codigo_agencia_digito, 1, 'N')
+ registro01 += ''.ljust(28)
+ registro01 += '\r\n'
+ return registro01
+
+ def _registro_trailler(self):
+ registro_trailler = self.tipo_de_registro_99
+ registro_trailler += \
+ self._validar(self.total_requerimentos_informados, 5, 'N')
+ registro_trailler += str.ljust('', 293)
+ registro_trailler += '\r\n'
+ return registro_trailler
+
+ def _gerar_arquivo_seguro_desemprego(self):
+ return \
+ self._registro_header() + \
+ self._registro_requerimento() + \
+ self._registro_trailler()
+
+ def __init__(self, *args, **kwargs):
+
+ # campos do HEADER ---------------------------------------------------
+ self.tipo_de_registro_00 = '00'
+ self.tipo_identificador = '1'
+ self.cnpj_empresa = ''
+ self.versao_layout = '001'
+ self.empregados = []
+ # ---------------------------------------------------------------------
+
+ # campos do REQUERIMENTO ----------------------------------------------
+ self.tipo_de_registro_01 = '01'
+ self.cpf = ''
+ self.nome = ''
+ self.endereco = ''
+ self.complemento = ''
+ self.cep = ''
+ self.uf = ''
+ self.ddd = ''
+ self.telefone = ''
+ self.nome_mae = ''
+ self.pis = ''
+ self.carteira_trabalho_numero = ''
+ self.carteira_trabalho_serie = ''
+ self.carteira_trabalho_estado = ''
+ self.cbo = ''
+ self.data_admissao = hoje()
+ self.data_demissao = hoje()
+ self.sexo = 'M'
+ self.grau_instrucao = '01'
+ self.data_nascimento = hoje()
+ self.horas_trabalhadas_semana = 44
+ self.remuneracao_antepenultimo_salario = 0
+ self.remuneracao_penultimo_salario = 0
+ self.ultimo_salario = 0
+ self.numero_meses_trabalhados = '00'
+ self.recebeu_6_salario = '0'
+ self.aviso_previo_indenizado = '1'
+ self.codigo_banco = ''
+ self.codigo_agencia = ''
+ self.codigo_agencia_digito = ''
+ # ---------------------------------------------------------------------
+
+ # campos do TRAILLER -------------------------------------------------
+ self.tipo_de_registro_99 = '99'
+ self.total_requerimentos_informados = u''
+ # ---------------------------------------------------------------------
diff --git a/l10n_br_hr_arquivos_governo/models/financial_move.py b/l10n_br_hr_arquivos_governo/models/financial_move.py
new file mode 100644
index 000000000..7edab3aa0
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/financial_move.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE INFORMATICA LTDA
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from __future__ import division, print_function, unicode_literals
+
+import logging
+
+from openerp import fields, models
+
+_logger = logging.getLogger(__name__)
+
+
+class FinancialMove(models.Model):
+ _inherit = b'financial.move'
+
+ sefip_id = fields.Many2one(
+ comodel_name='l10n_br.hr.sefip',
+ string='Sefip',
+ )
diff --git a/l10n_br_hr_arquivos_governo/models/hr_contract_type.py b/l10n_br_hr_arquivos_governo/models/hr_contract_type.py
new file mode 100644
index 000000000..8563f86d5
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/hr_contract_type.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import fields, models
+
+
+class HrContractType(models.Model):
+ _inherit = 'hr.contract.type'
+
+ code = fields.Char(
+ string=u'Código do tipo de contrato',
+ )
diff --git a/l10n_br_hr_arquivos_governo/models/hr_payslip.py b/l10n_br_hr_arquivos_governo/models/hr_payslip.py
new file mode 100644
index 000000000..6345e5793
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/hr_payslip.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import fields, models
+
+
+class HrPayslip(models.Model):
+ _inherit = 'hr.payslip'
+
+ sefip_id = fields.Many2one(
+ comodel_name='l10n_br.hr.sefip',
+ string='Sefip',
+ )
diff --git a/l10n_br_hr_arquivos_governo/models/inherited_hr_salary_rule.py b/l10n_br_hr_arquivos_governo/models/inherited_hr_salary_rule.py
new file mode 100644
index 000000000..465112b23
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/inherited_hr_salary_rule.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE INFORMATICA LTDA
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from __future__ import division, print_function, unicode_literals
+
+from openerp import models, fields
+
+
+class HrSalaryRule(models.Model):
+ _inherit = b"hr.salary.rule"
+
+ codigo_darf = fields.Char(
+ string=b"Código da DARF",
+ )
diff --git a/l10n_br_hr_arquivos_governo/models/l10n_br_hr_caged.py b/l10n_br_hr_arquivos_governo/models/l10n_br_hr_caged.py
new file mode 100644
index 000000000..c62564eb3
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/l10n_br_hr_caged.py
@@ -0,0 +1,449 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import base64
+import logging
+from datetime import datetime
+
+from dateutil.relativedelta import relativedelta
+from openerp import api, fields, models, _
+from openerp.addons.l10n_br_hr_arquivos_governo.models.arquivo_caged \
+ import Caged
+from openerp.addons.l10n_br_hr_payroll.models.hr_payslip import MES_DO_ANO
+from openerp.exceptions import ValidationError, Warning
+
+_logger = logging.getLogger(__name__)
+
+try:
+ from pybrasil import telefone
+except ImportError:
+ _logger.info('Cannot import pybrasil')
+
+
+class CagedAttachment(models.Model):
+ _name = 'l10n_br.hr.caged.attachments'
+ _order = 'create_date'
+
+ name = fields.Char(string='Observações')
+ caged_id = fields.Many2one(
+ string='Arquivo do governo relacionado',
+ comodel_name=b'hr.caged'
+ )
+ attachment_ids = fields.Many2many(
+ string='Arquivo anexo',
+ comodel_name='ir.attachment',
+ relation='ir_attachment_caged_rel',
+ column1='caged_attachment_id',
+ column2='attachment_id',
+ )
+
+
+class HrCaged(models.Model):
+
+ _name = 'hr.caged'
+ _inherit = ['abstract.arquivos.governo.workflow', 'mail.thread']
+
+ related_attachment_ids = fields.One2many(
+ string='Anexos Relacionados',
+ comodel_name='l10n_br.hr.caged.attachments',
+ inverse_name='caged_id',
+ readonly=True, track_visibility='onchange',
+ states={'draft': [('readonly', False)], 'open': [('readonly', False)]}
+ )
+ mes_do_ano = fields.Selection(
+ selection=MES_DO_ANO,
+ string=u'Mês',
+ default=fields.Date.from_string(fields.Date.today()).month,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ ano = fields.Integer(
+ string=u'Ano',
+ default=fields.Date.from_string(fields.Date.today()).year,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ company_id = fields.Many2one(
+ comodel_name='res.company',
+ string=u'Empresa',
+ default=lambda self: self.env.user.company_id or '',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ caged_txt = fields.Text(
+ string='CAGED TXT',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ primeira_declaracao = fields.Boolean(
+ string='Primeira declaração?',
+ help='Define se é ou não a primeira declaração do estabelecimento ao '
+ 'Cadastro Geral de Empregados e Desempregados - '
+ 'CAGED Lei nº 4.923/65.',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ responsavel = fields.Many2one(
+ comodel_name='res.users',
+ string=u'Responsável',
+ default=lambda self: self.env.user,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+
+ @api.depends('responsavel')
+ def _set_info_responsavel(self):
+ if self.responsavel and self.responsavel.employee_ids:
+ employee = self.responsavel.employee_ids[0]
+ if employee:
+ self.email_responsavel = employee.work_email
+ self.cpf_responsavel = employee.cpf
+ self.telefone_responsavel = employee.work_phone
+
+ email_responsavel = fields.Char(
+ string='Email do Responsável',
+ compute=_set_info_responsavel,
+ )
+ cpf_responsavel = fields.Char(
+ string='CPF do Responsável',
+ compute=_set_info_responsavel,
+ )
+ telefone_responsavel = fields.Char(
+ string='Telefone do Responsável',
+ compute=_set_info_responsavel,
+ )
+
+ @api.constrains('mes_do_ano', 'ano', 'company_id')
+ def caged_restriction(self):
+ caged = self.search_count([
+ ('mes_do_ano', '=', self.mes_do_ano),
+ ('ano', '=', self.ano),
+ ('company_id', '=', self.company_id.id),
+ ])
+ if caged > 1:
+ raise ValidationError(u'Ja existe Caged neste período.')
+
+# 5.1. Especificação Técnica do Arquivo
+# · Campos alfabéticos:
+# Todos os dados alfabéticos devem ser informados com caracteres maiúsculos.
+# Os caracteres de edição ou máscara (pontos, vírgulas, traços, barras, etc.)
+# devem ser omitidos.
+# · Campos numéricos:
+# Todos os dados numéricos devem ser completados com zeros à esquerda.
+# · Campo filler:
+# Campo sem informação, deixar em branco.
+# · Layout:
+# arquivo padrão ASCII
+# tamanho do registro: 240 posições
+# nome do arquivo de movimento mensal: CGEDaaaa.Mmm
+# Onde: aaaa = ano de referência
+# mm = mês de referência
+# Nome do arquivo Acerto: Addaaaa.Mmm
+# Onde: aaaa = ano de referência
+# mm = mês de referência
+# dd = dia de referência
+
+ def _preencher_registro_A(self, caged, total_movimentacoes, sequencia):
+ """
+ Registro A
+ Dado um contrato, computar a linha de preenchimento do caged relativa
+ ao preenchimento das informações da empresa responsavel pelas infos.
+ :param contrato - hr.contract -
+ :param caged - arquivo_caged
+ :return: str - Linha de preenchimento do funcioario
+ """
+ company_id = self.company_id
+ # Data da competencia
+ caged.A_competencia = str(self.mes_do_ano) + str(self.ano)
+ # 1 - Nada a alterar
+ # 2 - Alterar dados cadastrais
+ caged.A_alteracao = 1
+ caged.A_sequencia = sequencia
+ # Tipo de 1 - CNPJ | 2 - CEI
+ caged.A_tipo_identificador = 1
+ caged.A_identificador_autorizado = company_id.cnpj_cpf
+ caged.A_razao_social = company_id.legal_name
+ caged.A_endereco = (company_id.street or '') + \
+ (company_id.street2 or '') + \
+ (company_id.number or '')
+ caged.A_cep = company_id.zip
+ caged.A_uf = company_id.state_id.code
+ # Telefone e DDD a partir do phone do res_company
+ if company_id.phone:
+ ddd, numero = telefone.telefone.separa_fone(company_id.phone)
+ else:
+ ddd = ' '
+ numero = ' '
+
+ caged.A_ddd = ddd
+ caged.A_telefone = numero
+ caged.A_ramal = ''
+ # Quantidade de registros tipo B (Estabelecimento) no arquivo.
+ caged.A_total_estabelecimento_informados = 1
+ # Quantidade de registros tipo C e/ou X (Empregado) no arquivo.
+ caged.A_total_movimentacoes_informados = total_movimentacoes
+
+ return caged._registro_A()
+
+ def _preencher_registro_B(self, caged, sequencia):
+ """
+ Dado um contrato, computar a linha de preenchimento do caged relativa
+ ao preenchimento das informações da empresa que esta sendo informada.
+ :param contrato - hr.contract -
+ :return: str - Linha de preenchimento do funcioario
+ """
+ company_id = self.company_id
+ qtd_funcionarios = self.env['hr.contract'].search_count([
+ ('company_id', '=', self.company_id.id),
+ ('date_end', '=', False),
+ ('categoria', '=', 101),
+ ])
+
+ caged.B_sequencia = sequencia
+ # Tipo de 1 - CNPJ | 2 - CEI
+ caged.B_tipo_identificador = 1
+ caged.B_identificador_estabelecimento = company_id.cnpj_cpf
+
+ # TO DO : Definir como sera preenchido esse campo
+ # 1. primeira declaração
+ # 2. já informou ao CAGED anteriormente
+ caged.B_primeira_declaracao = 1 if self.primeira_declaracao else 2
+
+ # 1 - Nada a alterar
+ # 2 - Alterar dados cadastrais
+ caged.B_alteracao = 1
+
+ caged.B_cep = company_id.zip
+ caged.B_razao_social = company_id.legal_name
+ caged.B_endereco = (company_id.street or '') + \
+ (company_id.street2 or '') + \
+ (company_id.number or '')
+ caged.B_bairro = company_id.district
+ caged.B_uf = company_id.state_id.code
+ # Como vai calcular esse campo?
+ # criar categoria no contrato
+ caged.B_total_empregados_existentes = qtd_funcionarios
+ caged.B_total_empregados_existentes = 33
+
+ # 1 – Microempresa – para a pessoa jurídica, ou a ela equiparada,
+ # que auferir, em cada ano-calendário, receita bruta igual ou inferior
+ # a R$ 240.000,00 (duzentos e quarenta mil reais).
+ # 2 - Empresa de Pequeno Porte – para a pessoa jurídica, ou a ela
+ # equiparada, que auferir, em cada ano-calendário, receita bruta
+ # superior a R$ 240.000,00 (duzentos e quarenta mil reais) e igual ou
+ # inferior a R$ 2.400.000,00 (dois milhões e quatrocentos mil reais).
+ # 3 – Empresa/Órgão não classificados – este campo só deve ser
+ # selecionado se o estabelecimento não se enquadrar como
+ # MEI, microempresa ou empresa de pequeno porte.
+ # 4 – Microempreendedor Individual – para o empresário individual
+ # que tenha auferido receita bruta, no ano-calendário anterior,
+ # de até R$36.000,00 (trinta e seis mil reais).
+ caged.B_porte_estabelecimento = 3
+
+ caged.B_CNAE = company_id.cnae_main_id.code or ''
+ caged.B_ddd = '0061'
+ caged.B_telefone = company_id.phone
+ caged.B_telefone = company_id.phone
+ caged.B_email = company_id.email
+ return caged._registro_B()
+
+ def _preencher_registro_C(self, contrato, caged, seq):
+ """
+ Dado um contrato, computar a linha de preenchimento do caged relativa
+ ao preenchimento das informações do funcionario.
+ :param contrato - hr.contract -
+ :return: str - Linha de preenchimento do funcionario
+ """
+ company_id = self.company_id
+ employee_id = contrato.employee_id
+
+ caged.C_tipo_identificador = 1
+ caged.C_identificador_estabelecimento = company_id.cnpj_cpf
+ caged.C_sequencia = seq
+ caged.C_PIS_PASEP = employee_id.pis_pasep
+ caged.C_sexo = 1 if employee_id.gender == 'male' else 2
+ caged.C_nascimento = employee_id.birthday
+ caged.C_grau_instrucao = employee_id.educational_attainment.code
+ caged.C_salario_mensal = contrato.wage
+ caged.C_horas_trabalhadas = contrato.weekly_hours
+ caged.C_tipo_de_movimento = contrato.labor_bond_type_id.code
+ caged.C_admissao = contrato.date_start
+ caged.C_dia_desligamento = contrato.date_end
+ caged.C_nome_empregado = employee_id.name
+ caged.C_numero_ctps = employee_id.ctps
+ caged.C_serie_ctps = employee_id.ctps_series
+ caged.C_raca_cor = employee_id.ethnicity
+ # 1 - Para indicar SIM
+ # 2 - Para indicar NÃO
+ caged.C_pessoas_com_deficiencia = 2
+ caged.C_cbo2000 = contrato.job_id.cbo_id.code
+ # Informar se o empregado é Aprendiz ou não. pela categoria
+ # 1 - SIM
+ # 2 – NÃO
+ caged.C_aprendiz = 2 if contrato.categoria != '103' else 1
+ caged.C_uf_ctps = employee_id.ctps_uf_id.code
+ caged.C_tipo_deficiencia = employee_id.deficiency_id.code
+ caged.C_CPF = employee_id.cpf
+ caged.C_cep_residencia = employee_id.address_home_id.zip
+ return caged._registro_C()
+
+ def _preencher_registro_X(self, contrato, caged, seq):
+ """
+ Dado um contrato, computar a linha de preenchimento do caged relativa
+ ao preenchimento das informações do funcionario.
+ :param contrato - hr.contract -
+ :return: str - Linha de preenchimento do funcionario
+ """
+ caged.X_tipo_de_registro = ''
+ caged.X_tipo_identificador = ''
+ caged.X_identificador_estabelecimento = ''
+ caged.X_sequencia = seq
+ caged.X_PIS_PASEP = ''
+ caged.X_sexo = ''
+ caged.X_nascimento = ''
+ caged.X_grau_instrucao = ''
+ caged.X_salario_mensal = ''
+ caged.X_horas_trabalhadas = ''
+ caged.X_admissao = ''
+ caged.X_tipo_de_movimento = ''
+ caged.X_dia_desligamento = ''
+ caged.X_nome_empregado = ''
+ caged.X_numero_ctps = ''
+ caged.X_serie_ctps = ''
+ caged.X_uf_ctps = ''
+ caged.X_atualizacao = ''
+ caged.X_competencia = ''
+ caged.X_raca_cor = ''
+ caged.X_pessoas_com_deficiencia = ''
+ caged.X_cbo2000 = ''
+ caged.X_aprendiz = ''
+ caged.X_tipo_deficiencia = ''
+ caged.X_CPF = ''
+ caged.X_cep_residencia = ''
+ return caged._registro_X()
+
+ def _preencher_registro_Z(self, caged):
+ """
+ Preencher informações do contato referente ao registro Z
+ """
+ caged.Z_responsavel = self.responsavel.name
+ caged.Z_email_responsavel = self.email_responsavel
+ caged.Z_cpf_responsavel = self.cpf_responsavel
+ return caged._registro_Z()
+
+ @api.multi
+ def action_open(self):
+ for record in self:
+ record.criar_anexo_caged()
+ super(HrCaged, record).action_open()
+
+ @api.multi
+ def criar_anexo_caged(self):
+ caged = Caged()
+ # Cria um arquivo temporario txt do CAGED e escreve o que foi gerado
+ path_arquivo = caged._gerar_arquivo_temp(self.caged_txt, 'CAGED')
+ # Gera o anexo apartir do txt do grrf no temp do sistema
+ mes = str(self.mes_do_ano) \
+ if self.mes_do_ano > 9 else '0' + str(self.mes_do_ano)
+ nome_arquivo = 'CGED' + str(self.ano) + '.M' + mes
+ self._gerar_anexo(nome_arquivo, path_arquivo)
+
+ @api.multi
+ def doit(self):
+
+ contrato_model = self.env['hr.contract']
+
+ # Recuperar data inicial e final para CAGED
+ primeiro_dia_do_mes = datetime.strptime(str(self.mes_do_ano) + '-' +
+ str(self.ano), '%m-%Y')
+ ultimo_dia_do_mes = primeiro_dia_do_mes + relativedelta(months=1) - \
+ relativedelta(days=1)
+
+ # Contratacoes do mes
+ domain = [
+ ('company_id', '=', self.company_id.id),
+ ('date_start', '<=', ultimo_dia_do_mes),
+ ('date_start', '>=', primeiro_dia_do_mes),
+ ('categoria', 'not in', ['721', '722'])
+ ]
+ contratacoes = contrato_model.search(domain)
+
+ # Demissoes do mes
+ domain = [
+ ('company_id', '=', self.company_id.id),
+ ('date_end', '<=', ultimo_dia_do_mes),
+ ('date_end', '>=', primeiro_dia_do_mes),
+ ('categoria', 'not in', ['721', '722'])
+ ]
+ demissoes = contrato_model.search(domain)
+
+ # Total de movimentações (Registro C)
+ total_mov = len(contratacoes) + len(demissoes)
+
+ # Instancia um objeto do Caged
+ caged = Caged()
+
+ # Variavel para guardar as informacoes do caged e da sequencia
+ caged_txt = ''
+
+ sequencia = 1
+
+ # Preencher o objeto com informações da empresa
+ # Registro A
+ caged_txt += self._preencher_registro_A(caged, total_mov, sequencia)
+ sequencia += 1
+ # Registro B
+ caged_txt += self._preencher_registro_B(caged, sequencia)
+ sequencia += 1
+
+ # Registros C
+ for contrato in contratacoes:
+ caged_txt += \
+ self._preencher_registro_C(contrato, caged, sequencia)
+ sequencia += 1
+
+ for contrato in demissoes:
+ caged_txt += self._preencher_registro_C(contrato, caged, sequencia)
+ sequencia += 1
+
+ # Preencher informações do Registro Z (contato)
+ caged_txt += self._preencher_registro_Z(caged)
+
+ # Guardar campo no modelo com informações do CAGED
+ self.caged_txt = caged_txt
+
+ return True
+
+ def _gerar_anexo(self, nome_do_arquivo, path_arquivo_temp):
+ """
+ Função para gerar anexo dentro do holerite, apartir de um arquivo
+ temporário. Deve ser passado o path do arquivo temporário que se
+ tornará anexo da payslip
+ :param nome_do_arquivo:
+ :param path_arquivo_temp:
+ :return:
+ """
+ caged_attach_obj = self.env['l10n_br.hr.caged.attachments']
+ try:
+ file_attc = open(path_arquivo_temp, 'r')
+ attc = file_attc.read()
+
+ attachment_data = {
+ 'name': nome_do_arquivo,
+ 'datas_fname': nome_do_arquivo,
+ 'datas': base64.b64encode(attc),
+ 'res_model': 'l10n_br.hr.caged.attachments',
+ }
+
+ caged_attachment_data = {
+ 'name': 'Arquivo Caged',
+ 'attachment_ids': [(0, 0, attachment_data)],
+ 'caged_id': self.id,
+ }
+ caged_attach_obj.create(caged_attachment_data)
+
+ file_attc.close()
+ except:
+ raise Warning(
+ _('Impossível gerar Anexo do %s' % nome_do_arquivo))
diff --git a/l10n_br_hr_arquivos_governo/models/l10n_br_hr_contract.py b/l10n_br_hr_arquivos_governo/models/l10n_br_hr_contract.py
new file mode 100644
index 000000000..983fa25ad
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/l10n_br_hr_contract.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import api, exceptions, fields, models, _
+
+from ..constantes_rh import CATEGORIA_TRABALHADOR, CATEGORIA_TRABALHADOR_SEFIP
+
+
+class HrContract(models.Model):
+ _inherit = 'hr.contract'
+
+ weekly_hours = fields.Float(
+ default=40,
+ )
+
+ @api.constrains('weekly_hours')
+ def _check_weekly_hours(self):
+ if self.weekly_hours < 1:
+ raise exceptions.Warning(
+ _('A quantidade de horas semanais deve estar entre 1 e 44.'))
+
+ @api.multi
+ @api.depends('categoria')
+ def _compute_categoria_sefip(self):
+
+ for record in self:
+ if record.categoria in ('701', '702', '703'):
+ #
+ # Autônomo
+ #
+ record.categoria_sefip = '13'
+ elif record.categoria == '721':
+ #
+ # Pró-labore
+ #
+ record.categoria_sefip = '05'
+ elif record.categoria == '722':
+ #
+ # Pró-labore 2
+ #
+ record.categoria_sefip = '11'
+ elif record.categoria == '103':
+ #
+ # Aprendiz
+ #
+ record.categoria_sefip = '07'
+ else:
+ record.categoria_sefip = '01'
+
+ categoria_sefip = fields.Selection(
+ selection=CATEGORIA_TRABALHADOR_SEFIP,
+ compute='_compute_categoria_sefip',
+ store=True,
+ )
+
+ categoria = fields.Selection(
+ selection=CATEGORIA_TRABALHADOR,
+ string="Categoria do Contrato",
+ required=True,
+ default='101',
+ )
diff --git a/l10n_br_hr_arquivos_governo/models/l10n_br_hr_payslip.py b/l10n_br_hr_arquivos_governo/models/l10n_br_hr_payslip.py
new file mode 100644
index 000000000..76532438f
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/l10n_br_hr_payslip.py
@@ -0,0 +1,230 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import base64
+
+from openerp import api, fields, exceptions, models, _
+
+from .arquivo_grrf import Grrf
+from .arquivo_seguro_desemprego import SeguroDesemprego
+
+
+class HrPayslip(models.Model):
+
+ _inherit = 'hr.payslip'
+
+ attachment_ids = fields.Many2many(
+ comodel_name='ir.attachment',
+ relation='hr_payslip_attachment_rel',
+ column1='hr_payslip',
+ column2='attachment_id',
+ string=u'Attachments'
+ )
+
+ grrf_txt = fields.Text(
+ string='GRRF',
+ )
+
+ seguro_desemprego_txt = fields.Text(
+ string='Seguro Desemprego',
+ )
+
+ @api.multi
+ def compute_seguro_desemprego(self):
+ """
+ Método que inicia o processo para gerar novo GRRF. Disparado na view.
+ :return:
+ """
+ for holerite in self:
+ # Instancia a classe do seguro desemprego
+ seguro_desemprego = SeguroDesemprego()
+ # preenche o objeto com informações do holerite de rescisao
+ self._preencher_seguro_desemprego(holerite, seguro_desemprego)
+ # Gera o campo texto e atribui ao campo da payslip
+ holerite.seguro_desemprego_txt = \
+ seguro_desemprego._gerar_arquivo_seguro_desemprego()
+ # Gera um arquivo temporário com o texto do seguro Desemprego
+ path_arquivo = seguro_desemprego._gerar_arquivo_temp(
+ holerite.seguro_desemprego_txt, 'SEGURO_DESEMPREGO')
+ # Gera anexo da payslip
+ self._gerar_anexo('DESLIGAMENTOS.SD', path_arquivo)
+
+ @api.multi
+ def compute_grrf(self):
+ """
+ Método que inicia o processo para gerar novo TXt do Seguro Desemprego.
+ Disparado na view.
+ :return:
+ """
+ for holerite in self:
+ grrf = Grrf()
+ # Preencher o objeto com informações do holerite
+ self._preencher_grrf(holerite, grrf)
+ # Depois de preencher o objeto, chama a função para computar o txt
+ holerite.grrf_txt = grrf._gerar_grrf()
+ # Cria um arquivo temporario txt do grrf e escreve o que foi gerado
+ path_arquivo = grrf._gerar_arquivo_temp(holerite.grrf_txt, 'GRRF')
+ # Gera o anexo apartir do txt do grrf no temp do sistema
+ self._gerar_anexo('grrf.re', path_arquivo)
+
+ def _preencher_seguro_desemprego(self, holerite, seguro_desemprego):
+ """
+ Dado um holerite de rescisao preencher os campos do objeto de GRRF
+ :param holerite: hr.payslip
+ :param seguro_desemprego: obj arquivo_seguro_desemprego
+ :return:
+ """
+ # HEADER
+ seguro_desemprego.tipo_de_inscricao_empresa = 1 # 1 (CNPJ) ou 2 (CEI)
+ seguro_desemprego.cnpj_empresa = self.company_id.cnpj_cpf
+
+ # REQUERIMENTO
+ funcionario = holerite.contract_id.employee_id
+ seguro_desemprego.cpf = funcionario.cpf
+ seguro_desemprego.nome = funcionario.name
+ seguro_desemprego.endereco = funcionario.address_home_id.street
+ seguro_desemprego.complemento = funcionario.address_home_id.street2
+ seguro_desemprego.cep = funcionario.address_home_id.zip
+ seguro_desemprego.uf = funcionario.address_home_id.state_id.code
+ seguro_desemprego.telefone = funcionario.address_home_id.phone
+ seguro_desemprego.nome_mae = funcionario.mother_name
+ seguro_desemprego.pis = funcionario.pis_pasep
+ seguro_desemprego.carteira_trabalho_numero = funcionario.ctps
+ seguro_desemprego.carteira_trabalho_estado = \
+ funcionario.ctps_uf_id.code
+ seguro_desemprego.CBO = holerite.contract_id.job_id.cbo_id.code
+ seguro_desemprego.data_admissao = holerite.contract_id.date_start
+ seguro_desemprego.data_demissao = holerite.contract_id.date_end
+ seguro_desemprego.sexo = funcionario.gender
+ seguro_desemprego.grau_instrucao = \
+ funcionario.educational_attainment.code
+ seguro_desemprego.data_nascimento = funcionario.birthday
+ seguro_desemprego.horas_trabalhadas_semana = \
+ holerite.contract_id.weekly_hours
+ remuneracao_mes_rescisao = 0
+ for line in holerite.line_ids:
+ if line.code == 'BASE_FGTS':
+ remuneracao_mes_rescisao = line.total
+ # Get Rubrica do BASE_FGTS
+ seguro_desemprego.ultimo_salario = remuneracao_mes_rescisao
+ # self.numero_meses_trabalhados = '00'
+ # self.recebeu_6_salario = '0'
+ # self.aviso_previo_indenizado = '1'
+ self.codigo_banco = ''
+ self.codigo_agencia = ''
+ self.codigo_agencia_digito = ''
+
+ # TRAILLER
+ seguro_desemprego.sequencia = 1
+
+ def _preencher_grrf(self, holerite, grrf):
+ """
+ Dado um holerite de rescisao preencher os campos do objeto de GRRF
+ :param holerite:
+ :param grrf:
+ :return:
+ """
+ # Informações do Responsavel
+
+ # Data de pagamento do holerite de rescisao
+ grrf.data_recolhimento_grrf = ''
+ # Pessoa que esta logada
+ grrf.nome_do_contato_responsavel = self.env.user.name
+ # Telefone pessoa que esta logada
+ grrf.telefone_contato_responsavel = self.env.user.phone
+ # Email do usuario logado
+ grrf.email_contato = self.env.user.email
+
+ # informações da Empresa
+ grrf.tipo_de_inscricao_empresa = 1 # 1 (CNPJ) ou 2 (CEI)
+ grrf.inscricao_da_empresa = self.company_id.cnpj_cpf
+ grrf.razao_social_empresa = self.company_id.legal_name
+ grrf.endereco_empresa = \
+ (self.company_id.street or '') + (self.company_id.number or '')
+ grrf.bairro_empresa = self.company_id.street2
+ grrf.cep_empresa = self.company_id.zip
+ grrf.cidade_empresa = self.company_id.l10n_br_city_id.name
+ grrf.unidade_federacao_empresa = self.company_id.state_id.code
+ grrf.telefone_empresa = self.company_id.phone
+ grrf.CNAE_fiscal = self.company_id.cnae_main_id.code or ''
+ grrf.fpas = u'515' # Fixo
+
+ if self.company_id.fiscal_type == 1: # Simples nacional Odoo
+ simples = 2 # Simples do Layout
+ else: # Se nao for do simples
+ simples = 1 # 1 == Não Optante
+ grrf.simples = simples
+
+ # Informação do trabalhador
+ funcionario = holerite.contract_id.employee_id
+ grrf.PIS_PASEP = funcionario.pis_pasep
+ grrf.data_admissao = holerite.contract_id.date_start
+ # 01 Empregado; | 02 Trabalhador Avulso | 03 Trabalhador não vinculadO
+ grrf.categoria_trabalhador = u'01'
+ grrf.nome_do_trabalhador = funcionario.name
+ grrf.numero_ctps = funcionario.ctps
+ grrf.serie_ctps = funcionario.ctps_series
+ grrf.sexo = funcionario.gender
+ grrf.grau_de_instrucao = funcionario.educational_attainment.code
+ grrf.data_nascimento = funcionario.birthday
+ grrf.CBO = holerite.contract_id.job_id.cbo_id.code
+ # Data admissao
+ grrf.data_opcao = holerite.contract_id.date_start
+ # Código de movimentação da sefip
+ grrf.codigo_da_movimentacao = holerite.struct_id.tipo_afastamento_sefip
+ # Data cara sai da empresa
+ grrf.data_movimentacao = holerite.date_to
+ grrf.codigo_de_saque = holerite.struct_id.tipo_saque
+ grrf.aviso_previo = u'2'
+ grrf.data_inicio_aviso_previo = holerite.date_from
+ grrf.reposicao_de_vaga = u'N'
+
+ remuneracao_mes_rescisao = 0
+ aviso_previo_indenizado = 0
+ for line in holerite.line_ids:
+ if line.code == 'BASE_FGTS':
+ remuneracao_mes_rescisao = line.total
+ if line.code == 'BRUTO_AVISO_PREVIO':
+ aviso_previo_indenizado = line.total
+
+ # Get Rubrica do BASE_FGTS
+ grrf.remuneracao_mes_rescisao = remuneracao_mes_rescisao
+ # Rubrica Bruto Aviso previo para somar todos dados de aviso previo
+ grrf.aviso_previo_indenizado = aviso_previo_indenizado
+
+ grrf.CPF = funcionario.cpf
+ grrf.banco_conta_trabalhador = ''
+ grrf.agencia_trabalhador = ''
+ grrf.conta_trabalhador = ''
+ # saldo do FGTS consulta manual na caixa
+ grrf.saldo_para_fins_rescisorios = \
+ holerite.saldo_para_fins_rescisorios \
+ if holerite.saldo_para_fins_rescisorios else ''
+
+ def _gerar_anexo(self, nome_do_arquivo, path_arquivo_temp):
+ """
+ Função para gerar anexo dentro do holerite, apartir de um arquivo
+ temporário. Deve ser passado o path do arquivo temporário que se
+ tornará anexo da payslip
+ :param nome_do_arquivo:
+ :param path_arquivo_temp:
+ :return:
+ """
+ try:
+ file_attc = open(path_arquivo_temp, 'r')
+ attc = file_attc.read()
+ attachment_obj = self.env['ir.attachment']
+ attachment_data = {
+ 'name': nome_do_arquivo,
+ 'datas_fname': nome_do_arquivo,
+ 'datas': base64.b64encode(attc),
+ 'res_model': 'hr.payslip',
+ 'res_id': self.id,
+ }
+ attachment_obj.create(attachment_data)
+ file_attc.close()
+
+ except:
+ raise exceptions.Warning(
+ _('Impossível gerar Anexo do %s' % nome_do_arquivo))
diff --git a/l10n_br_hr_arquivos_governo/models/l10n_br_hr_sefip.py b/l10n_br_hr_arquivos_governo/models/l10n_br_hr_sefip.py
new file mode 100644
index 000000000..6ac63f12b
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/l10n_br_hr_sefip.py
@@ -0,0 +1,1631 @@
+# -*- coding: utf-8 -*-
+# (c) 2017 KMEE INFORMATICA LTDA - Daniel Sadamo
+# (c) 2017 KMEE INFORMATICA LTDA - Luis Felipe Mileo
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+from __future__ import (
+ division, print_function, unicode_literals, absolute_import
+)
+
+import os
+import tempfile
+import logging
+import base64
+import pybrasil
+from py3o.template import Template
+from datetime import timedelta
+from openerp import api, fields, models, _
+from openerp.exceptions import ValidationError
+from pybrasil.valor import formata_valor
+from pybrasil.data import formata_data
+import subprocess
+import calendar
+
+from openerp.addons.l10n_br_base.tools.misc import punctuation_rm
+
+from .arquivo_sefip import SEFIP
+from ..constantes_rh import (
+ MESES,
+ MODALIDADE_ARQUIVO,
+ CODIGO_RECOLHIMENTO,
+ RECOLHIMENTO_GPS,
+ RECOLHIMENTO_FGTS,
+)
+
+_logger = logging.getLogger(__name__)
+CURDIR = os.path.dirname(os.path.abspath(__file__))
+
+
+class SefipAttachments(models.Model):
+ _name = b'l10n_br.hr.sefip.attachments'
+ _order = b'create_date'
+
+ name = fields.Char(string='Observações')
+ type = fields.Selection(string='Tipo', selection=[
+ ('sent', 'Enviado'),
+ ('relatorio', 'relatorio'),
+ ], default='relatorio')
+ sefip_id = fields.Many2one(
+ string='Arquivo do governo relacionado',
+ comodel_name=b'l10n_br.hr.sefip'
+ )
+ attachment_ids = fields.Many2many(
+ string='Arquivo anexo',
+ comodel_name='ir.attachment',
+ relation='ir_attachment_sefip_rel',
+ column1='sefip_attachment_id',
+ column2='attachment_id',
+ )
+
+
+class L10nBrSefip(models.Model):
+ _name = b'l10n_br.hr.sefip'
+ _inherit = [b'abstract.arquivos.governo.workflow', b'mail.thread']
+
+ @api.multi
+ @api.onchange('company_id')
+ def onchange_company_id(self):
+ for sefip in self:
+ if sefip.responsible_user_id:
+ if sefip.responsible_user_id.parent_id != \
+ sefip.company_id.partner_id:
+ sefip.responsible_user_id = False
+ return {
+ 'domain': {
+ 'responsible_user_id':
+ [('parent_id', '=', sefip.company_id.partner_id.id)]
+ }
+ }
+
+ @api.multi
+ def name_get(self):
+ result = []
+ meses = dict(MESES)
+ for record in self:
+ name = (self.company_id.name + ' ' + meses.get(self.mes) +
+ '/' + self.ano + ' - Recolhimento: ' +
+ self.codigo_recolhimento)
+ result.append((record.id, name))
+ return result
+
+ @api.one
+ @api.depends('codigo_recolhimento')
+ def _compute_eh_obrigatorio_informacoes_processo(self):
+ if self.codigo_recolhimento in ('650', '660'):
+ self.eh_obrigatorio_informacoes_processo = True
+ else:
+ self.eh_obrigatorio_informacoes_processo = False
+
+ @api.one
+ @api.depends('codigo_recolhimento', 'codigo_fpas')
+ def _compute_eh_obrigatorio_codigo_outras_entidades(self):
+ if self.codigo_recolhimento in (
+ '115', '130', '135', '150', '155', '211', '608', '650'):
+ self.eh_obrigatorio_codigo_outras_entidades = True
+ else:
+ self.eh_obrigatorio_codigo_outras_entidades = False
+ self.codigo_outras_entidades = False
+ if self.codigo_fpas == '582':
+ self.codigo_outras_entidades = '0'
+
+ @api.multi
+ def _valor_rubrica(self, rubricas, codigo_rubrica):
+ for rubrica in rubricas:
+ if rubrica.code == codigo_rubrica:
+ return rubrica.total
+ return 0.00
+
+ @api.multi
+ def _buscar_codigo_outras_entidades(self):
+
+ # Se adaptar com o 13 salario onde mes == '13'. A variavel sera set 12
+ mes = self.mes if self.mes <= '12' else '12'
+
+ if (fields.Date.from_string(self.ano + "-" + mes + "-01") <
+ fields.Date.from_string("1998-10-01")):
+ return ' '
+ if self.codigo_recolhimento in \
+ ['115', '130', '135', '150', '155', '211', '608', '650']:
+ return self.company_id.codigo_outras_entidades
+ if self.codigo_recolhimento in \
+ ['145', '307', '317', '327', '337', '345', '640', '660']:
+ return self.company_id.codigo_outras_entidades
+ if self.codigo_fpas == "582" and fields.Date.\
+ from_string(mes + "-" + self.ano + "-01") >= fields.\
+ Date.from_string("1999-04-01"):
+ return '0000'
+ if self.codigo_fpas == "639" and fields.Date.\
+ from_string(mes + "-" + self.ano + "-01") < fields.Date.\
+ from_string("1998-10-01"):
+ return ' '
+ if self.codigo_fpas == "868":
+ return '0000'
+ if self._simples(self.company_id) in ['1', '4', '5']:
+ return self.company_id.codigo_outras_entidades
+ if self._simples(self.company_id) in ['2', '3', '6']:
+ return ' '
+
+ @api.multi
+ def _buscar_codigo_pagamento_gps(self):
+
+ # Se adaptar com o 13 salario onde mes == '13'. A variavel sera set 12
+ mes = self.mes if self.mes <= '12' else '12'
+
+ if fields.Date.from_string(self.ano + "-" + mes + "-01") <\
+ fields.Date.from_string("1998-10-01"):
+ return ' '
+ if self.codigo_recolhimento in ['115', '150', '211', '650']:
+ return self.company_id.codigo_recolhimento_GPS
+ if self.codigo_fpas == "868":
+ if self.company_id.codigo_recolhimento_GPS in ['1600', '1651']:
+ return self.company_id.codigo_recolhimento_GPS
+ return ' '
+
+ @api.multi
+ def _buscar_isencao_filantropia(self):
+ if self.codigo_fpas == "639":
+ return str("%05d" % self.porcentagem_filantropia * 100)
+ return ' '
+
+ related_attachment_ids = fields.One2many(
+ string='Anexos Relacionados',
+ comodel_name='l10n_br.hr.sefip.attachments',
+ inverse_name='sefip_id',
+ readonly=True, track_visibility='onchange',
+ states={'draft': [('readonly', False)], 'open': [('readonly', False)]}
+ )
+ responsible_user_id = fields.Many2one(
+ comodel_name='res.partner', string=u'Usuário Responsável',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ company_id = fields.Many2one(
+ comodel_name='res.company', string=u'Empresa',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ mes = fields.Selection(
+ selection=MESES, string=u'Mês',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ ano = fields.Char(
+ string=u'Ano', size=4,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ modalidade_arquivo = fields.Selection(
+ selection=MODALIDADE_ARQUIVO, string=u'Modalidade do arquivo',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ help= '• Pode ser:'
+ '\nBranco – Recolhimento ao FGTS e Declaração à Previdência'
+ '\n1 - Declaração ao FGTS e à Previdência'
+ '\n9 - Confirmação Informações anteriores – Rec/Decl ao FGTS e Decl à Previdência'
+ '\n • Para competência anterior a 10/1998 deve ser igual a branco ou 1.'
+ '\n • A modalidade 9 não pode ser informada para competências anteriores a 10/1998.'
+ '\n • Para os códigos 145, 307, 317, 327, 337, 345 e 640 deve ser igual a branco.'
+ '\n • Para o código 211 deve ser igual a 1 ou 9.'
+ '\n • Para o FPAS 868 deve igual a branco ou 9.'
+ '\n • Para a competência 13, deve ser igual a 1 ou 9.'
+ '\n • Serão acatadas até três cargas consecutivas de SEFIP.RE.'
+ '\n • Deverá existir apenas um arquivo SEFIP.RE para cada modalidade.',
+ )
+ codigo_recolhimento = fields.Selection(
+ string=u'Código de recolhimento', selection=CODIGO_RECOLHIMENTO,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ recolhimento_fgts = fields.Selection(
+ string=u'Recolhimento do FGTS', selection=RECOLHIMENTO_FGTS,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ data_recolhimento_fgts = fields.Date(
+ string=u'Data de recolhimento do FGTS',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ codigo_recolhimento_gps = fields.Integer(
+ string=u'Código de recolhimento do GPS',
+ related='company_id.codigo_recolhimento_GPS',
+ store=True,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ recolhimento_gps = fields.Selection(
+ string=u'Recolhimento do GPS', selection=RECOLHIMENTO_GPS,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ data_recolhimento_gps = fields.Date(
+ string=u'Data de recolhimento do GPS',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ codigo_fpas = fields.Char(
+ string=u'Código FPAS',
+ default='736',
+ required=True,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ help="""Campo obrigatório:\n
+ • Deve ser um FPAS válido.\n
+ • Deve ser diferente de 744 e 779, pois as GPS desses códigos serão
+ geradas automaticamente, sempre que forem informados os respectivos
+ fatos geradores dessas contribuições.\n
+ • Deve ser diferente de 620, pois a informação das categorias 15, 16,
+ 18, 23 e 25 indica os respectivos fatos geradores dessas
+ contribuições.\n
+ • Deve ser diferente de 663 e 671 a partir da competência 04/2004.\n
+ • Deve ser igual a 868 para empregador doméstico."""
+ )
+ eh_obrigatorio_codigo_outras_entidades = fields.Boolean(
+ compute='_compute_eh_obrigatorio_codigo_outras_entidades',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ codigo_outras_entidades = fields.Selection(
+ string=u'Código de outras entidades',
+ related='company_id.codigo_outras_entidades',
+ store=True,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ eh_obrigatorio_informacoes_processo = fields.Boolean(
+ compute='_compute_eh_obrigatorio_informacoes_processo',
+ default=False,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ data_geracao = fields.Date(
+ string=u'Data do arquivo',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ # Processo ou convenção coletiva
+ num_processo = fields.Char(
+ string=u'Número do processo',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ ano_processo = fields.Char(
+ string=u'Ano do processo', size=4,
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ vara_jcj = fields.Char(
+ string=u'Vara/JCJ',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ data_inicio = fields.Date(
+ string=u'Data de Início',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ data_termino = fields.Date(
+ string=u'Data de término',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ sefip = fields.Text(
+ string=u'Prévia do SEFIP',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+ data_vencimento_grcsu = fields.Date(
+ string=u'Data de Vencimento da GRCSU',
+ )
+
+ folha_ids = fields.One2many(
+ string='Holerites',
+ comodel_name='hr.payslip',
+ inverse_name='sefip_id',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+
+ boletos_ids = fields.One2many(
+ string='Guias/Boletos',
+ comodel_name='financial.move',
+ inverse_name='sefip_id',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+
+ @api.onchange('company_id', 'ano', 'mes')
+ def _onchange_data_vencimento_grcsu(self):
+ self.ensure_one()
+ if not (self.ano and self.mes and self.company_id):
+ return
+
+ mes = self.mes if self.mes < '13' else '12'
+ ultimo_dia_mes = str(self.ano) + '-' + mes + '-01'
+ ultimo_dia_mes = pybrasil.data.mes_que_vem(ultimo_dia_mes)
+ ultimo_dia_mes = pybrasil.data.ultimo_dia_mes(ultimo_dia_mes)
+ estado = self.company_id.state_id.code
+ municipio = self.company_id.l10n_br_city_id.name
+ self.data_vencimento_grcsu = pybrasil.data.dia_util_pagamento(
+ ultimo_dia_mes,
+ estado=estado,
+ municipio=municipio,
+ antecipa=True
+ )
+
+ # segundo o leiaute do SEFIP para competencia 13 esse campo deverá ser
+ # igual a 1 ou 9.
+ if self.mes == '13':
+ self.modalidade_arquivo = '1'
+ self.recolhimento_fgts = ' '
+
+ def _valida_tamanho_linha(self, linha):
+ """Valida tamanho da linha (sempre igual a 360 posições) e
+ adiciona quebra caso esteja correto"""
+ if len(linha) == 360:
+ return linha + '\r\n'
+ else:
+ raise ValidationError(
+ 'Tamanho da linha diferente de 360 posicoes.'
+ ' tam = %s, linha = %s' % (len(linha), linha)
+ )
+
+ def _logadouro_bairro_cep_cidade_uf_telefone(self, type, partner_id):
+ erro = ''
+
+ if not partner_id.street:
+ erro += _("Rua {0} não preenchida\n".format(type))
+ if not partner_id.district:
+ erro += _("Bairro {0} não preenchido\n".format(type))
+ if not partner_id.zip:
+ erro += _("Cep {0} não preenchido\n".format(type))
+ if not partner_id.city:
+ erro += _("Cidade {0} não preenchida\n".format(type))
+ if not partner_id.state_id and partner_id.state_id.code:
+ erro += _("UF {0} não preenchido\n".format(type))
+ if not partner_id.phone:
+ # TODO: Pode ser que este campo precise ser revisto por conta da
+ # formatação
+ erro += _("Telefone {0} não preenchido\n".format(type))
+ # if not partner_id.number:
+ # erro += _("Número {0} não preenchido\n".format(type))
+ if erro:
+ raise ValidationError(erro)
+
+ logadouro = ''
+ logadouro += partner_id.street or ''
+ logadouro += ' '
+ logadouro += partner_id.number or ''
+ logadouro += ' '
+ logadouro += partner_id.street2 or ''
+
+ return (logadouro, partner_id.district, partner_id.zip,
+ partner_id.city, partner_id.state_id.code,
+ partner_id.phone)
+
+ def _rat(self, company):
+ """
+ - Campo obrigatório.
+ - Campo com uma posição inteira e uma decimal.
+ - Campo obrigatório para competência maior ou igual a 10/1998.
+ - Não pode ser informado para competências anteriores a 10/1998.
+ - Não pode ser informado para competências anteriores a 04/99
+ quando o FPAS for 639.
+ - Não pode ser informado para os códigos de recolhimento
+ 145, 307, 317, 327, 337, 345, 640 e 660.
+ - Será zeros para FPAS 604, 647, 825, 833 e 868 (empregador doméstico)
+ e para a empresa optante pelo SIMPLES.
+ - Não pode ser informado para FPAS 604 com recolhimento de código 150
+ em competências posteriores a 10/2001.
+
+ Sempre que não informado o campo deve ficar em branco.
+
+ :return:
+ """
+
+ if self.codigo_recolhimento in (
+ '145', '307', '317', '327', '337', '345', '640', '660'):
+ return ''
+ elif (self.codigo_recolhimento in (
+ '604', '647', '825', '833', '868') or
+ self.company_id.fiscal_type in ('1', '2')):
+ return 0.00
+ elif self.codigo_fpas == '604' and self.codigo_recolhimento == '150':
+ return ''
+ return self.env['l10n_br.hr.rat.fap'].search(
+ [('year', '=', self.ano),
+ ('company_id', '=', company.id)
+ ], limit=1).rat_rate or '0'
+
+ def _simples(self, company_id):
+ """
+ Campo obrigatório.
+ Só pode ser:
+ 1 - Não Optante;
+ 2 – Optante;
+ 3 – Optante - faturamento anual superior a R$1.200.000,00 ;
+ 4 – Não Optante - Produtor Rural Pessoa Física (CEI e FPAS 604 )
+ com faturamento anual superior a R$1.200.000,00.
+ 5 – Não Optante – Empresa com Liminar para não recolhimento da
+ Contribuição Social – Lei Complementar 110/01, de 26/06/2001.
+ 6 – Optante - faturamento anual superior a R$1.200.000,00 -
+ Empresa com Liminar para não recolhimento da Contribuição
+ Social – Lei Complementar 110/01, de 26/06/2001.
+ Deve sempre ser igual a 1 ou 5 para
+ FPAS 582, 639, 663, 671, 680 e 736.
+ Deve sempre ser igual a 1 para o FPAS 868 (empregador doméstico).
+
+ Não pode ser informado para o código de recolhimento 640.
+ Não pode ser informado para competência anterior a 12/1996.
+
+ Os códigos 3, 4, 5 e 6 não podem ser informados a partir da
+ competência 01/2007.
+
+ Sempre que não informado o campo deve ficar em branco.
+ """
+ # TODO: Melhorar esta função para os outros casos de uso
+ if company_id.fiscal_type == '3':
+ return '1'
+ else:
+ return '2'
+
+ def _tipo_inscricao_cnae(self, company_id):
+ if company_id.partner_id.is_company:
+ tipo_inscr_empresa = '1'
+ inscr_empresa = company_id.cnpj_cpf
+ cnae = company_id.cnae_main_id.code
+ else:
+ tipo_inscr_empresa = '0'
+ # TODO: Campo não implementado
+ inscr_empresa = company_id.cei
+ cnae = company_id.cnae
+ if '9700500' not in cnae:
+ raise ValidationError(_(
+ 'Para empregador doméstico utilizar o número 9700500.'
+ ))
+ return tipo_inscr_empresa, inscr_empresa, cnae
+
+ def _ded_13_lic_maternidade(self):
+ """ Registro 12 item 5:
+
+ Dedução 13o Salário Licença
+ Maternidade
+ (Informar o valor da parcela de 13o salário referente ao período
+ em que a trabalhadora esteve em licença maternidade, nos casos
+ em que o empregador/contribuinte for responsável pelo pagamento do
+ salário-maternidade.
+ A informação deve ser prestada nas seguintes situações:
+ - na competência 13, referente ao valor pago durante o ano.
+ - na competência da rescisão do contrato de trabalho (exceto
+ rescisão por justa causa), aposentadoria sem continuidade
+ de vínculo ou falecimento )
+
+ Opcional para a competência 13.
+ Opcional para o código de recolhimento 115.
+ Opcional para os códigos de recolhimento 150, 155 e 608, quando o
+ CNPJ da empresa for igual ao CNPJ do tomador.
+ Deve ser informado quando houver movimentação por rescisão de
+ contrato de trabalho (exceto rescisão com justa causa),
+ aposentadoria sem continuidade de vínculo, aposentadoria por
+ invalidez ou falecimento, para empregada que possuir afastamento
+ por motivo de licença maternidade no ano.
+ Não pode ser informado para os códigos de recolhimento 130, 135,
+ 145, 211, 307, 317, 327, 337, 345, 640, 650, 660 e para empregador
+ doméstico (FPAS 868).
+ Não pode ser informado para licença maternidade iniciada a partir
+ de 01/12/1999 e com benefícios requeridos até 31/08/2003.
+ Não pode ser informado para competências anteriores a 10/1998.
+ Não pode ser informado para as competências 01/2001 a 08/2003.
+ Sempre que não informado preencher com zeros.
+
+ :return:
+ """
+ if self.mes == '13':
+ total = 0.00
+ for ocorrencia in self.env['hr.holidays'].search([
+ ('holiday_status_id.name', '=', 'Licença Maternidade'),
+ ('data_inicio', '>=', self.ano + '-01-01'),
+ ('data_fim', '<=', self.ano + '-12-31'),
+ ]):
+ total += (
+ ocorrencia.contrato_id.wage *
+ ocorrencia.number_of_days_temp / 30)
+ return total
+ else:
+ rescisoes = self.env['hr.payslip'].search([
+ ('mes_do_ano', '=', self.mes),
+ ('ano', '=', self.ano),
+ ('tipo_de_folha', '=', 'rescisao')
+ ])
+ total = 0.00
+ for rescisao in rescisoes:
+ ultimo_dia_mes = calendar.monthrange(int(self.ano), int(self.mes))[1]
+ for ocorrencia in self.env['hr.holidays'].search([
+ ('contrato_id.id', '=', rescisao.contract_id.id),
+ ('holiday_status_id.name', '=', 'Licença Maternidade'),
+ ('data_inicio', '>=', self.ano + '-01-01'),
+ ('data_fim', '<=', self.ano + '-' + self.mes + '-' +
+ str(ultimo_dia_mes)),
+ ]):
+ total += (ocorrencia.contrato_id.wage *
+ ocorrencia.number_of_days_temp / 30)
+ return total
+
+ def _get_folha_ids(self):
+ """
+ Buscar os holerites que irao compor o SEFIP do mes
+ :return:
+ """
+ mes_do_ano = self.mes
+ tipo_de_folha = ['normal', 'rescisao']
+
+ # No caso do demonstrativo de decimo terceiro
+ if mes_do_ano == '13':
+ # Monta data para algumas vericacoes, logo deve setar
+ tipo_de_folha = ['decimo_terceiro']
+
+ raiz = self.company_id.cnpj_cpf.split('/')[0]
+ folha_ids = self.env['hr.payslip'].search([
+ ('mes_do_ano', '=', mes_do_ano),
+ ('ano', '=', self.ano),
+ ('tipo_de_folha', 'in', tipo_de_folha),
+ ('state', 'in', ['done','verify']),
+ ('company_id.partner_id.cnpj_cpf', 'like', raiz),
+ ]).filtered('total_folha')
+ # Filtered eh para pegar apenas os holerites que nao estao zerados
+
+ return folha_ids
+
+ def _valida_centralizadora(self, companies):
+ options = []
+ for company in companies:
+ options.append(company.centralizadora)
+ if '1' in options:
+ if '2' not in options:
+ raise ValidationError(
+ _(u'Existe uma empresa centralizadora porém não '
+ u'existe nenhuma centralizada')
+ )
+ if '2' in options:
+ if '1' not in options:
+ raise ValidationError(
+ _(u'Existe uma empresa centralizada porém não '
+ u'existe nenhuma centralizadora')
+ )
+
+ @api.multi
+ def criar_anexo_sefip(self):
+ sefip = SEFIP()
+ for record in self:
+ # Cria um arquivo temporario txt e escreve o que foi gerado
+ path_arquivo = sefip._gerar_arquivo_temp(record.sefip, 'SEFIP')
+ # Gera o anexo apartir do txt do grrf no temp do sistema
+ nome_arquivo = 'SEFIP.re'
+ self._gerar_anexo(nome_arquivo, path_arquivo)
+
+ def valida_anexos(self):
+ tipos_anexo = [x.type for x in self.related_attachment_ids]
+ if 'sent'in tipos_anexo and 'relatorio' in tipos_anexo:
+ return True
+ else:
+ raise ValidationError(
+ _('É necessário adicionar o relatório gerado pelo '
+ 'aplicativo na aba "Arquivos Anexos" para confirmar o envio')
+ )
+
+ def prepara_financial_move(self, partner_id, sindicato_info):
+ '''
+ Tratar dados do sefip e criar um dict para criar financial.move de
+ contribuição sindical.
+ :param partner_id: id do partner do sindicato
+ :param valor: float com valor total de contribuição
+ :return: dict com valores para criar financial.move
+ '''
+
+ sequence_id = \
+ self.company_id.payment_mode_sindicato_id.sequence_arquivo_id.id
+ doc_number = str(self.env['ir.sequence'].next_by_id(sequence_id))
+
+ # Total de contratos ativos na empresa
+ total_contratos = self.env['hr.contract'].search([
+ '&',
+ ('company_id', '=', self.company_id.id),
+ '|',
+ ('date_end', '>', fields.Date.today()),
+ ('date_end', '=', False),
+ ])
+ # Filtrar contratos por usuarios
+ total_funcionarios = len(total_contratos.mapped('employee_id'))
+
+ return {
+ 'date_document': fields.Date.today(),
+ 'partner_id': partner_id,
+ 'doc_source_id': 'l10n_br.hr.sefip,' + str(self.id),
+ 'company_id': self.company_id.id,
+ 'amount_document': sindicato_info.get('contribuicao_sindicato'),
+ 'document_number': doc_number,
+ 'account_id': self.company_id.financial_account_sindicato_id.id,
+ 'document_type_id': self.company_id.document_type_sindicato_id.id,
+ 'payment_mode_id': self.company_id.payment_mode_sindicato_id.id,
+ 'type': '2pay',
+ 'sindicato_total_remuneracao_contribuintes':
+ sindicato_info.get('total_remuneracao'),
+ 'sindicato_qtd_contribuintes':
+ sindicato_info.get('qtd_contribuintes'),
+ 'sindicato_total_empregados': total_funcionarios,
+ 'date_maturity': self.data_vencimento_grcsu,
+ 'sefip_id': self.id,
+ }
+
+ def gerar_financial_move_darf(
+ self, codigo_receita, valor, partner_id=False):
+ '''
+ Tratar dados do sefip e criar um dict para criar financial.move de
+ guia DARF.
+ :param DARF: float com valor total do recolhimento
+ :return: dict com valores para criar financial.move
+ '''
+
+ # Número do documento da DARF
+ sequence_id = self.company_id.darf_sequence_id.id
+ doc_number = str(self.env['ir.sequence'].next_by_id(sequence_id))
+
+ # Definir quem sera o contribuinte da DARF, se nao passar nenhum
+ # nos parametros assume que é a empresa
+ if not partner_id:
+ partner_id = self.company_id.partner_id
+
+ # Preencher campo para indicar tipo de financial.move e tambem
+ # preencher a data de vencimento
+ descricao = 'DARF'
+
+ if codigo_receita == '0588':
+ descricao += ' - Diretores'
+
+ if codigo_receita == '0561':
+ descricao += ' - Funcionários'
+
+ if codigo_receita == '1661':
+ descricao += ' - PSS Plano de Seguridade Social'
+
+ if codigo_receita == '1769':
+ descricao += ' - PSS Patronal'
+
+ # Calcular data de vencimento da DARF
+ # data de vencimento setada na conf da empresa
+ dia = str(self.company_id.darf_dia_vencimento)
+ mes = self.mes
+
+ # ou se forem darfs especificas, cair no dia 07 de cada mes
+ if codigo_receita in ['1769', '1661']:
+ dia = '07'
+ mes = str(int(self.mes) + 1)
+
+ data = self.ano + '-' + mes + '-' + dia
+ data_vencimento = fields.Date.from_string(data) + timedelta(days=31)
+
+ # Gerar FINANCEIRO da DARF
+ vals_darf = {
+ 'date_document': fields.Date.today(),
+ 'partner_id': partner_id.id,
+ 'doc_source_id': 'l10n_br.hr.sefip,' + str(self.id),
+ 'company_id': self.company_id.id,
+ 'amount_document': valor,
+ 'document_number': 'DARF-' + str(doc_number),
+ 'account_id': self.company_id.darf_account_id.id,
+ 'document_type_id': self.company_id.darf_document_type.id,
+ 'type': '2pay',
+ 'date_maturity': data_vencimento,
+ 'payment_mode_id': self.company_id.darf_carteira_cobranca.id,
+ 'sefip_id': self.id,
+ 'cod_receita': codigo_receita,
+ 'descricao': descricao,
+ }
+ financial_move_darf = self.env['financial.move'].create(vals_darf)
+
+ # Gerar PDF da DARF
+ financial_move_darf.button_boleto()
+
+ return financial_move_darf
+
+ def gerar_financial_move_gps(self, empresa_id, dados_empresa):
+ '''
+ Criar financial.move de guia GPS, imprimir GPS e anexá-la ao move.
+ :param GPS: float com valor total do recolhimento
+ :return: financial.move
+ '''
+
+ empresa = self.env['res.company'].browse(empresa_id)
+
+ sequence_id = empresa.darf_sequence_id.id
+ doc_number = str(self.env['ir.sequence'].next_by_id(sequence_id))
+
+ GPS = dados_empresa['INSS_funcionarios'] + \
+ dados_empresa['INSS_empresa'] + \
+ dados_empresa['INSS_outras_entidades'] + \
+ dados_empresa['INSS_rat_fap']
+
+ INSS = dados_empresa['INSS_funcionarios'] + \
+ dados_empresa['INSS_empresa'] + \
+ dados_empresa['INSS_rat_fap']
+
+ TERCEIROS = dados_empresa['INSS_outras_entidades']
+
+ descricao = 'GPS - '+ empresa.name
+
+ # Gerar movimentação financeira do GPS
+ vals_gps = {
+ 'date_document': fields.Date.today(),
+ 'partner_id': self.env.ref('base.user_root').id,
+ 'doc_source_id': 'l10n_br.hr.sefip,' + str(self.id),
+ 'company_id': empresa_id,
+ 'document_number': 'GPS-' + str(doc_number),
+ 'account_id': empresa.gps_account_id.id,
+ 'document_type_id': empresa.gps_document_type.id,
+ 'type': '2pay',
+ 'date_maturity': self.data_recolhimento_gps,
+ 'payment_mode_id': empresa.gps_carteira_cobranca.id,
+ 'sefip_id': self.id,
+ 'valor_inss_terceiros': str(TERCEIROS),
+ 'valor_inss': str(INSS),
+ 'amount_document': GPS,
+ 'descricao': descricao,
+ }
+ financial_move_gps = self.env['financial.move'].create(vals_gps)
+
+ # Gerar PDF DA GPS
+ financial_move_gps.button_boleto()
+
+ return financial_move_gps
+
+ def buscar_IRPF_holerite_13(self, contrato):
+ """
+ Buscar o valor do IRPF do holerite de 13º
+ :param contrato:
+ :return:
+ """
+ holerite = self.env['hr.payslip'].search([
+ ('contract_id', '=', contrato.id),
+ ('mes_do_ano', '=', '13'),
+ ('ano', '=', self.ano),
+ ('tipo_de_folha', 'in', ['decimo_terceiro']),
+ ('state', 'in', ['done','verify']),
+ ])
+ for line_id in holerite.line_ids:
+ if line_id.code == 'IRPF':
+ return line_id.total
+
+ return 0.0
+
+ @api.multi
+ def gerar_boletos(self):
+ '''
+ Criar ordem de pagamento para boleto de sindicato
+ 1. Configurar os dados para criação das financial.moves
+ 2. Criar os financial.moves
+ '''
+
+ #
+ # Excluir registros financeiros anteriores
+ #
+ for boleto_id in self.boletos_ids:
+ boleto_id.unlink()
+
+ valor_totas_13 = 0
+ contribuicao_sindical = {}
+
+ for record in self:
+ created_ids = []
+ empresas = {}
+ darfs = {}
+
+ for holerite in self.folha_ids:
+
+ if not empresas.get(holerite.company_id.id):
+ empresas.update({
+ holerite.company_id.id: {
+ 'INSS_funcionarios': 0.00,
+ 'INSS_empresa': 0.00,
+ 'INSS_outras_entidades': 0.00,
+ 'INSS_rat_fap': 0.00,
+ }
+ })
+
+ for line in holerite.line_ids:
+ remuneracao = line.slip_id.line_ids.filtered(
+ lambda x: x.code == 'LIQUIDO')
+ if line.code == 'CONTRIBUICAO_SINDICAL':
+ id_sindicato = \
+ line.slip_id.contract_id.partner_union.id or 0
+ if id_sindicato in contribuicao_sindical:
+ contribuicao_sindical[id_sindicato][
+ 'contribuicao_sindicato'] += line.total
+ contribuicao_sindical[id_sindicato][
+ 'qtd_contribuintes'] += 1
+ contribuicao_sindical[id_sindicato][
+ 'total_remuneracao'] += remuneracao.total
+ else:
+ contribuicao_sindical[id_sindicato] = {}
+ contribuicao_sindical[id_sindicato][
+ 'contribuicao_sindicato'] = line.total
+ contribuicao_sindical[id_sindicato][
+ 'qtd_contribuintes'] = 1
+ contribuicao_sindical[id_sindicato][
+ 'total_remuneracao'] = remuneracao.total
+ elif line.code in ['INSS', 'INSS_13']:
+ empresas[line.slip_id.company_id.id][
+ 'INSS_funcionarios'] += line.total
+ elif line.code == 'INSS_EMPRESA':
+ empresas[line.slip_id.company_id.id][
+ 'INSS_empresa'] += line.total
+ elif line.code == 'INSS_OUTRAS_ENTIDADES':
+ empresas[line.slip_id.company_id.id][
+ 'INSS_outras_entidades'] += line.total
+ elif line.code == 'INSS_RAT_FAP':
+ empresas[line.slip_id.company_id.id][
+ 'INSS_rat_fap'] += line.total
+
+ # para gerar a DARF, identificar a categoria de contrato pois
+ # cada categoria tem um código de emissao diferente
+ elif line.code in ['IRPF', 'IRPF_13', 'IRPF_FERIAS'] and \
+ not line.slip_id.struct_id.code in ['FUNCIONARIO_CEDIDO_PSS']:
+
+ if line.slip_id.contract_id.categoria in \
+ ['721', '722']:
+ codigo_darf = '0588'
+ else:
+ codigo_darf = '0561'
+
+ if darfs.get(codigo_darf):
+ darfs[codigo_darf] += line.total
+ else:
+ darfs.update({
+ codigo_darf: line.total
+ })
+
+ # Para rubricas de PSS patronal gerar para cpf do
+ # funcionario
+ elif line.code in ['PSS_PATRONAL']:
+ partner_id = line.employee_id.address_home_id
+ financial_move_darf = self.gerar_financial_move_darf(
+ '1769', line.total, partner_id)
+ created_ids.append(financial_move_darf.id)
+
+ # Para rubricas de PSS do funcionario
+ elif line.code in ['PSS']:
+ partner_id = line.employee_id.address_home_id
+ financial_move_darf = self.gerar_financial_move_darf(
+ '1661', line.total, partner_id)
+ created_ids.append(financial_move_darf.id)
+
+ # buscar o valor do IRPF do holerite de 13º
+ valor_13 = record.buscar_IRPF_holerite_13(holerite.contract_id)
+ valor_totas_13 += valor_13
+ darfs[codigo_darf] += valor_13
+
+ for sindicato in contribuicao_sindical:
+ vals = self.prepara_financial_move(
+ sindicato, contribuicao_sindical[sindicato])
+
+ financial_move = self.env['financial.move'].create(vals)
+ created_ids.append(financial_move.id)
+
+ for company in empresas:
+ dados_empresa = empresas[company]
+ financial_move_gps = self.gerar_financial_move_gps(
+ company, dados_empresa)
+ created_ids.append(financial_move_gps.id)
+
+ for cod_darf in darfs:
+ financial_move_darf = \
+ self.gerar_financial_move_darf(cod_darf, darfs[cod_darf])
+
+ created_ids.append(financial_move_darf.id)
+
+ return {
+ 'domain': "[('id', 'in', %s)]" % created_ids,
+ 'name': _("Guias geradas pelo SEFIP"),
+ 'res_ids': created_ids,
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'auto_search': True,
+ 'res_model': 'financial.move',
+ 'view_id': False,
+ 'search_view_id': False,
+ 'type': 'ir.actions.act_window'
+ }
+
+ @api.multi
+ def action_sent(self):
+ """
+ Confirmar o Envio do Sefip:
+ 1. Validar se o sefip contem o relatorio em anexo
+ 2. Chamar a função que muda o status do holerite, liberando para pagamt
+ """
+ for record in self:
+ record.valida_anexos()
+ # Liberar holerites para pagamento
+ for holerite in record.folha_ids:
+ holerite.hr_verify_sheet()
+ super(L10nBrSefip, record).action_sent()
+
+ @api.multi
+ def action_open(self):
+ """
+ Confirmar a geração do Sefip
+ """
+ for record in self:
+ record.criar_anexo_sefip()
+ super(L10nBrSefip, record).action_open()
+
+ @api.multi
+ def gerar_sefip(self):
+ for record in self:
+ record.folha_ids = False
+ sefip = SEFIP()
+
+ if self.mes == '13':
+ if self.modalidade_arquivo != '1':
+ raise ValidationError(
+ 'Na competência 13 a Modalidade do Arquivo deverá ser igual a 1 ou 9.')
+
+ if self.recolhimento_fgts != ' ':
+ raise ValidationError('Na competência 13 o Indicador de Recolhimento FGTS não deverá ser informado.')
+
+ record.sefip = self._valida_tamanho_linha(
+ record._preencher_registro_00(sefip))
+ folha_ids = record._get_folha_ids()
+ self._valida_centralizadora(folha_ids.mapped('company_id'))
+
+ for company_id in folha_ids.mapped('company_id'):
+ folhas_da_empresa = folha_ids.filtered(
+ lambda r: r.company_id == company_id)
+
+ record.sefip += self._valida_tamanho_linha(
+ self._preencher_registro_10(company_id, sefip))
+
+ record.sefip += self._valida_tamanho_linha(
+ self._preencher_registro_12(company_id, sefip))
+
+ for folha in folhas_da_empresa.sorted(
+ key=lambda folha:
+ (
+ punctuation_rm(folha.employee_id.pis_pasep),
+ folha.contract_id.categoria_sefip
+ )):
+ record.sefip += self._valida_tamanho_linha(
+ record._preencher_registro_30(sefip, folha))
+
+ if folha.tipo_de_folha == 'rescisao':
+ record.sefip += self._valida_tamanho_linha(
+ record._preencher_registro_32(sefip, folha))
+
+ record.sefip += sefip._registro_90_totalizador_do_arquivo()
+
+ # Setar a relação entre Holerite e o SEFIP
+ for holerite in folha_ids:
+ holerite.sefip_id = record.id
+
+ def _preencher_registro_00(self, sefip):
+ sefip.tipo_inscr_resp = '1' if \
+ self.responsible_user_id.parent_id.is_company else '3'
+ sefip.inscr_resp = self.responsible_user_id.parent_id.cnpj_cpf
+ sefip.nome_resp = self.responsible_user_id.parent_id.legal_name
+ sefip.nome_contato = (self.responsible_user_id.legal_name or
+ self.responsible_user_id.name)
+ logadouro, bairro, cep, cidade, uf, telefone = \
+ self._logadouro_bairro_cep_cidade_uf_telefone(
+ 'do responsável', self.responsible_user_id
+ )
+ sefip.arq_logradouro = logadouro
+ sefip.arq_bairro = bairro
+ sefip.arq_cep = cep
+ sefip.arq_cidade = cidade
+ sefip.arq_uf = uf
+ sefip.tel_contato = telefone
+ sefip.internet_contato = self.responsible_user_id.email
+ sefip.competencia = self.ano + self.mes
+ sefip.cod_recolhimento = self.codigo_recolhimento
+ sefip.indic_recolhimento_fgts = self.recolhimento_fgts
+ sefip.modalidade_arq = self.modalidade_arquivo
+ sefip.data_recolhimento_fgts = fields.Datetime.from_string(
+ self.data_recolhimento_fgts).strftime('%d%m%Y') \
+ if self.data_recolhimento_fgts else ''
+ sefip.indic_recolh_ps = self.recolhimento_gps
+ sefip.data_recolh_ps = fields.Datetime.from_string(
+ self.data_recolhimento_gps).strftime('%d%m%Y') \
+ if self.data_recolhimento_gps else ''
+ if not self.company_id.supplier_partner_id:
+ raise ValidationError(
+ 'Campo "Fornecedor do Sistema" não está preenchido nesta '
+ 'Empresa ! - Favor preenchê-lo antes de gerar a SEFIP'
+ )
+ elif not self.company_id.supplier_partner_id.cnpj_cpf:
+ raise ValidationError(
+ 'Campo "CNPJ/CPF" do Fornecedor do Sistema '
+ 'não está preenchido! - Favor preenchê-lo '
+ 'antes de gerar a SEFIP'
+ )
+ sefip.tipo_inscr_fornec = (
+ '1' if self.company_id.supplier_partner_id.is_company else '3')
+ sefip.inscr_fornec = self.company_id.supplier_partner_id.cnpj_cpf
+
+ return sefip._registro_00_informacoes_responsavel()
+
+ def _preencher_registro_10(self, company_id, sefip):
+
+ tipo_inscr_empresa, inscr_empresa, cnae = self._tipo_inscricao_cnae(
+ company_id
+ )
+
+ sefip.tipo_inscr_empresa = tipo_inscr_empresa
+ sefip.inscr_empresa = inscr_empresa
+ sefip.emp_nome_razao_social = (
+ company_id.legal_name or company_id.name or ''
+ )
+ logadouro, bairro, cep, cidade, uf, telefone = \
+ self._logadouro_bairro_cep_cidade_uf_telefone(
+ 'da empresa', company_id.partner_id
+ )
+ sefip.emp_logradouro = logadouro
+ sefip.emp_bairro = bairro
+ sefip.emp_cep = cep
+ sefip.emp_cidade = cidade
+ sefip.emp_uf = uf
+ sefip.emp_tel = telefone
+ #
+ # A responsabilidade de alteração do enderço da empresa deve ser
+ # sempre feita pela receita federal, não ousamos usar esta campo.
+ #
+ sefip.emp_indic_alteracao_endereco = 'N'
+
+ sefip.emp_cnae = cnae
+ # sefip.emp_indic_alteracao_cnae = 'n'
+ sefip.emp_aliquota_RAT = self._rat(company_id)
+ sefip.emp_cod_centralizacao = company_id.centralizadora
+ sefip.emp_simples = self._simples(company_id)
+ sefip.emp_FPAS = self.codigo_fpas
+ sefip.emp_cod_outras_entidades = self._buscar_codigo_outras_entidades()
+ sefip.emp_cod_pagamento_GPS = self._buscar_codigo_pagamento_gps()
+ sefip.emp_percent_isencao_filantropia = \
+ self._buscar_isencao_filantropia()
+ # TODO:
+ sefip.emp_salario_familia = '' # rubrica salario familia
+ sefip.emp_salario_maternidade = '' # soma das li mat pagas no mês
+ sefip.emp_contrib_descont_empregados = '' # total inss retido
+ sefip.emp_indic_valor_pos_neg = 0 # Sempre positivo
+ sefip.emp_valor_devido_ps_referente = ''
+ # valor devido 13 salario, INSS décimo terceiro igual ao
+ # "emp_contrib_descont_empregados" #24
+
+ # TODO: implementação futura / não precisa preencher
+ # sefip.emp_banco = self.company_id.bank_id[0].bank
+ # sefip.emp_ag = self.company_id.bank_id[0].agency
+ # sefip.emp_cc = self.company_id.bank_id[0].account
+ return sefip._registro_10_informacoes_empresa()
+
+ def _preencher_registro_12(self, company_id, sefip):
+
+ tipo_inscr_empresa, inscr_empresa, cnae = self._tipo_inscricao_cnae(
+ company_id
+ )
+
+ sefip.tipo_inscr_empresa = tipo_inscr_empresa
+ sefip.inscr_empresa = inscr_empresa
+
+ # Item 5
+ # TODO: Implementar função
+ sefip.ded_13_lic_maternidade = self._ded_13_lic_maternidade()
+
+ # Campos da tela
+ if self.codigo_recolhimento in ('650', '660'):
+ sefip.rec_outras_info_processo = self.num_processo
+ sefip.rec_outras_info_processo_ano = self.ano_processo
+ sefip.rec_outras_info_vara_JCJ = self.vara_jcj
+ sefip.rec_outras_info_periodo_inicio = self.data_inicio
+ sefip.rec_outras_info_periodo_fim = self.data_termino
+
+ # Os outros campos são em branco
+ return sefip._registro_12_inf_adic_recolhimento_empresa()
+
+ def _trabalhador_remun_sem_13(self, folha):
+ """ Registro 30. Item 16
+
+ Rubrica Base do INSS
+
+ """
+ result = 0.00
+ #
+ # Não pode ser informado para a competência 13
+ #
+ if folha.tipo_de_folha == 'decimo_terceiro':
+ return result
+ #
+ # As remunerações pagas após rescisão do contrato de trabalho e
+ # conforme determinação do Art. 466 da CLT,
+ # não devem vir acompanhadas das respectivas movimentações.
+ #
+ #elif False:
+ # # TODO:
+ # result = 0.00
+
+ #
+ # Obrigatório
+ #
+ # elif folha.contract_id.categoria_sefip in (
+ # '05', '11', '13', '14', '15', '16', '17', '18', '22', '23',
+ # '24', '25'):
+ # result = folha.base_inss
+ #
+ # Opcional
+ #
+ # elif folha.contract_id.categoria_sefip in (
+ # '01', '02', '03', '04', '06', '07', '12', '19', '20', '21',
+ # '26'):
+ # result = folha.base_inss
+
+ # if not folha.base_inss:
+ # return self._valor_rubrica(folha.line_ids, "SALARIO")
+
+ result += self._valor_rubrica(folha.line_ids, "BASE_FGTS")
+ result += self._valor_rubrica(folha.line_ids, "BASE_FGTS_FERIAS")
+
+ # base_inss_ferias = self._valor_rubrica(
+ # folha.line_ids, "BASE_INSS_FERIAS"
+ # )
+ # result += base_inss_ferias
+ #
+ # if not base_inss_ferias:
+ # result += self._valor_rubrica(folha.line_ids, "1/3_FERIAS")
+ return result
+
+ def _trabalhador_remun_13(self, folha):
+ """ Registro 30. Item 17
+
+ Rúbrica 13 Base do INSS (Somente na rescisão temos o 16 e o 17!)
+
+ """
+ result = 0.00
+
+ # Na competencia 13 nao deve ser informado esses campos
+ if folha.tipo_de_folha == 'decimo_terceiro':
+ return result
+
+ # Se o funcionario adiantou ferias no holerite do mes
+ result += self._valor_rubrica(folha.line_ids, 'ADIANTAMENTO_13_FERIAS')
+
+ # Holerites de 13 gerados em dezembro tem a identificação do mes = 13
+ # quando sao gerados como adiantamento, sao setados com o mes corrente
+ mes_do_ano = [self.mes] if self.mes != '12' else [self.mes, '13']
+
+ # Buscar folha de 13 salario
+ folha_ids = self.env['hr.payslip'].search([
+ ('ano', '=', self.ano),
+ ('mes_do_ano', 'in', mes_do_ano),
+ ('tipo_de_folha', 'in', ['decimo_terceiro']),
+ ('is_simulacao', '=', False),
+ ('state', 'in', ['done','verify']),
+ ('contract_id', '=', folha.contract_id.id),
+ # ('company_id.partner_id.cnpj_cpf', 'like', raiz)
+ ], limit=1)
+
+ if folha_ids:
+
+ # Holerites de adiantamento de 13 gerados em maio para funcionarios
+ # que nao adiantaram o 13 salario nas ferias, vem com o codigo
+ # de rubrica de PRIMEIRA_PARCELA_13
+ result += \
+ self._valor_rubrica(folha_ids.line_ids, "PRIMEIRA_PARCELA_13")
+
+ # Holerites de decimo terceiro em dez, a rubrica é SALARIO_13
+ base_13 = \
+ self._valor_rubrica(folha_ids.line_ids, "SALARIO_13") - \
+ self._valor_rubrica(
+ folha_ids.line_ids, "DESCONTO_ADIANTAMENTO_13")
+
+ result += base_13
+
+ return result
+
+ # #
+ # # As remunerações pagas após rescisão do contrato de trabalho e
+ # # conforme determinação do Art. 466 da CLT,
+ # # não devem vir acompanhadas das respectivas movimentações .
+ # #
+ # elif False:
+ # # TODO:
+ # result = 0.00
+ # #
+ # # Campo obrigatório para categoria 02.
+ # #
+ # elif folha.contract_id.categoria_sefip == '02':
+ # # TODO: Implementar campo para calcular a rúbrica do 13 do INSS
+ # # BASE_INSS_13
+ # # ou pesquisar manualemnte
+ # result = 0.00
+ # elif folha.contract_id.categoria_sefip in (
+ # '01', '03', '04', '06', '07', '12', '19', '20', '21', '26'):
+ # # TODO:
+ # result = 0.00
+ # return result
+
+ # return self._valor_rubrica(folha.line_ids, 'ADIANTAMENTO_13_FERIAS')
+
+ def _trabalhador_classe_contrib(self, folha):
+ """ Registro 30. Item 18
+ Classe de Contribuição (Indicar a classe de contribuição do autônomo,
+ quando a empresa opta por contribuir sobre seu salário-base e os
+ classifica como categoria 14 ou 16. A classe deve estar compreendida
+ em tabela fornecida pelo INSS). """
+
+ result = ' '
+ # #
+ # # Não pode ser informado para a competência 13
+ # #
+ # if folha.tipo_de_folha == 'decimo_terceiro':
+ # return result
+ # #
+ # # Campo obrigatório para as categorias 14 e 16
+ # # (apenas em recolhimentos de competências anteriores a 03/2000).
+ # #
+ # elif (fields.Date.from_string(folha.date_from) <
+ # fields.Date.from_string('2000-03-01') and
+ # folha.contract_id.categoria_sefip in ('14', '16')):
+ # # TODO:
+ # return 0.00
+ return result
+
+ def _buscar_multiplos_vinculos(self, folha):
+ """ Esta informação deve ser lançada manualmente no payslip
+
+ :param folha:
+ :return:
+ """
+ # TODO: Implementar no payslip
+ return []
+
+ def _buscar_ocorrencias(self, folha):
+ """ Estas informações devem ser lançadas na folha
+
+ :param folha:
+ :return:
+ """
+ # FIXME: Deste jeito não deu certo, pois existem afastamentos s/ data
+ # folha_date_from = fields.Date.from_string(folha.date_from)
+ # folha_date_to = fields.Date.from_string(folha.date_to)
+ #
+ # ocorrencia_aprovada_ids = folha.contract_id.afastamento_ids.filtered(
+ # lambda r: r.state == 'validate')
+ # ocorrencias_no_periodo_ids = ocorrencia_aprovada_ids.filtered(
+ # lambda r: (folha_date_from >=
+ # fields.Date.from_string(r.data_inicio) and
+ # fields.Date.from_string(r.data_fim) <= folha_date_to))
+ #
+ # return ocorrencias_no_periodo_ids
+ return []
+
+ def _trabalhador_ocorrencia(self, folha):
+ """ Registro 30. Item 19
+ Ocorrencia: Acidente de trabalho, rescisão, afastamento por
+ doença lic maternidade, ( situaçeõs que o funcionario deixa de
+ trablalhar e o inss deverá assumir o pagamento do funcionário)
+
+ Nao implementado:
+
+ - Para empregado doméstico (Cat 06) e diretor não empregado
+ (Cat 05) permitido apenas branco ou 05.
+ -
+
+ """
+ if folha.contract_id.cnpj_empregador_cedente:
+ return '05'
+
+ folha_ids = self._get_folha_ids()
+ count = 0
+ for folha_id in folha_ids:
+ if folha.employee_id.id == folha_id.employee_id.id:
+ count += 1
+ if count == 2:
+ return '05'
+ ocorrencia = ' '
+
+ # TODO:
+ if folha.tipo_de_folha == 'rescisao':
+ # FIXME:
+ # return hr.payroll.structure.tipo_afastamento_sefip
+ #print ("tipo_afastamento_sefip - Registro 30. Item 19")
+ pass
+
+ ocorrencias_no_periodo_ids = self._buscar_ocorrencias(folha)
+
+ if not ocorrencias_no_periodo_ids:
+ return ocorrencia
+
+ # Vai o código do afastamento mais longo e é sempre informado
+ # A lógica abaixo pode ser removida
+
+ # #
+ # # Obrigatório para categoria 26,
+ # # devendo ser informado 05, 06, 07 ou 08.
+ # #
+ # if folha.contract_id.categoria_sefip == '26':
+ # permitido = ['05', '06', '07', '08']
+ # # TODO:
+ # ocorrencia = '05'
+ # elif folha.contract_id.categoria_sefip in (
+ # '02', '22', '23'
+ # ):
+ # permitido = [' ', '01', '02', '03', '04']
+ #
+ # if permitido and ocorrencia in permitido:
+ # return ocorrencia
+ # elif permitido and ocorrencia not in permitido:
+ # raise ValidationError(
+ # _("A ocorrência {0} não é permitida para folha de pagamento"
+ # " de \n {1}, referente a {2}."
+ # .format(
+ # OCORRENCIA_SEFIP[ocorrencia],
+ # folha.contract_id.name,
+ # folha.data_extenso
+ # )))
+ # return ocorrencia
+
+ def _trabalhador_valor_desc_segurado(self, folha):
+ """ Registro 30. Item 20.
+
+ Valor Descontado do Segurado (Destinado à informação do valor da
+ contribuição do trabalhador com mais de um vínculo empregatício;
+ ou quando tratar-se de recolhimento de trabalhador avulso,
+ dissídio coletivo ou reclamatória trabalhista, ou, ainda nos meses
+ de afastamento e retorno de licença maternidade)
+ O valor informado será considerado como contribuição do segurado.
+
+ --
+ Verificar se no cliente, por exemplo,
+ o funcionário esta contratado em 2 lugares pois o INSS recolhido
+ em outro lugar pode ter que ser informado aqui.
+
+ """
+ result = 0
+
+ if (fields.Date.from_string(folha.date_from) <
+ fields.Date.from_string('1998-10-01')):
+ return result
+ #
+ # Campo opcional para os códigos de recolhimento 130, 135 e 650.
+ #
+ if self.codigo_recolhimento in ('130', '135', '650'):
+ return 0
+
+ multiplos_vinculos_ids = self._buscar_multiplos_vinculos(folha)
+
+ if not multiplos_vinculos_ids:
+ return 0.00
+
+ # TODO:
+ # Campo opcional para as ocorrências 05, 06, 07 e 08.
+ # Campo opcional para as categorias de trabalhadores igual a
+ # 01, 02, 04, 06, 07, 12, 19, 20, 21 e 26.
+ # Campo opcional para as categorias de trabalhadores igual a
+ # 05, 11, 13, 15, 17, 18, 24 e 25 a partir da competência 04/2003.
+
+ return 0.00
+
+ def _trabalhador_remun_base_calc_contribuicao_previdenciaria(self, folha):
+ """ Registro 30. Item 21
+
+ Remuneração base de cálculo da contribuição previdenciária
+ (Destinado à informação da parcela de remuneração sobre a qual incide
+ contribuição previdenciária, quando o trabalhador estiver afastado
+ por motivo de acidente de trabalho e/ou prestação de serviço
+ militar obrigatório ou na informação de Recolhimento
+ Complementar de FGTS)
+
+
+ Preenchido somente quando o funcionário esta afastado.
+
+ Geralmente Zerado
+
+ """
+ return 0.00
+
+ def _trabalhador_base_calc_13_previdencia_competencia(self, folha):
+ """ Registro 30. Item 22
+
+ Base de Cálculo 13 Salário Previdência Social –
+ Referente à competência do movimento
+
+ (Na competência em que ocorreu o afastamento definitivo – informar o
+ valor total do 13o pago no ano ao trabalhador.
+ Na competência 12 – Indicar eventuais diferenças de gratificação
+ natalina de empregados que recebem remuneração variável – Art. 216,
+ Parágrafo 25, Decreto 3.265 de 29.11.1999)
+
+ Na competência 13, para a geração da GPS, indicar o valor total do
+ 13o salário pago no ano ao trabalhador)
+
+ """
+
+ if folha.tipo_de_folha == 'rescisao':
+ return self._valor_rubrica(folha.line_ids, "BASE_INSS_13")
+
+ if folha.tipo_de_folha == 'decimo_terceiro':
+ if folha.base_inss:
+ return folha.base_inss
+ # No caso dos contratos que nao tem INSS
+ # pegar a Rubrica do salario de decimo terceiro
+ else:
+ return self._valor_rubrica(folha.line_ids, "SALARIO_13")
+
+ return 0.00
+
+ def _trabalhador_base_calc_13_previdencia_GPS(self, folha):
+ """ Registro 30. Item 23
+
+ Base de Cálculo 13 Salário Previdência – Referente
+ à GPS da competência 13.
+
+ Deve ser utilizado apenas na competência 12, informando o valor
+ da base de cálculo do 13o dos empregados que recebem remuneração
+ variável, em relação a remuneração apurada até 20/12 sobre
+ a qual já houve recolhimento em GPS ).
+
+ """
+ # if folha.tipo_de_folha == 'decimo_terceiro':
+ # return folha.base_inss
+ return 0.00
+
+ def _preencher_registro_30(self, sefip, folha):
+ """
+
+ Recomendações gerais!:
+
+ Uma linha para cada folha do periodo, sendo rescisão, normal.
+ Férias não entra.
+ Na competência 13 considerar somente o 13.
+
+ """
+ # if folha.tipo_de_folha == 'ferias':
+
+ codigo_categoria = folha.contract_id.categoria_sefip
+
+ tipo_inscr_empresa, inscr_empresa, cnae = self._tipo_inscricao_cnae(
+ folha.company_id
+ )
+ sefip.tipo_inscr_empresa = tipo_inscr_empresa
+ sefip.inscr_empresa = inscr_empresa
+
+ if self.codigo_recolhimento in (
+ '130', '135', '211', '150', '155', '317', '337', '608'):
+ sefip.tipo_inscr_tomador = ' '
+ sefip.inscr_tomador = ' ' * 14
+
+ sefip.pis_pasep_ci = folha.employee_id.pis_pasep
+
+ if codigo_categoria in ('01', '03', '04', '05', '06', '07', '11',
+ '12', '19', '20', '21', '26'):
+ sefip.data_admissao = fields.Datetime.from_string(
+ folha.contract_id.date_start).strftime('%d%m%Y') or ''
+
+ if codigo_categoria in ('01', '03', '04', '05', '06', '07', '11',
+ '12', '19', '20', '21'):
+ sefip.categoria_trabalhador = codigo_categoria or ''
+
+ sefip.nome_trabalhador = folha.employee_id.name
+
+ if codigo_categoria not in (
+ '06', '13', '14', '15', '16', '17', '18', '22', '23',
+ '24', '25'):
+ sefip.matricula_trabalhador = folha.employee_id.registration or ''
+
+ if codigo_categoria in ('01', '03', '04', '06', '07', '26'):
+ sefip.num_ctps = folha.employee_id.ctps or ''
+ sefip.serie_ctps = folha.employee_id.ctps_series or ''
+ else:
+ sefip.num_ctps = ' ' * 7 or ''
+ sefip.serie_ctps = ' ' * 5 or ''
+
+ if codigo_categoria in ('01', '03', '04', '05', '06', '07'):
+ # Item 13: Data de opção do FGtS, é sempre a data de contratação!
+ sefip.data_de_opcao = fields.Datetime.from_string(
+ folha.contract_id.date_start).strftime('%d%m%Y') or ''
+ else:
+ sefip.data_de_opcao = ' '
+
+ if codigo_categoria in ('01', '02', '03', '04', '05', '06', '07',
+ '12', '19', '20', '21', '26') and \
+ folha.employee_id.birthday:
+ sefip.data_de_nascimento = fields.Datetime.from_string(
+ folha.employee_id.birthday).strftime('%d%m%Y')
+ else:
+ sefip.data_de_nascimento = ' '
+
+ if not folha.contract_id.job_id:
+ raise ValidationError("Contrato " + folha.contract_id.name + " faltando campo função !")
+
+ if codigo_categoria in '06':
+ sefip.trabalhador_cbo = '05121'
+ else:
+ sefip.trabalhador_cbo = '0' + \
+ folha.contract_id.job_id.cbo_id.code[:4]
+ # Revisar daqui para a frente
+
+ sefip.trabalhador_remun_13 = \
+ self._trabalhador_remun_13(folha) or ''
+ sefip.trabalhador_remun_sem_13 = \
+ self._trabalhador_remun_sem_13(folha) or ''
+
+ sefip.trabalhador_classe_contrib = \
+ self._trabalhador_classe_contrib(folha) or ''
+
+ sefip.trabalhador_ocorrencia = self._trabalhador_ocorrencia(folha) or ''
+ sefip.trabalhador_valor_desc_segurado = \
+ self._trabalhador_valor_desc_segurado(folha) or ''
+ sefip.trabalhador_remun_base_calc_contribuicao_previdenciaria = \
+ self._trabalhador_remun_base_calc_contribuicao_previdenciaria(
+ folha) or ''
+ sefip.trabalhador_base_calc_13_previdencia_competencia = \
+ self._trabalhador_base_calc_13_previdencia_competencia(folha) or ''
+ sefip.trabalhador_base_calc_13_previdencia_GPS = \
+ self._trabalhador_base_calc_13_previdencia_GPS(folha) or ''
+
+ return sefip._registro_30_registro_do_trabalhador()
+
+ def _preencher_registro_32(self, sefip, folha):
+ """
+
+ Registro de movimentação de Trabalhador
+
+ """
+ tipo_afastamento = folha.struct_id.tipo_afastamento_sefip
+ sefip.trabalhador_codigo_movimentacao = tipo_afastamento or ' '
+ sefip.trabalhador_data_movimentacao = \
+ formata_data(folha.data_afastamento) or ''
+ # Gerado GRRF
+ sefip.trabalhador_indic_recolhimento_fgts = 'S'
+
+ return sefip._registro_32_movimentacao_do_trabalhador()
+
+ def _gerar_anexo(self, nome_do_arquivo, path_arquivo_temp):
+ """
+ Função gerar anexo dentro do SEFIP, sobrescrevendo anexo existente.
+ Apartir de um arquivo temporário. Deve ser passado o path do
+ arquivo temporário que se tornará anexo da sefip
+ :param nome_do_arquivo:
+ :param path_arquivo_temp:
+ :return:
+ """
+ attachment_obj = self.env['ir.attachment']
+ sefip_attachment_obj = self.env['l10n_br.hr.sefip.attachments']
+
+ try:
+ file_attc = open(path_arquivo_temp, 'r')
+ attc = file_attc.read()
+
+ attachment_data = {
+ 'name': nome_do_arquivo,
+ 'datas_fname': nome_do_arquivo,
+ 'datas': base64.b64encode(attc),
+ 'res_model': 'l10n_br.hr.sefip.attachments',
+ }
+
+ if 'sent' in [line.type for line in self.related_attachment_ids]:
+ for line in self.related_attachment_ids:
+ if line.type == 'sent':
+ attach_id = attachment_obj.create(attachment_data)
+ line.attachment_ids = False
+ line.attachment_ids = [attach_id.id]
+ else:
+ sefip_attachment_data = {
+ 'name': 'Arquivo SEFIP',
+ 'sefip_id': self.id,
+ 'attachment_ids': [(0, 0, attachment_data)],
+ 'type': 'sent'
+ }
+ sefip_attachment_obj.create(sefip_attachment_data)
+
+ file_attc.close()
+
+ except:
+ raise Warning(
+ _('Impossível gerar Anexo do %s' % nome_do_arquivo))
diff --git a/l10n_br_hr_arquivos_governo/models/res_company.py b/l10n_br_hr_arquivos_governo/models/res_company.py
new file mode 100644
index 000000000..c25648375
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/models/res_company.py
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+
+import logging
+
+from openerp import api, exceptions, fields, models, _
+from ..constantes_rh import CENTRALIZADORA
+
+_logger = logging.getLogger(__name__)
+
+try:
+ from pybrasil import telefone
+except ImportError:
+ _logger.info('Cannot import pybrasil')
+
+
+OUTRAS_ENTIDADES = [
+ ('0000', "Em branco"),
+ ('0001', u"Salário educação"),
+ ('0002', u"INCRA"),
+ ('0003', u"Salário educação + INCRA"),
+ ('4096', u"SESCOOP"),
+ ('4097', u"SESCOOP + Salário educação"),
+ ('4098', u"SESCOOP + INCRA"),
+ ('4099', u"SESCOOP + INCRA + Salário educação"),
+]
+
+
+class ResCompany(models.Model):
+ """Override company to activate validate phones"""
+
+ _inherit = "res.company"
+
+ @api.constrains('phone')
+ def _check_phone_br(self):
+ if self.phone:
+ if not telefone.valida_fone(self.phone):
+ raise exceptions.Warning(
+ _('Número do Telefone Inválido'))
+
+ supplier_partner_id = fields.Many2one(
+ string='Fornecedor do sistema', comodel_name='res.partner'
+ )
+
+ codigo_outras_entidades = fields.Selection(
+ string="Código de Outras Entidades",
+ selection=OUTRAS_ENTIDADES,
+ default='0000'
+ )
+
+ codigo_recolhimento_GPS = fields.Integer(
+ string=u"Código de recolhimento do GPS",
+ )
+
+ porcentagem_filantropia = fields.Float(
+ string=u"Porcentagem de Isenção de Filantropia",
+ default=000.00,
+ )
+
+ centralizadora = fields.Selection(
+ selection=CENTRALIZADORA,
+ string=u'Centralizadora do FGTS'
+ )
+
+ document_type_sindicato_id = fields.Many2one(
+ comodel_name=u'financial.document.type',
+ string=u'Documento Sindicato',
+ help=u'Tipo de documento para boleto do sindicato.',
+ )
+
+ financial_account_sindicato_id = fields.Many2one(
+ comodel_name=u'financial.account',
+ string=u'Conta Sindicato',
+ help=u'Conta para lançamentos do sindicato.',
+ )
+
+ payment_mode_sindicato_id = fields.Many2one(
+ string=u'Carteira para Sindicato',
+ comodel_name=u'payment.mode',
+ help=u'Carteira padrão para geração de boletos do sindicato.',
+ )
+
+ darf_account_id = fields.Many2one(
+ string=u'Conta',
+ comodel_name=u'financial.account',
+ help=u'Conta para lançamentos da DARF'
+ )
+ darf_document_type = fields.Many2one(
+ string=u'Tipo do documento',
+ comodel_name=u'financial.document.type',
+ help=u'Tipo do documento que irá aparecer no lançamento financeiro'
+ )
+ darf_carteira_cobranca = fields.Many2one(
+ string=u'Carteira de cobrança',
+ comodel_name=u'payment.mode',
+ help=u'Nome da carteira de cobrança caso exista'
+ )
+ darf_sequence_id = fields.Many2one(
+ string=u'Sequencia dos documentos',
+ comodel_name=u'ir.sequence'
+ )
+ darf_dia_vencimento = fields.Integer(
+ string=u'Dia de vencimento',
+ help=u'Dia de vencimento da guia do DARF de todo mês'
+ )
+
+ gps_account_id = fields.Many2one(
+ string=u'Conta',
+ comodel_name=u'financial.account',
+ help=u'Conta para lançamentos da DARF'
+ )
+ gps_document_type = fields.Many2one(
+ string=u'Tipo do documento',
+ comodel_name=u'financial.document.type',
+ help=u'Tipo do documento que irá aparecer no lançamento financeiro'
+ )
+ gps_carteira_cobranca = fields.Many2one(
+ string=u'Carteira de cobrança',
+ comodel_name=u'payment.mode',
+ help=u'Nome da carteira de cobrança caso exista'
+ )
+ gps_sequence_id = fields.Many2one(
+ string=u'Sequencia dos documentos',
+ comodel_name=u'ir.sequence'
+ )
diff --git a/l10n_br_hr_arquivos_governo/security/hr_payslip.xml b/l10n_br_hr_arquivos_governo/security/hr_payslip.xml
new file mode 100644
index 000000000..8b7238801
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/security/hr_payslip.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ hr.payslip access name
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_arquivos_governo/security/ir.model.access.csv b/l10n_br_hr_arquivos_governo/security/ir.model.access.csv
new file mode 100644
index 000000000..06bbad3fc
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/security/ir.model.access.csv
@@ -0,0 +1,10 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+access_hr_caged,access_hr_caged,model_hr_caged,,1,0,0,0
+"access_hr_caged_manager","create_hr_caged","model_hr_caged","base.group_hr_manager",1,1,1,1
+"l10n_br_account_cnae","l10n_br_account.cnae","l10n_br_account.model_l10n_br_account_cnae","base.group_hr_user",1,0,0,0
+access_hr_sefip,access_hr_sefip,model_l10n_br_hr_sefip,,1,0,0,0
+"access_hr_sefip_manager","create_hr_sefip","model_l10n_br_hr_sefip","base.group_hr_manager",1,1,1,1
+access_hr_sefip_attachment,access_hr_sefip_attachment,model_l10n_br_hr_sefip_attachments,,1,0,0,0
+"access_hr_sefip_attachment_manager","create_hr_sefip_attachment","model_l10n_br_hr_sefip_attachments","base.group_hr_manager",1,1,1,1
+access_hr_caged_attachment,access_hr_caged_attachment,model_l10n_br_hr_caged_attachments,,1,0,0,0
+"access_hr_caged_attachment_manager","create_hr_caged_attachment","model_l10n_br_hr_caged_attachments","base.group_hr_manager",1,1,1,1
diff --git a/l10n_br_hr_arquivos_governo/views/hr_contract_type.xml b/l10n_br_hr_arquivos_governo/views/hr_contract_type.xml
new file mode 100644
index 000000000..99d13ca96
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/views/hr_contract_type.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ hr.contract.type.view.form (in l10n_br_hr_arquivos_governo)
+ hr.contract.type
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_arquivos_governo/views/hr_payslip.xml b/l10n_br_hr_arquivos_governo/views/hr_payslip.xml
new file mode 100644
index 000000000..e8f4e3e3a
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/views/hr_payslip.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+ hr.payslip.form (in l10n_br_hr_arquivos_governo)
+ hr.payslip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_arquivos_governo/views/inherited_hr_salary_rule_view.xml b/l10n_br_hr_arquivos_governo/views/inherited_hr_salary_rule_view.xml
new file mode 100644
index 000000000..241c3a197
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/views/inherited_hr_salary_rule_view.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ hr.salary.rule (Financial Payment Order)
+ hr.salary.rule
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_arquivos_governo/views/l10n_br_hr_caged.xml b/l10n_br_hr_arquivos_governo/views/l10n_br_hr_caged.xml
new file mode 100644
index 000000000..1ae068811
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/views/l10n_br_hr_caged.xml
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+ hr.caged.form (in l10n_br_hr_arquivos_governo)
+ hr.caged
+
+
+
+
+
+
+ hr.caged.tree (in l10n_br_hr_arquivos_governo)
+ hr.caged
+
+
+
+
+
+
+
+
+
+
+
+
+ CAGED's
+ hr.caged
+ tree,form
+
+
+
+ CAGED
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_arquivos_governo/views/l10n_br_hr_contract.xml b/l10n_br_hr_arquivos_governo/views/l10n_br_hr_contract.xml
new file mode 100644
index 000000000..15871780e
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/views/l10n_br_hr_contract.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+ hr.contract.view.form (in l10n_br_hr_arquivos_governo)
+ hr.contract
+
+
+
+ 1
+
+
+
+
+
+ l10n_br.hr.contract.view.form(in l10n_br_hr_arquivos_governo)
+ hr.contract
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_arquivos_governo/views/l10n_br_hr_employee.xml b/l10n_br_hr_arquivos_governo/views/l10n_br_hr_employee.xml
new file mode 100644
index 000000000..2b1994063
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/views/l10n_br_hr_employee.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+ hr.employee.view.form (in l10n_br_hr_arquivos_governo)
+ hr.employee
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+
+ l10n_br.hr.employee.view.form(in l10n_br_hr_arquivos_governo)
+ hr.employee
+
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_arquivos_governo/views/l10n_br_hr_sefip.xml b/l10n_br_hr_arquivos_governo/views/l10n_br_hr_sefip.xml
new file mode 100644
index 000000000..db3223f9f
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/views/l10n_br_hr_sefip.xml
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+ SEFIP
+ l10n_br.hr.sefip
+ tree,form
+ []
+ {}
+
+
+
+ SEFIP
+
+
+
+
+
+ SEFIP
+
+
+
+
+
+
+ hr.sefip.form
+ l10n_br.hr.sefip
+
+
+
+
+
+
+ hr.sefip.tree (in l10n_br_hr_arquivos_governo)
+ l10n_br.hr.sefip
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_arquivos_governo/views/res_company.xml b/l10n_br_hr_arquivos_governo/views/res_company.xml
new file mode 100644
index 000000000..9a2487774
--- /dev/null
+++ b/l10n_br_hr_arquivos_governo/views/res_company.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+ l10n_br.hr.arquivos.governo.res.company.form.view
+ res.company
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/l10n_br_hr_backup/README.rst b/l10n_br_hr_backup/README.rst
new file mode 100644
index 000000000..c4f33a181
--- /dev/null
+++ b/l10n_br_hr_backup/README.rst
@@ -0,0 +1,75 @@
+.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+=================
+l10n_br Hr Backup
+=================
+
+This module allow backup salary rules and payroll structures
+
+
+Installation
+============
+
+This module depends on :
+
+l10n_br_hr_payroll
+
+
+Configuration
+=============
+
+
+Usage
+=====
+
+Este módulo faz backup de tres modelos:
+
+- hr.salary.rule
+- hr.payroll.structure
+- hr.salary.rule.category
+
+Após instalado o modulo, navegar até o menu de backup em:
+
+ Recursos Humanos > Configurações > HR Backup
+
+Em seguida Confirmar o backup.
+
+
+A rotina de backup consiste em varrer o sistema, identificar todas as regras de salarios,
+ estruturas de salario e categorias de salarios que foram criadas ou editadas via interface
+ e escrever em arquivos XML que estão pre-estabelecidos na pasta data do próprio modelo.
+
+
+Estrutura de arquivos:
+
+.. image:: /l10n_br_hr_backup/static/description/tree_files.png
+
+
+
+For further information, please visit:
+
+ * https://www.odoo.com/forum/help-1
+
+Known issues / Roadmap
+======================
+
+ * no known issues
+
+
+Credits
+=======
+
+Contributors
+------------
+
+* Hendrix Costa
+
+
+Maintainer
+----------
+
+.. image:: http://www.abgf.gov.br/wp-content/themes/abgf/images/header-logo.png
+ :alt: ABGF
+ :target: http://www.abgf.gov.br
diff --git a/l10n_br_hr_backup/__init__.py b/l10n_br_hr_backup/__init__.py
new file mode 100644
index 000000000..f0750d8eb
--- /dev/null
+++ b/l10n_br_hr_backup/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import models
diff --git a/l10n_br_hr_backup/__openerp__.py b/l10n_br_hr_backup/__openerp__.py
new file mode 100644
index 000000000..c60510284
--- /dev/null
+++ b/l10n_br_hr_backup/__openerp__.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ 'name': 'Backup HR',
+ 'summary': 'Backup Human Resource',
+ 'version': '8.0.0.0.1',
+ 'category': 'Generic Modules',
+ 'website': 'http://www.kmee.com.br',
+ 'author': "KMEE, Odoo Community Association (OCA)",
+ "license": "AGPL-3",
+ 'depends': [
+ 'l10n_br_hr_payroll',
+ ],
+ 'data': [
+ # 'data/hr_salary_rule_category.xml',
+ # 'data/hr_salary_rule.xml',
+ # 'data/hr_payroll_structure.xml',
+ 'views/hr_backup.xml',
+ 'views/hr_payroll_structure.xml',
+ 'views/hr_salary_rule.xml',
+ # 'views/hr_salary_rule_category.xml',
+ 'security/ir.model.access.csv',
+ ],
+ 'installable': True,
+}
diff --git a/l10n_br_hr_backup/data/hr_payroll_structure.xml b/l10n_br_hr_backup/data/hr_payroll_structure.xml
new file mode 100644
index 000000000..4f640ca50
--- /dev/null
+++ b/l10n_br_hr_backup/data/hr_payroll_structure.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_backup/data/hr_salary_rule.xml b/l10n_br_hr_backup/data/hr_salary_rule.xml
new file mode 100644
index 000000000..4f640ca50
--- /dev/null
+++ b/l10n_br_hr_backup/data/hr_salary_rule.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_backup/data/hr_salary_rule_category.xml b/l10n_br_hr_backup/data/hr_salary_rule_category.xml
new file mode 100644
index 000000000..4f640ca50
--- /dev/null
+++ b/l10n_br_hr_backup/data/hr_salary_rule_category.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_backup/data/template_model.xml b/l10n_br_hr_backup/data/template_model.xml
new file mode 100644
index 000000000..4f640ca50
--- /dev/null
+++ b/l10n_br_hr_backup/data/template_model.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_backup/models/__init__.py b/l10n_br_hr_backup/models/__init__.py
new file mode 100644
index 000000000..26441c79e
--- /dev/null
+++ b/l10n_br_hr_backup/models/__init__.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import hr_backup
+from . import hr_payroll_structure
+from . import hr_salary_rule
+from . import hr_salary_rule_category
diff --git a/l10n_br_hr_backup/models/hr_backup.py b/l10n_br_hr_backup/models/hr_backup.py
new file mode 100644
index 000000000..7e77d9aa4
--- /dev/null
+++ b/l10n_br_hr_backup/models/hr_backup.py
@@ -0,0 +1,267 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2017 KMEE (http://www.kmee.com.br)
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+import logging
+import os
+import re
+
+from openerp import api, fields, models
+
+_logger = logging.getLogger(__name__)
+
+
+class HrBackup(models.Model):
+ _name = 'hr.backup'
+
+ @api.multi
+ def get_many_to_one_field(self, field_val, field_name,
+ criar_model_data=False):
+ """
+ Função para retornar campo e valor no formato XML.
+ """
+ # if isinstance(field_val, )
+
+ if field_val:
+ if field_val._get_external_ids().get(field_val.id):
+ field_val = field_val._get_external_ids().get(field_val.id)[0]
+
+ elif criar_model_data:
+ # self.registrar_modelo_ir_model_data(field_val)
+ # _logger.info('Criado ir_model_data do Objeto relacional %s '
+ # 'do modelo %s - %s' %
+ # (field_name, field_val._name, field_val.name))
+ field_val = 'l10n_br_hr_payroll.' + \
+ str(field_val._model).replace('.', '_') +\
+ '_' + field_val.code
+
+ else:
+ _logger.info(
+ "Informacao do campo %s no modelo %s nao foi salva."
+ "Campo relacional %s nao possui XML." %
+ (field_name, field_val._name, field_val.name))
+
+ linha = "\t\t\t\n" % \
+ (field_name, field_val or '')
+ return linha
+
+ @api.multi
+ def get_text_field(self, field_val, field_name):
+ """
+ Função para retornar campo e valor no formato XML.
+ """
+ linha = "\t\t\t%s\n" % \
+ (field_name, field_val or '')
+ return linha
+
+ @api.multi
+ def get_many_to_many(self, field_vals, field_name):
+ """
+ Função para retornar campo e valor no formato XML.
+ """
+ refs = ''
+ for field in field_vals:
+ if field and field._get_external_ids().get(field.id):
+ refs += "ref('%s'), " % \
+ field._get_external_ids().get(field.id)[0]
+ line = \
+ "\t\t\t\n" %\
+ (field_name, refs[:-2])
+
+ return line
+
+ @api.multi
+ def formata_caracteres_xml(self, field):
+ """
+ Formata o XML que nao pode conter caracateres como '<=' ou '>='
+ """
+ # Validar a entrada de dados
+ if not isinstance(field, (str, unicode)):
+ return field
+
+ # Menor igual
+ field = re.sub('<=', ' <= ', field)
+ # Menor
+ field = re.sub('<', ' < ', field)
+ # Maior Igual
+ field = re.sub('>=', ' >= ', field)
+ # Maior
+ field = re.sub('>', ' > ', field)
+
+ return field
+
+ @api.multi
+ def get_external_id(self, object, name):
+ """
+ Retorna a referencia externa se existir senao retorna o nome
+ passado como parametro
+ :param object: instancia do objeto
+ :param name: str - nome do record ex.: hr_salary_rule_RUBRICA01
+ """
+ if object._get_external_ids().get(object.id):
+ return object._get_external_ids().get(object.id)[0]
+ return name
+
+ @api.multi
+ def registrar_modelo_ir_model_data(self, objeto, name=False):
+ """
+ Função que registra na tabela ir_model_data a existencia do objeto que
+ foi criado via interface
+ :param objeto: Objeto a ser registrado
+ :param name: nome do objeto a ser registrado na tabela,
+ :return: instancia do ir_model_data
+ """
+ ir_model_data_obj = self.env['ir.model.data']
+
+ # Se nao passar nenhum nome no parametro, utilizar o nome do objeto
+ if not name:
+ name = objeto._name
+
+ vals = {
+ 'name': name,
+ 'module': 'l10n_br_hr_payroll',
+ 'model': objeto._model,
+ 'res_id': objeto.id,
+ }
+
+ return ir_model_data_obj.create(vals)
+
+ @api.multi
+ def escrever_arquivo_backup(self, name, texto):
+
+ template_path = '{}/../data/' + name + '.xml'
+ template_path = template_path.format(os.path.dirname(__file__))
+
+ xml_antigo = open(template_path, 'r')
+ xml_antigo = xml_antigo.read()
+
+ if xml_antigo:
+ # Remover as TAGS de fechamento do arquivo
+ xml_antigo = re.sub(r'\<\/data>', '', xml_antigo)
+ xml_antigo = re.sub(r'\<\/openerp>', '', xml_antigo)
+ else:
+ xml_antigo = '\t\n\t\t\n'
+
+ xml_final = xml_antigo + '\t\t\n'
+ xml_final += texto
+ xml_final += '\t\t\n\t\n'
+
+ backup_xml = open(template_path, 'w')
+ backup_xml.write(xml_final)
+ backup_xml.close()
+
+ @api.multi
+ def gerar_backup_objetos_criados(self, modelo):
+ """
+ Função que busca as regras que foram criadas somente pela interface,
+ dispara uma função para registro na tabela ir_model_data e retorna um
+ texto em xml para gerar o backup das regras
+ """
+ model_obj = self.env[modelo]
+ ir_model_data_obj = self.env['ir.model.data']
+
+ # Buscar todas as regras que foram geradas apartir do XML
+ res_id = ir_model_data_obj.search([
+ ('model', '=', modelo),
+ ]).mapped('res_id')
+
+ # Identificar regras geradas pela interface, que nao tem XML
+ regras_sem_xml = model_obj.search([
+ ('id', 'not in', res_id),
+ ])
+
+ # variavel que contem as regras em xml
+ models_xml = u''
+
+ for model_sem_xml in regras_sem_xml:
+ # Se nao achar um id externo cria na tabela ir_model_data
+ if not self.get_external_id(model_sem_xml, False):
+ model_label = model_sem_xml.code \
+ if model_sem_xml.code else str(model_sem_xml.id)
+ name = modelo.replace('.', '_') + '_' + model_label
+ self.registrar_modelo_ir_model_data(model_sem_xml, name)
+ models_xml += model_sem_xml.generate_xml
+
+ return models_xml.encode('utf-8'), len(regras_sem_xml)
+
+ @api.multi
+ def gerar_backup_objetos_editados(self, modelo):
+ """
+ Função que gera um texto no formato xml para realizar o backup
+ """
+ model_obj = self.env[modelo]
+ models = model_obj.search([])
+
+ models_xml = u''
+ models_qty = 0
+ for model in models:
+ if model.create_date != model.write_date:
+ if (not model.last_backup) or \
+ (model.write_date > model.last_backup):
+ models_xml += model.generate_xml
+ models_qty += 1
+ model.last_backup = fields.datetime.now()
+ return models_xml.encode('utf-8'), models_qty
+
+ @api.multi
+ def atualizar_modelos_ja_exportados(self, model):
+ """
+ Os modelos exportadas anteriormente, ja possuem registro no
+ ir_model_data, mas o registro aponta para um modulo inválido (export)
+ A função readequara esses registros apontando para o modulo de backup
+ :return:
+ """
+ model_obj = self.env[model]
+ ir_model_data_obj = self.env['ir.model.data']
+
+ modelos_ja_exportados = ir_model_data_obj.search([
+ ('model', '=', model),
+ ('module', '=', '__export__'),
+ ])
+
+ for modelo_ja_exportado in modelos_ja_exportados:
+ modelo_id = model_obj.browse(modelo_ja_exportado.res_id)
+ name = model.replace('.', '_') + '_' + modelo_id.code \
+ if modelo_id.code else str(modelo_id.id)
+ modelo_ja_exportado.module = 'l10n_br_hr_payroll'
+ modelo_ja_exportado.name = name
+ modelo_id.write_date = fields.datetime.now()
+
+ @api.multi
+ def gerar_backup(self):
+ """
+ Rotina chamada pela interface para fazer backup dos objetos de RH
+ editados e criados via interface
+ """
+ models = [
+ 'hr.salary.rule.category',
+ 'hr.salary.rule',
+ 'hr.payroll.structure',
+ ]
+
+ for model in models:
+ # Verificar Modelos ja exportados anteriormente
+ self.atualizar_modelos_ja_exportados(model)
+
+ # Gerar xml com todas os objetos criados via interface
+ xml_objetos_criadas, qty_objetos_criadas = \
+ self.gerar_backup_objetos_criados(model)
+
+ # Gerar xml com todos os objetos editados via interface
+ xml_objetos_editadas, qty_objetos_editados = \
+ self.gerar_backup_objetos_editados(model)
+
+ # Ajustar estrutura do xml
+ xml_objetos = '\n\t\t \n\n' % \
+ qty_objetos_criadas
+
+ xml_objetos += xml_objetos_criadas
+
+ xml_objetos += '\n\t\t \n\n' % \
+ qty_objetos_editados
+
+ xml_objetos += xml_objetos_editadas
+
+ # Escreve no arquivo XML do modulo
+ self.escrever_arquivo_backup(model.replace('.', '_'), xml_objetos)
diff --git a/l10n_br_hr_backup/models/hr_payroll_structure.py b/l10n_br_hr_backup/models/hr_payroll_structure.py
new file mode 100644
index 000000000..caf64d3a4
--- /dev/null
+++ b/l10n_br_hr_backup/models/hr_payroll_structure.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2017 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
+
+
+class HrPayrollStructure(models.Model):
+ _inherit = 'hr.payroll.structure'
+
+ @api.multi
+ def _compute_xml_rubrica(self):
+ """
+ Função que gera XML da estrutura atual
+ """
+
+ for regra in self:
+
+ # Se a regra ja tiver identificação no ir_model_data exibe a
+ # external_id, senão exibe a external id que sera criada pelo
+ # modulo de backup
+ backup = self.env['hr.backup']
+
+ id = backup.get_external_id(
+ regra, 'hr_payroll_structure_%s' % regra.code)
+
+ record = \
+ "\t\t \n" % id
+
+ record += backup.get_text_field(regra.code, 'code')
+ record += backup.get_text_field(regra.name, 'name')
+ record += backup.get_text_field(regra.note, 'note')
+ record += backup.get_many_to_many(regra.rule_ids, 'rule_ids')
+ record += backup.get_text_field(regra.tipo_saque, 'tipo_saque')
+ record += backup.get_many_to_one_field(
+ regra.parent_id, 'parent_id', criar_model_data=True)
+ record += backup.get_many_to_one_field(
+ regra.estrutura_ferias_id, 'estrutura_ferias_id', criar_model_data=True)
+ record += backup.get_many_to_one_field(
+ regra.estrutura_adiantamento_13_id, 'estrutura_adiantamento_13_id', criar_model_data=True)
+ record += backup.get_many_to_one_field(
+ regra.estrutura_13_id, 'estrutura_13_id', criar_model_data=True)
+ # record += backup.get_many_to_many(
+ # regra.children_ids, 'children_ids')
+ record += backup.get_many_to_one_field(
+ regra.company_id, 'company_id')
+ record += backup.get_text_field(
+ regra.tipo_afastamento_cef, 'tipo_afastamento_cef')
+ record += backup.get_text_field(
+ regra.tipo_afastamento_sefip, 'tipo_afastamento_sefip')
+ record += backup.get_text_field(
+ regra.tipo_estrutura, 'tipo_estrutura')
+ record += backup.get_text_field(
+ regra.tipo_desligamento_rais, 'tipo_desligamento_rais')
+
+ record += "\t\t\n\n"
+
+ regra.generate_xml = record
+
+ generate_xml = fields.Text(
+ string='XML da rubrica gerado automaticamente',
+ compute='_compute_xml_rubrica',
+ help='Cole esse xml em seu modulo',
+ )
+
+ last_backup = fields.Datetime(
+ string='Data do ultimo backup',
+ )
diff --git a/l10n_br_hr_backup/models/hr_salary_rule.py b/l10n_br_hr_backup/models/hr_salary_rule.py
new file mode 100644
index 000000000..42fa46912
--- /dev/null
+++ b/l10n_br_hr_backup/models/hr_salary_rule.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2017 KMEE (http://www.kmee.com.br)
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+from __future__ import unicode_literals, division, print_function
+
+from openerp import api, fields, models
+
+
+class HrSalaryRule(models.Model):
+ _inherit = b'hr.salary.rule'
+
+ @api.multi
+ def _compute_xml_rubrica(self):
+ """
+ Função que gera XML da rubrica atual
+ """
+
+ for regra in self:
+
+ # Se a regra ja tiver identificação no ir_model_data exibe a
+ # external_id, senão exibe a external id que sera criada pelo
+ # modulo de backup
+ backup = self.env['hr.backup']
+
+ id = backup.get_external_id(
+ regra, 'hr_salary_rule_%s' % regra.code)
+
+ record = \
+ "\t\t \n" % id
+
+ record += backup.get_text_field(regra.code, 'code')
+ record += backup.get_text_field(regra.name, 'name')
+ record += backup.get_text_field(regra.active, 'active')
+ record += backup.get_text_field(regra.sequence, 'sequence')
+
+ record += backup.get_many_to_one_field(
+ regra.category_id, 'category_id')
+ record += backup.get_text_field(
+ regra.condition_select, 'condition_select')
+
+ condition = backup.formata_caracteres_xml(regra.condition_python)
+ record += backup.get_text_field(condition, 'condition_python')
+ amount = backup.formata_caracteres_xml(regra.amount_python_compute)
+ record += backup.get_text_field(amount, 'amount_python_compute')
+
+ custom_amount = backup.formata_caracteres_xml(
+ regra.custom_amount_python_compute)
+ record += backup.get_text_field(
+ custom_amount, 'custom_amount_python_compute')
+
+ record += backup.get_text_field(
+ regra.amount_select, 'amount_select')
+ record += backup.get_text_field(
+ regra.custom_amount_select, 'custom_amount_select')
+ record += backup.get_text_field(
+ regra.compoe_base_INSS, 'compoe_base_INSS')
+ record += backup.get_text_field(
+ regra.compoe_base_IR, 'compoe_base_IR')
+ record += backup.get_text_field(
+ regra.compoe_base_FGTS, 'compoe_base_FGTS')
+ record += backup.get_text_field(
+ regra.amount_fix, 'amount_fix')
+ record += backup.get_text_field(
+ regra.custom_amount_fix, 'custom_amount_fix')
+ record += backup.get_text_field(
+ regra.amount_percentage, 'amount_percentage')
+ record += backup.get_text_field(
+ regra.amount_percentage_base, 'amount_percentage_base')
+ record += backup.get_text_field(
+ regra.custom_amount_percentage_base,
+ 'custom_amount_percentage_base')
+ record += backup.get_text_field(
+ regra.custom_amount_percentage, 'custom_amount_percentage')
+ record += backup.get_text_field(
+ regra.appears_on_payslip, 'appears_on_payslip')
+ record += backup.get_text_field(
+ regra.condition_range, 'condition_range')
+ record += backup.get_text_field(
+ regra.condition_range_min, 'condition_range_min')
+ record += backup.get_text_field(
+ regra.condition_range_max, 'condition_range_max')
+ record += backup.get_text_field(regra.note, 'note')
+ record += backup.get_text_field(
+ regra.calculo_nao_padrao, 'calculo_nao_padrao')
+ record += backup.get_text_field(regra.quantity, 'quantity')
+ record += backup.get_text_field(
+ regra.custom_quantity, 'custom_quantity')
+ record += backup.get_text_field(regra.tipo_media, 'tipo_media')
+ record += backup.get_many_to_one_field(
+ regra.parent_rule_id, 'parent_rule_id', criar_model_data=True)
+ record += backup.get_many_to_one_field(
+ regra.company_id, 'company_id')
+ record += backup.get_many_to_one_field(
+ regra.register_id, 'register_id')
+
+ record += "\t\t\n\n"
+
+ regra.generate_xml = record
+
+ generate_xml = fields.Text(
+ string='XML da rubrica gerado automaticamente',
+ compute='_compute_xml_rubrica',
+ help='Cole esse xml em seu modulo',
+ )
+
+ last_backup = fields.Datetime(
+ string='Data do ultimo backup',
+ )
diff --git a/l10n_br_hr_backup/models/hr_salary_rule_category.py b/l10n_br_hr_backup/models/hr_salary_rule_category.py
new file mode 100644
index 000000000..b8318609c
--- /dev/null
+++ b/l10n_br_hr_backup/models/hr_salary_rule_category.py
@@ -0,0 +1,50 @@
+# -*- 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 __future__ import unicode_literals, division, print_function
+
+from openerp import api, fields, models
+
+
+class HrSalaryRuleCategory(models.Model):
+ _inherit = b'hr.salary.rule.category'
+
+ @api.multi
+ def _compute_xml_rubrica(self):
+ """
+ Função que gera XML da rubrica atual
+ """
+
+ for categoria in self:
+
+ # Se a regra ja tiver identificação no ir_model_data exibe a
+ # external_id, senão exibe a external id que sera criada pelo
+ # modulo de backup
+ backup = self.env['hr.backup']
+
+ id = backup.get_external_id(
+ categoria, 'hr_salary_rule_category_%s' % categoria.code)
+
+ record = \
+ "\t\t \n" % id
+ record += backup.get_text_field(categoria.name, 'name')
+ record += backup.get_text_field(categoria.code, 'code')
+ record += backup.get_many_to_one_field(
+ categoria.company_id, 'company_id')
+ record += backup.get_text_field(categoria.note, 'note')
+ record += backup.get_many_to_one_field(
+ categoria.parent_id, 'parent_id', criar_model_data=True)
+ record += "\t\t\n\n"
+ categoria.generate_xml = record
+
+ generate_xml = fields.Text(
+ string='XML da rubrica gerado automaticamente',
+ compute='_compute_xml_rubrica',
+ help='Cole esse xml em seu módulo',
+ )
+
+ last_backup = fields.Datetime(
+ string='Data do ultimo backup',
+ )
diff --git a/l10n_br_hr_backup/security/ir.model.access.csv b/l10n_br_hr_backup/security/ir.model.access.csv
new file mode 100644
index 000000000..ec9a83d94
--- /dev/null
+++ b/l10n_br_hr_backup/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+access_hr_backup,access_hr_backup,model_hr_backup,,1,0,0,0
diff --git a/l10n_br_hr_backup/static/description/tree_files.png b/l10n_br_hr_backup/static/description/tree_files.png
new file mode 100644
index 000000000..1f47f0a64
Binary files /dev/null and b/l10n_br_hr_backup/static/description/tree_files.png differ
diff --git a/l10n_br_hr_backup/views/hr_backup.xml b/l10n_br_hr_backup/views/hr_backup.xml
new file mode 100644
index 000000000..ca8bfa9b5
--- /dev/null
+++ b/l10n_br_hr_backup/views/hr_backup.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+ hr.backup
+ hr.backup
+
+
+
+
+
+
+ HR Backup
+ hr.backup
+ form
+ form
+
+ new
+
+
+
+
+
+
diff --git a/l10n_br_hr_backup/views/hr_payroll_structure.xml b/l10n_br_hr_backup/views/hr_payroll_structure.xml
new file mode 100644
index 000000000..8b6061312
--- /dev/null
+++ b/l10n_br_hr_backup/views/hr_payroll_structure.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+ hr.payroll.structure.form (in l10n_br_hr_backup)
+ hr.payroll.structure
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_backup/views/hr_salary_rule.xml b/l10n_br_hr_backup/views/hr_salary_rule.xml
new file mode 100644
index 000000000..537c42263
--- /dev/null
+++ b/l10n_br_hr_backup/views/hr_salary_rule.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+ hr.salaray.rule.form (in l10n_br_hr_backup)
+
+ hr.salary.rule
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_backup/views/hr_salary_rule_category.xml b/l10n_br_hr_backup/views/hr_salary_rule_category.xml
new file mode 100644
index 000000000..03504e3b2
--- /dev/null
+++ b/l10n_br_hr_backup/views/hr_salary_rule_category.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+ hr.salaray.rule.category.form (in l10n_br_hr_backup)
+
+ hr.salary.rule.category
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_gerador_holerite/README.rst b/l10n_br_hr_gerador_holerite/README.rst
new file mode 100644
index 000000000..10fa0f66b
--- /dev/null
+++ b/l10n_br_hr_gerador_holerite/README.rst
@@ -0,0 +1,84 @@
+.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+========================================
+Gerador de Folha de Pagamento Brasileira
+========================================
+
+Gerador de Holerites para simulações em férias ou 13º salario.
+
+Installation
+============
+
+To install this module, you need to:
+
+#. Do this ...
+
+Configuration
+=============
+
+To configure this module, you need to:
+
+#. Go to ...
+
+.. figure:: path/to/local/image.png
+ :alt: alternative description
+ :width: 600 px
+
+Usage
+=====
+
+To use this module, you need to:
+
+#. Go to ...
+
+.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt
+.. branch is "8.0" for example
+
+Known issues / Roadmap
+======================
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues
+`_. In case of trouble, please
+check there if your issue has already been reported. If you spotted it first,
+help us smashing it by providing a detailed and welcomed feedback.
+
+Credits
+=======
+
+Images
+------
+
+* Odoo Community Association: `Icon `_.
+
+Contributors
+------------
+
+* Hendrix Costa
+
+Funders
+-------
+
+The development of this module has been financially supported by:
+
+* Company 1 name
+* Company 2 name
+
+Maintainer
+----------
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+This module is maintained by the OCA.
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+To contribute to this module, please visit https://odoo-community.org.
diff --git a/l10n_br_hr_gerador_holerite/__init__.py b/l10n_br_hr_gerador_holerite/__init__.py
new file mode 100644
index 000000000..b1e7ef842
--- /dev/null
+++ b/l10n_br_hr_gerador_holerite/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import models
diff --git a/l10n_br_hr_gerador_holerite/__openerp__.py b/l10n_br_hr_gerador_holerite/__openerp__.py
new file mode 100644
index 000000000..3b93fe50b
--- /dev/null
+++ b/l10n_br_hr_gerador_holerite/__openerp__.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ 'name': 'Brazilian Localization HR Payroll Generator',
+ 'category': 'Localization',
+ 'license': 'AGPL-3',
+ 'author': 'KMEE, Odoo Community Association (OCA)',
+ 'maintainer': 'KMEE',
+ 'website': 'http://www.kmee.com.br',
+ 'version': '8.0.1.0.0',
+ 'depends': [
+ 'l10n_br_hr_payroll',
+ ],
+ 'data': [
+ 'views/hr_payslip_gerador.xml',
+ 'security/ir.model.access.csv',
+ ],
+ 'installable': True,
+ 'auto_install': False,
+}
diff --git a/l10n_br_hr_gerador_holerite/models/__init__.py b/l10n_br_hr_gerador_holerite/models/__init__.py
new file mode 100644
index 000000000..7d7528c97
--- /dev/null
+++ b/l10n_br_hr_gerador_holerite/models/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import hr_payslip_gerador
diff --git a/l10n_br_hr_gerador_holerite/models/hr_payslip_gerador.py b/l10n_br_hr_gerador_holerite/models/hr_payslip_gerador.py
new file mode 100644
index 000000000..bcfb43032
--- /dev/null
+++ b/l10n_br_hr_gerador_holerite/models/hr_payslip_gerador.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from datetime import datetime
+
+from dateutil.relativedelta import relativedelta
+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 HrPayslipGenerator(models.Model):
+ _name = 'hr.payslip.generator'
+
+ contract_id = fields.Many2one(
+ comodel_name='hr.contract',
+ string="Contrato",
+ )
+
+ 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,
+ )
+
+ def processar_holerites(self, holerite):
+
+ holerite._compute_set_employee_id()
+ holerite.compute_sheet()
+ holerite.process_sheet()
+
+ return holerite
+
+ @api.multi
+ def gerar_holerites(self):
+ data_inicio_gerador = \
+ str(self.ano) + '-' + str(self.mes_do_ano) + '-01'
+ cont = 0
+
+ data_inicio = fields.Date.from_string(data_inicio_gerador)
+ data_fim = data_inicio + relativedelta(months=1, days=-1)
+
+ while cont <= 12:
+
+ payslip_dict = {
+ 'contract_id': self.contract_id.id,
+ 'date_from': data_inicio,
+ 'date_to': data_fim,
+ 'employee_id': self.contract_id.employee_id.id,
+ 'mes_do_ano': data_inicio.month,
+ 'ano': data_inicio.year,
+ }
+
+ payslip = self.env['hr.payslip'].create(payslip_dict)
+ self.processar_holerites(payslip)
+
+ data_inicio += relativedelta(months=1)
+ data_fim = data_inicio + relativedelta(months=1, days=-1)
+ cont += 1
diff --git a/l10n_br_hr_gerador_holerite/security/ir.model.access.csv b/l10n_br_hr_gerador_holerite/security/ir.model.access.csv
new file mode 100644
index 000000000..6c61453e0
--- /dev/null
+++ b/l10n_br_hr_gerador_holerite/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+"access_hr_payslip_generator","access_hr_payslip_generator","model_hr_payslip_generator",,1,0,0,0
diff --git a/l10n_br_hr_gerador_holerite/views/hr_payslip_gerador.xml b/l10n_br_hr_gerador_holerite/views/hr_payslip_gerador.xml
new file mode 100644
index 000000000..42cafa0e9
--- /dev/null
+++ b/l10n_br_hr_gerador_holerite/views/hr_payslip_gerador.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+ l10n_br.hr.payslip.gerador.form
+ hr.payslip.generator
+ form
+
+
+
+
+
+
+ Action Generator Payslip
+ hr.payslip.generator
+ form
+ form
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_holiday/README.rst b/l10n_br_hr_holiday/README.rst
index 9c35f1f3c..5ff1f4e9d 100644
--- a/l10n_br_hr_holiday/README.rst
+++ b/l10n_br_hr_holiday/README.rst
@@ -2,12 +2,13 @@
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
-==========================================================
-Controle de folgas/atrasos com particularidades brasileira
-==========================================================
+====================================================================
+Controle de folgas/atrasos e férias com particularidades brasileiras
+====================================================================
Este módulo extende a funcionalidade de requisição de faltas (hr_holidays),
-e permite que vocễ registre novos tipos de faltas com algumas validaçoes extras:
+permitindo a solicitação de férias e registro de novos tipos de faltas com
+algumas validaçoes extras:
- Validação de anexo para justificativa de faltas
- limite de dias por tipo de falta (holiday.status)
diff --git a/l10n_br_hr_holiday/__openerp__.py b/l10n_br_hr_holiday/__openerp__.py
index b1dce1d03..caf4763b1 100644
--- a/l10n_br_hr_holiday/__openerp__.py
+++ b/l10n_br_hr_holiday/__openerp__.py
@@ -11,13 +11,14 @@
'depends': [
'hr_holidays',
'l10n_br_resource',
- 'l10n_br_hr_vacation'
],
'data': [
- 'views/hr_holidays.xml',
- 'views/hr_holidays_status.xml',
'data/hr_holidays_status_data.xml',
'security/hr_holidays_status.xml',
+ 'security/ir.model.access.csv',
+ 'views/hr_holidays.xml',
+ 'views/hr_holidays_status.xml',
+ 'views/calendar_event_view.xml',
],
'demo': [
],
diff --git a/l10n_br_hr_holiday/data/hr_holidays_status_data.xml b/l10n_br_hr_holiday/data/hr_holidays_status_data.xml
index 28d45fc71..7cb1d0683 100644
--- a/l10n_br_hr_holiday/data/hr_holidays_status_data.xml
+++ b/l10n_br_hr_holiday/data/hr_holidays_status_data.xml
@@ -19,14 +19,6 @@
Trueocorrencias
-
- Yearly Leave Days
-
- brown
- corridos
-
- ocorrencias
- End of year recess
@@ -102,6 +94,26 @@
Trueocorrencias
+
+ Licença Maternidade - Complemento
+ True
+ red
+ corridos
+ 60
+ True
+ True
+ ocorrencias
+
+
+ Licença Paternidade - Complemento
+ True
+ red
+ corridos
+ 15
+ True
+ True
+ ocorrencias
+ Paternity leaveTrue
@@ -196,8 +208,11 @@
ocorrencias
-
+
+ Férias
+ lightgreenferias
+
diff --git a/l10n_br_hr_holiday/i18n/pt_BR.po b/l10n_br_hr_holiday/i18n/pt_BR.po
index 830e0cb3b..86dee1a6b 100644
--- a/l10n_br_hr_holiday/i18n/pt_BR.po
+++ b/l10n_br_hr_holiday/i18n/pt_BR.po
@@ -15,6 +15,11 @@ msgstr ""
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
+#. module: hr_holidays
+#: field:hr.employee,remaining_leaves:0
+msgid "Remaining Legal Leaves"
+msgstr "Abonos Restantes"
+
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_abono_estudante
msgid "Abono de Falta Estudante"
@@ -81,10 +86,15 @@ msgstr "Compensação - 1 hora"
msgid "Compensation 2 hours"
msgstr "Compensação - 2 horas"
+#. module: l10n_br_hr_holiday
+#: field:hr.holidays,contrato_id:0
+msgid "Funcionário"
+msgstr "Funcionário"
+
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_death_of_relatives
msgid "Death of relatives"
-msgstr "Falecimento de parentes"
+msgstr "Luto"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_dental_treatment
@@ -104,7 +114,7 @@ msgstr "Dias úteis Consecutivos"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_disposicao_TRE
msgid "Disposicao TRE"
-msgstr "Disposicao TRE"
+msgstr "Disposição TRE"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_end_of_year_recess
@@ -155,12 +165,12 @@ msgstr "Licença Casamento"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_maternity_leave
msgid "Maternity leave"
-msgstr "Licença maternidade"
+msgstr "Licença Maternidade"
#. module: l10n_br_hr_holiday
#: model:hr.holidays.status,name:l10n_br_hr_holiday.holiday_status_medical_certificate
msgid "Medical Certificate"
-msgstr "Atestado médico"
+msgstr "Licença Médica"
#. module: l10n_br_hr_holiday
#: field:hr.holidays,message:0
@@ -187,22 +197,10 @@ msgstr "Quantidade de dias excedido!"
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"
+msgstr "Licença Paternidade"
#. module: l10n_br_hr_holiday
#: field:hr.holidays,payroll_discount:0
diff --git a/l10n_br_hr_holiday/models/__init__.py b/l10n_br_hr_holiday/models/__init__.py
index a8013a924..035783af3 100644
--- a/l10n_br_hr_holiday/models/__init__.py
+++ b/l10n_br_hr_holiday/models/__init__.py
@@ -2,6 +2,6 @@
# Copyright 2016 KMEE - Hendrix Costa
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from . import calendar
from . import hr_holidays
from . import hr_holidays_status
-from . import resource_calendar
diff --git a/l10n_br_hr_holiday/models/calendar.py b/l10n_br_hr_holiday/models/calendar.py
new file mode 100644
index 000000000..8fbd07f5f
--- /dev/null
+++ b/l10n_br_hr_holiday/models/calendar.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 KMEE - Luiz Felipe do Divino
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import fields, models, api
+from openerp.osv.orm import setup_modifiers
+from openerp.exceptions import Warning
+from lxml import etree
+
+
+class L10nBrHrCalendar(models.Model):
+ _inherit = "calendar.event"
+
+ models_id = fields.Many2one(
+ comodel_name="ir.model",
+ string="Modelo de Origem",
+ )
+
+ @api.model
+ def _get_recurrent_fields(self):
+ res = super(L10nBrHrCalendar, self)._get_recurrent_fields()
+ res.append('models_id')
+ return res
+
+ @api.model
+ def fields_view_get(self, view_id=None, view_type='form',
+ toolbar=False, submenu=False):
+ res = super(L10nBrHrCalendar, self).fields_view_get(
+ view_id=view_id, view_type=view_type, toolbar=toolbar,
+ submenu=submenu
+ )
+ if view_type == "form" and not res['name'] == u'Meetings Popup':
+ doc = etree.XML(res['arch'])
+ nodes = doc.xpath("//field")
+ id_found = self.env.ref('hr_holidays.model_hr_holidays').id
+ # or try to search for the id using the external id
+ for node in nodes:
+ node.set('attrs',
+ "{'readonly':[('models_id','=',%s)]}" % id_found)
+ setup_modifiers(node, res['fields'])
+ res['arch'] = etree.tostring(doc)
+ return res
+
+ @api.model
+ def get_date_formats(self):
+ lang = self._context.get("lang") or self.env.user.lang or ''
+ res_lang_obj = self.env['res.lang']
+ lang_params = {}
+
+ lang_id = res_lang_obj.search([("code", "=", lang)])
+ if lang_id:
+ lang_params = {
+ 'date_format': lang_id.date_format,
+ 'time_format': lang_id.time_format,
+ }
+
+ # formats will be used for str{f,p}time() which do
+ # not support unicode in Python 2, coerce to str
+ format_date = \
+ lang_params.get("date_format", '%B-%d-%Y').encode('utf-8')
+ format_time = \
+ lang_params.get("time_format", '%I-%M %p').encode('utf-8')
+ return (format_date, format_time)
+
+ @api.multi
+ def unlink(self):
+ """
+ Validação que permite apenas ao grupo de Gerente de RH à excluir
+ eventos do calendario, que tenham um holidays atrelado
+ """
+ if not self.env.user.has_group('base.group_hr_manager'):
+ if self.models_id.id == \
+ self.env.ref('hr_holidays.model_hr_holidays').id:
+ raise Warning(
+ 'Ocorrências já aprovadas somente podem ser rejeitadas '
+ 'por usuários com perfil de Gerente de RH')
+ return super(L10nBrHrCalendar, self).unlink()
diff --git a/l10n_br_hr_holiday/models/hr_contract.py b/l10n_br_hr_holiday/models/hr_contract.py
new file mode 100644
index 000000000..688e45383
--- /dev/null
+++ b/l10n_br_hr_holiday/models/hr_contract.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import fields, models
+
+
+class HrContract(models.Model):
+ _inherit = 'hr.contract'
+
+ hr_holiday_ids = fields.One2many(
+ comodel_name='hr.holidays',
+ inverse_name='contrato_id',
+ string='Abonos de faltas'
+ )
diff --git a/l10n_br_hr_holiday/models/hr_holidays.py b/l10n_br_hr_holiday/models/hr_holidays.py
index 215745632..b8bdfe4e8 100644
--- a/l10n_br_hr_holiday/models/hr_holidays.py
+++ b/l10n_br_hr_holiday/models/hr_holidays.py
@@ -34,39 +34,115 @@ class HrHolidays(models.Model):
tipo = fields.Selection(
selection=OCORRENCIA_TIPO,
string="Tipo",
- default='ferias',
+ default='ocorrencias',
)
holiday_status_id = fields.Many2one(
domain="[('tipo', '=', tipo)]",
)
+ contrato_id = fields.Many2one(
+ comodel_name='hr.contract',
+ string=u'Contrato Associado',
+ )
+
+ department_id=fields.Many2one(
+ string="Departamento/lotação",
+ comodel_name='hr.department',
+ compute='_compute_department_id',
+ store=True,
+ )
+
+ @api.depends('contrato_id')
+ def _compute_department_id(self):
+ for holiday in self:
+ if holiday.contrato_id:
+ holiday.department_id = holiday.contrato_id.department_id
+
+ @api.onchange('contrato_id')
+ def onchange_contrato(self):
+ for holiday in self:
+ holiday.employee_id = holiday.contrato_id.employee_id
@api.constrains('attachment_ids', 'holiday_status_id', 'date_from',
'date_to', 'number_of_days_temp')
def validate_days_status_id(self):
- # Validar anexo
- if self.need_attachment:
- if not self.attachment_ids:
- raise UserError(_("Atestado Obrigatório!"))
- resource_calendar_obj = self.env['resource.calendar']
for record in self:
- if record.holiday_status_id.days_limit:
- if record.holiday_status_id.type_day == u'uteis':
- if resource_calendar_obj.quantidade_dias_uteis(
- fields.Datetime.from_string(record.date_from),
- fields.Datetime.from_string(record.date_to)) > \
- record.holiday_status_id.days_limit:
- raise UserError(_("Number of days exceeded!"))
- if record.holiday_status_id.type_day == u'corridos':
- if record.number_of_days_temp > \
- record.holiday_status_id.days_limit:
- raise UserError(_("Number of days exceeded!"))
- if record.holiday_status_id.hours_limit:
- if fields.Datetime.from_string(record.date_to) - \
- fields.Datetime.from_string(record.date_from) > \
- timedelta(minutes=60 *
- record.holiday_status_id.hours_limit):
- raise UserError(_("Number of hours exceeded!"))
+ if record.type == 'remove':
+ # Validar anexo
+ if record.need_attachment:
+ if not record.attachment_ids:
+ raise UserError(_("Atestado Obrigatório!"))
+ # Validar Limite de dias
+ if record.holiday_status_id.days_limit:
+ if record.holiday_status_id.type_day == u'uteis':
+ resource_calendar_obj = self.env['resource.calendar']
+ date_to = fields.Date.from_string(record.date_to)
+ date_from = fields.Date.from_string(record.date_from)
+ if resource_calendar_obj.quantidade_dias_uteis(
+ date_from, date_to) > \
+ record.holiday_status_id.days_limit:
+ raise UserError(_("Number of days exceeded!"))
+ if record.holiday_status_id.type_day == u'corridos':
+ if record.number_of_days_temp > \
+ record.holiday_status_id.days_limit:
+ raise UserError(_("Number of days exceeded!"))
+ # Validar Limite de Horas
+ if record.holiday_status_id.hours_limit:
+ if fields.Datetime.from_string(record.date_to) - \
+ fields.Datetime.from_string(record.date_from) > \
+ timedelta(minutes=60 *
+ record.holiday_status_id.hours_limit):
+ raise UserError(_("Number of hours exceeded!"))
@api.onchange('payroll_discount', 'holiday_status_id')
def _set_payroll_discount(self):
self.payroll_discount = self.holiday_status_id.payroll_discount
+
+ @api.multi
+ def get_ocurrences(self, employee_id, data_from, data_to):
+ """Calcular a quantidade de faltas/ocorrencias que devem ser
+ descontadas da folha de pagamento em determinado intervalo de tempo.
+ :param employee_id: Id do funcionario
+ str data_from: Data inicial do intervalo de tempo.
+ str data_end: Data final do intervalo
+ :return dict {
+ - int faltas_remuneradas: Quantidade de faltas que devem
+ ser remuneradas dentro do intervalo passado como parâmetro
+ - int faltas_nao_remuneradas: Quantidade de faltas que NAO
+ serao remuneradas. (Descontadas da folha de pagamento)
+ }
+ """
+ faltas = {
+ 'faltas_remuneradas': [],
+ 'quantidade_dias_faltas_remuneradas': 0,
+ 'faltas_nao_remuneradas': [],
+ 'quantidade_dias_faltas_nao_remuneradas': 0,
+ }
+ domain = [
+ ('state', '=', 'validate'),
+ ('employee_id', '=', employee_id),
+ ('type', '=', 'remove'),
+ ('date_from', '>=', data_from),
+ ('date_to', '<=', data_to),
+ ]
+ holidays_ids = self.env['hr.holidays'].search(domain)
+
+ for leave in holidays_ids:
+ if leave.payroll_discount:
+ faltas['faltas_nao_remuneradas'].append(leave)
+ faltas['quantidade_dias_faltas_nao_remuneradas'] += \
+ leave.number_of_days_temp
+ else:
+ faltas['faltas_remuneradas'].append(leave)
+ faltas['quantidade_dias_faltas_remuneradas'] += \
+ leave.number_of_days_temp
+ return faltas
+
+ @api.multi
+ def holidays_validate(self):
+ super(HrHolidays, self).holidays_validate()
+ model_obj_id = self.env.ref("hr_holidays.model_hr_holidays").id
+ self.meeting_id.write({
+ 'models_id': model_obj_id,
+ 'class': 'private',
+ })
+ return True
diff --git a/l10n_br_hr_holiday/models/hr_holidays_status.py b/l10n_br_hr_holiday/models/hr_holidays_status.py
index f99a26ed0..ccc46e139 100644
--- a/l10n_br_hr_holiday/models/hr_holidays_status.py
+++ b/l10n_br_hr_holiday/models/hr_holidays_status.py
@@ -43,5 +43,6 @@ class HrHolidaysStatus(models.Model):
tipo = fields.Selection(
string=u'Tipo',
- selection=OCORRENCIA_TIPO
+ selection=OCORRENCIA_TIPO,
+ default='ocorrencias',
)
diff --git a/l10n_br_hr_holiday/models/resource_calendar.py b/l10n_br_hr_holiday/models/resource_calendar.py
deleted file mode 100644
index 01d0efc32..000000000
--- a/l10n_br_hr_holiday/models/resource_calendar.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2016 KMEE - Hendrix Costa
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-from openerp import api, models
-
-
-class ResourceCalendar(models.Model):
-
- _inherit = 'resource.calendar'
-
- @api.multi
- def get_ocurrences(self, employee_id, data_from, data_to):
- """Calcular a quantidade de faltas/ocorrencias que devem ser
- descontadas da folha de pagamento em determinado intervalo de tempo.
- :param employee_id: Id do funcionario
- str data_from: Data inicial do intervalo de tempo.
- str data_end: Data final do intervalo
- :return dict {
- - int faltas_remuneradas: Quantidade de faltas que devem
- ser remuneradas dentro do intervalo passado como parâmetro
- - int faltas_nao_remuneradas: Quantidade de faltas que NAO
- serao remuneradas. (Descontadas da folha de pagamento)
- }
- """
- faltas = {
- 'faltas_remuneradas': [],
- 'quantidade_dias_faltas_remuneradas': 0,
- 'faltas_nao_remuneradas': [],
- 'quantidade_dias_faltas_nao_remuneradas': 0,
- }
- domain = [
- ('state', '=', 'validate'),
- ('employee_id', '=', employee_id),
- ('type', '=', 'remove'),
- ('date_from', '>=', data_from),
- ('date_to', '<=', data_to),
- ]
- holidays_ids = self.env['hr.holidays'].search(domain)
-
- for leave in holidays_ids:
- if leave.payroll_discount:
- faltas['faltas_nao_remuneradas'].append(leave)
- faltas['quantidade_dias_faltas_nao_remuneradas'] += \
- leave.number_of_days_temp
- else:
- faltas['faltas_remuneradas'].append(leave)
- faltas['quantidade_dias_faltas_remuneradas'] += \
- leave.number_of_days_temp
- return faltas
diff --git a/l10n_br_hr_holiday/security/hr_holidays_status.xml b/l10n_br_hr_holiday/security/hr_holidays_status.xml
index bd690ba6f..561b181e5 100644
--- a/l10n_br_hr_holiday/security/hr_holidays_status.xml
+++ b/l10n_br_hr_holiday/security/hr_holidays_status.xml
@@ -15,5 +15,14 @@
+
+
+ Employee Read Contract
+
+ [('employee_id.user_id','=',user.id)]
+
+
+
+
diff --git a/l10n_br_hr_holiday/security/ir.model.access.csv b/l10n_br_hr_holiday/security/ir.model.access.csv
new file mode 100644
index 000000000..6b386a4d2
--- /dev/null
+++ b/l10n_br_hr_holiday/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_hr_contract_employee,access_hr_contract_employee,hr_contract.model_hr_contract,base.group_user,1,0,0,0
diff --git a/l10n_br_hr_holiday/tests/__init__.py b/l10n_br_hr_holiday/tests/__init__.py
old mode 100755
new mode 100644
diff --git a/l10n_br_hr_holiday/tests/test_hr_holiday.py b/l10n_br_hr_holiday/tests/test_hr_holiday.py
index 4a35cd092..34cc4fd9c 100644
--- a/l10n_br_hr_holiday/tests/test_hr_holiday.py
+++ b/l10n_br_hr_holiday/tests/test_hr_holiday.py
@@ -120,7 +120,7 @@ def test_03_holiday_limit_days(self):
'holiday_status_id': holiday_status_id.id,
'employee_id': self.employee_hruser_id.id,
'date_from': fields.Datetime.from_string('2016-12-07 07:00:00'),
- 'date_to': fields.Datetime.from_string('2016-12-11 19:00:00'),
+ 'date_to': fields.Datetime.from_string('2016-12-11 19:00:00'),
'number_of_days_temp': 5,
'attachment_ids': [(6, 0, [self.attach1.id])],
})
@@ -141,7 +141,7 @@ def test_04_holiday_limit_days(self):
'holiday_status_id': holiday_status_id.id,
'employee_id': self.employee_hruser_id.id,
'date_from': fields.Datetime.from_string('2016-12-07 07:00:00'),
- 'date_to': fields.Datetime.from_string('2016-12-13 19:00:00'),
+ 'date_to': fields.Datetime.from_string('2016-12-13 19:00:00'),
'number_of_days_temp': 7,
'attachment_ids': [(6, 0, [self.attach1.id])],
})
@@ -161,7 +161,7 @@ def test_05_holiday_limit_hours(self):
'holiday_status_id': holiday_status_id.id,
'employee_id': self.employee_hruser_id.id,
'date_from': fields.Datetime.from_string('2016-12-07 07:00:00'),
- 'date_to': fields.Datetime.from_string('2016-12-07 08:00:00'),
+ 'date_to': fields.Datetime.from_string('2016-12-07 08:00:00'),
'number_of_days_temp': 1,
})
self.assertEqual(self.hr_holidays.search_count([
diff --git a/l10n_br_hr_holiday/tests/test_resource_calendar.py b/l10n_br_hr_holiday/tests/test_resource_calendar.py
index 54c60ab19..d7773821c 100644
--- a/l10n_br_hr_holiday/tests/test_resource_calendar.py
+++ b/l10n_br_hr_holiday/tests/test_resource_calendar.py
@@ -53,7 +53,7 @@ def test_01_get_ocurrences(self):
data_inicio = '2017-01-01 00:00:01'
data_final = '2017-01-31 23:59:59'
- faltas = self.resource_calendar.get_ocurrences(
+ faltas = self.hr_holidays.get_ocurrences(
self.employee_hruser_id.id, data_inicio, data_final)
quantidade_faltas = faltas['quantidade_dias_faltas_nao_remuneradas']
@@ -61,8 +61,11 @@ def test_01_get_ocurrences(self):
quantidade_faltas, 1,
'ERRO: Nao foi possivel obter faltas do Funcionario!')
self.assertEqual(
- faltas['faltas_nao_remuneradas'][0].name, u'Falta Injusticada',
- 'ERRO: Nao foi possivel obter faltas do Funcionario!')
+ faltas['faltas_nao_remuneradas'][0].name,
+ # u'[Employee Luiza] Absence unjustified (10/01/2017-10/01/2017)',
+ u'Falta Injusticada',
+ 'ERRO: Nao foi possivel obter faltas do Funcionario!'
+ )
def test_02_get_ocurrences(self):
""" teste da funcao que obtem a quantidade de faltas de determinado
@@ -87,7 +90,7 @@ def test_02_get_ocurrences(self):
data_inicio = '2017-01-01 00:00:01'
data_final = '2017-01-31 23:59:59'
- faltas = self.resource_calendar.get_ocurrences(
+ faltas = self.hr_holidays.get_ocurrences(
self.employee_hruser_id.id, data_inicio, data_final)
quantidade_faltas = faltas['quantidade_dias_faltas_nao_remuneradas']
@@ -96,5 +99,7 @@ def test_02_get_ocurrences(self):
'ERRO: Nao foi possivel obter faltas do Funcionario!')
self.assertEqual(
faltas['faltas_nao_remuneradas'][0].name,
+ # u'[Employee Luiza] Absence unjustified (10/01/2017-12/01/2017)',
u'Falta Injusticada de 3 dias',
- 'ERRO: Nao foi possivel obter faltas do Funcionario!')
+ 'ERRO: Nao foi possivel obter faltas do Funcionario!'
+ )
diff --git a/l10n_br_hr_holiday/views/calendar_event_view.xml b/l10n_br_hr_holiday/views/calendar_event_view.xml
new file mode 100644
index 000000000..d1fbcb622
--- /dev/null
+++ b/l10n_br_hr_holiday/views/calendar_event_view.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ L10n Br Hr Holiday Calendar Event
+ calendar.event
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/l10n_br_hr_holiday/views/hr_holidays.xml b/l10n_br_hr_holiday/views/hr_holidays.xml
index 9fbbf7637..49dce2300 100644
--- a/l10n_br_hr_holiday/views/hr_holidays.xml
+++ b/l10n_br_hr_holiday/views/hr_holidays.xml
@@ -10,6 +10,22 @@
hr.holidays
+
+
+
+
+ Período
+
+
+
+
+
@@ -23,6 +39,11 @@
+
+
+ {'invisible':[('holiday_type','=','category')]}
+
+
@@ -39,12 +60,38 @@
name="Ocorrencias"
action="l10n_br_hr_holiday_action_ocorrencias"
parent="hr_holidays.menu_open_ask_holidays"
- groups="base.group_hr_manager"
+ groups="base.group_user"
sequence="6"/>
-
- Evento
+
+
+
+
+ Pedido de Férias
+ hr.holidays
+
+ form
+
+ { 'default_tipo': 'ferias',
+ 'default_type': 'remove',
+ 'search_default_my_leaves':1}
+ [('type', '=', 'remove'),
+ ('tipo', '=', 'ferias')]
+
+
+
+ Clique para criar um novo pedido de férias.
+
+ Uma vez criado o pedido de férias, ele será enviado ao
+ gerente para a aprovação. Verifique se foi selecionado
+ corretamente o número de dias e o período aquisitivo.
+
+
+
+
+
diff --git a/l10n_br_hr_payment_order/README.rst b/l10n_br_hr_payment_order/README.rst
new file mode 100644
index 000000000..4148462d6
--- /dev/null
+++ b/l10n_br_hr_payment_order/README.rst
@@ -0,0 +1,79 @@
+.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+========================
+L10n Br Hr Payment Order
+========================
+
+Integração da folha de pagamento com as ordens de pagamento
+
+Installation
+============
+
+To install this module, you need to:
+
+#. Do this ...
+
+Configuration
+=============
+
+To configure this module, you need to:
+
+#. Go to ...
+
+Usage
+=====
+
+To use this module, you need to:
+
+#. Go to ...
+
+.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
+ :alt: Try me on Runbot
+ :target: https://runbot.odoo-community.org/runbot/{repo_id}/{branch}
+
+.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt
+.. branch is "8.0" for example
+
+Known issues / Roadmap
+======================
+
+* ...
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues
+`_. In case of trouble, please
+check there if your issue has already been reported. If you spotted it first,
+help us smashing it by providing a detailed and welcomed feedback.
+
+Credits
+=======
+
+Images
+------
+
+* Odoo Community Association: `Icon `_.
+
+Contributors
+------------
+
+* Firstname Lastname
+* Second Person
+
+Maintainer
+----------
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+This module is maintained by the OCA.
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+To contribute to this module, please visit https://odoo-community.org.
diff --git a/l10n_br_hr_payment_order/__init__.py b/l10n_br_hr_payment_order/__init__.py
new file mode 100644
index 000000000..ec485ab97
--- /dev/null
+++ b/l10n_br_hr_payment_order/__init__.py
@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import models
+from . import wizard
diff --git a/l10n_br_hr_payment_order/__openerp__.py b/l10n_br_hr_payment_order/__openerp__.py
new file mode 100644
index 000000000..40391ffa3
--- /dev/null
+++ b/l10n_br_hr_payment_order/__openerp__.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ 'name': 'L10n Br Hr Payment Order',
+ 'summary': """
+ Integração da folha de pagamento com as ordens de pagamento""",
+ 'version': '8.0.1.0.0',
+ 'license': 'AGPL-3',
+ 'author': 'KMEE,Odoo Community Association (OCA)',
+ 'website': 'www.kmee.com.br',
+ 'depends': [
+ 'l10n_br_hr_payroll',
+ 'l10n_br_financial_payment_order',
+ 'l10n_br_account_banking_payment_cnab',
+ 'account_payment_purchase',
+ ],
+ 'data': [
+ 'security/hr_payslip.xml',
+ 'security/payment_order.xml',
+ 'security/ir.model.access.csv',
+
+ 'wizard/payslip_payment_create_order_view.xml',
+
+ 'views/hr_payslip.xml',
+ 'views/hr_contract.xml',
+ 'views/hr_salary_rule_view.xml',
+ 'views/payment_mode.xml',
+ 'views/payment_order.xml',
+ 'views/res_config_view.xml',
+
+ 'hr_payroll_workflow.xml',
+ 'payment_order_workflow.xml',
+ ],
+ 'demo': [
+ 'demo/hr_salary_rule.xml',
+ 'demo/hr_payslip.xml',
+ 'demo/payment_order.xml',
+ ],
+}
diff --git a/l10n_br_hr_payment_order/demo/hr_payslip.xml b/l10n_br_hr_payment_order/demo/hr_payslip.xml
new file mode 100644
index 000000000..f33605d09
--- /dev/null
+++ b/l10n_br_hr_payment_order/demo/hr_payslip.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payment_order/demo/hr_salary_rule.xml b/l10n_br_hr_payment_order/demo/hr_salary_rule.xml
new file mode 100644
index 000000000..15eca9911
--- /dev/null
+++ b/l10n_br_hr_payment_order/demo/hr_salary_rule.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ True
+
+
+
+ True
+
+
+
+
diff --git a/l10n_br_hr_payment_order/demo/payment_order.xml b/l10n_br_hr_payment_order/demo/payment_order.xml
new file mode 100644
index 000000000..b1f6faf12
--- /dev/null
+++ b/l10n_br_hr_payment_order/demo/payment_order.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payment_order/hr_payroll_workflow.xml b/l10n_br_hr_payment_order/hr_payroll_workflow.xml
new file mode 100644
index 000000000..6e6ccd3d0
--- /dev/null
+++ b/l10n_br_hr_payment_order/hr_payroll_workflow.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+ paid_order
+
+
+
diff --git a/l10n_br_hr_payment_order/models/__init__.py b/l10n_br_hr_payment_order/models/__init__.py
new file mode 100644
index 000000000..424de0b3f
--- /dev/null
+++ b/l10n_br_hr_payment_order/models/__init__.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import payment_order
+from . import payment_line
+from . import hr_payslip
+from . import hr_contract
+# from . import hr_payslip_run
+from . import res_config
+from . import hr_salary_rule
+from . import bank_payment_line
diff --git a/l10n_br_hr_payment_order/models/bank_payment_line.py b/l10n_br_hr_payment_order/models/bank_payment_line.py
new file mode 100644
index 000000000..bdd50691e
--- /dev/null
+++ b/l10n_br_hr_payment_order/models/bank_payment_line.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+from openerp import models, fields
+
+
+class BankPaymentLine(models.Model):
+ _inherit = 'bank.payment.line'
+
+ payslip_id = fields.Many2one(
+ string="Holerite",
+ comodel_name="hr.payslip"
+ )
diff --git a/l10n_br_hr_payment_order/models/hr_contract.py b/l10n_br_hr_payment_order/models/hr_contract.py
new file mode 100644
index 000000000..a69c8a286
--- /dev/null
+++ b/l10n_br_hr_payment_order/models/hr_contract.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 KMEE - Hendrix Costa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import fields, models
+
+
+class HrContract(models.Model):
+ _inherit = 'hr.contract'
+
+ payment_mode_id = fields.Many2one(
+ string="Forma de Pagamento padrão do holerite",
+ comodel_name='payment.mode',
+ domain="[('tipo_pagamento', '=', 'folha')]"
+ )
diff --git a/l10n_br_hr_payment_order/models/hr_payslip.py b/l10n_br_hr_payment_order/models/hr_payslip.py
new file mode 100644
index 000000000..bf5a7d776
--- /dev/null
+++ b/l10n_br_hr_payment_order/models/hr_payslip.py
@@ -0,0 +1,139 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE
+# 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
+
+
+class HrPayslip(models.Model):
+
+ _inherit = 'hr.payslip'
+
+ payment_mode_id = fields.Many2one(
+ string="Modo de Pagamento",
+ comodel_name='payment.mode',
+ domain="[('tipo_pagamento', '=', 'folha')]"
+ )
+
+ payment_order_id = fields.Many2one(
+ string="Ordem de pagamento",
+ comodel_name='payment.order',
+ readonly=True,
+ # domain="[('type', '=', type)]",
+ )
+
+ payment_line_ids = fields.One2many(
+ string="Pagamentos",
+ comodel_name="payment.line",
+ inverse_name="payslip_id",
+ readonly=True,
+ )
+
+ paid_order = fields.Boolean(
+ string='Pago',
+ compute='_compute_paid',
+ readonly=True,
+ store=True,
+ )
+
+ @api.multi
+ def test_paid(self):
+ if not self.payment_line_ids:
+ return False
+ for line in self.payment_line_ids:
+ if not line.state2:
+ return False
+ if line.state2 != 'paid':
+ return False
+ return True
+
+ @api.one
+ @api.depends('payment_line_ids.bank_line_id.state2')
+ def _compute_paid(self):
+ self.paid_order = self.test_paid()
+
+ def _compute_set_employee_id(self):
+ """
+ Setar a forma de pagamento no compute do holerite, buscando do contrato
+ """
+ super(HrPayslip, self)._compute_set_employee_id()
+ for record in self:
+ if record.contract_id:
+ record.payment_mode_id = record.contract_id.payment_mode_id
+ # partner_id = \
+ # record.contract_id.employee_id.parent_id.user_id.partner_id
+ # record.payment_mode_id = partner_id.supplier_payment_mode
+
+ @api.multi
+ def action_done(self):
+ self.write({'state': 'done'})
+ return True
+
+ def create_payorder(self, mode_payment):
+ '''
+ Cria um payment order com base no metodo de pagamento
+ :param mode_payment: Modo de pagamento
+ :return: objeto do payment.order
+ '''
+ payment_order_model = self.env['payment.order']
+ vals = {'mode': mode_payment.id, }
+ return payment_order_model.create(vals)
+
+ @api.multi
+ def create_payment_order_line(
+ self, payment_order, total, communication, partner_id):
+ """
+ Cria a linha da ordem de pagamento
+ """
+ payment_line_model = self.env['payment.line']
+ vals = {
+ 'order_id': payment_order.id,
+ 'bank_id': self.contract_id.conta_bancaria_id.id,
+ 'partner_id': partner_id.id,
+ # 'move_line_id': self.id,
+ 'communication': communication,
+ # 'communication_type': communication_type,
+ # 'currency_id': currency_id,
+ 'amount_currency': total,
+ # date is set when the user confirms the payment order
+ 'payslip_id': self.id,
+ }
+ return payment_line_model.create(vals)
+
+ @api.multi
+ def create_payment_order(self):
+
+ payment_order_model = self.env['payment.order']
+
+ for holerite in self:
+ if holerite.state != 'verify':
+ raise UserError(_(
+ "The payslip %s is not in Open state") %
+ holerite.contract_id.nome_contrato)
+ if not holerite.payment_mode_id:
+ raise UserError(_(
+ "No Payment Mode on holerite %s") % holerite.number)
+
+ # Buscar ordens de pagamento do mesmo tipo
+ payorders = payment_order_model.search([
+ ('mode', '=', holerite.payment_mode_id.id),
+ ('state', '=', 'draft')]
+ )
+
+ if payorders:
+ payorder = payorders[0]
+ else:
+ payorder = self.create_payorder(holerite.payment_mode_id)
+
+ for rubrica in holerite.line_ids:
+ if rubrica.code == 'LIQUIDO':
+ self.create_payment_order_line(
+ payorder, rubrica.total,
+ 'SALARIO ' + holerite.data_mes_ano, rubrica.partner_id)
+
+ if rubrica.code == 'PENSAO_ALIMENTICIA':
+ self.create_payment_order_line(
+ payorder, rubrica.total,
+ 'PENSAO ALIMENTICIA ' + holerite.data_mes_ano,
+ rubrica.partner_id)
diff --git a/l10n_br_hr_payment_order/models/hr_payslip_run.py b/l10n_br_hr_payment_order/models/hr_payslip_run.py
new file mode 100644
index 000000000..5942e3bf5
--- /dev/null
+++ b/l10n_br_hr_payment_order/models/hr_payslip_run.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+# import logging
+# from openerp import exceptions, _
+# from openerp import api, models
+#
+# _logger = logging.getLogger(__name__)
+#
+# class HrPayslipRun(models.Model):
+# # _inherit = "hr.payslip.run"
+#
+# @api.multi
+# def gerar_holerites(self):
+# for lote in self:
+# lote.verificar_holerites_gerados()
+# for contrato in lote.contract_id:
+# try:
+# payslip_obj = self.env['hr.payslip']
+# payslip = payslip_obj.create({
+# 'contract_id': contrato.id,
+# 'mes_do_ano': self.mes_do_ano,
+# 'mes_do_ano2': self.mes_do_ano,
+# 'ano': self.ano,
+# 'employee_id': contrato.employee_id.id,
+# 'tipo_de_folha': self.tipo_de_folha,
+# 'payslip_run_id': self.id,
+# })
+# payslip._compute_set_dates()
+# payslip.compute_sheet()
+# _logger.info(u"Holerite " + contrato.name + u" processado com sucesso!")
+# # Mudado o processo para executar o hr_verify_sheet no
+# # botão "Close" do Lote do Holerite ao invés do botão
+# # "Gerar Holerites"
+# # payslip.hr_verify_sheet()
+# except:
+# _logger.warning(u"Holerite " + contrato.name + u" falhou durante o cálculo!")
+# payslip.unlink()
+# continue
+# lote.verificar_holerites_gerados()
diff --git a/l10n_br_hr_payment_order/models/hr_salary_rule.py b/l10n_br_hr_payment_order/models/hr_salary_rule.py
new file mode 100644
index 000000000..5b9c84311
--- /dev/null
+++ b/l10n_br_hr_payment_order/models/hr_salary_rule.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import models, fields
+
+
+class HrSalaryRule(models.Model):
+ _inherit = "hr.salary.rule"
+
+ eh_pagavel = fields.Boolean(
+ string="É pagavel?"
+ )
diff --git a/l10n_br_hr_payment_order/models/payment_line.py b/l10n_br_hr_payment_order/models/payment_line.py
new file mode 100644
index 000000000..da335ebee
--- /dev/null
+++ b/l10n_br_hr_payment_order/models/payment_line.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import api, fields, models
+
+
+class PaymentLine(models.Model):
+ _inherit = 'payment.line'
+
+ payslip_id = fields.Many2one(
+ string="Ref do Holerite",
+ comodel_name="hr.payslip",
+ )
+
+ def _get_payment_line_reference(self):
+ res = super(PaymentLine, self)._get_payment_line_reference()
+ res.append((
+ self.env['hr.payslip']._name,
+ self.env['hr.payslip']._description
+ ))
+ return res
+
+ @api.multi
+ @api.depends('payslip_id', 'financial_id')
+ def _compute_reference_id(self):
+
+ # if not mode == 'folha':
+ # return super
+
+ for record in self:
+ if record.payslip_id:
+ record.reference_id = (
+ record.payslip_id._name +
+ ',' +
+ str(record.payslip_id.id)
+ )
diff --git a/l10n_br_hr_payment_order/models/payment_order.py b/l10n_br_hr_payment_order/models/payment_order.py
new file mode 100644
index 000000000..e5268c677
--- /dev/null
+++ b/l10n_br_hr_payment_order/models/payment_order.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import api, fields, models
+
+from openerp.addons.l10n_br_hr_payroll.models.hr_payslip import (
+ TIPO_DE_FOLHA,
+)
+
+
+class PaymentOrder(models.Model):
+ _inherit = 'payment.order'
+
+ tipo_de_folha = fields.Selection(
+ selection=TIPO_DE_FOLHA,
+ string=u'Tipo de folha',
+ default='normal',
+ states={'done': [('readonly', True)]},
+ )
+
+ hr_payslip_ids = fields.One2many(
+ string='Holerites',
+ comodel_name='hr.payslip',
+ inverse_name='payment_order_id',
+ readonly=True,
+ states={'draft': [('readonly', False)]},
+ )
+
+ mesmo_banco = fields.Boolean(
+ string="Somente para Mesmo Banco ?",
+ default=True,
+ )
+
+ cnab_file = fields.Binary(
+ string='CNAB File',
+ readonly=True,
+ )
+
+ cnab_filename = fields.Char("CNAB Filename")
+
+ @api.multi
+ def _prepare_folha_payment_line(self, line):
+ self.ensure_one()
+# date_to_pay = False # no payment date => immediate payment
+ state = 'normal'
+ communication = 'Holerite: ' + line.display_name or '-'
+ amount_currency = line.total
+
+ # Seta no Holerite em qual remessa esta o pagamento
+ line.slip_id.payment_order_id = self.id
+
+ if line.partner_id != line.slip_id.employee_id.address_home_id:
+ banco = line.partner_id.bank_ids[0].id,
+ else:
+ banco = line.slip_id.employee_id.bank_account_id.id,
+
+ res = {
+ 'amount_currency': amount_currency,
+ 'bank_id': banco,
+ 'order_id': self.id,
+ 'partner_id': line.partner_id and line.partner_id.id or False,
+ # account banking
+ 'communication': communication,
+ 'state': state,
+ # end account banking
+ 'date': self.date_scheduled,
+ 'payslip_id': line.slip_id.id,
+ }
+ return res
+
+ @api.one
+ def folha_payment_import(self):
+ """ A importação de holerites nas payment orders funciona da
+ seguinte maneira:
+
+ 1. Busca holerites que estão no status: "Aguardando pagamento" e
+ coincidem com o tipo setado no filtro
+
+ 2. Preparar: Prepara os dados para inclusão:
+ _prepare_financial_payment_line
+ 3. Criar
+ """
+
+ # Identifica o banco de pagamento
+ banco = self.mode.bank_id.bank.id
+
+ self.line_ids.unlink()
+ self.hr_payslip_ids = False
+
+ payslip_ids = self.env['hr.payslip'].search([
+ ('tipo_de_folha', '=', self.tipo_de_folha),
+ ('state', '=', 'verify'),
+ ('payment_mode_id', '=', self.mode.id),
+ ])
+
+ rubricas_pagaveis = self.env['hr.salary.rule'].search([
+ ('eh_pagavel', '=', True)
+ ])
+
+ payslip_line_ids = self.env['hr.payslip.line'].search([
+ ('slip_id', 'in', payslip_ids.ids),
+ ('salary_rule_id', 'in', rubricas_pagaveis.ids)
+ ])
+
+ # Populate the current payment with new lines:
+ for line in payslip_line_ids:
+
+ # Identifica o banco de pagamento do holerite
+ if line.partner_id != line.slip_id.employee_id.address_home_id:
+ if line.partner_id.bank_ids:
+ banco_holerite = line.partner_id.bank_ids[0].bank.id
+ else:
+ banco_holerite = False
+ else:
+ banco_holerite = \
+ line.slip_id.employee_id.bank_account_id.bank.id
+
+ if banco_holerite and banco == banco_holerite:
+ vals = self._prepare_folha_payment_line(line)
+ self.env['payment.line'].create(vals)
+
+ return
diff --git a/l10n_br_hr_payment_order/models/res_config.py b/l10n_br_hr_payment_order/models/res_config.py
new file mode 100644
index 000000000..33789a69c
--- /dev/null
+++ b/l10n_br_hr_payment_order/models/res_config.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 KMEE
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import fields, models
+
+
+class AccountResConfig(models.Model):
+ _inherit = "account.config.settings"
+
+ automated_payslip_payment_order = fields.Boolean(
+ string="Gerar Ordem de Pagamento dos Holerites Automaticamente",
+ )
diff --git a/l10n_br_hr_payment_order/payment_order_workflow.xml b/l10n_br_hr_payment_order/payment_order_workflow.xml
new file mode 100644
index 000000000..e52aa37a7
--- /dev/null
+++ b/l10n_br_hr_payment_order/payment_order_workflow.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ cancel
+
+ cancel()
+ function
+ True
+
+
+
+
diff --git a/l10n_br_hr_payment_order/security/hr_payslip.xml b/l10n_br_hr_payment_order/security/hr_payslip.xml
new file mode 100644
index 000000000..67fe21c16
--- /dev/null
+++ b/l10n_br_hr_payment_order/security/hr_payslip.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ hr.payslip access name
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payment_order/security/ir.model.access.csv b/l10n_br_hr_payment_order/security/ir.model.access.csv
new file mode 100644
index 000000000..2be2aa486
--- /dev/null
+++ b/l10n_br_hr_payment_order/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+access_payslip_payment_order_create,access_payslip_payment_order_create,model_payslip_payment_order_create,,1,0,1,0
+access_account_config_settings,access_account_config_settings,model_account_config_settings,,1,0,0,0
\ No newline at end of file
diff --git a/l10n_br_hr_payment_order/security/payment_order.xml b/l10n_br_hr_payment_order/security/payment_order.xml
new file mode 100644
index 000000000..3e7116a37
--- /dev/null
+++ b/l10n_br_hr_payment_order/security/payment_order.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ payment.order access name
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payment_order/static/description/icon.png b/l10n_br_hr_payment_order/static/description/icon.png
new file mode 100644
index 000000000..3a0328b51
Binary files /dev/null and b/l10n_br_hr_payment_order/static/description/icon.png differ
diff --git a/l10n_br_hr_payment_order/views/hr_contract.xml b/l10n_br_hr_payment_order/views/hr_contract.xml
new file mode 100644
index 000000000..f49156245
--- /dev/null
+++ b/l10n_br_hr_payment_order/views/hr_contract.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ hr.contract.form (in l10n_br_hr_payment_order)
+ hr.contract
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payment_order/views/hr_payslip.xml b/l10n_br_hr_payment_order/views/hr_payslip.xml
new file mode 100644
index 000000000..c31674519
--- /dev/null
+++ b/l10n_br_hr_payment_order/views/hr_payslip.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+ hr.payslip.form (in l10n_br_hr_payment_order)
+ hr.payslip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payment_order/views/hr_salary_rule_view.xml b/l10n_br_hr_payment_order/views/hr_salary_rule_view.xml
new file mode 100644
index 000000000..b9c61d9b0
--- /dev/null
+++ b/l10n_br_hr_payment_order/views/hr_salary_rule_view.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ hr.salary.rule.payment
+ hr.salary.rule
+
+
+
+
+
+
+
+
+
+
diff --git a/l10n_br_hr_payment_order/views/payment_mode.xml b/l10n_br_hr_payment_order/views/payment_mode.xml
new file mode 100644
index 000000000..ab0482be5
--- /dev/null
+++ b/l10n_br_hr_payment_order/views/payment_mode.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+ Pagamento Folha
+ payment.mode
+ tree,form
+ [('tipo_pagamento', '=', 'folha'), ('tipo_servico', '=', '30')]
+ {'default_tipo_pagamento': 'folha', 'default_tipo_servico': '30'}
+
+
+
+ Pagamento Folha
+
+
+
+
+
+
+
+ form
+
+
+
+
+
+
+ tree
+
+
+
+
+
+
\ No newline at end of file
diff --git a/l10n_br_hr_payment_order/views/payment_order.xml b/l10n_br_hr_payment_order/views/payment_order.xml
new file mode 100644
index 000000000..740cac484
--- /dev/null
+++ b/l10n_br_hr_payment_order/views/payment_order.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+ payment.order.folha.form (in l10n_br_financial_payment_order)
+ payment.order
+ primary
+
+
+
+ Pagamento da Folha
+
+
+
+
+
+
+
+
+