Acesso Externo via API (Web Service)
Índice
- Apresentação
- Ambiente de Teste e Produção
- Autenticação
- Consultar Notas Fiscais
- Emitir Notas Fiscais
- Cancelar Notas Fiscais
- Consultar Faturas
- Gerar Boleto de Faturas Selecionadas
Apresentação
Visando atender a necessidade dos contribuintes que precisam enviar ou consultar muitos registros, ou que desejam automatizar o acesso fazendo integração nos seus próprios sistemas, a prefeitura disponibiliza um acesso externo via API (Web Service).
Ambiente de Teste e Produção
O usuário tem à disposição dois ambientes, um somente para realizar testes, chamado de Ambiente de Teste, acessível através da URL https://riachao.teste.cecsystem.com.br, e o outro chamado Ambiente de Produção, acessível através da URL https://riachao.cecsystem.com.br. Antes de submeter qualquer dado para o Ambiente de Produção, é altamente recomendável utilizar primeiro o Ambiente de Teste para entender como a API funciona.
Qualquer usuário cadastrado no sistema pode fazer o acesso via API, desde que tenha a devida permissão para fazer operações de consulta, criação, atualização ou cancelamento sobre o registro em questão. Se ainda não está cadastrado, faça o seu cadastro antes de continuar, bastando acessar os links postados anteriormente. Observe que no Ambiente de Produção, é necessário aguardar a aprovação do cadastro para acessar o sistema (e consequentemente a API).
Autenticação
Para fazer a comunicação com a API, o usuário pode usar qualquer linguagem de programação capaz de fazer chamadas XML-RPC. Também é necessário criar uma Chave de API, bastando acessar o menu Perfil > Preferências:
Acessando aba Segurança da Conta:
Clicando no botão para criar uma Nova Chave de API:
O usuário pode criar quantas chaves quiser, bem como pode revogar o acesso para as chaves existentes. Isso é muito útil para fornecer acesso à sistemas de terceiros, sem precisar informar a sua senha de acesso ao sistema (login).
De posse do nome de usuário (o mesmo usado para fazer login no sistema) e da chave de API (recém criada anteriormente), basta preencher os seguintes parâmetros:
# Ambiente de Produção
# url = 'https://riachao.cecsystem.com.br'
# Ambiente de Teste
url = 'https://riachao.teste.cecsystem.com.br'
banco = 'riachao'
usuario = 'inserir nome de usuário'
chave = 'inserir chave da API'
// Ambiente de Produção
// final String url = "https://riachao.cecsystem.com.br";
// Ambiente de Teste
final String url = "https://riachao.teste.cecsystem.com.br";
final String db = "riachao",
username = "nserir nome de usuário",
password = "inserir chave da API";
# Ambiente de Produção
# url = 'https://riachao.cecsystem.com.br'
# Ambiente de Teste
url = 'https://riachao.teste.cecsystem.com.br'
db = 'riachao'
username = 'inserir nome de usuário'
password = 'inserir chave da API'
Utilize os parâmetros anteriores para autenticar:
import xmlrpc.client
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(banco, usuario, chave, {})
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
def call(model, method, *args, **kwargs):
"""
Função auxiliar para ser usada nas futuras chamadas.
"""
return models.execute_kw(banco, uid, chave, model, method, args, kwargs)
Note que a biblioteca xmlrpc
já vem instalada por padrão em qualquer ambiente
Python, não sendo necessária nenhuma dependência externa para realizar a comunicação.
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.XmlRpcException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
final XmlRpcClient client = new XmlRpcClient();
final XmlRpcClientConfigImpl common_config = new XmlRpcClientConfigImpl();
common_config.setServerURL(new URL(String.format("%s/xmlrpc/2/common", url)));
int uid = (int)client.execute(
common_config, "authenticate",
Arrays.asList(db, username, password, Collections.emptyMap())
);
final XmlRpcClient models = new XmlRpcClient() {{
setConfig(new XmlRpcClientConfigImpl() {{
setServerURL(new URL(String.format("%s/xmlrpc/2/object", url)));
}});
}};
require "xmlrpc/client"
common = XMLRPC::Client.new2("#{url}/xmlrpc/2/common")
uid = common.call('authenticate', db, username, password, {})
models = XMLRPC::Client.new2("#{url}/xmlrpc/2/object").proxy
Note que a biblioteca xmlrpc
já vem instalada por padrão em qualquer ambiente
Ruby, não sendo necessária nenhuma dependência externa para realizar a comunicação.
Consultar Notas Fiscais
Liste as dez primeiras identificações id de notas fiscais do usuário:
call('prefeitura.nota_fiscal', 'search', [], limit=10)
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "search",
Arrays.asList(Collections.emptyList()),
new HashMap() {{ put("limit", 10); }}
)));
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'search', [[]],
{limit: 10})
Exemplo de resultado:
[3986, 3985, 3984, 3983, 3982, 3981, 3979, 3978, 3977, 3976]
Pula os três primeiros registros e lista as sete identificações id da sequência de notas
fiscais (utilize offset
e limit
para controlar a paginação):
call('prefeitura.nota_fiscal', 'search', [], offset=3, limit=7)
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "search",
Arrays.asList(Collections.emptyList()),
new HashMap() {{ put("offset", 3); put("limit", 7); }}
)));
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'search', [[]],
{offset: 3, limit: 7})
Exemplo de resultado:
[3983, 3982, 3981, 3979, 3978, 3977, 3976]
Utilize filtros para listar as dez primeiras identificações id de notas fiscais já canceladas, em ordem decrescente pela data de cancelamento (data_hora_cancelamento):
call('prefeitura.nota_fiscal', 'search', [['state', '=', 'CANCELADA']],
limit=10, order='data_hora_cancelamento DESC')
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "search",
Arrays.asList(Arrays.asList(Arrays.asList("state", "=", "CANCELADA"))),
new HashMap() {{
put("limit", 10);
put("order", "data_hora_cancelamento DESC");
}}
)));
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'search',
[[['state', '=', 'CANCELADA']]],
{limit: 10, order: 'data_hora_cancelamento DESC'})
Exemplo de resultado:
[3901, 3833, 3856, 3838, 3818, 3793, 3497, 3781, 3780, 3758]
Leia os campos de identificação id
, número da nota name
e data de
cancelamento data_hora_cancelamento
dos registros utilizando cinco identificações
id de notas fiscais retornadas pela chamada search
realizada anteriormente:
call('prefeitura.nota_fiscal', 'read', [3901, 3833, 3856, 3838, 3818],
fields=['id', 'name', 'data_hora_cancelamento'])
Exemplo de resultado:
[
{'id': 3901,
'name': 'NF-2023-483-00001',
'data_hora_cancelamento': '2023-01-10 17:51:48'},
{'id': 3833,
'name': 'NF-2023-498-00001',
'data_hora_cancelamento': '2023-01-04 16:41:24'},
{'id': 3856,
'name': 'NF-2023-52-00001',
'data_hora_cancelamento': '2023-01-03 20:13:19'},
{'id': 3838,
'name': 'NF-2023-27-00002',
'data_hora_cancelamento': '2023-01-02 20:04:13'},
{'id': 3818,
'name': 'NF-2022-498-00001',
'data_hora_cancelamento': '2022-12-29 12:43:10'},
]
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "read",
Arrays.asList(Arrays.asList(3901, 3833, 3856, 3838, 3818)),
new HashMap() {{
put("fields", Arrays.asList("id", "name", "data_hora_cancelamento"));
}}
)));
Exemplo de resultado:
[
{'id': 3901,
'name': 'NF-2023-483-00001',
'data_hora_cancelamento': '2023-01-10 17:51:48'},
{'id': 3833,
'name': 'NF-2023-498-00001',
'data_hora_cancelamento': '2023-01-04 16:41:24'},
{'id': 3856,
'name': 'NF-2023-52-00001',
'data_hora_cancelamento': '2023-01-03 20:13:19'},
{'id': 3838,
'name': 'NF-2023-27-00002',
'data_hora_cancelamento': '2023-01-02 20:04:13'},
{'id': 3818,
'name': 'NF-2022-498-00001',
'data_hora_cancelamento': '2022-12-29 12:43:10'},
]
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'read',
[[3901, 3833, 3856, 3838, 3818]],
{fields: %w(id name data_hora_cancelamento)})
Exemplo de resultado:
[
{"id" => 3901,
"name" => "NF-2023-483-00001",
"data_hora_cancelamento" => "2023-01-10 17:51:48"},
{"id" => 3833,
"name" => "NF-2023-498-00001",
"data_hora_cancelamento" => "2023-01-04 16:41:24"},
{"id" => 3856,
"name" => "NF-2023-52-00001",
"data_hora_cancelamento" => "2023-01-03 20:13:19"},
{"id" => 3838,
"name" => "NF-2023-27-00002",
"data_hora_cancelamento" => "2023-01-02 20:04:13"},
{"id" => 3818,
"name" => "NF-2022-498-00001",
"data_hora_cancelamento" => "2022-12-29 12:43:10"}
]
Como é muito comun se utilizar filtros para ler os campos dos registros, existe o comando
search_read
que combina as chamadas search
e read
em uma só:
call('prefeitura.nota_fiscal', 'search_read', [['state', '=', 'CANCELADA']],
['id', 'name', 'data_hora_cancelamento'],
limit=5, order='data_hora_cancelamento DESC')
Exemplo de resultado:
[
{'id': 3901,
'name': 'NF-2023-483-00001',
'data_hora_cancelamento': '2023-01-10 17:51:48'},
{'id': 3833,
'name': 'NF-2023-498-00001',
'data_hora_cancelamento': '2023-01-04 16:41:24'},
{'id': 3856,
'name': 'NF-2023-52-00001',
'data_hora_cancelamento': '2023-01-03 20:13:19'},
{'id': 3838,
'name': 'NF-2023-27-00002',
'data_hora_cancelamento': '2023-01-02 20:04:13'},
{'id': 3818,
'name': 'NF-2022-498-00001',
'data_hora_cancelamento': '2022-12-29 12:43:10'},
]
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "search_read",
Arrays.asList(
Arrays.asList(Arrays.asList("state", "=", "CANCELADA")),
Arrays.asList("id", "name", "data_hora_cancelamento")
),
new HashMap() {{
put("limit", 5);
put("order", "data_hora_cancelamento DESC");
}}
)));
Exemplo de resultado:
[
{'id': 3901,
'name': 'NF-2023-483-00001',
'data_hora_cancelamento': '2023-01-10 17:51:48'},
{'id': 3833,
'name': 'NF-2023-498-00001',
'data_hora_cancelamento': '2023-01-04 16:41:24'},
{'id': 3856,
'name': 'NF-2023-52-00001',
'data_hora_cancelamento': '2023-01-03 20:13:19'},
{'id': 3838,
'name': 'NF-2023-27-00002',
'data_hora_cancelamento': '2023-01-02 20:04:13'},
{'id': 3818,
'name': 'NF-2022-498-00001',
'data_hora_cancelamento': '2022-12-29 12:43:10'},
]
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'search_read',
[[['state', '=', 'CANCELADA']],
['id', 'name', 'data_hora_cancelamento']],
{limit: 5, order: 'data_hora_cancelamento DESC'})
Exemplo de resultado:
[
{"id" => 3901,
"name" => "NF-2023-483-00001",
"data_hora_cancelamento" => "2023-01-10 17:51:48"},
{"id" => 3833,
"name" => "NF-2023-498-00001",
"data_hora_cancelamento" => "2023-01-04 16:41:24"},
{"id" => 3856,
"name" => "NF-2023-52-00001",
"data_hora_cancelamento" => "2023-01-03 20:13:19"},
{"id" => 3838,
"name" => "NF-2023-27-00002",
"data_hora_cancelamento" => "2023-01-02 20:04:13"},
{"id" => 3818,
"name" => "NF-2022-498-00001",
"data_hora_cancelamento" => "2022-12-29 12:43:10"}
]
Utilize o método search_count
para contar a quantidade de registros de um determinado filtro:
call('prefeitura.nota_fiscal', 'search_count', [['state', '=', 'CANCELADA']])
(Integer)models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "search_count",
Arrays.asList(Arrays.asList(Arrays.asList("state", "=", "CANCELADA")))
));
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'search_count',
[[['state', '=', 'CANCELADA']]])
Exemplo de resultado:
23
Obtenha todos os nomes dos campos, tipos e descrições de ajuda de um determinado
model, sendo nesse caso prefeitura.nota_fiscal
(funciona para inspecionar
qualquer model):
call('prefeitura.nota_fiscal', 'fields_get',
attributes=['string', 'help', 'type', 'required', 'selection', 'relation'])
Exemplo de resultado:
{
'name': {'type': 'char',
'required': False,
'string': 'Número da Nota'},
'state': {'type': 'selection',
'required': False,
'selection': [['RASCUNHO', 'Rascunho'],
['CONCLUIDO', 'Emitida'],
['CANCELADA', 'Cancelada']],
'string': 'Estado'},
'prestador_id': {'type': 'many2one',
'help': 'Identificação do PRESTADOR.\n É importante que a Atividade Econômica esteja previamente registrada no cadastro do Prestador.',
'required': True,
'string': 'Prestador de Serviço',
'relation': 'res.partner'},
'tomador_id': {'type': 'many2one',
'help': "Identificação do TOMADOR.\n Para criar um novo registro basta digitar o nome do prestador e teclar 'Enter'. \nLogo após, uma tela será exibida para completar o cadastro. \nDá próxima vez este tomador estará disponível para seleção.",
'required': True,
'string': 'Tomador de Serviço',
'relation': 'prefeitura.tomador'},
'city_id': {'type': 'many2one',
'required': True,
'string': 'Local de Prestação do Serviço',
'relation': 'res.city'},
'description': {'type': 'text',
'help': 'Escreva aqui informações sobre os serviços prestados.',
'required': False,
'string': 'Descrição'},
'competencia': {'type': 'date',
'help': 'Selecione uma data dentro do mês corrente. ',
'required': True,
'string': 'Competência'},
'emissao': {'type': 'datetime',
'required': False,
'string': 'Data de Emissão'},
'data_hora_cancelamento': {'type': 'datetime',
'required': False,
'string': 'Data de Cancelamento'},
'cnae_ids': {'type': 'many2many',
'help': 'Selecione entre os CNAEs informados no cadastro do prestador.',
'required': False,
'string': 'CNAE',
'relation': 'prefeitura.cnae'},
'servico_ids': {'type': 'many2many',
'help': 'Selecione entre os serviços informados no cadastro do prestador.',
'required': True,
'string': 'Serviços',
'relation': 'prefeitura.servico'},
'local_incidencia_iss': {'type': 'selection',
'required': False,
'selection': [['PRESTADOR', 'Local do Prestador'],
['TOMADOR', 'Local do Tomador'],
['SERVICO', 'Local da prestação de serviço']],
'string': 'Local de Incidência do ISS'},
'tipo_recolhimento': {'type': 'selection',
'required': False,
'selection': [['ISS_RETIDO', 'ISS retido.'],
['ISS_A_RECOLHER', 'ISS a recolher.']],
'string': 'Tipo de Recolhimento'},
'item_ids': {'type': 'one2many',
'help': 'Especifique os serviços prestados informando a quantidade e valor unitário para cada ítem.',
'required': False,
'string': 'Itens',
'relation': 'prefeitura.item_nota_fiscal'},
'item_total': {'type': 'float',
'required': False,
'string': 'Total dos Itens'},
'base_calculo': {'type': 'monetary',
'help': 'Valor utilizado para a base de cálculo do ISS.',
'required': False,
'string': 'Base de Cálculo'},
'aliquota': {'type': 'float',
'help': 'Alíquota estabelecida pelo CTM.',
'required': False,
'string': 'Alíquota (%)'},
'valor_iss': {'type': 'monetary',
'required': False,
'string': 'Valor do ISS'},
'valor_total_deducoes': {'type': 'monetary',
'required': False,
'string': 'Valor Total das Retenções'},
'nome_arquivo_pdf': {'type': 'char',
'help': 'Nome do arquivo PDF.',
'required': False,
'string': 'Nome do Arquivo PDF'},
'arquivo_pdf': {'type': 'binary',
'help': 'Este arquivo permanecerá como RASCUNHO até a confirmação do pagamento da guia de ISS. \n Exceto para contribuintes optantes pelo Simples Nacional.',
'required': False,
'string': 'Arquivo PDF'},
'nome_arquivo_xml': {'type': 'char',
'help': 'Nome do arquivo XML.',
'required': False,
'string': 'Nome do Arquivo XML'},
'arquivo_xml': {'type': 'binary',
'help': 'Arquivo no formato XML.',
'required': False,
'string': 'Arquivo XML'},
'boleto_id': {'type': 'many2one', 'required': False, 'string': 'Boleto', 'relation': 'prefeitura.boleto'},
'boleto_state': {'type': 'selection',
'required': False,
'selection': [['RASCUNHO', 'Rascunho'],
['ABERTO', 'Emitido'],
['VENCIDO', 'Vencido'],
['PAGO', 'Pago'],
['CANCELADO', 'Cancelado']],
'string': 'Estado do Boleto'},
'possui_pagamento_pendente': {'type': 'boolean',
'required': False,
'string': 'Possui Pagamento Pendente'},
}
(Map<String, Map<String, Object>>)models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "fields_get",
Collections.emptyList(),
new HashMap() {{
put("attributes", Arrays.asList("string", "help", "type", "required",
"selection", "relation"));
}}
));
Exemplo de resultado:
{
'name': {'type': 'char',
'required': False,
'string': 'Número da Nota'},
'state': {'type': 'selection',
'required': False,
'selection': [['RASCUNHO', 'Rascunho'],
['CONCLUIDO', 'Emitida'],
['CANCELADA', 'Cancelada']],
'string': 'Estado'},
'prestador_id': {'type': 'many2one',
'help': 'Identificação do PRESTADOR.\n É importante que a Atividade Econômica esteja previamente registrada no cadastro do Prestador.',
'required': True,
'string': 'Prestador de Serviço',
'relation': 'res.partner'},
'tomador_id': {'type': 'many2one',
'help': "Identificação do TOMADOR.\n Para criar um novo registro basta digitar o nome do prestador e teclar 'Enter'. \nLogo após, uma tela será exibida para completar o cadastro. \nDá próxima vez este tomador estará disponível para seleção.",
'required': True,
'string': 'Tomador de Serviço',
'relation': 'prefeitura.tomador'},
'city_id': {'type': 'many2one',
'required': True,
'string': 'Local de Prestação do Serviço',
'relation': 'res.city'},
'description': {'type': 'text',
'help': 'Escreva aqui informações sobre os serviços prestados.',
'required': False,
'string': 'Descrição'},
'competencia': {'type': 'date',
'help': 'Selecione uma data dentro do mês corrente. ',
'required': True,
'string': 'Competência'},
'emissao': {'type': 'datetime',
'required': False,
'string': 'Data de Emissão'},
'data_hora_cancelamento': {'type': 'datetime',
'required': False,
'string': 'Data de Cancelamento'},
'cnae_ids': {'type': 'many2many',
'help': 'Selecione entre os CNAEs informados no cadastro do prestador.',
'required': False,
'string': 'CNAE',
'relation': 'prefeitura.cnae'},
'servico_ids': {'type': 'many2many',
'help': 'Selecione entre os serviços informados no cadastro do prestador.',
'required': True,
'string': 'Serviços',
'relation': 'prefeitura.servico'},
'local_incidencia_iss': {'type': 'selection',
'required': False,
'selection': [['PRESTADOR', 'Local do Prestador'],
['TOMADOR', 'Local do Tomador'],
['SERVICO', 'Local da prestação de serviço']],
'string': 'Local de Incidência do ISS'},
'tipo_recolhimento': {'type': 'selection',
'required': False,
'selection': [['ISS_RETIDO', 'ISS retido.'],
['ISS_A_RECOLHER', 'ISS a recolher.']],
'string': 'Tipo de Recolhimento'},
'item_ids': {'type': 'one2many',
'help': 'Especifique os serviços prestados informando a quantidade e valor unitário para cada ítem.',
'required': False,
'string': 'Itens',
'relation': 'prefeitura.item_nota_fiscal'},
'item_total': {'type': 'float',
'required': False,
'string': 'Total dos Itens'},
'base_calculo': {'type': 'monetary',
'help': 'Valor utilizado para a base de cálculo do ISS.',
'required': False,
'string': 'Base de Cálculo'},
'aliquota': {'type': 'float',
'help': 'Alíquota estabelecida pelo CTM.',
'required': False,
'string': 'Alíquota (%)'},
'valor_iss': {'type': 'monetary',
'required': False,
'string': 'Valor do ISS'},
'valor_total_deducoes': {'type': 'monetary',
'required': False,
'string': 'Valor Total das Retenções'},
'nome_arquivo_pdf': {'type': 'char',
'help': 'Nome do arquivo PDF.',
'required': False,
'string': 'Nome do Arquivo PDF'},
'arquivo_pdf': {'type': 'binary',
'help': 'Este arquivo permanecerá como RASCUNHO até a confirmação do pagamento da guia de ISS. \n Exceto para contribuintes optantes pelo Simples Nacional.',
'required': False,
'string': 'Arquivo PDF'},
'nome_arquivo_xml': {'type': 'char',
'help': 'Nome do arquivo XML.',
'required': False,
'string': 'Nome do Arquivo XML'},
'arquivo_xml': {'type': 'binary',
'help': 'Arquivo no formato XML.',
'required': False,
'string': 'Arquivo XML'},
'boleto_id': {'type': 'many2one', 'required': False, 'string': 'Boleto', 'relation': 'prefeitura.boleto'},
'boleto_state': {'type': 'selection',
'required': False,
'selection': [['RASCUNHO', 'Rascunho'],
['ABERTO', 'Emitido'],
['VENCIDO', 'Vencido'],
['PAGO', 'Pago'],
['CANCELADO', 'Cancelado']],
'string': 'Estado do Boleto'},
'possui_pagamento_pendente': {'type': 'boolean',
'required': False,
'string': 'Possui Pagamento Pendente'},
}
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal',
'fields_get', [],
{attributes: %w(string help type required selection relation)})
Exemplo de resultado:
{
"name" => {
"type" => "char",
"required" => false,
"string" => "Número da Nota"},
"state" => {
"type" => "selection",
"required" => false,
"selection" => [
["RASCUNHO", "Rascunho"],
["CONCLUIDO", "Emitida"],
["CANCELADA", "Cancelada"]
],
"string" => "Estado"},
"prestador_id" => {
"type" => "many2one",
"help" => "Identificação do PRESTADOR.\n É importante que a Atividade Econômica esteja previamente registrada no cadastro do Prestador.",
"required" => true,
"string" => "Prestador de Serviço",
"relation" => "res.partner"},
"tomador_id" => {
"type" => "many2one",
"help" => "Identificação do TOMADOR.\n Para criar um novo registro basta digitar o nome do prestador e teclar 'Enter'. \nLogo após, uma tela será exibida para completar o cadastro. \nDá próxima vez este tomador estará disponível para seleção.",
"required" => true,
"string" => "Tomador de Serviço",
"relation" => "prefeitura.tomador"},
"city_id" => {
"type" => "many2one",
"required" => true,
"string" => "Local de Prestação do Serviço",
"relation" => "res.city"},
"description" => {
"type" => "text",
"help" => "Escreva aqui informações sobre os serviços prestados.",
"required" => false,
"string" => "Descrição"},
"competencia" => {
"type" => "date",
"help" => "Selecione uma data dentro do mês corrente. ",
"required" => true,
"string" => "Competência"},
"emissao" => {
"type" => "datetime",
"required" => false,
"string" => "Data de Emissão"},
"data_hora_cancelamento" => {
"type" => "datetime",
"required" => false,
"string" => "Data de Cancelamento"},
"cnae_ids" => {
"type" => "many2many",
"help" => "Selecione entre os CNAEs informados no cadastro do prestador.",
"required" => false,
"string" => "CNAE",
"relation" => "prefeitura.cnae"},
"servico_ids" => {
"type" => "many2many",
"help" => "Selecione entre os serviços informados no cadastro do prestador.",
"required" => true,
"string" => "Serviços",
"relation" => "prefeitura.servico"},
"local_incidencia_iss" => {
"type" => "selection",
"required" => false,
"selection" => [
["PRESTADOR", "Local do Prestador"],
["TOMADOR", "Local do Tomador"],
["SERVICO", "Local da prestação de serviço"]
],
"string" => "Local de Incidência do ISS"},
"tipo_recolhimento" => {
"type" => "selection",
"required" => false,
"selection" => [
["ISS_RETIDO", "ISS retido."],
["ISS_A_RECOLHER", "ISS a recolher."]
],
"string" => "Tipo de Recolhimento"},
"item_ids" => {
"type" => "one2many",
"help" => "Especifique os serviços prestados informando a quantidade e valor unitário para cada ítem.",
"required" => false,
"string" => "Itens",
"relation" => "prefeitura.item_nota_fiscal"},
"item_total" => {
"type" => "float",
"required" => false,
"string" => "Total dos Itens"},
"base_calculo" => {
"type" => "monetary",
"help" => "Valor utilizado para a base de cálculo do ISS.",
"required" => false,
"string" => "Base de Cálculo"},
"aliquota" => {
"type" => "float",
"help" => "Alíquota estabelecida pelo CTM.",
"required" => false,
"string" => "Alíquota (%)"},
"valor_iss" => {
"type" => "monetary",
"required" => false,
"string" => "Valor do ISS"},
"valor_total_deducoes" => {
"type" => "monetary",
"required" => false,
"string" => "Valor Total das Retenções"},
"nome_arquivo_pdf" => {
"type" => "char",
"help" => "Nome do arquivo PDF.",
"required" => false,
"string" => "Nome do Arquivo PDF"},
"arquivo_pdf" => {
"type" => "binary",
"help" => "Este arquivo permanecerá como RASCUNHO até a confirmação do pagamento da guia de ISS. \n Exceto para contribuintes optantes pelo Simples Nacional.",
"required" => false,
"string" => "Arquivo PDF"},
"nome_arquivo_xml" => {
"type" => "char",
"help" => "Nome do arquivo XML.",
"required" => false,
"string" => "Nome do Arquivo XML"},
"arquivo_xml" => {
"type" => "binary",
"help" => "Arquivo no formato XML.",
"required" => false,
"string" => "Arquivo XML"},
"boleto_id" => {
"type" => "many2one",
"required" => false,
"string" => "Boleto",
"relation" => "prefeitura.boleto"},
"boleto_state" => {
"type" => "selection",
"required" => false,
"selection" => [
["RASCUNHO", "Rascunho"],
["ABERTO", "Emitido"],
["VENCIDO", "Vencido"],
["PAGO", "Pago"],
["CANCELADO", "Cancelado"]
],
"string" => "Estado do Boleto"},
"possui_pagamento_pendente" => {
"type" => "boolean",
"required" => false,
"string" => "Possui Pagamento Pendente"
}
}
Emitir Notas Fiscais
O processo segue o mesmo procedimento de emissão de nota fiscal utilizando o formulário no
navegador, primeiro é necessário criar o registro, que por padrão estará no
estado RASCUNHO
. Nessa fase, o usuário pode realizar alterações e correções
nos dados submetidos. Após tudo conferido, o usuário executa a ação de Emitir,
que mudará o estado do registro para CONCLUIDO
(emitido).
Antes de realizar a criação da nota fiscal, é preciso definir os valores dos campos obrigatórios.
Para identificar esses campos, basta localicar os atributos dos campos marcados como
'required': True
(ver saída do comando anterior). No caso da nota fiscal, os campos
obrigatórios são: tomador_id
, city_id
e competencia
. Observe
que os campos prestador_id
e servico_ids
também são obrigatórios, mas
não é necessário definir um valor, pois o sistema obtem um valor padrão para eles (baseado
no usuário logado que está fazendo a requisição).
tomador_id = call('prefeitura.tomador', 'search', [
('name', 'ilike', 'peças'),
], limit=1)[0]
city_id = call('res.city', 'search', [
('name', 'ilike', 'riachão'),
('state_id.name', 'ilike', 'maranhão'),
], limit=1)[0]
Object tomadorId = Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.tomador", "search",
Arrays.asList(Arrays.asList(Arrays.asList("name", "ilike", "peças"))),
new HashMap() {{
put("limit", 1);
}}
))).get(0);
Object cityId = Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"res.city", "search",
Arrays.asList(Arrays.asList(
Arrays.asList("name", "ilike", "riachão"),
Arrays.asList("state_id.name", "ilike", "maranhão")
)),
new HashMap() {{
put("limit", 1);
}}
))).get(0);
tomador_id = models.execute_kw(db, uid, password, 'prefeitura.tomador', 'search', [[
['name', 'ilike', 'peças']
]], {limit: 1})[0]
city_id = models.execute_kw(db, uid, password, 'res.city', 'search', [[
['name', 'ilike', 'riachão'],
['state_id.name', 'ilike', 'maranhão'],
]], {limit: 1})[0]
Observe que os comandos anteriores estão realizando consulta de dados em diferentes tabelas.
A cidade está sendo consultada na tabela res.city
, procurando o primeiro registro
que possua o nome riachão
em que está localizado no estado maranhão
.
O tomador é localizado na tabela prefeitura.tomador
, a consulta procura o primeiro
registro que possua o nome peças
. Note que foi utilizado o operador
ilike
. É possível usar qualquer um dos seguintes operadores:
=
Igual.
!=
Diferente.
>
Maior.
>=
Maior ou igual.
<
Menor.
<=
Menor ou igual.
=?
Indefinido ou igual (retorna true
se valor é None
ou False
,
do contrário se comporta como =
)
=like
Corresponde field_name
no seguinte padrão de valor: um sublinhado _
no
padrão significa (corresponde) qualquer caractere único; e um sinal de porcentagem %
corresponde qualquer string de zero ou mais caracteres.
like
Corresponde field_name
no padrão %valor%
. Parecido com =like
mas embrulha o valor com %
antes de corresponder.
not like
Não corresponde no padrão %value%
.
ilike
Caso maúsculo ou minúsculo de like
.
not ilike
Caso maúsculo ou minúsculo de not like
.
=ilike
Caso maúsculo ou minúsculo de =like
.
in
É igual a qualquer um dos itens da lista (nos casos do valor ser uma lista).
not in
É diferente de qualquer um dos itens da lista (nos casos do valor ser uma lista).
É possível criar um ou mais registros de notas fiscais na mesma submissão:
call('prefeitura.nota_fiscal', 'create', [
{
'tomador_id': tomador_id,
'city_id': city_id,
'competencia': '2023-02-10',
},
{
'tomador_id': tomador_id,
'city_id': city_id,
'competencia': '2023-02-10',
},
])
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "create",
Arrays.asList(Arrays.asList(
new HashMap() {{
put("tomador_id", tomadorId);
put("city_id", cityId);
put("competencia", "2023-02-10");
}},
new HashMap() {{
put("tomador_id", tomadorId);
put("city_id", cityId);
put("competencia", "2023-02-10");
}}
))
)));
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'create', [[
{
tomador_id: tomador_id,
city_id: city_id,
competencia: '2023-02-10',
},
{
tomador_id: tomador_id,
city_id: city_id,
competencia: '2023-02-10',
},
]])
Caso os dados submetidos estejam corretos, a requisição deverá retornar um ou mais números
de identificação id
dos registros recém criados:
[4279, 4280]
Utilize esses valores para consultar os estados de cada registro de nota fiscal:
call('prefeitura.nota_fiscal', 'read', [4279, 4280],
fields=['id', 'name', 'state'])
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "read",
Arrays.asList(Arrays.asList(4279, 4280)),
new HashMap() {{
put("fields", Arrays.asList("id", "name", "state"));
}}
)));
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'read',
[[4279, 4280]],
{fields: %w(id name state)})
[
{'id': 4279, 'name': 'NF-2023-23-00004', 'state': 'RASCUNHO'},
{'id': 4280, 'name': 'NF-2023-23-00003', 'state': 'RASCUNHO'},
]
Observe que os dois registros estão no estado de RASCUNHO
. Significa que esses
eles podem ser alterados (ainda não foram emitidos CONCLUIDO
). Para
adicionar um ou mais Itens da Nota, execute:
call('prefeitura.nota_fiscal', 'write', [4279], {
'item_ids': [
(0, 0, {
'name': "Primeiro Item",
'price': 123.45,
'quantity': 2,
}),
(0, 0, {
'name': "Segundo Item",
'price': 321.54,
'quantity': 1,
}),
]
})
(boolean)models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "write",
Arrays.asList(
Arrays.asList(4279),
new HashMap() {{
put("item_ids", Arrays.asList(
Arrays.asList(0, 0, new HashMap() {{
put("name", "Primeiro Item");
put("price", 123.45);
put("quantity", 2);
}}),
Arrays.asList(0, 0, new HashMap() {{
put("name", "Segundo Item");
put("price", 321.54);
put("quantity", 1);
}})
));
}}
)
))
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'write', [[4279], {
item_ids: [
[0, 0, {
name: "Primeiro Item",
price: 123.45,
quantity: 2,
}],
[0, 0, {
name: "Segundo Item",
price: 321.54,
quantity: 1,
}],
]
}])
Para consultar os campos alterados dos Itens da Nota, execute:
call('prefeitura.nota_fiscal', 'read', [4279],
fields=['id', 'name', 'state', 'item_ids'])
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "read",
Arrays.asList(Arrays.asList(4279)),
new HashMap() {{
put("fields", Arrays.asList("id", "name", "state", "item_ids"));
}}
)))
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'read',
[[4279]],
{fields: %w(id name state item_ids)})
[
{'id': 4279, 'name': 'NF-2023-23-00004', 'state': 'RASCUNHO', 'item_ids': [6171, 6172]},
]
Para remover um item da nota fiscal, execute:
call('prefeitura.nota_fiscal', 'write', [4279], {
'item_ids': [
(2, 6171, 0),
]
})
(boolean)models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "write",
Arrays.asList(
Arrays.asList(4279),
new HashMap() {{
put("item_ids", Arrays.asList(
Arrays.asList(2, 6171, 0)
));
}}
)
))
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'write', [[4279], {
item_ids: [
[2, 6171, 0],
]
}])
Observe que o item de identificação 6171
foi removido da relação.
Para consultar os campos alterados dos Itens da Nota, execute:
call('prefeitura.nota_fiscal', 'read', [4279],
fields=['id', 'name', 'state', 'item_ids'])
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "read",
Arrays.asList(Arrays.asList(4279)),
new HashMap() {{
put("fields", Arrays.asList("id", "name", "state", "item_ids"));
}}
)))
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal', 'read',
[[4279]],
{fields: %w(id name state item_ids)})
[
{'id': 4279, 'name': 'NF-2023-23-00004', 'state': 'RASCUNHO', 'item_ids': [6172]},
]
Observe que os comandos anteriores estão acessando os registros relacionados (itens da nota) usando o seguinte formato:
(0, 0, valores)
Adiciona um novo registro, criado a partir do dicionário valores
fornecido.
(1, id, valores)
Atualiza um registro existente de id
com os valores
fornecidos.
(2, id, 0)
Remove o registro de id
da relação, e depois deleta da tabela de origem.
(3, id, 0)
Remove o registro de id
da relação, mas não deleta da tabela de origem.
(4, id, 0)
Adiciona um registro existente de id
na relação.
(5, 0, 0)
Remove todos os registros da relação, e não os remove da tabela de origem.
(6, 0, ids)
Substitui todos os registros existentes da relação pelos ids
da lista, e não
os remove da tabela de origem.
Finalmente, para emitir a nota fiscal, execute:
call('prefeitura.nota_fiscal', 'action_emitir_nota_fiscal', [4279])
(Object)models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "action_emitir_nota_fiscal",
Arrays.asList(Arrays.asList(4279))
))
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal',
'action_emitir_nota_fiscal', [[4279]])
Baixar PDF do Boleto da Nota Fiscal
Após emissão da nota fiscal (p.ex. id = 4382), caso exista algum débito a ser pago, você poderá baixar o PDF do boleto de cobrança utilizando a URL do arquivo:
url = 'https://riachao.teste.cecsystem.com.br'
path = call('prefeitura.nota_fiscal', 'action_baixar_arquivo_pdf', [4382])['url']
print('{}/{}'.format(url, path))
String baseUrl = "https://riachao.teste.cecsystem.com.br";
String path = ((Map) models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "action_baixar_arquivo_pdf",
Arrays.asList(Arrays.asList(4382))
))).get("url");
System.out.println(baseUrl + "/" + path);
url = 'https://riachao.teste.cecsystem.com.br'
path = models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal',
'action_baixar_arquivo_pdf', [[4382]])['url']
puts url + '/' + path
"https://riachao.teste.cecsystem.com.br/web/content/prefeitura.nota_fiscal/4382/arquivo_pdf/nota-fiscal-nf-2023-23-00001.pdf?download=true"
Cancelar Notas Fiscais
Para cancelar uma ou mais notas fiscais (p.ex. id = 4279), execute:
call('prefeitura.nota_fiscal', 'action_cancelar', [4279])
(boolean)models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.nota_fiscal", "action_cancelar",
Arrays.asList(Arrays.asList(4279))
))
models.execute_kw(db, uid, password, 'prefeitura.nota_fiscal',
'action_cancelar', [[4279]])
Consultar Faturas
Para listar todas as faturas em aberto, execute:
call('account.move', 'search', [['state', '=', 'posted'], ['payment_state', '=', 'not_paid']])
Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"account.move", "search",
Arrays.asList(Arrays.asList(
Arrays.asList("state", "=", "posted"),
Arrays.asList("payment_state", "=", "not_paid")
)),
new HashMap() {{ }}
)));
models.execute_kw(db, uid, password, 'account.move', 'search', [[
['state', '=', 'posted'],
['payment_state', '=', 'not_paid'],
]], {})
Exemplo de resultado:
[356, 341, 134]
Gerar Boleto de Faturas Selecionadas
É possível gerar um boleto para pagar uma ou mais faturas, nesse caso para as faturas ids = [356, 341, 134]. Mas primeiro, certifique-se que todas as faturas possuem o mesmo contribuinte associado:
contribuintes = call('account.move', 'search_read', [['id', 'in', [356, 341, 134]]], ['partner_id'])
for contribuinte in contribuintes:
print(contribuinte)
List<Object> contribuintes = Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"account.move", "search_read",
Arrays.asList(
Arrays.asList(Arrays.asList("id", "in", Arrays.asList(356, 341, 134))),
Arrays.asList("partner_id")
),
new HashMap() {{ }}
)));
for (Object contribuinte : contribuintes) {
System.out.println(contribuinte);
}
contribuintes = models.execute_kw(db, uid, password, 'account.move', 'search_read', [[
['id', 'in', [356, 341, 134]],
], ['partner_id']], {})
for contribuinte in contribuintes do
puts contribuinte
end
Exemplo de resultado:
{'id': 356, 'partner_id': [378, 'Felipe Silva']}
{'id': 341, 'partner_id': [378, 'Felipe Silva']}
{'id': 134, 'partner_id': [378, 'Felipe Silva']}
Após confirmar que todas as faturas ids = [356, 341, 134] pertencem ao mesmo contribuinte id = 378, basta criar o boleto:
result = call('prefeitura.boleto', 'create', [{
'contribuinte_id': 378,
'move_ids': [356, 341, 134],
}])
print(result)
List<Object> result = Arrays.asList((Object[])models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.boleto", "create",
Arrays.asList(Arrays.asList(
new HashMap() {{
put("contribuinte_id", 378);
put("move_ids", Arrays.asList(356, 341, 134));
}}
))
)));
System.out.println(result);
result = models.execute_kw(db, uid, password, 'prefeitura.boleto', 'create', [[
{
contribuinte_id: 378,
'move_ids': [356, 341, 134],
},
]])
puts result
Exemplo de resultado:
[495]
O boleto recém-criado estará no estado RASCUNHO
. Nessa fase, o usuário pode realizar
alterações e correções nos dados submetidos. Após tudo conferido, o usuário executa a ação
de Emitir Boleto:
result = call('prefeitura.boleto', 'action_gerar_boleto', [495])
print(result)
Object result = (Object)models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.boleto", "action_gerar_boleto",
Arrays.asList(Arrays.asList(495))
));
System.out.println(result);
result = models.execute_kw(db, uid, password, 'prefeitura.boleto',
'action_gerar_boleto', [[495]])
puts result
Exemplo de resultado:
True
Após emissão do boleto de cobrança id = 495, você poderá baixar o arquivo PDF utilizando a URL do arquivo:
url = 'https://riachao.teste.cecsystem.com.br'
path = call('prefeitura.boleto', 'action_baixar_arquivo_pdf', [495])['url']
print('{}/{}'.format(url, path))
String baseUrl = "https://riachao.teste.cecsystem.com.br";
String path = ((Map) models.execute("execute_kw", Arrays.asList(
db, uid, password,
"prefeitura.boleto", "action_baixar_arquivo_pdf",
Arrays.asList(Arrays.asList(495))
))).get("url");
System.out.println(baseUrl + "/" + path);
url = 'https://riachao.teste.cecsystem.com.br'
path = models.execute_kw(db, uid, password, 'prefeitura.boleto',
'action_baixar_arquivo_pdf', [[495]])['url']
puts url + '/' + path
"https://riachao.teste.cecsystem.com.br/web/content/prefeitura.boleto/495/conteudo_pdf/boleto-495-felipe-silva-aberto-2023-04-10.pdf?download=true"
- Prefeitura de Currais
- Rua Padre Manoel Paredes, nº S/N
- Currais - PI 64905-000
- (86) 9 9903-9494
- suporte.currais@cecsystem.com.br
- Ver localização no Google Maps