[weboob] [PATCH 6/6] Add module [amelipro] for the heathcare professional ameli website

Kitof git at kitof.net
Mon Jul 22 16:11:29 CEST 2013


From: Christophe Lampin <weboob at lampin.net>


Signed-off-by: Christophe Lampin <weboob at lampin.net>
---
 modules/amelipro/__init__.py |  24 ++++++++++
 modules/amelipro/backend.py  |  93 ++++++++++++++++++++++++++++++++++++
 modules/amelipro/browser.py  | 109 ++++++++++++++++++++++++++++++++++++++++++
 modules/amelipro/favicon.png | Bin 0 -> 6369 bytes
 modules/amelipro/pages.py    | 111 +++++++++++++++++++++++++++++++++++++++++++
 modules/amelipro/test.py     |  34 +++++++++++++
 6 files changed, 371 insertions(+)
 create mode 100644 modules/amelipro/__init__.py
 create mode 100755 modules/amelipro/backend.py
 create mode 100755 modules/amelipro/browser.py
 create mode 100755 modules/amelipro/favicon.png
 create mode 100755 modules/amelipro/pages.py
 create mode 100755 modules/amelipro/test.py

diff --git a/modules/amelipro/__init__.py b/modules/amelipro/__init__.py
new file mode 100644
index 0000000..48b13b9
--- /dev/null
+++ b/modules/amelipro/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013      Christophe Lampin
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from .backend import AmeliProBackend
+
+
+__all__ = ['AmeliProBackend']
diff --git a/modules/amelipro/backend.py b/modules/amelipro/backend.py
new file mode 100755
index 0000000..3f0285f
--- /dev/null
+++ b/modules/amelipro/backend.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013      Christophe Lampin
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+import urllib
+from weboob.capabilities.bill import ICapBill, SubscriptionNotFound, BillNotFound, Subscription, Bill
+from weboob.tools.backend import BaseBackend, BackendConfig
+from weboob.tools.value import ValueBackendPassword
+from .browser import AmeliProBrowser
+
+__all__ = ['AmeliProBackend']
+
+
+class AmeliProBackend(BaseBackend, ICapBill):
+    NAME = 'amelipro'
+    DESCRIPTION = u'Ameli website: French Health Insurance for Professionals'
+    MAINTAINER = u'Christophe Lampin'
+    EMAIL = 'weboob at lampin.net'
+    VERSION = '0.g'
+    LICENSE = 'AGPLv3+'
+    BROWSER = AmeliProBrowser
+    CONFIG = BackendConfig(ValueBackendPassword('login',
+                                                label='numero de SS',
+                                                masked=False),
+                           ValueBackendPassword('password',
+                                                label='Password',
+                                                masked=True)
+                           )
+    BROWSER = AmeliProBrowser
+
+    def create_default_browser(self):
+        return self.create_browser(self.config['login'].get(),
+                                   self.config['password'].get())
+
+    def iter_subscription(self):
+        return self.browser.get_subscription_list()
+
+    def get_subscription(self, _id):
+        if not _id.isdigit():
+            raise SubscriptionNotFound()
+        with self.browser:
+            subscription = self.browser.get_subscription(_id)
+        if not subscription:
+            raise SubscriptionNotFound()
+        else:
+            return subscription
+
+    def iter_bills_history(self, subscription):
+        if not isinstance(subscription, Subscription):
+            subscription = self.get_subscription(subscription)
+        with self.browser:
+            return self.browser.iter_history(subscription)
+
+    def get_details(self, subscription):
+        if not isinstance(subscription, Subscription):
+            subscription = self.get_subscription(subscription)
+        with self.browser:
+            return self.browser.get_details(subscription)
+
+    def iter_bills(self, subscription):
+        if not isinstance(subscription, Subscription):
+            subscription = self.get_subscription(subscription)
+        with self.browser:
+            return self.browser.iter_bills()
+
+    def get_bill(self, id):
+        with self.browser:
+            bill = self.browser.get_bill(id)
+        if not bill:
+            raise BillNotFound()
+        else:
+            return bill
+
+    def download_bill(self, bill):
+        if not isinstance(bill, Bill):
+            bill = self.get_bill(bill)
+        with self.browser:
+            return self.browser.readurl(bill._url,urllib.urlencode(bill._args))
diff --git a/modules/amelipro/browser.py b/modules/amelipro/browser.py
new file mode 100755
index 0000000..d65c599
--- /dev/null
+++ b/modules/amelipro/browser.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013      Christophe Lampin
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+import urllib
+import mechanize
+from weboob.tools.browser import BaseBrowser
+from weboob.capabilities.bill import Detail
+from decimal import *
+from .pages import LoginPage, HomePage, AccountPage, HistoryPage, BillsPage
+
+__all__ = ['AmeliProBrowser']
+
+class AmeliProBrowser(BaseBrowser):
+    PROTOCOL = 'https'
+    DOMAIN = 'espacepro.ameli.fr'
+    ENCODING = None
+
+    PAGES = {'.*_pageLabel=vp_login_page.*':  LoginPage,
+             '.*_pageLabel=vp_accueil.*': HomePage,
+             '.*_pageLabel=vp_coordonnees_infos_perso_page.*': AccountPage,
+             '.*_pageLabel=vp_recherche_par_date_paiements_page.*': HistoryPage,
+             '.*_pageLabel=vp_releves_mensuels_page.*': BillsPage,
+             }
+
+    loginp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_login_page'
+    homep = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_accueil_book'
+    accountp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_coordonnees_infos_perso_page'
+    billsp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_releves_mensuels_page'
+    searchp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_recherche_par_date_paiements_page'
+    historyp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_windowLabel=vp_recherche_paiement_tiers_payant_portlet_1&vp_recherche_paiement_tiers_payant_portlet_1_actionOverride=%2Fportlets%2Fpaiements%2Frecherche&_pageLabel=vp_recherche_par_date_paiements_page'
+
+    def home(self):
+        self.location(self.homep)
+
+    def is_logged(self):
+        if self.is_on_page(LoginPage):
+            return False
+        return True
+
+    def login(self):
+        assert isinstance(self.username, basestring)
+        assert isinstance(self.password, basestring)
+        if not self.is_on_page(LoginPage):
+            self.location(self.loginp)
+        self.page.login(self.username, self.password)
+        if self.is_on_page(LoginPage):
+            raise BrowserIncorrectPassword()
+
+    def get_subscription_list(self):
+        if not self.is_on_page(AccountPage):
+            self.location(self.accountp)
+        return self.page.get_subscription_list()
+
+    def get_subscription(self, id):
+        assert isinstance(id, basestring)
+        return self.get_subscription_list()
+
+    def iter_history(self, subscription):
+        if not self.is_on_page(HistoryPage):
+            self.location(self.searchp)
+
+        date_deb = self.page.document.xpath('//input[@name="vp_recherche_paiement_tiers_payant_portlet_1dateDebutRecherche"]')[0].value
+        date_fin = self.page.document.xpath('//input[@name="vp_recherche_paiement_tiers_payant_portlet_1dateFinRecherche"]')[0].value
+
+        data = {'vp_recherche_paiement_tiers_payant_portlet_1dateDebutRecherche': date_deb,
+                'vp_recherche_paiement_tiers_payant_portlet_1dateFinRecherche': date_fin,
+                'vp_recherche_paiement_tiers_payant_portlet_1codeOrganisme': 'null',
+                'vp_recherche_paiement_tiers_payant_portlet_1actionEvt': 'rechercheParDate',
+                'vp_recherche_paiement_tiers_payant_portlet_1codeRegime': '01',
+               }
+
+        self.location(self.historyp, urllib.urlencode(data))
+        return self.page.iter_history()
+
+    def get_details(self, sub):
+        det = Detail()
+        det.id = sub.id
+        det.label = sub.label
+        det.infos = ''
+        det.price = Decimal('0.0')
+        return det
+
+    def iter_bills(self):
+        if not self.is_on_page(BillsPage):
+            self.location(self.billsp)
+        return self.page.iter_bills()
+
+    def get_bill(self, id):
+        assert isinstance(id, basestring)
+        for b in self.get_bills():
+            if id == b.id:
+                return b
+        return None
diff --git a/modules/amelipro/favicon.png b/modules/amelipro/favicon.png
new file mode 100755
index 0000000000000000000000000000000000000000..a6098aee9b4015f2a953dc0ac2ea552a90cf3d80
GIT binary patch
literal 6369
zcmV<77#`<|P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02*{fSaefwW^{L9
za%BKeVQFr3E>1;MAa*k at H7+qQF!XYv000<JNkl<ZcwX&Vd2roVb!LKzvrrOJ+D<!x
zq%$o;DIq1y0G)KmP-sgFlmUiz0u)H%B}o&U-~@=tN+59(9LI4?0<mLkS=Me_vMhO#
zWn0$1T2D{Q)06b}ecxB<>vw+3)3YPlBBXyb<w)oKmb;$so^$Rw_q})F9Z3uPlg~@j
zI~0JG(;ooPt~zyT*LONawCf)<Km%YU?&6(E at 4^Cw7bbO2dvVR$Jqq8vsX=-7c2ar&
zLR(wMl>4u3J)u08lU`QNGN<~!Ii+0MTv&d?hAKRDU`Qz!I%aU-wx2hb%H>{fFC<bE
zfO+1{8|1}<`+Cmn&|nYA>$i<A1mI${6ac~^WGInY5&)e=aN(uOgr#pGO0H>uM$)-d
z&^s4EbkZA3$5Q_NU!PF`lFsB=>dM4~q>ikX-bSzcRy9DVTp;O3pQGN^;*XcgrLDg5
za+NZfo6JMriJU at 3G6CS{!osih0c7I(y<SmBo-f63oHmt&l!0YXd8a at BJ^+a7>d)l>
zEX5asp;P(zaz9VuH2_dTN4FupqHZ(#vw%}RnQ~-B3(6;cA-`1s%2{8Or2vq{)6G_Y
zw;TX!y?GUYP&`vAxR6CSA^ll8xtJjOy{-Y}^!oxJed+ at 00LWF|>2-9omAZPHrA=Ug
z$Or(W`o7sx2TQRu*6%L`KzUg?%iwPnfTgG$0HN~wGETYAxR9l;N;CnnfUj*mt`z92
zEmUqtx*ZE&3IHK7k#Z-fJIMb{0HptNCoUu)=$arba}rrJt5-+?Kz$USSWuqc$y6 at 9
zP+2Hk{u*BG`hS25nS})|oWin*YAU=kl3n0!rewZAU0R at fk-r5+ukz%aFk_C~yvha6
zvRGoNr}8`lvw1$Viq>9uUM<u9<ZeL?;Ml8NIf at 2?ycY<R_GFbxH!8`a@~UhbBu~q$
zl~5>?L!OgV2UDje#*=10k-|J&$t-3<30UJf`11=$@O_HqI;Y85vH&CPG?7FU_9m?N
zDx$ElGC#Sp#yne)m9YgVDI%+%>XTAke^q)|niL-(eXo=vx%^WiysVNsi6U39NP!j*
zDb8aultk004X>OqU{AjTr=2NG#IrER(=f+Un2D!gO=jRpXA!2hq!ewC{?rvK2VoHa
zy-)yPsW8VB0CZNhfx5!0qCtG(+e?xPfO@|oDsbTWg*@ky<Cs}qGsyFr;yY(5ji(#?
z at SeN&Dg2=a>aek41TVB1 at k~<>9 at yK4YwxC~zNZS;-cyY$)>h$$A2uM8%_ChXB2y%g
z6jC_HadK4Y0(pKu&#^dOF+)!CK8+&BE%04|+8_%c3n5~Q at QPV+t}6k70B9($fU?DG
zB$bIEmhd1Nb08YGBNDeE$g3yrfx+#-)oUtM0M?N2)L5SN>s?y8eqVaO4_B_O#M$XN
z*usAH=ZBwthT<+nWUQE-Y~{TL;kZ>9)5kI&>qXKr0+?6KQq>++_!R;m)mBECd<=oG
z1vck7%-Z at eXYawRy$fc0FUB3C=r9 at ZomcA56Kavm1=qM7lsnb(8-G}Z<A!bwTSqYE
z7{ZLbk7IRntS-ztI$?Hp!sP6R(b<auYacpI{pg>a#B4B#a4wH5C06~4D!jsCBFoUb
z=wHu|S1&^OVjPLI8=>e70+9&>BV%L(e7v_sEEw at RQ8_Y!`|CPY;dBAZ0QusUX1s7}
z3>Cv>?CUpT=a~WgpyC);e;-z}eEloC(9m-nV@?BH;Yp5T<QSvmbMQw;;Ej&L5jDc-
zH=uQ at 8^3C6!i$YfsOcWYm_LFr^<M-kfuIP#{35S-8x&hC(A5<dlC=2<Z7)bW^pkza
z%!lDhMRCgF!M4sRtf?Nr=eGCamMw$$;A3a7dR<iskQ*PW#|d`?({zB=Tmdt5h9kik
zj!jNuf5#croIZ{|^C-LtH+ at 2g;{-T{m+axV9*#wo=lemg6}LRupn&>;yZ7S0oy}+%
zbHSXNM}+cbL=(umvtEu?3_zZp(De}n+2`r}xS1_1q&YwuX*$6P3h@%1-Su>QBIs(W
z^_A<YapihGmubOgpFM(sU;;k&DJPRrPBP5h!<Wgz9goqbBZy`b6qHVm(F0v0ImLSd
z&uf;?!D1FICTmHnbpGk#2{f7_7!9W2N*58QHc0GIcsl@)t%|!ZCnH;yy8Q{ylT-BC
zgIv{zYZiBa5^F0j_p9j`w;dmYF_MCxf(N;^iOR-#O|k#1fGk&TbFpj|!E~B-ontx0
z=Qs(D9wYQl?il+G_BV}lIYGatVgTDtPUEO41XGxO<cn-8X0SA^2mm!QQ#Kh*cr^$S
zmMAVs0eYNa+*{GBO{M}@QP|71i3wkI*IumKaRT*24ot+dFmZ*>MRHuNEann<WugK?
zirV01%+PDHp?P2e9cC{k!YSCeRXS-lHu4AqtZjW706M at L%a{W6)ik at m{b>_=T`|}*
z5^^m~D+WLhdgf(cR#*)>#57{mfHU?W?$~{{v?4eC>>$4X#wpysqZQwLu?cHmZNaN2
z$8l;lgp;#=>>adV%gG6Bp+ at ZMp2CPLh!Eod38pOJ1eymY at uP}1#tfCX?!IdL+m=@B
z>KH~vp8?y>7;sl*cWJCuIso!qe$@bJ8h2`vyqPWu07dsooFD*5;E~Cvkjll8%*GI>
zt%kEH*i$JSny}%vXAhPJ-Zp4P<D3f(Q#MqMS<qy*qk}@WOu6ujLw&er-F{BAqBPmB
zY;D1GG!9QD4SPI_UW*l<e3Jc1xn56aWsJplt0d+qFVnAz7FOcFceQEKyqPWyfTrr=
zNMbpvV$g{x=M?wo2~4 at Can3o1V^bzP+kB=J{9M6c=)lwrx?MBqaZIAqK8X(JELvx+
z*wQwP_us1pKo{`qoulk;78A}149yMW&_D-1^uztQQWsF_DPWMx+g>2}>h(3aVbd|(
zu(1vw+qeg}J-Szu=FN0*07UI+-(u%6+TL_9g!b`K9PU4jc0(72Y!uF7!f)D7<Bk_!
zS0_Ne^Nlm;vD+}^o5r+n3{!q1h6q;8=mfsBwXsxBo%9=vf>6)_`z)rt6EJ&5U~&(`
z=o&^J!8khFgQpL);?}3Dam(XXxcRYa{K*D}(ht?*I)>GHe_{^r`#}>v_{dS*_;3S0
z^+W@{v8`1T=*@I#04RKhc4-dA(J*Afa|ci0sr|Ls-F}ju--!{w4|_X0v0?j8{L53j
zv1aFS^g09ZrfDXHAVX9)5(N+JNk1A4W~^3(R{3%UKUc2RSF at 7w!hQ^fVsK_72<5ro
z=e<mreDLK$uw|k!Mj2~3yr>(WL*=9eJ0~3YUPU)<+`#Cw3;@x95B#78fAf=i-0|CP
zyxeWq1bQ<q3jlY{L9u;8fH=3EcG~X7J*RN%BYW_78(zZ$I~mZ>#?7e=9he6vxVopt
zXJGV(5XjP3FgYqRR+vYeyE*rL`if>wSP at p6tOQ6BE2sdFsR1?SAi8~Fm=iI$*v6aB
zz at E)uDv_iQ3E{q)etctl8=gHrggUban+_Y!>vPpz`xPMHqva%<nnp3;mjrxiS{493
zsbC())hMEI%#CmFI9(d-U!SW*<BSJ$%>O+!4 at qx**#g1 at E1_g|44ITnEl&Un2o?(H
z^2E3 at wd_M(^()raU^Q8pyv|zxq8+U!H#!|r9HAHAabg(P+^y#m75HV_IGX1I_}=aw
z^_}K_R;{hZ<%-V`Ur~vzr_J!?-$EcHJEt64$N`3%9W+b^@vWVMTF2bx9y@?~YXDOW
zWSle;CxMuW=P}|8VQ9w5q{WADBCVYM$XP*v^?JiOMuuD+UC1 at H^x(C0a%CWBWu^NI
zpS5f2Tm)x4aoqXau2T7Gu70Vm^1P2)R8S6NmZN0>pzzaC+P))|MZYJE?VYpu@{Yy5
z_XGFWVB63v4%@vrX{QOyx$%W9Cs at W1m}zZmuK^Z+m_ZU_b83VHGy4rbwY?%(1y`Ti
zuvYB17OU@|>fX7htemW at Dpy@wU7fd|nZ`_}h`vA^|G2qDZ6my<3;@>K)i(z}$CgE0
zjxOp19q|l~8Ex2DacXg5+5oGmqF>xnkAHu$7JvT)lO26v0wCA3W(RE4058pB)EB`o
zny5Wx?Jr+bf%mSjRzO&FmuP_2hbE+MCh|_U)jz$j4jnUY*x6@@p|X!!*XNJoV~-pt
z^(pGFx0Pt{;J6C`YUc7D;35E|=ND{7cZjKGFW$di9iX%l`b4#XFTDTi%dIfQlbB)n
zdWJi~^&7a-QdYK-pL+H%Zv0U_K~UQXAbOc_gDrz2mMHyziyG*Mg}X|ykf25}C1*w&
zSjeH94)@RQUj%=Z?oZhM`UmS30Q>|XsmZhyEpGy}Sp&W9^9OtJxhJ%YPP2bS5N)MP
zD at DF~T_q+0)6CVa+zRbzoG?>M%JzNoH5B;4!(F(ut{<P?+>Gn)-Obh7O^5gfF4y|`
zqxF^O4Mi{!@na at rhb?M>J7GZ}Ig3z|PL21oaSx8pFeQFWoT}RQsx<^dnOg<^`o{-x
zaKa5A0f=idEk(;aK{_vIGKa$xUOZSmgik%ze4em>d|wrAdg?HqYU at YS^f{ci4&tn(
zAMK`I)b*Xl3kMJ3o*jEjlauQs4JWX at djP*0nZm}FbNGknk0=0KNdT^1yQ at _1&$&}{
z+GjB8Fks5wk7;`k%#Lo%I?0YMOxgz+DjTu4e-xi(U{o4IXU_BEPc)-x%KH`pSeW-J
z(H}uDFs0nyVZoPv*{)=G%3z9(RpN<u3!0e(bub`mF;AglU;xiHwP4*VyBX`32~YmX
zfnI{-qT>ppY0iWD8wPOG<A?A*YJ~JFUtQ^w|BDCeU<~?T3)|rdnc)vj!5^MNfb0*O
z;0(=SGT=fZ<BorNMhk*2;7|Un702folhBbTG_jVVB>_;6y5|+|X-VZ#HR8dyUhBk%
zxauXLc>Tpm2Tr+D%<i1new at DI-ZE!cCj4ifZh<!=u|QEtO<T-<d}n6|u799bi3P6U
zHh3*}4!w;yFk3E<XpsTce46n at 62<uhIgUaxfpk$0MGEM42l4e6C1KLdQ6ICCq4E)Q
zIAY8&nXap1ElC8RJV+=S)bsYDlKe<Rs{(+F05CDRUz;RZLfS_UnYjH$(M*;8^rKol
zu1|)1#oGNCaE6tW89Aa#k*&=AtA<_p@|HGScQ>8Z8m{1)I$SOGtF;sE_9qw;GpOP`
z<RnV at Zb**fC9vYV2xE(We}w6_n5MMR{F8FHT7gf{1bSS|R;k4o-3FCZSN$`nU?|5P
zjNWJhe42=+u;th}MOD?wsRMoZfhs)OForYM2*$lZyxzt-ckjoI8xP==C9K*W%}D<i
zNDeCF1i%!@VP}sMU)X$tW>SrJ6M)Mk7LcfrPE-|QAD%uojy6k-3s6u_jMOh<)B_ng
z<_eMfxeea2^Q1Z_wz*2q9u+6J54UbUj*(y%(MtiKicGav9_3Twe|6FkK8^%p*i_xl
zm|X<doFE7I{Npuvp~Z+{cbtJvfr(F^A#fhaA~OI^GRqZ{6FoUS6ye1V{j|p(cLG0e
zG2t^$wBWsKt8f`3!OJ-5%NW1ETL)R3tp>#Uie7sBEVW1uU(_Qx0l>p8wr$pn+h5TF
zA=drNhYpnhc(DE)rlJIoGF&tc&;bzENfIClg=1_y9!_9uYahP%S_{7VD?wWZsKkH1
z*oe9T3oOwz?Uaen0!39g$M&k&a*CW)jx!e&;YUJA?Ci7P_E$UbR~s9+_iHAl^eL<h
zu3fcvU*CQfmN-)?MwMa?S(>Od5<~sqB>w9a*=AL>|L5nL at a3ng@U5+faKPY!Eh*=L
zs`f2MrLV?>brKyAq(uw7jHSD5A=Hd}@WNS>HW+h$s@|w8fN&;-ECZB6F-ndooG*r$
z1B4h%MY)q?;GshsqPqUN$Bb|P<`h2qBXNErsK$!m<wA=i)Xo<)Fm8GL2qVi3wJeKN
zA&FVP3k`h(c&@RX<ua#Ae3wz_cc0&f&Go0z=Lj>2Q+<!fu^cJ8!1(~ko#=oH0wY4I
z+dPc%B5I9HXEn5Ix`r|1bHg8F&K`3rUy()PRwh7J1j)Xn9gd_2rdR~+Rxh4EI)HDy
zbQm9bs1jG`f@^#e&FL$z9mV_Z(Gn#Qnyd##Iw;4PlFx;M2*kb2Gv?4WW5m(PNwiE^
z&@^sAWzQIDd&l_R0T*+aG}SssaW1L>+I0y4iu{!C0p!S<nm{zWtbTm{=LhlC%?Ht8
zFkr?t3zvTu?tmHYpb3uP6fD7Mm_xJN$8G3z*->RMW7EMNeE8w=Ol@(sZ+^4^n;35I
z9G)SYaoY<`i}iE>G!ULYGDzX9um-HKb4+t!7L!3Iv(N~fxg1>7G at oprl8)0)$QL8>
zyM&A90wu|1Cs4(g)tB{Gy{_7kfZ&X$(Py%vYit7J7Bd_H8+;K5*$#Ki&egGC#669Z
zGvlZ;81Zt)Fm8UFwyq0Q&J^lDwzXn=JH7pk2cry-#)5wIyFJX|Cs|(RACzkaZeWCX
zaKwz+fE(_Jm1ElAiaQa=MCcz1TxmK;vMieTH158N23#5dVScE$@~3LR;`zV&HB*XP
zTQHfX+Q$%1Mi9@&5X;38$|d1SCn$suwZrGIq2ds(E_w7arV#JtR(Jc3GuV7=f?>7?
z27g>ROo`@Gi09+HGSSKBFvl>w)f~h}H)$H7_3=<`KW69vBiSetd8XU>5Hbvo3KAp8
zyp=f%Qx>u~^WP~OR6$SyP|k$dne?QCAUQ&T-dMgX%#fo*-o_~Jls$~A)@#9xBCIN~
z{``qY58$3RI`K^N7;1){81fM``W6YdRdp?JRM|M?1c~7*-&qm`)Q$QWDV~4OG3+G(
z1xAUindhhMI<oHST-EuCAaePg0Z>T=KqA6L00;{^6qY<ee#8*u4lxl-sN0z)s4Bdw
zzSrJeiElDgeX_n2yE>=QHXUSr`E^JEG3uxMq(*F1{U%p6Jo!`hdcKR$@ANtn_;IzI
zL`lCYpf~-rk>D}rQ0i$dlvP*f$^Q~d-z##0<-{)7SpD9wykikwv>?ly09ACz8o&o1
z)N*}Yc=E>|Ys5=TplZk6Xt(*f+7Zk!UhriY+EQ at Jr3k6BD!k4DhRReBZhd)F4|(vB
zhYzrC*&PIkeK=w9BP80xHe&PT!Yhl!w#s~^AM$dvBmnAnfkd{%szJ!a<p&5NgwYwm
ztIX^52?;;fI*6JPD^6L%7!BoMp#)yeBFy#)PEu7=5mIrnWckxpP`eWl^gksdrQaC~
zrtx}*3D=gLC(3n}i=c$btgE!s7E1(Im>&f`|IPrgjn;`wg45$wCN3dpnk;99{c|on
zxkpb#$P7UTd{M>>Ic`JxH at XGx9&$J?A+cDu9F?n)qP&qvQNI3GzG_!k_u~{vj at 21e
zX2~J;H|PxFWddB<QM6sck&v(F#V3j2>dvKWf?Q?pvJ)&v%lH5>1GNL`PyvC{%rWGR
z=Th*cq8PMTu&wa~Zhd4IJ-Zx0jxo^*A(RRsp7N2si18X#*sok;DG%al7ZT)n%Ef27
zI*~{@kW4y|;&U?PCVTkKO?I)J8$tGEjrwrZXu^h_hZjMoPk82FKWxD$GR#Mc^PDAF
zG(kf^Swu10<!D&|1Oc at VK~s>Wzs)D$jWF<VPh!A4gu1gQ at nl6cHvP5+yW1Ilnny9`
z9EH`<4~xAQbHa{3%#!7IM6*slyLuF!b&?&tw|B#C?}Ecdw)eo!x)!_q{z%&PVuo#|
zo&7M{N6=;*!V3qEVckniqX~j&!?xPvI6X3nNJ at UJA;QaUK$f4<2^dsm(dOmoq5vo@
zg_VxE<rKM3CtdJ{r(yGt!{{)gee4_#502pUxDh7T6g)vAe1T!|5WETx!xI>Ri&tlG
z1dh-s>||STjM3Z}qsUSC{UZqYhY?^sKc78h7ugXsDD|wtaRxur7-QslYSM%Q14dML
zjiRP=6ivMbjLbP0lZa`_uB8K at fuJm)D$-JPaR8*H0)Y5r at dC8jc}aXC$T8tb6{3jH
zB!by2uW3HV_&&&TABtsMDEj$6fHcdJY?mm8$x)=pStWrAvR*)8xtC-r!#XLJNxeid
z#&kGI-;!a_m4lDMdNNss{bc##R#IiIHRmbnFM_MWE1E3wEJMo!a2`n)!ZH9mRyG#_
zL_C9hN{LKByt$M~_;Eg~Zd8ID`Hhk8|E2z7e~bO<eXD$7?eZ4t*yTd%b6tFMF<K!2
j?_Bx=0NVBcDFOcjxo_{~#9zQZ00000NkvXXu0mjf#3lRT

literal 0
HcmV?d00001

diff --git a/modules/amelipro/pages.py b/modules/amelipro/pages.py
new file mode 100755
index 0000000..c9f059c
--- /dev/null
+++ b/modules/amelipro/pages.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013      Christophe Lampin
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from datetime import datetime
+from decimal import Decimal
+import re
+from weboob.tools.browser import BasePage
+from weboob.capabilities.bill import Subscription, Detail, Bill
+
+
+__all__ = ['LoginPage', 'HomePage', 'AccountPage', 'HistoryPage', 'BillsPage']
+
+# Ugly array to avoid the use of french locale
+FRENCH_MONTHS = [u'janvier', u'février', u'mars', u'avril', u'mai', u'juin', u'juillet', u'août', u'septembre', u'octobre', u'novembre', u'décembre']
+
+class LoginPage(BasePage):
+    def login(self, login, password):
+        self.browser.select_form('connexionCompteForm')
+        self.browser["vp_connexion_portlet_1numPS"] = login.encode('utf8')
+        self.browser["vp_connexion_portlet_1password"] = password.encode('utf8')
+        self.browser.submit()
+
+class HomePage(BasePage):
+
+    def on_loaded(self):
+        pass
+
+
+class AccountPage(BasePage):
+
+    def get_subscription_list(self):
+        ident = self.document.xpath('//div[@id="identification"]')[0]
+        prof = self.document.xpath('//div[@id="profession"]')[0]
+        name = ident.xpath('//p/b')[0].text.replace(' ', ' ').strip()
+        number = ident.xpath('//p')[1].text.replace('Cabinet', '').strip()
+        label = prof.xpath('//div[@class="zoneTexte"]')[0].text.strip()
+        sub = Subscription(number)
+        sub._id = number
+        sub.label = unicode(name) + ' ' + unicode(label)
+        sub.subscriber = unicode(name)
+        return sub
+
+class HistoryPage(BasePage):
+
+    def iter_history(self):
+        table = self.document.xpath('//table[contains(concat(" ", @class, " "), " cTableauTriable ")]')[0].xpath('.//tr')
+        for tr in table:
+            list_a = tr.xpath('.//a')
+            if len(list_a) == 0:
+                continue
+            date = tr.xpath('.//td')[0].text.strip()
+            lot = list_a[0].text
+            factures = tr.xpath('.//div[@class="cAlignGauche"]/a')
+            factures_lbl = ''
+            for a in factures:
+                factures_lbl = factures_lbl + a.text + ' '
+            montant = tr.xpath('.//div[@class="cAlignDroite"]')[0].text.strip()
+            det = Detail()
+            det.id = lot
+            det.label = lot
+            det.infos = factures_lbl
+            det.datetime = datetime.strptime(date, "%d/%m/%Y").date()
+            det.price = Decimal(montant.replace(',','.'))
+            yield det
+
+class BillsPage(BasePage):
+
+    def iter_bills(self):
+        table = self.document.xpath('//table[@id="releveCompteMensuel"]')[0].xpath('.//tr')
+        for tr in table:
+            list_tds = tr.xpath('.//td')
+            if len(list_tds) == 0:
+                continue
+
+            date_str = tr.xpath('.//td[@class="cAlignGauche"]')[0].text
+            month_str = date_str.split()[0]
+            date = datetime.strptime(re.sub(month_str,str(FRENCH_MONTHS.index(month_str) + 1),date_str),"%m %Y").date()
+            amount = tr.xpath('.//td[@class="cAlignDroite"]')[0].text
+            for format in ('CSV', 'PDF'):
+                bil = Bill()
+                bil.id = date.strftime("%Y%m") + format
+                bil.date = date
+                bil.label = u''+amount.strip()
+                bil.format = u''+format
+                filedate = date.strftime("%m%Y")
+                bil._url = '/PortailPS/fichier.do'
+                bil._args = {'FICHIER.type': format.lower() + '.releveCompteMensuel',
+                             'dateReleve': filedate,
+                             'FICHIER.titre': '',
+                }
+                yield bil
+
+    def get_bill(self,bill):
+       self.location(bill._url, urllib.urlencode(bill._args))
diff --git a/modules/amelipro/test.py b/modules/amelipro/test.py
new file mode 100755
index 0000000..97bcebe
--- /dev/null
+++ b/modules/amelipro/test.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013      Christophe Lampin
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from weboob.tools.test import BackendTest
+
+
+__all__ = ['AmeliProTest']
+
+
+class AmeliProTest(BackendTest):
+    BACKEND = 'AmeliPro'
+
+    def test_AmeliPro(self):
+        for subscription in self.backend.iter_subscription():
+            list(self.backend.iter_history(subscription.id))
+            for bill in self.backend.iter_bills(subscription.id):
+                self.backend.download_bill(bill.id)
-- 
1.8.1.4




More information about the weboob mailing list