diff --git a/.gitignore b/.gitignore index 900205c..072a880 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dist/** .pydevproject .settings nbproject/ +.idea \ No newline at end of file diff --git a/README.md b/README.md index 5f073de..95d90af 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,10 @@ Camada de abstração para integração via API com o MoIP em Python. - Author: Hebert Amaral - Contributor: Ale Borba - Contributor: Igor Hercowitz + - Contributor: Victor Hugo + - Contributor: Felipe Gubert Cruz - - Version: v0.2 + - Version: v0.4 Dependências ------------ @@ -15,7 +17,7 @@ Dependências O MoIPy tem as seguintes dependências: - lxml - - pycurl + - httplib Instalação ---------- @@ -37,9 +39,9 @@ Uso Basta importar a classe do MoIP e sair brincando :-) - from moipy import MoIP + from moipy import Moip - moip = MoIP('Razao do Pagamento') + moip = Moip('Razao do Pagamento') moip.set_credenciais(token='seu_token',key='sua_key') moip.set_ambiente('sandbox') @@ -50,21 +52,41 @@ Basta importar a classe do MoIP e sair brincando :-) print moip.get_resposta() # {sucesso:'Sucesso','token':'KJHSDASKD392847293AHFJKDSAH'} + +Para checkout transparente basta chamar: + + self.moip.set_checkout_transparente() + +neste caso é obrigatorio passar os dados do pagador: + + endereco = dict(Logradouro='Rua xxxxx',Numero='222',Bairro='xxxx',Cidade='xxxx',Estado='xx',CEP='xxxxxx',TelefoneFixo='xxxxxxxxxx') + self.moip.set_pagador(Nome='xxxx',Email='xxxxxx',Apelido='vitalbh',IdPagador='x',EnderecoCobranca=endereco) + + ChangeLog ---------- - v0.2 - - Refatorações de código - - Retirada dos DocTests +v0.4 + - Troca do pyCurl por httplib + - Melhorias no código/documentação + - Adiciona arquivo de teste na raiz do projeto. + +v0.3 + - Suporte a checkout transparente + - Adição dos dados do Pagador + - Teste do envio de intrução para checkout transparente + +v0.2 + - Refatorações de código + - Retirada dos DocTests - v0.1 - - First version +v0.1 + - First version ToDo ------ - Aplicar testes automatizados usando unittest - - Incluir dados do pagador - Validar campos diff --git a/moipy/moip.py b/moipy/moip.py index 4692846..8979dd0 100644 --- a/moipy/moip.py +++ b/moipy/moip.py @@ -1,129 +1,153 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- import base64 -import pycurl - +import httplib from lxml import etree class Moip(): - def __init__(self, razao, xml_node = "EnviarInstrucao"): - + def __init__(self, razao, xml_node="EnviarInstrucao"): + if xml_node: self.xml_node = etree.Element(xml_node) - - self._monta_xml(self.xml_node, unique = True, InstrucaoUnica = dict(Razao=razao)) - - + + self._monta_xml(self.xml_node, unique=True, InstrucaoUnica=dict(Razao=razao)) + def _monta_xml(self, parent, unique=False, **kwargs): """Metodo interno que monta o XML utilizando os parametros passados por outros metodos.""" - + if isinstance(parent, etree._Element): node_parent = parent else: node_parent = etree.Element(parent) - - for k,v in kwargs.items(): + + for k, v in kwargs.items(): if unique and node_parent.find(k) is not None: - node = node_parent.find(k) + node = node_parent.find(k) else: node = etree.SubElement(node_parent, k) - + if isinstance(v, dict): self._monta_xml(node, **v) else: node.text = v - - return node_parent + return node_parent def set_credenciais(self, token, key): - + """Define as credenciais utilizadas para autenticar a chamada aos webservices + """ + self.token = token self.key = key - + return self - - def set_ambiente(self,ambiente): + def set_ambiente(self, ambiente): + """Define se o ambiente é o de homologação (sandbox) ou de produção + """ - if ambiente=="sandbox": + if ambiente == "sandbox": + self.host = 'desenvolvedor.moip.com.br' + self.post_url = '/sandbox/ws/alpha/EnviarInstrucao/Unica' self.url = "https://desenvolvedor.moip.com.br/sandbox/ws/alpha/EnviarInstrucao/Unica" - elif ambiente=="producao": + elif ambiente == "producao": + self.host = 'www.moip.com.br' + self.post_url = '/ws/alpha/EnviarInstrucao/Unica' self.url = "https://www.moip.com.br/ws/alpha/EnviarInstrucao/Unica" else: raise ValueError("Ambiente inválido") - - + def set_valor(self, valor): - + """Define o valor a ser enviado + """ + self._monta_xml(self.xml_node, unique=True, InstrucaoUnica=dict(Valores=dict(Valor=valor))) - - return self + return self def set_id_proprio(self, id): - + """Define o ID proprio da transação + """ + self._monta_xml(self.xml_node, unique=True, InstrucaoUnica=dict(IdProprio=id)) - + return self + def set_data_vencimento(self, data): + """Define a data de vencimento + """ - def set_data_vencimento(self,data): - self._monta_xml(self.xml_node, unique=True, InstrucaoUnica=dict(DataVencimento=data)) - + return self + def set_recebedor(self, login_moip, email, apelido): + """Define o recebedor + """ - def set_recebedor(self,login_moip,email,apelido): - self._monta_xml(self.xml_node, unique=True, InstrucaoUnica=dict(Recebedor=dict(LoginMoip=login_moip, Email=email, Apelido=apelido))) return self - - def envia(self): - resposta = RespostaMoIP() - - passwd = self.token + ":" + self.key - - passwd64 = base64.b64encode(passwd) - - curl = pycurl.Curl() - curl.setopt(pycurl.URL,self.url) - curl.setopt(pycurl.HTTPHEADER,["Authorization: Basic " + passwd64]) - curl.setopt(pycurl.USERAGENT,"Mozilla/4.0") - curl.setopt(pycurl.USERPWD,passwd) - curl.setopt(pycurl.POST,True) - curl.setopt(pycurl.POSTFIELDS,self._get_xml()) - curl.setopt(pycurl.WRITEFUNCTION,resposta.callback) - curl.perform() - curl.close() - - self.retorno = resposta.conteudo + def set_pagador(self, **pagador): + """Define o pagador e endereço de cobrança + """ + + if not 'EnderecoCobranca' in pagador: + return False + + if not 'Pais' in pagador['EnderecoCobranca']: + pagador['EnderecoCobranca']['Pais'] = 'BRA' + + self._monta_xml(self.xml_node, unique=True, InstrucaoUnica=dict(Pagador=pagador)) return self + def set_checkout_transparente(self): + """Define que o checkout sera transparente + """ - def _get_xml(self): - """Metodo interno que retorna o objeto etree em formato string""" - - return etree.tostring(self.xml_node) - + instrucao = self._monta_xml(self.xml_node, unique=True, InstrucaoUnica=dict()) + instrucao.find('InstrucaoUnica').set('TipoValidacao', 'Transparente') - def get_resposta(self): - - resposta = etree.XML(self.retorno) - return {'sucesso':resposta[0][1].text,'token':resposta[0][2].text} + def envia(self): + """Comunica com o webservice e envia a transação + """ + # base64 encode the username and password + auth = base64.encodestring('%s:%s' % (self.token, self.key)).replace('\n', '') + + webservice = httplib.HTTPSConnection(self.host) + # headers + webservice.putrequest("POST", self.post_url) + webservice.putheader("Host", self.host) + webservice.putheader("User-Agent", "Mozilla/4.0") + webservice.putheader("Content-type", "text/html; charset=\"UTF-8\"") + webservice.putheader("Content-length", "%d" % len(self._get_xml())) + webservice.putheader("Authorization", "Basic %s" % auth) + webservice.endheaders() + webservice.send(self._get_xml()) -class RespostaMoIP: - def __init__(self): - self.conteudo = '' + resposta = webservice.getresponse() + self.status = resposta.status + self.retorno = resposta.read() - def callback(self,buf): - self.conteudo = buf \ No newline at end of file + return self + + def _get_xml(self): + """Metodo interno que retorna o objeto etree em formato string""" + + return etree.tostring(self.xml_node) + + def get_resposta(self): + """Trata o retorno + """ + if self.status == 200: + resposta = etree.XML(self.retorno) + return {'sucesso': resposta[0][1].text, 'token': resposta[0][2].text} + else: + return {'sucesso': u'Falha', 'token': u'Não autorizado. Verifique seu Token/key'} diff --git a/setup.py b/setup.py index c9cf5b7..a45cf97 100644 --- a/setup.py +++ b/setup.py @@ -3,10 +3,10 @@ from distutils.core import setup setup(name='Moipy', - version='0.2', + version='0.4', description='Python integration with MoIP payment gateway via API', - author=['Herberth Amaral','Ale Borba'], - author_email=['herberthamaral@gmail.com','ale.alvesborba@gmail.com'], + author=['Herberth Amaral','Ale Borba','Victor', 'Felipe Gubert'], + author_email=['herberthamaral@gmail.com','ale.alvesborba@gmail.com','vitalbh@gmail.com', 'felipe.gubert@gmail.com'], url='http://labs.moip.com.br/', packages=['moipy'], classifiers=[ diff --git a/test.py b/test.py new file mode 100644 index 0000000..a6814f5 --- /dev/null +++ b/test.py @@ -0,0 +1,12 @@ +from moipy import Moip + +moip = Moip('Razao do Pagamento') + +moip.set_credenciais(token='seu_token',key='sua_key') +moip.set_ambiente('sandbox') +moip.set_valor('12345') +moip.set_data_vencimento('yyyy-mm-dd') +moip.set_id_proprio('abc1234') +moip.envia() + +print moip.get_resposta() \ No newline at end of file diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/test.py b/test/test.py index e69de29..62c6aea 100644 --- a/test/test.py +++ b/test/test.py @@ -0,0 +1,34 @@ +import unittest +from moipy.moip import Moip +import random + +class MoipTestCase(unittest.TestCase): + + def setUp(self): + self.moip = Moip('Razao do Pagamento') + self.moip.set_credenciais(token='seu token',key='sua key') + self.moip.set_ambiente('sandbox') + + + def test_set_pagador(self): + + self.moip.set_checkout_transparente() + self.moip.set_valor('12345') + self.moip.set_data_vencimento('yyyy-mm-dd') + self.moip.set_id_proprio(str(random.randrange(500000))) + + endereco = dict(Logradouro='Rua santa ceia',Numero='222',Bairro='Buritis',Cidade='Belo Horizonte',Estado='MG',CEP='30850170',TelefoneFixo='3125124444') + + self.moip.set_pagador(Nome='Victor',Email='vitalbh@gmail.com',Apelido='vitalbh',IdPagador='1',EnderecoCobranca=endereco) + + self.moip.envia() + + resposta = self.moip.get_resposta() + + self.assertEqual(resposta['sucesso'],'Sucesso') + self.assertIsInstance(resposta['token'],str) + + + + if __name__ == '__main__': + unittest.main() \ No newline at end of file