delete protfolio folder
This commit is contained in:
@@ -7,7 +7,6 @@ import zope.sqlalchemy
|
||||
# Base.metadata prior to any initialization routines
|
||||
from .user import User
|
||||
from .blog_record import BlogRecord
|
||||
from .portfolio import Actifs
|
||||
|
||||
# run configure_mappers after defining all of the models to ensure
|
||||
# all relationships can be setup
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import datetime #<- will be used to set default dates on models
|
||||
from ctp_blogr.models.meta import Base #<- we need to import our sqlalchemy metadata from which model classes will inherit
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy import (
|
||||
Column,
|
||||
Integer,
|
||||
Float,
|
||||
Unicode, #<- will provide Unicode field
|
||||
UnicodeText, #<- will provide Unicode text field
|
||||
DateTime, #<- time abstraction field
|
||||
Index,
|
||||
ForeignKey,
|
||||
)
|
||||
|
||||
|
||||
class Actifs(Base):
|
||||
__tablename__ = 'actifs'
|
||||
no_id = Column(Integer, primary_key=True)
|
||||
symbole = Column(Unicode(45), unique=True, nullable=False)
|
||||
libelle = Column(Unicode(45), nullable=False)
|
||||
classe = Column(Unicode(45), nullable=False)
|
||||
nombre = Column(Integer)
|
||||
cours = Column(Float)
|
||||
pru = Column(Float)
|
||||
valeur = Column(Float)
|
||||
plus_value = Column(Float)
|
||||
pc_plusvalue = Column(Float)
|
||||
rendement = Column(Float)
|
||||
pc_rdt = Column(Float)
|
||||
pc_allocation = Column(Float)
|
||||
ter = Column(Float)
|
||||
ter_pondere = Column(Float)
|
||||
devise = Column(Unicode(45), default='EUR')
|
||||
parite = Column(Float)
|
||||
website = Column(Unicode(100))
|
||||
modif_le = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
__table_args__ = (Index('symbole_index', 'symbole'),)
|
||||
|
||||
|
||||
class Allocation(Base):
|
||||
__tablename__ = 'allocation'
|
||||
no_cat = Column(Integer, primary_key=True)
|
||||
classe = Column(Unicode(45), ForeignKey('actifs.classe'))
|
||||
pc_cible = Column(Integer)
|
||||
pc_atteint = Column(Float)
|
||||
pc_ecart = Column(Float)
|
||||
valeur = Column(Float)
|
||||
type = Column(Unicode(45), default='ACTION')
|
||||
ordre = Column(Integer)
|
||||
bg_color = Column(Unicode(45))
|
||||
__table_args__ = (Index('classe_index', 'classe'), Index('ordre_index', 'ordre'),)
|
||||
|
||||
|
||||
class Histo(Base):
|
||||
__tablename__ = 'histo'
|
||||
no_id = Column(Integer, primary_key=True)
|
||||
date = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
mvt_cash = Column(Float)
|
||||
valeur_pf = Column(Float)
|
||||
nb_part = Column(Float)
|
||||
val_part = Column(Float)
|
||||
cours_ref = Column(Float)
|
||||
val_part_ref = Column(Float)
|
||||
@@ -1,106 +0,0 @@
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import func
|
||||
from ..models.portfolio import Actifs, Allocation, Histo
|
||||
|
||||
class PFService(object):
|
||||
|
||||
@classmethod
|
||||
def get_actifs(cls, request, no_id):
|
||||
if no_id == '0':
|
||||
items = request.dbsession.query(Actifs, Allocation).join(Allocation).order_by(Allocation.ordre, Actifs.libelle).all()
|
||||
else:
|
||||
# lire une allocation par le no_id
|
||||
items = request.dbsession.query(Actifs).filter(Actifs.no_id == no_id).first()
|
||||
return items
|
||||
|
||||
@classmethod
|
||||
def get_allocation(cls, request, no_cat):
|
||||
if no_cat == '0':
|
||||
query = request.dbsession.query(Allocation)
|
||||
query = query.order_by(sa.asc(Allocation.ordre)).all()
|
||||
else:
|
||||
# lire une allocation par le no_id
|
||||
query = request.dbsession.query(Allocation).filter(Allocation.no_cat == no_cat).first()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
def get_allocation_byType(cls, request, type):
|
||||
# lire une allocation par le no_id
|
||||
query = request.dbsession.query(Allocation).filter(Allocation.type == type).all()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
def get_histo(cls, request, no_id):
|
||||
if no_id == '0':
|
||||
items = request.dbsession.query(Histo).order_by(sa.asc(Histo.date)).all()
|
||||
elif no_id == '-1':
|
||||
items = request.dbsession.query(Histo).order_by(sa.desc(Histo.date)).all()
|
||||
else:
|
||||
# lire le histo par le no_id
|
||||
items = request.dbsession.query(Histo).filter(Histo.no_id == no_id).first()
|
||||
return items
|
||||
|
||||
@classmethod
|
||||
def get_last_histo(cls, request):
|
||||
# lire le dernier histo créé
|
||||
items = request.dbsession.query(Histo).order_by(sa.desc(Histo.date)).first()
|
||||
return items
|
||||
|
||||
@classmethod
|
||||
def delete_allocation(cls, request, no_cat):
|
||||
request.dbsession.query(Allocation).filter(Allocation.no_cat == no_cat).delete(synchronize_session=False)
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def delete_histo(cls, request, no_id):
|
||||
request.dbsession.query(Histo).filter(Histo.no_id == no_id).delete(synchronize_session=False)
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def update_actif_devise(cls, request, devise, taux):
|
||||
request.dbsession.query(Actifs).filter(Actifs.devise == devise).update({'parite': taux})
|
||||
return
|
||||
|
||||
def update_actif_valeur(request, symbole, cours, valeur, plus_value, pc_plusvalue):
|
||||
request.dbsession.query(Actifs).filter(Actifs.symbole == symbole
|
||||
).update({'cours': cours,
|
||||
'valeur': valeur,
|
||||
'plus_value':plus_value,
|
||||
'pc_plusvalue': pc_plusvalue,
|
||||
})
|
||||
return
|
||||
|
||||
def update_portefeuille(request, today):
|
||||
# cumuler la valeur totale des actifs
|
||||
result = request.dbsession.query(Actifs, func.sum(Actifs.valeur).label("TotalValue")).first()
|
||||
TotalValue = result.TotalValue
|
||||
# maj du pourcentage d'allocation des lignes du portefeuille
|
||||
items = PFService.get_actifs(request, '0')
|
||||
for item in items:
|
||||
pc_allocation = round(item.Actifs.valeur / TotalValue * 100, 3)
|
||||
request.dbsession.query(Actifs).filter(Actifs.no_id == item.Actifs.no_id).update({'pc_allocation': pc_allocation,
|
||||
'modif_le': today})
|
||||
|
||||
# maj des allocations
|
||||
items = PFService.get_allocation(request, '0')
|
||||
for item in items:
|
||||
# cumuler la valeur totale des actifs de cette classe
|
||||
result = request.dbsession.query(Actifs, func.sum(Actifs.valeur).label("TotalClasse")
|
||||
).filter(Actifs.classe == item.classe).first()
|
||||
TotalClasse = result.TotalClasse
|
||||
pc_atteint = round(TotalClasse / TotalValue * 100, 3)
|
||||
# maj du pourcentage d'allocation de cette classe
|
||||
request.dbsession.query(Allocation).filter(Allocation.classe == item.classe
|
||||
).update({'valeur': TotalClasse,
|
||||
'pc_atteint': pc_atteint})
|
||||
|
||||
return
|
||||
|
||||
def delete_actif(request, no_id):
|
||||
request.dbsession.query(Actifs).filter(Actifs.no_id == no_id).delete(synchronize_session=False)
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
ctp_blogr/static/blog/Conso_2024_en_euro.png
Normal file
BIN
ctp_blogr/static/blog/Conso_2024_en_euro.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 158 KiB |
BIN
ctp_blogr/static/blog/Conso_2024_en_kWh.png
Normal file
BIN
ctp_blogr/static/blog/Conso_2024_en_kWh.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 176 KiB |
BIN
ctp_blogr/static/blog/Conso_2025_en_KWh.png
Normal file
BIN
ctp_blogr/static/blog/Conso_2025_en_KWh.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
BIN
ctp_blogr/static/blog/Conso_2025_en_euro.png
Normal file
BIN
ctp_blogr/static/blog/Conso_2025_en_euro.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
@@ -1,88 +0,0 @@
|
||||
{% extends "ctp_blogr:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form action="{{ url }}" method="post" class="form">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field">{{ form.classe.label }}</label>
|
||||
{{ form.classe(class_='form-control') }}
|
||||
</div>
|
||||
|
||||
{% for error in form.symbole.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="symbole">{{form.symbole.label}}</label>
|
||||
{{form.symbole(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
{% for error in form.libelle.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="libelle">{{form.libelle.label}}</label>
|
||||
{{form.libelle(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="pru">{{form.pru.label}}</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">{{ item.devise }}</div>
|
||||
{{form.pru(class_='form-control')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="cours">{{form.cours.label}}</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">{{ item.devise }}</div>
|
||||
{{form.cours(class_='form-control')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<p class="form-control-static"><b>Dernière modif. :</b> {{ item.modif_le }}</p>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<a class="btn btn-default" href="{{ request.route_url('portfolio') }}">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||
{% if form.no_id.data %}
|
||||
<button class="btn btn-danger" type="button" data-toggle="modal" data-target="#confirmDelete">
|
||||
<span class="glyphicon glyphicon-remove"></span> Supprimer</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Modal : Confirmation SUPRESSION -->
|
||||
<div id="confirmDelete" class="modal" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Supprimer cette allocation</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- The form is placed inside the body of modal -->
|
||||
<p>Etes-vous certain(e) de vouloir supprimer la ligne <b>{{ form.symbole.data }}</b> ?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="form-group">
|
||||
<div class="text-center">
|
||||
<form id="confirmForm" method="post">
|
||||
<button type="submit" class="btn btn-danger" name="form.deleted">Supprimer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,111 +0,0 @@
|
||||
{% extends "ctp_blogr:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form action="{{ url }}" method="post" class="form">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field">{{ form.classe.label }}</label>
|
||||
{{ form.classe(class_='form-control') }}
|
||||
</div>
|
||||
|
||||
{% for error in form.symbole.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="symbole">{{form.symbole.label}}</label>
|
||||
{{form.symbole(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
{% for error in form.libelle.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="libelle">{{form.libelle.label}}</label>
|
||||
{{form.libelle(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="nombre">{{form.nombre.label}}</label>
|
||||
{{form.nombre(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label required-field" for="pru">{{form.pru.label}}</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">{{ item.devise }}</div>
|
||||
{{form.pru(class_='form-control')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="ter">{{form.ter.label}}</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">%</div>
|
||||
{{form.ter(class_='form-control')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="pc_rdt">{{form.pc_rdt.label}}</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">%</div>
|
||||
{{form.pc_rdt(class_='form-control')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="website">{{form.website.label}}</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">
|
||||
<a href="{{ item.website }}" target="_blank"><span class="glyphicon glyphicon-globe"></span></a>
|
||||
</div>
|
||||
{{form.website(class_='form-control')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<p class="form-control-static"><b>Dernière modif. :</b> {{ item.modif_le }}</p>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<a class="btn btn-default" href="{{ request.route_url('portfolio') }}">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||
{% if form.no_id.data %}
|
||||
<button class="btn btn-danger" type="button" data-toggle="modal" data-target="#confirmDelete">
|
||||
<span class="glyphicon glyphicon-remove"></span> Supprimer</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Modal : Confirmation SUPRESSION -->
|
||||
<div id="confirmDelete" class="modal" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Supprimer cette allocation</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- The form is placed inside the body of modal -->
|
||||
<p>Etes-vous certain(e) de vouloir supprimer la ligne <b>{{ form.symbole.data }}</b> ?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="form-group">
|
||||
<div class="text-center">
|
||||
<form id="confirmForm" method="post">
|
||||
<button type="submit" class="btn btn-danger" name="form.deleted">Supprimer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,69 +0,0 @@
|
||||
{% extends "ctp_blogr:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form action="{{ url }}" method="post" class="form">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field">{{ form.classe.label }}</label>
|
||||
{{ form.classe(class_='form-control') }}
|
||||
</div>
|
||||
|
||||
{% for error in form.pc_cible.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="tag">{{form.pc_cible.label}}</label>
|
||||
{{form.pc_cible(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="tag">{{form.type.label}}</label>
|
||||
{{form.type(class_='form-control')}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="tag">{{form.bg_color.label}}</label>
|
||||
{{form.bg_color(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<a class="btn btn-default" href="{{ request.route_url('portfolio') }}">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||
{% if form.no_cat.data %}
|
||||
<button class="btn btn-danger" type="button" data-toggle="modal" data-target="#confirmDelete">
|
||||
<span class="glyphicon glyphicon-remove"></span> Supprimer</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Modal : Confirmation SUPRESSION -->
|
||||
<div id="confirmDelete" class="modal" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Supprimer cette allocation</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- The form is placed inside the body of modal -->
|
||||
<p>Etes-vous certain(e) de vouloir supprimer la ligne <b>{{ form.classe.data }}</b> ?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="form-group">
|
||||
<div class="text-center">
|
||||
<form id="confirmForm" method="post">
|
||||
<button type="submit" class="btn btn-danger" name="form.deleted">Supprimer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,64 +0,0 @@
|
||||
{% extends "ctp_blogr:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form action="{{ url }}" method="post" class="form">
|
||||
|
||||
<div class="form-group">
|
||||
<p class="form-control-static">Date : <b>{{ item.date.strftime('%d-%m-%Y') }}</b></p>
|
||||
</div>
|
||||
|
||||
{% for error in form.mvt_cash.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="tag">{{form.mvt_cash.label}}</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">€</div>
|
||||
{{form.mvt_cash(class_='form-control')}}
|
||||
</div>
|
||||
<p class="form-control-static">(si le montant est négatif, le montant est retiré du portefeuille)</b></p>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<a class="btn btn-default" href="{{ request.route_url('histo_list') }}">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
{% if form.no_id.data %}
|
||||
<button class="btn btn-danger" type="button" data-toggle="modal" data-target="#confirmDelete">
|
||||
<span class="glyphicon glyphicon-remove"></span> Supprimer</button>
|
||||
{% else %}
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Modal : Confirmation SUPRESSION -->
|
||||
<div id="confirmDelete" class="modal" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Supprimer cet historique</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- The form is placed inside the body of modal -->
|
||||
<p>Etes-vous certain(e) de vouloir supprimer la ligne <b>{{ form.no_id.data }}</b> ?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="form-group">
|
||||
<div class="text-center">
|
||||
<form id="confirmForm" method="post">
|
||||
<button type="submit" class="btn btn-danger" name="form.deleted">Supprimer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,49 +0,0 @@
|
||||
{% extends "ctp_blogr:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<p>
|
||||
<a class="btn btn-default" href="{{ request.route_url('portfolio') }}">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
<a href="{{ request.route_url('histo_edit', no_id='0') }}" class="btn btn-success" role="button">
|
||||
<span class="glyphicon glyphicon-plus"></span> Entrée / Sortie cash</a>
|
||||
</p>
|
||||
|
||||
<table id="histo_list" class="table table-striped table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th align='right'>E/S Cash</th>
|
||||
<th align='right'>Valeur Pf</th>
|
||||
<th align='right'>Nb Part</th>
|
||||
<th align='right'>Valeur Part</th>
|
||||
<th align='right'>Cours ref</th>
|
||||
<th align='right'>Nb Part ref</th>
|
||||
<th align='center'>No Id</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for item in items %}
|
||||
<tr>
|
||||
<td>{{ item.date.strftime('%d/%m/%Y') }}</td>
|
||||
<td align='right'>{{ '{0:0.2f} €'.format(item.mvt_cash) }}</td>
|
||||
<td align='right'>{{ '{0:0.2f} €'.format(item.valeur_pf) }}</td>
|
||||
<td align='right'>{{ '{0:0.2f}'.format(item.nb_part) }}</td>
|
||||
<td align='right'>{{ '{0:0.2f} €'.format(item.val_part) }}</td>
|
||||
<td align='right'>{{ '{0:0.2f} €'.format(item.cours_ref) }}</td>
|
||||
<td align='right'>{{ '{0:0.2f}'.format(item.val_part_ref) }}</td>
|
||||
<td align='center'>
|
||||
<a href="{{ request.route_url('histo_edit', no_id=item.no_id) }}">{{ item.no_id }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
{% extends "ctp_blogr:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<p>
|
||||
<a href="allocation_edit/0">[ Nouvelle classe ]</a>
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<table 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>
|
||||
{% for item in items %}
|
||||
<tr>
|
||||
<td class="{{ item.bg_color }}"><a href="allocation_edit/{{ item.no_cat }}">{{ item.classe }}</a></td>
|
||||
<td class="text-right">{{ item.pc_cible }} %</td>
|
||||
<td class="text-right">{{ '{0:0.1f}'.format(item.pc_atteint) }} %</td>
|
||||
{% if (item.pc_atteint - item.pc_cible) >= 0 %}
|
||||
<td class="text-right" style="color: green;">{{ '{0:0.1f}'.format(item.pc_ecart) }}</td>
|
||||
{% else %}
|
||||
<td class="text-right" style="color: red;">{{ '{0:0.1f}'.format(item.pc_ecart) }}</td>
|
||||
{% endif %}
|
||||
<td class="text-right">{{ '{0:0,.0f} €'.format(item.valeur).replace(',',' ') }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</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">{{ '{0:0.2f} €'.format(total_valeur).replace(',',' ') }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Plus value</td>
|
||||
<td class="text-right">{{ '{0:0,.0f} €'.format(total_pv).replace(',',' ') }}</td>
|
||||
<td class="text-right">{{ '{0:0.1f} %'.format(total_pc_value) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Safe Withdrawal Rate</td>
|
||||
<td class="text-right text-success"><b>{{ '{0:0,.0f} €'.format(swr_amount) }}</b></td>
|
||||
<td class="text-right text-success"><b>{{ '{0:0.1f} %'.format(swr_rate) }}</b></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
<b>Allocation globale</b> : 70% actions + 30% obligations<br />
|
||||
[Inspirée du
|
||||
<a href="https://www.nbim.no/en/the-fund/how-we-invest/benchmark-index/" target="_blank">Fond souverain Norvégien</a>]<br />
|
||||
<b>Allocation actions</b> : 80% Monde (56%) + 20% Croissance (14%)<br />
|
||||
</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">
|
||||
<h2>Mes actifs</h2>
|
||||
<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="#" data-toggle="modal" data-target="#choixTypeActif">[ Nouvel actif ]</a>
|
||||
<a href="/histo_list">[ Historique ]</a>
|
||||
<a href="/blog/2/mouvements-du-portefeuille">[ Mouvements ]</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<table 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">% TER</th>
|
||||
<th class="text-right">% PF</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ligne in actifs %}
|
||||
<tr>
|
||||
<td class="{{ ligne.Allocation.bg_color }}">{{ ligne.Allocation.classe }}</td>
|
||||
{% if ligne.Allocation.type=='ACTION' %}
|
||||
<td><a href="actif_edit/{{ ligne.Actifs.no_id }}">{{ ligne.Actifs.libelle }}</a></td>
|
||||
{% else %}
|
||||
<td><a href="actif2_edit/{{ ligne.Actifs.no_id }}">{{ ligne.Actifs.libelle }}</a></td>
|
||||
{% endif %}
|
||||
{% if ligne.Actifs.devise=='EUR' %}
|
||||
<td class="text-right">{{ '{0:0.2f} €'.format(ligne.Actifs.cours) }}</td>
|
||||
{% else %}
|
||||
<td class="text-right">{{ '{0:0.2f} $'.format(ligne.Actifs.cours) }}</td>
|
||||
{% endif %}
|
||||
<td class="text-right">{{ ligne.Actifs.nombre }}</td>
|
||||
<td class="text-right">{{ '{0:0,.2f} €'.format(ligne.Actifs.valeur).replace(',',' ') }}</td>
|
||||
{% if ligne.Actifs.plus_value >= 0 %}
|
||||
<td class="text-right" style="color: green;">{{ '{0:0,.2f} €'.format(ligne.Actifs.plus_value).replace(',',' ') }}</td>
|
||||
<td class="text-right" style="color: green;">{{ '{0:0.1f}'.format(ligne.Actifs.pc_plusvalue) }}</td>
|
||||
{% else %}
|
||||
<td class="text-right" style="color: red;">{{ '{0:0,.2f} €'.format(ligne.Actifs.plus_value).replace(',',' ') }}</td>
|
||||
<td class="text-right" style="color: red;">{{ '{0:0.1f}'.format(ligne.Actifs.pc_plusvalue) }}</td>
|
||||
{% endif %}
|
||||
<td class="text-right">{{ '{0:0.1f}'.format(ligne.Actifs.ter) }}</td>
|
||||
<td class="text-right">{{ '{0:0.1f}'.format(ligne.Actifs.pc_allocation) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
<tr>
|
||||
<td class="text-right" colspan="4"><b>Total au {{ maj_pf_le.strftime('%d/%m/%Y') }}</b></td>
|
||||
<td>{{ '{0:0,.2f} €'.format(total_valeur).replace(',',' ') }}</td>
|
||||
{% if total_pv >= 0 %}
|
||||
<td class="text-right" style="color: green;">{{ '{0:0,.2f} €'.format(total_pv).replace(',',' ') }}</td>
|
||||
<td class="text-right" style="color: green;">{{ '{0:0.1f}'.format(total_pc_value) }}</td>
|
||||
{% else %}
|
||||
<td class="text-right" style="color: red;">{{ '{0:0,.2f} €'.format(total_pv).replace(',',' ') }}</td>
|
||||
<td class="text-right" style="color: red;">{{ '{0:0.1f}'.format(total_pc_value) }}</td>
|
||||
{% endif %}
|
||||
<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</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
Voulez-vous créer un actif de type <br />
|
||||
<br />
|
||||
<a href="/actif_edit/0" class="btn btn-primary" role="button">
|
||||
ACTION</a> ou
|
||||
<a href="/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 | safe }};
|
||||
var dataSet_actuel = {{ donut_actuel | safe }};
|
||||
var dataSet_evoln = {{ courbe_evoln | safe }};
|
||||
|
||||
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>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,373 +0,0 @@
|
||||
from pyramid.view import (
|
||||
view_config,
|
||||
)
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
from ..services.portfolio import PFService
|
||||
from ..forms import ActifForm, Actif2Form, AllocationForm, HistoForm
|
||||
from ..models.portfolio import Actifs, Histo, Allocation
|
||||
|
||||
import datetime #<- will be used to set default dates on models
|
||||
import yfinance as yf
|
||||
import json
|
||||
import html
|
||||
|
||||
@view_config(route_name='portfolio', renderer='../templates/portfolio/portfolio.jinja2', permission='view')
|
||||
def portfolio(request):
|
||||
logged_in = request.authenticated_userid
|
||||
url = request.route_url('portfolio')
|
||||
|
||||
# lire les categories
|
||||
items = PFService.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
|
||||
|
||||
swr_rate = 3.5
|
||||
if total != 100:
|
||||
request.session.flash('Attention, le total de votre répartition cible dépasse 100% : ' + str(total), 'warning')
|
||||
|
||||
# lire les actifs
|
||||
actifs = PFService.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
|
||||
taux = ticker.fast_info.get('lastPrice')
|
||||
PFService.update_actif_devise(request, 'USD', taux)
|
||||
|
||||
for item in actifs:
|
||||
if item.Allocation.type == 'ACTION':
|
||||
symbole = item.Actifs.symbole
|
||||
# lire le cours de l'action
|
||||
ticker = yf.Ticker(symbole)
|
||||
# ticker delisted ?
|
||||
if symbole == 'SHLDQ':
|
||||
cours = 0.1
|
||||
else:
|
||||
cours = round(ticker.fast_info.get('lastPrice'), 3)
|
||||
|
||||
valeur = round(cours * item.Actifs.parite * item.Actifs.nombre, 3)
|
||||
plus_value = round(valeur - (item.Actifs.pru * item.Actifs.nombre),2)
|
||||
pc_plusvalue = round(valeur * 100 / (item.Actifs.pru * item.Actifs.nombre) - 100, 3)
|
||||
PFService.update_actif_valeur(request, symbole, cours, valeur, plus_value, pc_plusvalue)
|
||||
# time.sleep(1) # attendre 2 secondes
|
||||
|
||||
# update du portefeuille
|
||||
today = datetime.datetime.now()
|
||||
PFService.update_portefeuille(request, today)
|
||||
# relire les actifs
|
||||
actifs = PFService.get_actifs(request, '0')
|
||||
request.session.flash('Le portefeuille est mis à jour avec succès.', 'success')
|
||||
|
||||
total_valeur = 0
|
||||
total_pv = 0
|
||||
total_rdt = 0
|
||||
maj_pf_le = None
|
||||
for item in actifs:
|
||||
maj_pf_le = item.Actifs.modif_le
|
||||
total_valeur += item.Actifs.valeur
|
||||
total_pv += item.Actifs.plus_value
|
||||
if total_valeur == 0:
|
||||
total_pc_value = 0
|
||||
else:
|
||||
total_pc_value = total_pv / total_valeur * 100
|
||||
total_rdt += item.Actifs.rendement
|
||||
|
||||
# lire l'historique
|
||||
histos = PFService.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",
|
||||
'url': url,
|
||||
'items': items,
|
||||
'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,
|
||||
'maj_pf_le' : maj_pf_le,
|
||||
'swr_rate' : swr_rate,
|
||||
'swr_amount': float(total_valeur) * swr_rate / 100,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='histo_list', renderer='../templates/portfolio/histo_list.jinja2', permission='view')
|
||||
def histo_list(request):
|
||||
# lire l historique
|
||||
items = PFService.get_histo(request, '-1')
|
||||
|
||||
return {
|
||||
'page_title': 'Historique des parts',
|
||||
'items': items,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='allocation_edit', renderer='../templates/portfolio/allocation_edit.jinja2', permission='view')
|
||||
def allocation_edit(request):
|
||||
no_cat = request.matchdict['no_cat']
|
||||
url = request.route_url('allocation_edit', no_cat=no_cat)
|
||||
|
||||
if no_cat == '0':
|
||||
# create a new allocation
|
||||
entry = Allocation()
|
||||
form = AllocationForm(request.POST, entry)
|
||||
page_title = "Nouvelle allocation"
|
||||
|
||||
else:
|
||||
# modify post
|
||||
entry = PFService.get_allocation(request, no_cat)
|
||||
if not entry:
|
||||
request.session.flash(u"Allocation non trouvée : %s" % no_cat, 'warning')
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
form = AllocationForm(request.POST, entry)
|
||||
page_title = "Modifier Allocation : " + str(entry.no_cat)
|
||||
|
||||
if 'form.submitted' in request.params :
|
||||
if no_cat == '0':
|
||||
form.populate_obj(entry)
|
||||
entry.pc_atteint = 0
|
||||
entry.pc_ecart = 0
|
||||
entry.valeur = 0
|
||||
request.dbsession.add(entry)
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
else:
|
||||
del form.no_cat # SECURITY: prevent overwriting of primary key
|
||||
form.populate_obj(entry)
|
||||
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
|
||||
if 'form.deleted' in request.params:
|
||||
PFService.delete_allocation(request, entry.no_cat)
|
||||
request.session.flash("La fiche a été supprimée avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
|
||||
return {
|
||||
'page_title': page_title,
|
||||
'url': url,
|
||||
'form': form,
|
||||
'item': entry,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='histo_edit', renderer='../templates/portfolio/histo_edit.jinja2', permission='view')
|
||||
def histo_edit(request):
|
||||
no_id = request.matchdict['no_id']
|
||||
url = request.route_url('histo_edit', no_id=no_id)
|
||||
|
||||
if no_id == '0':
|
||||
# create a new tag
|
||||
entry = Histo()
|
||||
entry.mvt_cash = 0
|
||||
entry.date = datetime.datetime.now()
|
||||
form = HistoForm(request.POST, entry)
|
||||
page_title = "Nouveau Histo"
|
||||
|
||||
else:
|
||||
# modify post
|
||||
entry = PFService.get_histo(request, no_id)
|
||||
if not entry:
|
||||
request.session.flash(u"Histo non trouvé : %s" % no_id, 'warning')
|
||||
return HTTPFound(location=request.route_url('histo_list'))
|
||||
form = HistoForm(request.POST, entry)
|
||||
page_title = "Modifier histo no " + str(entry.no_id)
|
||||
|
||||
if 'form.submitted' in request.params and form.validate():
|
||||
form.populate_obj(entry)
|
||||
|
||||
# lire le cours de l'indice de réfence : Carmignac Investissement A EUR Acc
|
||||
ticker = yf.Ticker('0P00000FB2.F')
|
||||
entry.cours_ref = round(ticker.fast_info.last_price, 3)
|
||||
|
||||
# lire le dernier histo
|
||||
last = PFService.get_last_histo(request)
|
||||
|
||||
# lire les actifs et cumuler leurs valeurs
|
||||
actifs = PFService.get_actifs(request, '0')
|
||||
valeur_pf = 0
|
||||
for item in actifs:
|
||||
valeur_pf += item.Actifs.valeur
|
||||
|
||||
entry.valeur_pf = valeur_pf
|
||||
# nlle valeur part = ancienne + nouvelle ratio
|
||||
entry.nb_part = round(last.nb_part + (float(entry.mvt_cash) / (valeur_pf - float(entry.mvt_cash))/last.nb_part), 3)
|
||||
entry.val_part = round(entry.valeur_pf / entry.nb_part, 3)
|
||||
entry.val_part_ref = round(float(entry.cours_ref) * last.val_part_ref / last.cours_ref, 3)
|
||||
|
||||
request.dbsession.add(entry)
|
||||
|
||||
return HTTPFound(location=request.route_url('histo_list'))
|
||||
|
||||
if 'form.deleted' in request.params:
|
||||
PFService.delete_histo(request, entry.no_id)
|
||||
request.session.flash("La fiche a été supprimée avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('histo_list'))
|
||||
|
||||
return {
|
||||
'page_title': page_title,
|
||||
'url': url,
|
||||
'form': form,
|
||||
'item': entry,
|
||||
}
|
||||
|
||||
@view_config(route_name='actif_edit', renderer='../templates/portfolio/actif_edit.jinja2', permission='view')
|
||||
def actif_edit(request):
|
||||
no_id = request.matchdict['no_id']
|
||||
url = request.route_url('actif_edit', no_id=no_id)
|
||||
|
||||
# get the list of classes
|
||||
classes = PFService.get_allocation_byType(request, 'ACTION')
|
||||
|
||||
if no_id == '0':
|
||||
# create a new allocation
|
||||
entry = Actifs()
|
||||
entry.pru = 0
|
||||
entry.cours = 0
|
||||
entry.pc_rdt = 0
|
||||
entry.ter = 0
|
||||
form = ActifForm(request.POST, entry)
|
||||
form.classe.choices = [(row.classe, row.classe) for row in classes]
|
||||
page_title = "Nouvel actif"
|
||||
|
||||
else:
|
||||
# modify post
|
||||
entry = PFService.get_actifs(request, no_id)
|
||||
if not entry:
|
||||
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
form = ActifForm(request.POST, entry)
|
||||
form.classe.choices = [(row.classe, row.classe) for row in classes]
|
||||
page_title = "Modifier Actif : " + entry.symbole
|
||||
|
||||
if 'form.submitted' in request.params :
|
||||
if no_id == '0':
|
||||
form.populate_obj(entry)
|
||||
# récupérer le cours du symbole de Yahoo finance
|
||||
ticker = yf.Ticker(entry.symbole)
|
||||
entry.cours = ticker.fast_info.get('lastPrice')
|
||||
entry.devise = ticker.fast_info.get('currency')
|
||||
# raccourcir le libelle
|
||||
entry.pc_allocation = 1.0
|
||||
entry.valeur = round(float(entry.cours) * entry.parite * entry.nombre, 3)
|
||||
entry.plus_value = round(entry.valeur - float(entry.pru * entry.nombre), 3)
|
||||
entry.pc_plusvalue = round(entry.plus_value / entry.valeur * 100, 3)
|
||||
entry.rendement = 0 # round(entry.valeur * float(entry.pc_rdt) / 100, 3)
|
||||
request.dbsession.add(entry)
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
else:
|
||||
if entry.symbole != 'SHLDQ':
|
||||
del form.no_id # SECURITY: prevent overwriting of primary key
|
||||
form.populate_obj(entry)
|
||||
# récupérer le cours du symbole de Yahoo finance
|
||||
ticker = yf.Ticker(entry.symbole)
|
||||
entry.cours = ticker.fast_info.get('lastPrice')
|
||||
entry.devise = ticker.fast_info.get('currency')
|
||||
# raccourcir le libelle
|
||||
entry.valeur = round(float(entry.cours) * entry.parite * entry.nombre, 3)
|
||||
entry.plus_value = round(entry.valeur - float(entry.pru * entry.nombre), 3)
|
||||
entry.pc_plusvalue = round(entry.plus_value / entry.valeur * 100, 3)
|
||||
entry.rendement = 0 # round(entry.valeur * float(entry.pc_rdt) / 100, 3)
|
||||
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
|
||||
if 'form.deleted' in request.params:
|
||||
PFService.delete_actif(request, entry.no_id)
|
||||
request.session.flash("La fiche a été supprimée avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
|
||||
return {
|
||||
'page_title': page_title,
|
||||
'url': url,
|
||||
'form': form,
|
||||
'item': entry,
|
||||
}
|
||||
|
||||
@view_config(route_name='actif2_edit', renderer='../templates/portfolio/actif2_edit.jinja2', permission='view')
|
||||
def actif2_edit(request):
|
||||
no_id = request.matchdict['no_id']
|
||||
url = request.route_url('actif2_edit', no_id=no_id)
|
||||
|
||||
# get the list of classes
|
||||
classes = PFService.get_allocation_byType(request, 'AUTRE')
|
||||
|
||||
if no_id == '0':
|
||||
# create a new allocation
|
||||
entry = Actifs()
|
||||
entry.pru = 0
|
||||
entry.cours = 0
|
||||
entry.pc_rdt = 0
|
||||
entry.ter = 0
|
||||
entry.devise = 'EUR'
|
||||
form = Actif2Form(request.POST, entry)
|
||||
form.classe.choices = [(row.classe, row.classe) for row in classes]
|
||||
page_title = "Nouvel actif"
|
||||
|
||||
else:
|
||||
# modify post
|
||||
entry = PFService.get_actifs(request, no_id)
|
||||
if not entry:
|
||||
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
form = Actif2Form(request.POST, entry)
|
||||
form.classe.choices = [(row.classe, row.classe) for row in classes]
|
||||
page_title = "Modifier Actif : " + entry.symbole
|
||||
|
||||
if 'form.submitted' in request.params :
|
||||
if no_id == '0':
|
||||
form.populate_obj(entry)
|
||||
entry.nombre = 1000
|
||||
entry.devise = 'EUR'
|
||||
entry.parite = 1.0
|
||||
entry.pc_allocation = 1.0
|
||||
entry.valeur = float(entry.cours) * entry.parite * entry.nombre;
|
||||
entry.plus_value = entry.valeur - float(entry.pru * entry.nombre);
|
||||
entry.pc_plusvalue = entry.plus_value / entry.valeur * 100;
|
||||
entry.rendement = entry.valeur * float(entry.pc_rdt) / 100;
|
||||
request.dbsession.add(entry)
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
else:
|
||||
del form.no_id # SECURITY: prevent overwriting of primary key
|
||||
form.populate_obj(entry)
|
||||
entry.valeur = float(entry.cours) * entry.parite * entry.nombre;
|
||||
entry.plus_value = entry.valeur - float(entry.pru * entry.nombre);
|
||||
entry.pc_plusvalue = entry.plus_value / entry.valeur * 100;
|
||||
entry.rendement = entry.valeur * float(entry.pc_rdt) / 100;
|
||||
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
|
||||
if 'form.deleted' in request.params:
|
||||
PFService.delete_actif(request, entry.no_id)
|
||||
request.session.flash("La fiche a été supprimée avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('portfolio'))
|
||||
|
||||
return {
|
||||
'page_title': page_title,
|
||||
'url': url,
|
||||
'form': form,
|
||||
'item': entry,
|
||||
}
|
||||
Reference in New Issue
Block a user