refonte de monaa pour remplacer caotek.fr

This commit is contained in:
2020-04-27 21:38:48 +02:00
parent 5e6495e3ae
commit cb73317f8c
24 changed files with 495 additions and 416 deletions

View File

@@ -8,19 +8,36 @@ Author-email:
License: UNKNOWN License: UNKNOWN
Description: # README # Description: # README #
Cette application permet de :
Cette application permet le suivi des avoirs financiers : actions, ETF, obligations (assurances-vie), livrets, etc... 1. faire le suivi des actifs financiers : actions, ETF, obligations (assurances-vie), livrets
2. compararer les écarts avec une allocation cible
Elle est développée avec les composants open source suivants :
## Backend
- [Python](https://www.python.org/downloads/) 3.7
- [Pyramid web framework](https://trypyramid.com/) 1.10
- [MySQL server](https://mysql.com/) 5.7 sur Debian GNU/Linux 9 (stretch)
- [Apache web server](https://apache.org/) 2.4 sur Debian GNU/Linux 9 (stretch)
## Frontend
- [Bootstrap framework](https://getbootstrap.com/) for CSS 3.3.7
- [Jquery](https://jquery.com/download/) for JavaScript 3.2.1
- Chameleon templates
- [FormValidation](https://formvalidation.io/) form validator 0.7.0
## Jquery Plugins
- [DataTables](https://datatables.net/) 1.10.20
- [less.js](http://lesscss.org/) 3.11.1
- [moment.js](https://momentjs.com/) with-locales.min.js
- [Google Charts](https://developers.google.com/chart)
[Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
Développé avec :
- Pyramid Framework
- MySQL
- Chameleon
* [Exemple d'une comptabilité simple] (http://perso.numericable.fr/assoc1901/droit/comptabilite1.htm)
* [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
@@ -29,6 +46,25 @@ Description: # README #
- Initial version - Initial version
>>> quote.info
{'language': 'en-US', 'region': 'US', 'quoteType': 'ETF', 'quoteSourceName': 'Delayed Quote', 'currency': 'USD', 'regularMarketChange': -0.5200043,
'regularMarketOpen': 93.81, 'regularMarketDayHigh': 93.91, 'regularMarketDayLow': 92.44, 'regularMarketVolume': 4040066, 'askSize': 14,
'messageBoardId': 'finmb_22939711', 'fullExchangeName': 'NYSEArca', 'longName': 'Vanguard Real Estate Index Fund ETF Shares',
'financialCurrency': 'USD', 'averageDailyVolume3Month': 4826021, 'averageDailyVolume10Day': 4604087, 'fiftyTwoWeekLowChange': 22.009995,
'fiftyTwoWeekLowChangePercent': 0.30965102, 'fiftyTwoWeekRange': '71.08 - 94.07', 'fiftyTwoWeekHighChange': -0.98000336,
'fiftyTwoWeekHighChangePercent': -0.01041781, 'fiftyTwoWeekLow': 71.08, 'fiftyTwoWeekHigh': 94.07, 'esgPopulated': False, 'tradeable': True,
'trailingAnnualDividendRate': 3.533, 'trailingPE': 8.381201, 'trailingAnnualDividendYield': 0.037741695, 'ytdReturn': 25.76,
'trailingThreeMonthReturns': 7.14, 'trailingThreeMonthNavReturns': 7.21, 'epsTrailingTwelveMonths': 11.107, 'marketState': 'CLOSED',
'postMarketChangePercent': 0.042970154, 'postMarketTime': 1569618175, 'postMarketPrice': 93.13, 'postMarketChange': 0.040000916,
'regularMarketChangePercent': -0.55550075, 'regularMarketDayRange': '92.44 - 93.91', 'regularMarketPreviousClose': 93.61, 'bid': 93.03,
'ask': 93.13, 'bidSize': 11, 'exchange': 'PCX', 'shortName': 'Vanguard Real Estate ETF', 'exchangeDataDelayedBy': 0, 'priceHint': 2,
'sharesOutstanding': 370180992, 'bookValue': 63.751, 'fiftyDayAverage': 92.157425, 'fiftyDayAverageChange': 0.9325714,
'fiftyDayAverageChangePercent': 0.01011933, 'twoHundredDayAverage': 88.83857, 'twoHundredDayAverageChange': 4.2514267,
'twoHundredDayAverageChangePercent': 0.04785564, 'marketCap': 34460147712, 'priceToBook': 1.4602123, 'sourceInterval': 15,
'exchangeTimezoneName': 'America/New_York', 'exchangeTimezoneShortName': 'EDT', 'gmtOffSetMilliseconds': -14400000, 'triggerable': False,
'market': 'us_market', 'regularMarketPrice': 93.09, 'regularMarketTime': 1569614400, 'symbol': 'VNQ'}
Keywords: web wsgi bfg pylons pyramid Keywords: web wsgi bfg pylons pyramid
Platform: UNKNOWN Platform: UNKNOWN
Classifier: Programming Language :: Python Classifier: Programming Language :: Python

View File

@@ -9,7 +9,7 @@ transaction
zope.sqlalchemy zope.sqlalchemy
waitress waitress
mysqlclient mysqlclient
beautifulsoup4 yfinance
docutils docutils
[testing] [testing]

View File

@@ -29,10 +29,18 @@ def get_docs(request, doc_id):
def get_docs_bytheme(request, theme): def get_docs_bytheme(request, theme):
"""Lire les doc""" """Lire les doc"""
query = "SELECT * FROM docs WHERE theme=:theme ORDER BY intitule;" if theme == 'BLOG':
query = "SELECT * FROM docs WHERE theme=:theme ORDER BY cree_le DESC LIMIT 10;"
else:
query = "SELECT * FROM docs WHERE theme=:theme ORDER BY intitule;"
results = request.dbsession.execute(query, {'theme': theme}).fetchall() results = request.dbsession.execute(query, {'theme': theme}).fetchall()
return results return results
def get_blog_themes(request):
query = "SELECT * FROM blog_themes;"
results = request.dbsession.execute(query).fetchall()
return results
def update_doc(request, doc_id, intitule, texte, theme): def update_doc(request, doc_id, intitule, texte, theme):
"""créér ou modifier le doc""" """créér ou modifier le doc"""
if doc_id == '0': if doc_id == '0':

View File

@@ -10,6 +10,7 @@ def includeme(config):
config.add_route('allocation_edit', '/allocation_edit/{no_cat}') config.add_route('allocation_edit', '/allocation_edit/{no_cat}')
config.add_route('histo_list', '/histo_list') config.add_route('histo_list', '/histo_list')
config.add_route('histo_edit', '/histo_edit/{no_id}') config.add_route('histo_edit', '/histo_edit/{no_id}')
config.add_route('portfolio', '/portfolio')
# members # members
config.add_route('changer_mdp', '/changer_mdp') config.add_route('changer_mdp', '/changer_mdp')
config.add_route('envoyer_mdp', '/envoyer_mdp') config.add_route('envoyer_mdp', '/envoyer_mdp')

View File

@@ -3,15 +3,15 @@
.navbar { .navbar {
margin-bottom: 0; margin-bottom: 0;
color: #404040 !important; color: #000000 !important;
background-color: #ffffff !important;
border: 0; border: 0;
border-radius: 0; border-radius: 0;
font-size: 20px !important; font-size: 20px !important;
letter-spacing: 4px;
} }
.navbar li a, .navbar .navbar-brand { .navbar li a, .navbar .navbar-brand {
color: #404040 !important; color: #000000 !important;
font-size: 14px !important; font-size: 14px !important;
} }
@@ -26,6 +26,12 @@
color: #fff !important; color: #fff !important;
} }
.navbar-brand {
transform: translateX(-50%);
left: 50%;
position: absolute;
}
/* Dropdown */ /* Dropdown */
.open .dropdown-toggle { .open .dropdown-toggle {
color: #000000 ; color: #000000 ;
@@ -43,6 +49,12 @@
color: #000000 !important; color: #000000 !important;
} }
@media (min-width: 1200px) {
.container{
max-width: 900px;
}
}
.container-fluid { .container-fluid {
padding-top: 2em; padding-top: 2em;
padding-bottom: 1em; padding-bottom: 1em;
@@ -54,7 +66,7 @@
} }
} }
#doc-text { .monospace-font {
font-family: Monaco, "Courier New", Courier, monospace; font-family: Monaco, "Courier New", Courier, monospace;
} }
@@ -79,9 +91,6 @@
.bg-grey { .bg-grey {
background-color: #f6f6f6; background-color: #f6f6f6;
} }
.logo {
height: 60px;
}
.logo-primary { .logo-primary {
font-size: 50px; font-size: 50px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

View File

@@ -12,7 +12,7 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="classe">Classe</label> <label class="control-label col-xs-2" for="classe">Classe</label>
<div class="col-xs-3"> <div class="col-xs-8">
<select class="form-control" id="classe" name="classe"> <select class="form-control" id="classe" name="classe">
<div tal:repeat="item allocation_list"> <div tal:repeat="item allocation_list">
<option value="${item.classe}" tal:attributes="selected actif.classe==item.classe and 'selected' or None">${item.classe}</option> <option value="${item.classe}" tal:attributes="selected actif.classe==item.classe and 'selected' or None">${item.classe}</option>
@@ -22,7 +22,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-xs-2 control-label">Identifiant</label> <label class="col-xs-2 control-label">Identifiant</label>
<div class="col-xs-3"> <div class="col-xs-8">
<input class="form-control" type="text" name="symbole" <input class="form-control" type="text" name="symbole"
value="${actif.symbole}" placeholder="15 caractères maximum" value="${actif.symbole}" placeholder="15 caractères maximum"
data-fv-notempty="true" data-fv-notempty="true"
@@ -34,7 +34,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-xs-2 control-label">Libellé</label> <label class="col-xs-2 control-label">Libellé</label>
<div class="col-xs-3"> <div class="col-xs-8">
<input class="form-control" type="text" name="libelle" <input class="form-control" type="text" name="libelle"
value="${actif.libelle}" placeholder="45 caractères maximum" value="${actif.libelle}" placeholder="45 caractères maximum"
data-fv-notempty="true" data-fv-notempty="true"
@@ -46,7 +46,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="pru">Total investi</label> <label class="control-label col-xs-2" for="pru">Total investi</label>
<div class="col-xs-2"> <div class="col-xs-6">
<div class="input-group"> <div class="input-group">
<div class="input-group-addon">K€</div> <div class="input-group-addon">K€</div>
<input class="form-control" type="text" id="pru" name="pru" value="${actif.pru}" <input class="form-control" type="text" id="pru" name="pru" value="${actif.pru}"
@@ -57,7 +57,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="cours">Total valeur</label> <label class="control-label col-xs-2" for="cours">Total valeur</label>
<div class="col-xs-2"> <div class="col-xs-6">
<div class="input-group"> <div class="input-group">
<div class="input-group-addon">K€</div> <div class="input-group-addon">K€</div>
<input class="form-control" type="text" id="cours" name="cours" value="${actif.cours}" <input class="form-control" type="text" id="cours" name="cours" value="${actif.cours}"
@@ -68,7 +68,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="pc_rdt">% Rendement</label> <label class="control-label col-xs-2" for="pc_rdt">% Rendement</label>
<div class="col-xs-2"> <div class="col-xs-6">
<div class="input-group"> <div class="input-group">
<div class="input-group-addon">%</div> <div class="input-group-addon">%</div>
<input class="form-control" type="text" id="rdt" name="pc_rdt" value="${actif.pc_rdt}" <input class="form-control" type="text" id="rdt" name="pc_rdt" value="${actif.pc_rdt}"
@@ -79,14 +79,14 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2">Dernière modif.</label> <label class="control-label col-xs-2">Dernière modif.</label>
<div class="col-xs-7"> <div class="col-xs-8">
<p class="form-control-static" tal:condition="actif.modif_le">${actif.modif_le.strftime('%d/%m/%Y - %H:%M')}</p> <p class="form-control-static" tal:condition="actif.modif_le">${actif.modif_le.strftime('%d/%m/%Y - %H:%M')}</p>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-xs-offset-2 col-xs-10"> <div class="col-xs-offset-2 col-xs-10">
<div class="form-group"> <div class="form-group">
<a class="btn btn-default" href="${request.application_url}/"> <a class="btn btn-default" href="${request.application_url}/portfolio">
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a> <span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
<button class="btn btn-primary" type="submit" name="form.submitted"> <button class="btn btn-primary" type="submit" name="form.submitted">
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button> <span class="glyphicon glyphicon-ok"></span> Enregistrer</button>

View File

@@ -12,7 +12,7 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="classe">Classe</label> <label class="control-label col-xs-2" for="classe">Classe</label>
<div class="col-xs-4"> <div class="col-xs-8">
<select class="form-control" id="classe" name="classe"> <select class="form-control" id="classe" name="classe">
<div tal:repeat="item allocation_list"> <div tal:repeat="item allocation_list">
<option value="${item.classe}" tal:attributes="selected actif.classe==item.classe and 'selected' or None">${item.classe}</option> <option value="${item.classe}" tal:attributes="selected actif.classe==item.classe and 'selected' or None">${item.classe}</option>
@@ -21,8 +21,8 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-xs-2 control-label">Symbole FT</label> <label class="col-xs-2 control-label">Symbole Yahoo</label>
<div class="col-xs-4"> <div class="col-xs-8">
<input class="form-control" type="text" name="symbole" <input class="form-control" type="text" name="symbole"
value="${actif.symbole}" placeholder="15 caractères maximum" value="${actif.symbole}" placeholder="15 caractères maximum"
data-fv-notempty="true" data-fv-notempty="true"
@@ -37,7 +37,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="nombre">Nombre</label> <label class="control-label col-xs-2" for="nombre">Nombre</label>
<div class="col-xs-4"> <div class="col-xs-8">
<input class="form-control" type="text" id="nombre" name="nombre" value="${actif.nombre}" <input class="form-control" type="text" id="nombre" name="nombre" value="${actif.nombre}"
data-fv-digits="true" data-fv-digits="true"
data-fv-digits-message="Le nombre doit être composé que de chiffres" /> data-fv-digits-message="Le nombre doit être composé que de chiffres" />
@@ -45,7 +45,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="pru">PRU</label> <label class="control-label col-xs-2" for="pru">PRU</label>
<div class="col-xs-4"> <div class="col-xs-8">
<div class="input-group"> <div class="input-group">
<div class="input-group-addon">€</div> <div class="input-group-addon">€</div>
<input class="form-control" type="text" id="pru" name="pru" value="${actif.pru}" <input class="form-control" type="text" id="pru" name="pru" value="${actif.pru}"
@@ -56,7 +56,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="ter">TER</label> <label class="control-label col-xs-2" for="ter">TER</label>
<div class="col-xs-4"> <div class="col-xs-8">
<div class="input-group"> <div class="input-group">
<div class="input-group-addon">%</div> <div class="input-group-addon">%</div>
<input class="form-control" type="text" id="ter" name="ter" value="${actif.ter}" <input class="form-control" type="text" id="ter" name="ter" value="${actif.ter}"
@@ -67,7 +67,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="pc_rdt">% Rendement</label> <label class="control-label col-xs-2" for="pc_rdt">% Rendement</label>
<div class="col-xs-4"> <div class="col-xs-8">
<div class="input-group"> <div class="input-group">
<div class="input-group-addon">%</div> <div class="input-group-addon">%</div>
<input class="form-control" type="text" id="pc_rdt" name="pc_rdt" value="${actif.pc_rdt}" <input class="form-control" type="text" id="pc_rdt" name="pc_rdt" value="${actif.pc_rdt}"
@@ -78,7 +78,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2">Devise</label> <label class="control-label col-xs-2">Devise</label>
<div class="col-xs-7"> <div class="col-xs-8">
<p class="form-control-static">${actif.devise}</p> <p class="form-control-static">${actif.devise}</p>
</div> </div>
</div> </div>
@@ -94,7 +94,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2">Dernière modif.</label> <label class="control-label col-xs-2">Dernière modif.</label>
<div class="col-xs-7"> <div class="col-xs-8">
<p class="form-control-static" tal:condition="actif.modif_le">${actif.modif_le.strftime('%d/%m/%Y - %H:%M')}</p> <p class="form-control-static" tal:condition="actif.modif_le">${actif.modif_le.strftime('%d/%m/%Y - %H:%M')}</p>
</div> </div>
</div> </div>
@@ -102,7 +102,7 @@
<div class="form-group"> <div class="form-group">
<div class="col-xs-offset-2 col-xs-10"> <div class="col-xs-offset-2 col-xs-10">
<div class="form-group"> <div class="form-group">
<a class="btn btn-default" href="${request.application_url}/"> <a class="btn btn-default" href="${request.application_url}/portfolio">
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a> <span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
<button class="btn btn-primary" type="submit" name="form.submitted"> <button class="btn btn-primary" type="submit" name="form.submitted">
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button> <span class="glyphicon glyphicon-ok"></span> Enregistrer</button>

View File

@@ -2,8 +2,6 @@
<div metal:fill-slot="content"> <div metal:fill-slot="content">
<p> <p>
<a href="${request.application_url}/" class="btn btn-default" role="button">
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
<a href="histo_edit/0" class="btn btn-success" role="button"> <a href="histo_edit/0" class="btn btn-success" role="button">
<span class="glyphicon glyphicon-plus"></span> Entrée / Sortie cash</a> <span class="glyphicon glyphicon-plus"></span> Entrée / Sortie cash</a>
</p> </p>

View File

@@ -0,0 +1,232 @@
<metal:block use-macro="main_template">
<div metal:fill-slot="content">
<div tal:condition="message" tal:content="message" class="alert alert-success" />
<p>
<a href="allocation_edit/0" class="btn btn-success" role="button">
<span class="glyphicon glyphicon-plus"></span> Nouvelle classe</a>
</p>
<div class="row">
<div class="col-md-6">
<table id="categories_list" class="table table-condensed table-bordered">
<thead>
<tr>
<th>Classe</th>
<th class="text-right">% cible</th>
<th class="text-right">% actuel</th>
<th class="text-right">Ecart</th>
<th class="text-right">Valeur</th>
</tr>
</thead>
<tbody>
<tr tal:repeat="item items">
<td class="${item.bg_color}">${item.classe}</td>
<td class="text-right"><a href="allocation_edit/${item.no_cat}">${item.pc_cible} %</a></td>
<td class="text-right">${layout.to_percent(item.pc_atteint,1)}</td>
<td tal:condition="(item.pc_atteint - item.pc_cible)>=0" class="text-right" style="color: green;">${layout.to_percent(item.pc_atteint - item.pc_cible,1)}</td>
<td tal:condition="(item.pc_atteint - item.pc_cible) <0" class="text-right" style="color: red;">${layout.to_percent(item.pc_atteint - item.pc_cible,1)}</td>
<td class="text-right">${layout.to_euro(item.valeur)}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<table id="portfolio" class="table table-condensed table-bordered">
<thead>
<tr>
<th>Portefeuille</th>
<th class="text-right">Montant</th>
<th class="text-right">%</th>
</tr>
</thead>
<tbody>
<tr>
<td>Valorisation</td>
<td class="text-right">${layout.to_euro(member.pf_valeur)}</td>
<td></td>
</tr>
<tr>
<td>Plus value</td>
<td class="text-right">${layout.to_euro(member.pf_plusvalue)}</td>
<td class="text-right">${layout.to_percent(member.pf_plusvalue_pc, 1)}</td>
</tr>
<tr>
<td>Rendemant brut</td>
<td class="text-right">${layout.to_euro(member.pf_rendement)}</td>
<td class="text-right">${layout.to_percent(member.pf_rdt_pc, 1)}</td>
</tr>
</tbody>
</table>
<p>
<b>Allocation globale</b> : 60% actions + 5% REITS + 35% obligations<br />
<b>Allocation actions D</b> (1/2) : 60% US (18%) + 30% Europe (12%)<br />
<b>Allocation actions C</b> (1/2) : 100% World (30%) <br />
[Cette allocation est inspirée de celle du <a href="https://www.nbim.no/en/the-fund/how-we-invest/benchmark-index/">Fond souverain Norvégien</a>]
</p>
</div>
</div>
<div class="row">
<div class="col-md-6">
<!-- graphique donut cible -->
<div id="donutchart_cible" style="width: 100%; height: 500px;"></div>
</div>
<div class="col-md-6">
<!-- graphique donut actuel -->
<div id="donutchart_actuel" style="width: 100%; height: 500px;"></div>
</div>
</div>
<div class="row">
<h3>Mes actifs</h3>
<p>"<i>Diversification is not determined by the number of securities held.</i>"
<a href="http://www.etf.com/sections/index-investor-corner" target="_blank">Larry Swedroe</a></p>
<form id="actif_list-form" action="${url}" method="post">
<div class="form-group">
<button id="updateButton" class="btn btn-primary" type="submit" name="form.submitted">
<i class="glyphicon glyphicon-refresh"></i> MAJ du portefeuille</button>
<a href="#" class="btn btn-success" role="button"
data-toggle="modal" data-target="#choixTypeActif"><span class="glyphicon glyphicon-plus"></span> Nouvel actif</a>
<a href="${request.application_url}/histo_list" class="btn btn-default" role="button">
<span class="glyphicon glyphicon-stats"></span> Historique</a>
<a href="${request.application_url}/doc_view/2" class="btn btn-default" role="button">
<span class="glyphicon glyphicon-folder-close"></span> Mouvements</a>
</div>
</form>
<table id="actifs_list" class="table table-condensed table-bordered">
<thead>
<tr>
<th>Classe</th>
<th>Libellé</th>
<th class="text-right">Cours</th>
<th class="text-right">Nb</th>
<th class="text-right">Valeur</th>
<th class="text-right">+/- Valeur</th>
<th class="text-right">% de +/-</th>
<th class="text-right">Rdt brut</th>
<th class="text-right">% Rdt</th>
<th class="text-right">% PF</th>
</tr>
</thead>
<tbody>
<tr tal:repeat="ligne actifs">
<td class="${ligne.bg_color}">${ligne.classe}</td>
<td tal:condition="ligne.type=='ACTION'"><a href="actif_edit/${ligne.no_id}">${ligne.libelle}</a></td>
<td tal:condition="ligne.type!='ACTION'"><a href="actif2_edit/${ligne.no_id}">${ligne.libelle}</a></td>
<td tal:condition="ligne.devise=='EUR'" class="text-right">${layout.to_euro(ligne.cours)}</td>
<td tal:condition="ligne.devise=='USD'" class="text-right">${layout.to_usd(ligne.cours)}</td>
<td class="text-right">${ligne.nombre}</td>
<td class="text-right">${layout.to_euro(ligne.valeur)}</td>
<td tal:condition="ligne.plus_value>=0" class="text-right" style="color: green;">${layout.to_euro(ligne.plus_value)}</td>
<td tal:condition="ligne.plus_value <0" class="text-right" style="color: red;">${layout.to_euro(ligne.plus_value)}</td>
<td tal:condition="ligne.pc_plusvalue>=0" class="text-right" style="color: green;">${layout.to_percent(ligne.pc_plusvalue,1)}</td>
<td tal:condition="ligne.pc_plusvalue <0" class="text-right" style="color: red;">${layout.to_percent(ligne.pc_plusvalue,1)}</td>
<td class="text-right">${u'%.0f €' % (ligne.rendement)}</td>
<td class="text-right">${layout.to_percent(ligne.pc_rdt,1)}</td>
<td class="text-right">${ligne.pc_allocation} %</td>
</tr>
<tr>
<td class="text-right" colspan="4"><b>Total</b></td>
<td tal:condition="total_valeur>=0" class="text-right" style="color: green;"><b>${layout.to_euro(total_valeur)}</b></td>
<td tal:condition="total_valeur <0" class="text-right" style="color: red;"><b>${layout.to_euro(total_valeur)}</b></td>
<td tal:condition="total_pv>=0" class="text-right" style="color: green;"><b>${layout.to_euro(total_pv)}</b></td>
<td tal:condition="total_pv <0" class="text-right" style="color: red;"><b>${layout.to_euro(total_pv)}</b></td>
<td class="text-right"><b>${layout.to_percent(total_pc_value, 1)}</b></td>
<td class="text-right"><b>${total_rdt} €</b></td>
<td></td>
<td class="text-right"><b>100.0 %</b></td>
</tr>
</tbody>
</table>
</div>
<div class="row">
<div>
<!-- graphique evolution -->
<div id="curve_chart" style="width: 100%; height: 500px;"></div>
</div>
</div>
<!-- MODAL POPUP : Affichage de la FAQ -->
<div class="modal fade" id="choixTypeActif" tabindex="-1" role="dialog" aria-labelledby="choixTypeActif" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span class="glyphicon glyphicon-remove"></span></button>
<h4 class="modal-title" id="choixTypeActif">Choix du type d'actif à créer</h4>
</div>
<div class="modal-body">
<p>
Voulez-vous créer un actif de type <br />
<br />
<a href="${request.application_url}/actif_edit/0" class="btn btn-primary" role="button">
ACTION</a> ou
<a href="${request.application_url}/actif2_edit/0" class="btn btn-warning" role="button">
AUTRE</a>
<br />
<br />
<p>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$('#updateButton').on('click', function(){
$('i.gly-spin').removeClass('gly-spin');
$('i').addClass('gly-spin');
});
</script>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load("current", {packages:["corechart"]});
google.charts.setOnLoadCallback(drawChart);
var dataSet_cible = ${donut_cible};
var dataSet_actuel = ${donut_actuel};
var dataSet_evoln = ${courbe_evoln};
function drawChart() {
var data_cible = google.visualization.arrayToDataTable(dataSet_cible);
var data_actuel = google.visualization.arrayToDataTable(dataSet_actuel);
var data_evoln = google.visualization.arrayToDataTable(dataSet_evoln);
var options_cible = {
title: 'Allocation cible',
pieHole: 0.4,
slices: {
0: {color: 'SteelBlue'}, 1: {color: 'LightSteelBlue'},
2: {color: 'Maroon'}, 3: {color: 'Brown'},
5: {offset: 0.2, color: 'DarkGreen'}, 6: {offset: 0.3, color: 'Green'},
},
};
var options_actuel = {
title: 'Allocation actuelle',
pieHole: 0.4,
slices: {
0: {color: 'SteelBlue'}, 1: {color: 'LightSteelBlue'},
2: {color: 'Maroon'}, 3: {color: 'Brown'},
5: {offset: 0.2, color: 'DarkGreen'}, 6: {offset: 0.3, color: 'Green'},
},
};
var options_evoln = {
title: 'Evolution du portefeuille VS fond Carmignac Investissement',
curveType: 'function',
legend: { position: 'top' }
};
var chart_cible = new google.visualization.PieChart(document.getElementById('donutchart_cible'));
chart_cible.draw(data_cible, options_cible);
var chart_actuel = new google.visualization.PieChart(document.getElementById('donutchart_actuel'));
chart_actuel.draw(data_actuel, options_actuel);
var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
chart.draw(data_evoln, options_evoln);
}
</script>
</div><!-- content -->
</metal:block>

View File

@@ -8,30 +8,29 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="intitule">Intitulé</label> <label class="control-label col-xs-2" for="intitule">Intitulé</label>
<div class="col-xs-8"> <div class="col-xs-10">
<input class="form-control" type="text" id="intitule" name="intitule" value="${intitule}" <input class="form-control" type="text" id="intitule" name="intitule" value="${intitule}"
placeholder="40 caractères maximum"
data-fv-notempty="true" data-fv-notempty="true"
data-fv-notempty-message="L'intitule est obligatoire" data-fv-notempty-message="L'intitule est obligatoire"
data-fv-stringlength="true" data-fv-stringlength="true"
data-fv-stringlength-max="40" data-fv-stringlength-max="100"
data-fv-stringlength-message="40 caractères maximum" /> data-fv-stringlength-message="100 caractères maximum" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="texte">Texte</label> <label class="control-label col-xs-2" for="texte">Texte</label>
<div class="col-xs-8"> <div class="col-xs-10">
<textarea class="form-control" rows="15" cols="40" id="texte" name="texte">${texte}</textarea> <textarea class="form-control monospace-font" rows="15" cols="40" id="texte" name="texte">${texte}</textarea>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-2" for="theme">Thème</label> <label class="control-label col-xs-2" for="theme">Thème</label>
<div class="col-xs-4"> <div class="col-xs-6">
<select class="form-control" id="theme" name="theme"> <select class="form-control" id="theme" name="theme">
<div tal:repeat="item themes"> <div tal:repeat="item themes">
<option value="${item}" tal:attributes="selected theme==item and 'selected' or None">${item}</option> <option value="${item.theme}" tal:attributes="selected theme==item.theme and 'selected' or None">${item.theme}</option>
</div> </div>
</select> </select>
</div> </div>
@@ -66,16 +65,6 @@ $(document).ready(function() {
invalid: 'glyphicon glyphicon-remove', invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh' validating: 'glyphicon glyphicon-refresh'
}, },
fields: {
texte: {
validators: {
stringLength: {
max: 30000,
message: '30000 caractères maximum'
},
}
},
},
}); });
$('form input').on('keypress', function(e) { $('form input').on('keypress', function(e) {
return e.which !== 13; return e.which !== 13;

View File

@@ -7,35 +7,24 @@
<span class="glyphicon glyphicon-plus"></span>&nbsp; <span class="glyphicon glyphicon-plus"></span>&nbsp;
Créér une nouvelle doc</a> Créér une nouvelle doc</a>
</p> </p>
<div class="col-md-4"> <div class="col-md-6">
<table class="table table-condensed table-striped table-bordered"> <table class="table table-condensed table-striped table-bordered">
<tr> <tr>
<th>FINANCE</th> <th>MEMOS</th>
</tr> </tr>
<tr tal:repeat="ligne docs_finance"> <tr tal:repeat="ligne memos">
<td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td> <td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td>
</tr> </tr>
</table> </table>
</div> </div>
<div class="col-md-4"> <div class="col-md-6">
<table class="table table-condensed table-striped table-bordered"> <table class="table table-condensed table-striped table-bordered">
<tr> <tr>
<th>VOITURE</th> <th>DOCUMENTS</th>
</tr> </tr>
<tr tal:repeat="ligne docs_voiture"> <tr tal:repeat="ligne docs">
<td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td>
</tr>
</table>
</div>
<div class="col-md-4">
<table class="table table-condensed table-striped table-bordered">
<tr>
<th class="text-center">MAISON</th>
</tr>
<tr tal:repeat="ligne docs_maison">
<td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td> <td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td>
</tr> </tr>
</table> </table>

View File

@@ -1,232 +1,31 @@
<metal:block use-macro="main_template"> <metal:block use-macro="main_template">
<div metal:fill-slot="content"> <div metal:fill-slot="content">
<div tal:condition="message" tal:content="message" class="alert alert-success" /> <h1>Blog</h1>
<p tal:condition="not layout.isAnonymous()">
<p> <a href="doc_edit/0">Créer un nouveau post</a>
<a href="allocation_edit/0" class="btn btn-success" role="button"> </p>
<span class="glyphicon glyphicon-plus"></span> Nouvelle classe</a>
</p>
<div class="row">
<div class="col-md-6">
<table id="categories_list" class="table table-condensed table-bordered">
<thead>
<tr>
<th>Classe</th>
<th class="text-right">% cible</th>
<th class="text-right">% actuel</th>
<th class="text-right">Ecart</th>
<th class="text-right">Valeur</th>
</tr>
</thead>
<tbody>
<tr tal:repeat="item items">
<td class="${item.bg_color}">${item.classe}</td>
<td class="text-right"><a href="allocation_edit/${item.no_cat}">${item.pc_cible} %</a></td>
<td class="text-right">${layout.to_percent(item.pc_atteint,1)}</td>
<td tal:condition="(item.pc_atteint - item.pc_cible)>=0" class="text-right" style="color: green;">${layout.to_percent(item.pc_atteint - item.pc_cible,1)}</td>
<td tal:condition="(item.pc_atteint - item.pc_cible) <0" class="text-right" style="color: red;">${layout.to_percent(item.pc_atteint - item.pc_cible,1)}</td>
<td class="text-right">${layout.to_euro(item.valeur)}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<table id="portfolio" class="table table-condensed table-bordered">
<thead>
<tr>
<th>Portefeuille</th>
<th class="text-right">Montant</th>
<th class="text-right">%</th>
</tr>
</thead>
<tbody>
<tr>
<td>Valorisation</td>
<td class="text-right">${layout.to_euro(member.pf_valeur)}</td>
<td></td>
</tr>
<tr>
<td>Plus value</td>
<td class="text-right">${layout.to_euro(member.pf_plusvalue)}</td>
<td class="text-right">${layout.to_percent(member.pf_plusvalue_pc, 1)}</td>
</tr>
<tr>
<td>Rendemant brut</td>
<td class="text-right">${layout.to_euro(member.pf_rendement)}</td>
<td class="text-right">${layout.to_percent(member.pf_rdt_pc, 1)}</td>
</tr>
</tbody>
</table>
<p>
<b>Allocation globale</b> : 60% actions + 5% REITS + 35% obligations<br />
<b>Allocation actions D</b> (1/2) : 60% US (18%) + 30% Europe (12%)<br />
<b>Allocation actions C</b> (1/2) : 100% World (30%) <br />
[Cette allocation est inspirée de celle du <a href="https://www.nbim.no/en/the-fund/how-we-invest/benchmark-index/">Fond souverain Norvégien</a>]
</p>
</div>
</div>
<div class="row">
<div class="col-md-6">
<!-- graphique donut cible -->
<div id="donutchart_cible" style="width: 100%; height: 500px;"></div>
</div>
<div class="col-md-6">
<!-- graphique donut actuel -->
<div id="donutchart_actuel" style="width: 100%; height: 500px;"></div>
</div>
</div>
<div class="row"> <div class="row">
<h3>Mes actifs</h3> <table class="table">
<p>"<i>Diversification is not determined by the number of securities held.</i>" <tr tal:repeat="ligne items">
<a href="http://www.etf.com/sections/index-investor-corner" target="_blank">Larry Swedroe</a></p> <td>${ligne.cree_le.strftime("%Y")}</td>
<td>${ligne.cree_le.strftime("%d %b")}</td>
<form id="actif_list-form" action="${url}" method="post"> <td><a href="doc_view/${ligne.doc_id}"><b>${ligne.intitule}</b></a></td>
<div class="form-group">
<div class="form-group">
<button id="updateButton" class="btn btn-primary" type="submit" name="form.submitted">
<i class="glyphicon glyphicon-refresh"></i> MAJ du portefeuille</button>
<a href="#" class="btn btn-success" role="button"
data-toggle="modal" data-target="#choixTypeActif"><span class="glyphicon glyphicon-plus"></span> Nouvel actif</a>
</div>
</div>
</form>
<table id="actifs_list" class="table table-condensed table-bordered">
<thead>
<tr>
<th>Classe</th>
<th>Libellé</th>
<th class="text-right">Cours</th>
<th class="text-right">Nb</th>
<th class="text-right">Valeur</th>
<th class="text-right">+/- Valeur</th>
<th class="text-right">% de +/-</th>
<th class="text-right">Rdt brut</th>
<th class="text-right">% Rdt</th>
<th class="text-right">% PF</th>
</tr>
</thead>
<tbody>
<tr tal:repeat="ligne actifs">
<td class="${ligne.bg_color}">${ligne.classe}</td>
<td tal:condition="ligne.type=='ACTION'"><a href="actif_edit/${ligne.no_id}">${ligne.libelle}</a></td>
<td tal:condition="ligne.type!='ACTION'"><a href="actif2_edit/${ligne.no_id}">${ligne.libelle}</a></td>
<td tal:condition="ligne.devise=='EUR'" class="text-right">${layout.to_euro(ligne.cours)}</td>
<td tal:condition="ligne.devise=='USD'" class="text-right">${layout.to_usd(ligne.cours)}</td>
<td class="text-right">${ligne.nombre}</td>
<td class="text-right">${layout.to_euro(ligne.valeur)}</td>
<td tal:condition="ligne.plus_value>=0" class="text-right" style="color: green;">${layout.to_euro(ligne.plus_value)}</td>
<td tal:condition="ligne.plus_value <0" class="text-right" style="color: red;">${layout.to_euro(ligne.plus_value)}</td>
<td tal:condition="ligne.pc_plusvalue>=0" class="text-right" style="color: green;">${layout.to_percent(ligne.pc_plusvalue,1)}</td>
<td tal:condition="ligne.pc_plusvalue <0" class="text-right" style="color: red;">${layout.to_percent(ligne.pc_plusvalue,1)}</td>
<td class="text-right">${u'%.0f €' % (ligne.rendement)}</td>
<td class="text-right">${layout.to_percent(ligne.pc_rdt,1)}</td>
<td class="text-right">${ligne.pc_allocation} %</td>
</tr>
<tr>
<td class="text-right" colspan="4"><b>Total</b></td>
<td tal:condition="total_valeur>=0" class="text-right" style="color: green;"><b>${layout.to_euro(total_valeur)}</b></td>
<td tal:condition="total_valeur <0" class="text-right" style="color: red;"><b>${layout.to_euro(total_valeur)}</b></td>
<td tal:condition="total_pv>=0" class="text-right" style="color: green;"><b>${layout.to_euro(total_pv)}</b></td>
<td tal:condition="total_pv <0" class="text-right" style="color: red;"><b>${layout.to_euro(total_pv)}</b></td>
<td class="text-right"><b>${layout.to_percent(total_pc_value, 1)}</b></td>
<td class="text-right"><b>${total_rdt} €</b></td>
<td></td>
<td class="text-right"><b>100.0 %</b></td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
<div class="row"> <div class="row well text-center" tal:condition="not layout.isAnonymous()">
<div class="col-md-6"> <div class="col-sm-3">
<!-- graphique evolution --> <a href="${request.application_url}/portfolio"><span class="glyphicon glyphicon-piggy-bank logo-primary"></span></a>
<div id="curve_chart" style="width: 200%; height: 500px;"></div> <h4>EPARGNE</h4>
</div> </div>
<div class="col-md-6"> <div class="col-sm-3">
<a href="${request.application_url}/doc_list"><span class="glyphicon glyphicon-list-alt logo-primary"></span></a>
<h4>MEMOS</h4>
</div> </div>
</div> </div>
<!-- MODAL POPUP : Affichage de la FAQ -->
<div class="modal fade" id="choixTypeActif" tabindex="-1" role="dialog" aria-labelledby="choixTypeActif" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span class="glyphicon glyphicon-remove"></span></button>
<h4 class="modal-title" id="choixTypeActif">Choix du type d'actif à créer</h4>
</div>
<div class="modal-body">
<p>
Voulez-vous créer un actif de type <br />
<br />
<a href="${request.application_url}/actif_edit/0" class="btn btn-primary" role="button">
ACTION</a> ou
<a href="${request.application_url}/actif2_edit/0" class="btn btn-warning" role="button">
AUTRE</a>
<br />
<br />
<p>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$('#updateButton').on('click', function(){
$('i.gly-spin').removeClass('gly-spin');
$('i').addClass('gly-spin');
});
</script>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load("current", {packages:["corechart"]});
google.charts.setOnLoadCallback(drawChart);
var dataSet_cible = ${donut_cible};
var dataSet_actuel = ${donut_actuel};
var dataSet_evoln = ${courbe_evoln};
function drawChart() {
var data_cible = google.visualization.arrayToDataTable(dataSet_cible);
var data_actuel = google.visualization.arrayToDataTable(dataSet_actuel);
var data_evoln = google.visualization.arrayToDataTable(dataSet_evoln);
var options_cible = {
title: 'Allocation cible',
pieHole: 0.4,
slices: {
0: {color: 'SteelBlue'}, 1: {color: 'LightSteelBlue'},
2: {color: 'Maroon'}, 3: {color: 'Brown'},
5: {offset: 0.2, color: 'DarkGreen'}, 6: {offset: 0.3, color: 'Green'},
},
};
var options_actuel = {
title: 'Allocation actuelle',
pieHole: 0.4,
slices: {
0: {color: 'SteelBlue'}, 1: {color: 'LightSteelBlue'},
2: {color: 'Maroon'}, 3: {color: 'Brown'},
5: {offset: 0.2, color: 'DarkGreen'}, 6: {offset: 0.3, color: 'Green'},
},
};
var options_evoln = {
title: 'Evolution du portefeuille VS fond Carmignac Investissement',
curveType: 'function',
legend: { position: 'top' }
};
var chart_cible = new google.visualization.PieChart(document.getElementById('donutchart_cible'));
chart_cible.draw(data_cible, options_cible);
var chart_actuel = new google.visualization.PieChart(document.getElementById('donutchart_actuel'));
chart_actuel.draw(data_actuel, options_actuel);
var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
chart.draw(data_evoln, options_evoln);
}
</script>
</div><!-- content --> </div><!-- content -->
</metal:block> </metal:block>

View File

@@ -7,6 +7,7 @@
<title>${page_title}</title> <title>${page_title}</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, user-scalable=yes" /> <meta name="viewport" content="initial-scale=1.0, user-scalable=yes" />
<link rel="shortcut icon" href="${request.static_url('caotek_mesavoirs:static/img/favicon.ico')}">
<!-- Bootstrap core + Plug-ins CSS --> <!-- Bootstrap core + Plug-ins CSS -->
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
@@ -48,26 +49,24 @@
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a href="${request.application_url}" alt="Accueil"> <a class="navbar-brand" class="text-center" href="${request.application_url}" alt="Accueil">
<img src="${request.static_url('caotek_mesavoirs:static/img/logo.png')}" class="logo" /></a> <img src="${request.static_url('caotek_mesavoirs:static/img/logo-caotek.png')}" class="logo" /></a>
&nbsp;MON PORTEFEUILLE
</div> </div>
<div class="collapse navbar-collapse" id="myNavbar" tal:condition="not layout.isAnonymous()"> <div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li><a href="${request.application_url}/histo_list">HISTORIQUE</a></li> <!-- <li><a href="${request.application_url}/histo_list">HISTORIQUE</a></li> -->
<li><a href="${request.application_url}/doc_list">DOCS</a></li> <li tal:condition="layout.isAnonymous()"><a href="${request.application_url}/login">se connecter</a></li>
${panel('dropdown_menu_panel')} ${panel('dropdown_menu_panel')}
</ul> </ul>
</div> </div>
</div> </div>
</nav> </nav>
<br /> <br />
<br /> <br />
<br /> <br />
<hr>
<div class="container"> <div class="container">
<h1>${page_title}</h1> <h1 tal:condition="request.path != '/'">${page_title}</h1>
<br />
<div id="messages" tal:attributes="class request.is_xhr and 'ajax-replace' or None"> <div id="messages" tal:attributes="class request.is_xhr and 'ajax-replace' or None">
<div tal:repeat="queue ('', 'info', 'success', 'warning', 'danger')" <div tal:repeat="queue ('', 'info', 'success', 'warning', 'danger')"
tal:omit-tag=""> tal:omit-tag="">
@@ -86,8 +85,24 @@
<br /> <br />
</div> </div>
<footer class="container-fluid bg-footer text-center"> <footer class="container-fluid bg-footer">
<p>&copy; 2017&nbsp;-&nbsp;www.caotek.fr&nbsp;-&nbsp;Powered by <a href="https://trypyramid.com/">Pyramid</a></p> <div class="row">
<div class="col-xs-offset-2 col-xs-4">
<p>L'argent que l'on possède est l'instrument de la liberté; celui que l'on pourchasse est celui de la servitude - <b>Rousseau</b></p>
<p>L'intelligence ce n'est pas ce que l'on sait mais ce que l'on fait quand on ne sait pas - <b>Jean Piaget</b></p>
</div>
<div class="col-xs-offset-2 col-xs-4">
<p>
Apprendre Restructured Text <a href="https://github.com/ralsina/rst-cheatsheet/blob/master/rst-cheatsheet.rst">(reST)</a><br />
Apprendre Markdown <a href="https://www.markdownguide.org/basic-syntax/">(md)</a><br />
<a href="http://www.marinestylefitness.com/">Marine Style Fitness </a><br />
</p>
</div>
</div>
<br />
<div class="row">
<p class="text-center">&copy; 2017&nbsp;-&nbsp;www.caotek.fr&nbsp;-&nbsp;Powered by <a href="https://trypyramid.com/">Pyramid</a></p>
</div>
</footer> </footer>
<div metal:define-slot="additional_scripts" /> <div metal:define-slot="additional_scripts" />

View File

@@ -34,6 +34,97 @@ import time
import yfinance as yf import yfinance as yf
import html import html
@view_config(route_name='portfolio', renderer='../templates/actifs/portfolio.pt', permission='view')
def portfolio(request):
logged_in = request.authenticated_userid
member = get_member_by_email(request, logged_in)
url = request.route_url('portfolio')
message = ''
# lire les categories
items = get_allocation(request, '0')
# construire la liste pour donut
donut_cible=[]
donut_cible.append(('Allocation cible', 'Pourcent'))
donut_actuel=[]
donut_actuel.append(('Allocation actuelle', 'Pourcent'))
# calculer % total
total = 0
for item in items:
# construire la liste pour donut cible
d = (item.classe, item.pc_cible)
donut_cible.append(d)
# construire la liste pour donut actuel
d = (item.classe, int(item.pc_atteint * 10))
donut_actuel.append(d)
# totaliser les pourcentages
total += item.pc_cible
if total != 100:
message = 'Attention, le total de votre répartition cible est incorrect : %s.' % total
# lire les actifs
actifs = get_actifs(request, '0')
# MAJ du prtefeuille
if 'form.submitted' in request.params:
# lire le cours de EURUSD
ticker = yf.Ticker('EUR=X')
# maj des parités des devises
update_actif_devise(request, 'USD', ticker.info.get('regularMarketPrice'))
for item in actifs:
if item.type == 'ACTION':
# lire le cours de l'action
ticker = yf.Ticker(item.symbole)
# caluler son rendement
dividends = get_dividends(ticker)
update_actif_valeur(request, item.symbole, ticker.info.get('regularMarketPrice'), dividends)
time.sleep(1) # attendre 2 secondes
# update du portefeuille
update_portefeuille(request, logged_in)
# relire les actifs
actifs = get_actifs(request, '0')
message = 'Le portefeuille est mis à jour avec succès.'
total_valeur = 0
total_pv = 0
total_rdt = 0
for item in actifs:
total_valeur += item.valeur
total_pv += item.plus_value
total_pc_value = total_pv / total_valeur * 100
total_rdt += item.rendement
# lire l'historique
histos = get_histo(request,'0')
courbe_evoln=[]
courbe_evoln.append(('Date', 'Valeur part PF', 'Valeur part CARINVT:FP'))
for item in histos:
# construire la liste pour donut cible
d = (item.date.strftime('%d/%m/%Y'), int(item.val_part * 1000), int(item.val_part_ref * 1000))
courbe_evoln.append(d)
return {
'page_title': "Portefeuille",
'message': message,
'url': url,
'items': items,
'member': member,
'donut_cible': json.dumps(donut_cible),
'donut_actuel': json.dumps(donut_actuel),
'courbe_evoln': json.dumps(courbe_evoln),
'actifs': actifs,
'total_valeur': total_valeur,
'total_pv': total_pv,
'total_pc_value': total_pc_value,
'total_rdt': total_rdt
}
@view_config(route_name='actif_edit', renderer='../templates/actifs/actif_edit.pt', permission='view') @view_config(route_name='actif_edit', renderer='../templates/actifs/actif_edit.pt', permission='view')
def actif_edit(request): def actif_edit(request):
no_id = request.matchdict['no_id'] no_id = request.matchdict['no_id']
@@ -61,7 +152,7 @@ def actif_edit(request):
actif = get_actifs(request, no_id) actif = get_actifs(request, no_id)
if not actif: if not actif:
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning') request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('portfolio'))
page_title= "Actif ACTION : %s" % (actif.libelle) page_title= "Actif ACTION : %s" % (actif.libelle)
if 'form.submitted' in request.params: if 'form.submitted' in request.params:
@@ -80,16 +171,15 @@ def actif_edit(request):
ticker = yf.Ticker(symbole) ticker = yf.Ticker(symbole)
new_values['cours'] = ticker.info.get('regularMarketPrice') new_values['cours'] = ticker.info.get('regularMarketPrice')
new_values['devise'] = ticker.info.get('currency') new_values['devise'] = ticker.info.get('currency')
longName = html.unescape(ticker.info.get('longName')) new_values['libelle'] = html.unescape(ticker.info.get('shortName'))
new_values['libelle'] = longName.replace('Vanguard Funds Public Limited Company - ','').replace('Amundi Index Solutions - ','').replace('Distributing','')
update_actif(request, no_id, new_values) update_actif(request, no_id, new_values)
request.session.flash(u"La fiche a été mise à jour avec succès.", 'success') request.session.flash(u"La fiche a été mise à jour avec succès.", 'success')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('portfolio'))
if 'form.deleted' in request.params: if 'form.deleted' in request.params:
delete_actif(request, no_id) delete_actif(request, no_id)
request.session.flash(u"La fiche a été supprimée avec succès.", 'success') request.session.flash(u"La fiche a été supprimée avec succès.", 'success')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('portfolio'))
return { return {
'page_title': page_title, 'page_title': page_title,
@@ -124,7 +214,7 @@ def actif2_edit(request):
actif = get_actifs(request, no_id) actif = get_actifs(request, no_id)
if not actif: if not actif:
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning') request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('portfolio'))
page_title= "Actif : %s" % (actif.symbole) page_title= "Actif : %s" % (actif.symbole)
if 'form.submitted' in request.params: if 'form.submitted' in request.params:
@@ -137,12 +227,12 @@ def actif2_edit(request):
new_values['devise'] = 'EUR' new_values['devise'] = 'EUR'
update_actif(request, no_id, new_values) update_actif(request, no_id, new_values)
request.session.flash(u"La fiche a été mise à jour avec succès.", 'success') request.session.flash(u"La fiche a été mise à jour avec succès.", 'success')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('portfolio'))
if 'form.deleted' in request.params: if 'form.deleted' in request.params:
delete_actif(request, no_id) delete_actif(request, no_id)
request.session.flash(u"La fiche a été supprimée avec succès.", 'success') request.session.flash(u"La fiche a été supprimée avec succès.", 'success')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('portfolio'))
return { return {
'page_title': page_title, 'page_title': page_title,
@@ -174,7 +264,7 @@ def allocation_edit(request):
allocation = get_allocation(request, no_cat) allocation = get_allocation(request, no_cat)
if not allocation: if not allocation:
request.session.flash(u"Classe non trouvé : %s" % no_cat, 'warning') request.session.flash(u"Classe non trouvé : %s" % no_cat, 'warning')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('portfolio'))
page_title= "Classe : %s" % (allocation.classe) page_title= "Classe : %s" % (allocation.classe)
if 'form.submitted' in request.params: if 'form.submitted' in request.params:
@@ -186,12 +276,12 @@ def allocation_edit(request):
if new_values: if new_values:
update_allocation(request, no_cat, new_values) update_allocation(request, no_cat, new_values)
request.session.flash(u"La fiche a été mise à jour avec succès.", 'success') request.session.flash(u"La fiche a été mise à jour avec succès.", 'success')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('portfolio'))
if 'form.deleted' in request.params: if 'form.deleted' in request.params:
delete_allocation(request, no_cat) delete_allocation(request, no_cat)
request.session.flash(u"La fiche a été supprimée avec succès.", 'success') request.session.flash(u"La fiche a été supprimée avec succès.", 'success')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('portfolio'))
return { return {
'page_title': page_title, 'page_title': page_title,

View File

@@ -18,10 +18,6 @@ from sqlalchemy.exc import DBAPIError
from ..security import groupfinder from ..security import groupfinder
from ..models.default import * from ..models.default import *
from ..models.actifs import *
from ..models.members import (
get_member_by_email,
)
# import datetime # import datetime
import time import time
@@ -70,110 +66,28 @@ def to_percent(x, d):
return pc.replace('.', ',') return pc.replace('.', ',')
@view_config(route_name='home', renderer='../templates/home.pt', permission='view') @view_config(route_name='home', renderer='../templates/home.pt')
def home(request): def home(request):
logged_in = request.authenticated_userid
member = get_member_by_email(request, logged_in)
url = request.route_url('home')
message = '' # lire toutes les docs
items = get_docs_bytheme(request, 'BLOG')
# lire les categories
items = get_allocation(request, '0')
# construire la liste pour donut
donut_cible=[]
donut_cible.append(('Allocation cible', 'Pourcent'))
donut_actuel=[]
donut_actuel.append(('Allocation actuelle', 'Pourcent'))
# calculer % total
total = 0
for item in items:
# construire la liste pour donut cible
d = (item.classe, item.pc_cible)
donut_cible.append(d)
# construire la liste pour donut actuel
d = (item.classe, int(item.pc_atteint * 10))
donut_actuel.append(d)
# totaliser les pourcentages
total += item.pc_cible
if total != 100:
message = 'Attention, le total de votre répartition cible est incorrect : %s.' % total
# lire les actifs
actifs = get_actifs(request, '0')
# MAJ du prtefeuille
if 'form.submitted' in request.params:
# lire le cours de EURUSD
ticker = yf.Ticker('EUR=X')
# maj des parités des devises
update_actif_devise(request, 'USD', ticker.info.get('regularMarketPrice'))
for item in actifs:
if item.type == 'ACTION':
# lire le cours de l'action
ticker = yf.Ticker(item.symbole)
# caluler son rendement
dividends = get_dividends(ticker)
update_actif_valeur(request, item.symbole, ticker.info.get('regularMarketPrice'), dividends)
time.sleep(1) # attendre 2 secondes
# update du portefeuille
update_portefeuille(request, logged_in)
# relire les actifs
actifs = get_actifs(request, '0')
message = 'Le portefeuille est mis à jour avec succès.'
total_valeur = 0
total_pv = 0
total_rdt = 0
for item in actifs:
total_valeur += item.valeur
total_pv += item.plus_value
total_pc_value = total_pv / total_valeur * 100
total_rdt += item.rendement
# lire l'historique
histos = get_histo(request,'0')
courbe_evoln=[]
courbe_evoln.append(('Date', 'Valeur part PF', 'Valeur part CARINVT:FP'))
for item in histos:
# construire la liste pour donut cible
d = (item.date.strftime('%d/%m/%Y'), int(item.val_part * 1000), int(item.val_part_ref * 1000))
courbe_evoln.append(d)
return { return {
'page_title': "Allocation d'actifs", 'page_title': "Home",
'message': message,
'url': url,
'items': items, 'items': items,
'member': member,
'donut_cible': json.dumps(donut_cible),
'donut_actuel': json.dumps(donut_actuel),
'courbe_evoln': json.dumps(courbe_evoln),
'actifs': actifs,
'total_valeur': total_valeur,
'total_pv': total_pv,
'total_pc_value': total_pc_value,
'total_rdt': total_rdt
} }
@view_config(route_name='doc_list', renderer='../templates/doc_list.pt', permission='view') @view_config(route_name='doc_list', renderer='../templates/doc_list.pt', permission='view')
def doc_list(request): def doc_list(request):
# lire toutes les docs # lire toutes les docs
docs_finance = get_docs_bytheme(request, 'FINANCE') memos = get_docs_bytheme(request, 'memo')
docs_maison = get_docs_bytheme(request, 'MAISON') docs = get_docs_bytheme(request, 'doc')
docs_voiture = get_docs_bytheme(request, 'VOITURE')
return { return {
'page_title': "Documents", 'page_title': "Documents",
'docs_finance': docs_finance, 'memos': memos,
'docs_maison': docs_maison, 'docs': docs,
'docs_voiture': docs_voiture,
} }
@view_config(route_name='doc_edit', renderer='../templates/doc_edit.pt', permission='view') @view_config(route_name='doc_edit', renderer='../templates/doc_edit.pt', permission='view')
@@ -182,6 +96,8 @@ def doc_edit(request):
url = request.route_url('doc_edit',doc_id=doc_id) url = request.route_url('doc_edit',doc_id=doc_id)
message = "" message = ""
themes = get_blog_themes(request)
if doc_id == '0': if doc_id == '0':
titre = "Nouveau doc" titre = "Nouveau doc"
intitule = "" intitule = ""
@@ -222,7 +138,7 @@ def doc_edit(request):
'intitule': intitule, 'intitule': intitule,
'texte': texte, 'texte': texte,
'theme': theme, 'theme': theme,
'themes': ["MAISON","FINANCE","VOITURE"], 'themes': themes,
} }
@view_config(route_name='doc_view', renderer='../templates/doc_view.pt', permission='view') @view_config(route_name='doc_view', renderer='../templates/doc_view.pt', permission='view')

View File

@@ -190,10 +190,7 @@ def logout(request):
request.session.invalidate() request.session.invalidate()
headers = forget(request) headers = forget(request)
request.session.flash(u"Vous avez bien été déconnecté.") request.session.flash(u"Vous avez bien été déconnecté.")
return HTTPFound(location=request.route_url('login', login=''), return HTTPFound(location=request.route_url('home'), headers=headers)
headers=headers)
@view_config(route_name='user_edit', renderer='../templates/members/user_edit.pt', permission='manage') @view_config(route_name='user_edit', renderer='../templates/members/user_edit.pt', permission='manage')

View File

@@ -18,7 +18,7 @@ pyramid.includes =
pyramid_mailer pyramid_mailer
pyramid_tm pyramid_tm
sqlalchemy.url = mysql://phuoc:phuoc!@localhost/bd_mesavoirs?charset=utf8 sqlalchemy.url = mysql://root:phuoc!@localhost/bd_mesavoirs?charset=utf8
caotek_mesavoirs.admin_email = cao.thien-phuoc@orange.fr caotek_mesavoirs.admin_email = cao.thien-phuoc@orange.fr
@@ -29,7 +29,7 @@ mail.port = 25
[server:main] [server:main]
use = egg:waitress#main use = egg:waitress#main
host = 0.0.0.0 host = 0.0.0.0
port = 6543 port = 9080
### ###
# logging configuration # logging configuration