Nouvelle feuille de style + gestion fournisseurs

This commit is contained in:
Doug Le Tough 2017-10-27 00:41:13 +02:00
parent 1e1ead5888
commit a0b4516f98
13 changed files with 2219 additions and 538 deletions

1121
result.log Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,10 @@ var light_green = "#D5FCD8";
var base_bg = "#FEFEFE";
var base_border = "#555555";
/* **************************************************************************************
* GLOBAL
* **************************************************************************************/
///////////////////////////////////////////
// Cookies
///////////////////////////////////////////
@ -42,9 +46,11 @@ function valid_input(obj) {
, 2000);
}
///////////////////////////////////////////
/* **************************************************************************************
* COMPONTANTS
* **************************************************************************************/
// Update result
///////////////////////////////////////////
function update_componants() {
obj = document.getElementById('result_container');
var xhttp = new XMLHttpRequest();
@ -70,9 +76,8 @@ function update_componants() {
xhttp.send();
}
///////////////////////////////////////////
// Result ordering
///////////////////////////////////////////
function update_componants_by_reference(order) {
setcookie('c_order', order, 30);
setcookie('c_sort', 'reference', 30);
@ -101,19 +106,19 @@ function update_componants_by_place(order) {
update_componants();
}
function previous_page(prevhop) {
function c_previous_page(prevhop) {
setcookie('c_offset', prevhop, 30);
update_componants();
}
function next_page(nexthop) {
function c_next_page(nexthop) {
setcookie('c_offset', nexthop, 30);
update_componants();
}
///////////////////////////////////////////
// Search componants
///////////////////////////////////////////
function search_componants_by_reference(obj) {
setcookie('c_reference', obj.value, 30);
update_componants();
@ -134,22 +139,20 @@ function search_componants_by_provider(obj) {
update_componants();
}
///////////////////////////////////////////
// Delete componant
///////////////////////////////////////////
function confirm_delete() {
function confirm_componant_delete() {
var msg="La suppression est définitive \net n'est pas autorisée si le \ncomposant fait partie d'un Kit.\n\nConfirmer ?";
return confirm(msg)
}
///////////////////////////////////////////
// New componant
///////////////////////////////////////////
function new_componant() {
var err = false;
var obj = {};
if (getcookie('c_count') > 0){
var errr = true;
var err = true;
obj[0] = document.getElementById('reference');
}
if (getcookie('c_designation').length < 1){
@ -160,6 +163,9 @@ function new_componant() {
var err = true;
obj[2] = document.getElementById('place');
}
if (document.getElementById('provider_id').value == 1){
setcookie('c_provider', '2', 30);
}
if (err == true) {
for (i in obj){
invalid_input(obj[i]);
@ -194,9 +200,8 @@ function create_componant() {
xhttp.send();
}
///////////////////////////////////////////
// Update componant
///////////////////////////////////////////
function update_componant(obj, componant_id, type) {
if (type == 'numeric') {
if (isNaN(obj.value)) {
@ -226,3 +231,182 @@ function update_componant(obj, componant_id, type) {
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.send('field='+obj.id+'&value='+obj.value);
}
/* **************************************************************************************
* PROVIDERS
* **************************************************************************************/
// Update result
function update_providers() {
obj = document.getElementById('result_container');
var xhttp = new XMLHttpRequest();
xhttp.onerror = function(){
obj.innerHTML = "Erreur lors de la mise à jour de la liste (1)"
};
xhttp.onload = function(){
if (xhttp.status != 200) {
obj.innerHTML = "Erreur lors de la mise à jour de la liste (2)"
}
};
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
var response = xhttp.responseText;
obj.innerHTML = response;
return true;
}
};
xhttp.open('POST', '/providers/update', true);
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.send();
}
// Result ordering
function update_providers_by_name(order) {
setcookie('p_order', order, 30);
setcookie('p_sort', 'name', 30);
setcookie('p_order_refresh', '1', 30);
update_providers();
}
function update_providers_by_address(order) {
setcookie('p_order', order, 30);
setcookie('p_sort', 'address', 30);
setcookie('p_order_refresh', '1', 30);
update_providers();
}
function update_providers_by_mail(order) {
setcookie('p_order', order, 30);
setcookie('p_sort', 'mail', 30);
setcookie('p_order_refresh', '1', 30);
update_providers();
}
function update_providers_by_url(order) {
setcookie('p_order', order, 30);
setcookie('p_sort', 'url', 30);
setcookie('p_order_refresh', '1', 30);
update_providers();
}
function update_providers_by_commentl(order) {
setcookie('p_order', order, 30);
setcookie('p_sort', 'comment', 30);
setcookie('p_order_refresh', '1', 30);
update_providers();
}
function p_previous_page(prevhop) {
setcookie('p_offset', prevhop, 30);
update_providers();
}
function p_next_page(nexthop) {
setcookie('p_offset', nexthop, 30);
update_providers();
}
// Search providers
function search_providers_by_name(obj) {
setcookie('p_name', obj.value, 30);
update_providers();
}
function search_providers_by_address(obj) {
setcookie('p_address', obj.value, 30);
update_providers();
}
function search_providers_by_mail(obj) {
setcookie('p_mail', obj.value, 30);
update_providers();
}
function search_providers_by_url(obj) {
setcookie('p_url', obj.value, 30);
update_providers();
}
function search_providers_by_comment(obj) {
setcookie('p_comment', obj.value, 30);
update_providers();
}
// New provider
function new_provider() {
var err = false;
var obj = {};
if (getcookie('p_count') > 0){
var err = true;
obj[0] = document.getElementById('name');
}
if (err == true) {
for (i in obj){
invalid_input(obj[i]);
}
return;
}
create_provider();
update_providers();
}
function create_provider() {
var MSG='Erreur lors de la creation du fournisseur.';
var xhttp = new XMLHttpRequest();
xhttp.onerror = function(){
alert(MSG);
return false;
};
xhttp.onload = function(){
if (xhttp.readyState == 4 && xhttp.status == 200) {
var response = xhttp.responseText;
if (response == 'OK'){
return true;
}
alert(MSG);
return false;
}
};
xhttp.open('POST', '/providers/new', true);
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.send();
}
// Delete provider
function confirm_provider_delete() {
var msg="La suppression est définitive \net n'est pas autorisée si le \nfournisseur est référencé \npar un composant.\n\nConfirmer ?";
return confirm(msg)
}
// Update provider
function update_provider(obj, provider_id, type) {
var xhttp = new XMLHttpRequest();
xhttp.onerror = function(){
invalid_input(obj);
};
xhttp.onload = function(){
if (xhttp.readyState == 4 && xhttp.status == 200) {
var response = xhttp.responseText;
if (response == 'OK'){
valid_input(obj);
return;
}
obj.style.borderColor = red;
invalid_input(obj);
}
};
xhttp.open('POST', '/providers/update/'+provider_id, true);
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.send('field='+obj.id+'&value='+obj.value);
}

View File

@ -140,8 +140,8 @@ div.content {
}
div.note {
font-size: 12px;
line-height: 12px;
font-size: 14px;
line-height: 14px;
}
div.error {
@ -177,226 +177,6 @@ div.footer {
text-align: center;
}
/* ***********************************
* Résultats
*********************************** */
div.row_count {
padding: 5px;
}
div.result_container {
text-align: left;
}
.border_left {
border-left-width: 1px;
border-left-style: solid;
}
.border_right {
border-right-width: 1px;
border-right-style: solid;
}
div.block, div.noborder {
overflow: hidden;
border-top-style: solid;
border-top-width: 1px;
height: 20px;
}
div.noborder {
border-style: none;
}
div.inner{
overflow: hidden;
float: center;
height: 20px;
}
div.pages_nav_bar {
overflow: hidden;
width: 1000px;
border-top-style: solid;
border-top-width: 1px;
height: 20px;
text-align: right;
padding-top: 10px;
}
div.block text{
width: 200px;
float: left;
text-align: left;
padding: 0 4px 0 4px;
}
div.block text.num{
width: 200px;
float: left;
padding: 0 4px 0 4px;
text-align: right;
}
div.inner text.edit, div.block text.edit {
background: url(../images/edit.png);
margin: 2px 0px 0px 20px;
}
div.inner text.trash {
background: url(../images/trash.png);
margin: 2px 0px 0px 20px;
}
div.block text.refresh {
background: url(../images/refresh.png);
margin: 2px 0px 0px 20px;
}
div.block text.search {
background: url(../images/search.png);
margin-left: 255px;
}
div.block text.save {
background: url(../images/save.png);
margin-left: 32px;
}
div.inner text.edit:hover,
div.inner text.trash:hover,
div.block text.refresh:hover,
div.block text.search:hover,
div.block text.save:hover{
background-color: #FFB387;
cursor: pointer;
}
div.inner text.edit {
width: 16px;
float:left;
height: 16px;
margin: 2px 0px 0px 20px;
border-radius: 2px;
background-repeat: no-repeat;
}
div.inner text.trash,
div.inner text.edit,
div.block text.refresh,
div.block text.search,
div.block text.save {
width: 8px;
float:left;
height: 16px;
border-radius: 2px;
background-repeat: no-repeat;
}
div.even {
background-color: #E5E5E5;
}
div.odd {
background-color: #FFFFFF;
}
div.block label {
width: 200px;
display: block;
float: left;
text-align: center;
font-weight: bold;
background-color: #FF5D00;
}
div.block label:hover {
cursor: pointer;
}
div.block .input{
margin-left:4px;
float:left;
}
div.action_bar {
display: inline-block;
width: 50px;
height: 32px;
}
span.prev_page, span.next_page {
color: #FF5D00;
font-weight: bold;
font-size: 12px;
}
span.prev_page:hover, span.next_page:hover {
color: #FFFFFF;
background-color: #FF5D00;
cursor: pointer;
}
span.page_num {
font-size: 12px;
}
/* ***********************************
* Editables
*********************************** */
div.no_border {
border-style: none;
border-width: 0px;
}
div.margin_bottom {
margin-bottom: 4px;
}
div.block label.editable {
height: 20px;
text-align: left;
vertical-align: middle;
padding: 0 4px 0 4px;
}
div.block text.editable {
width: 200px;
float: left;
padding: 0 4px 0 4px;
margin-left: 4px;
text-align: right;
background-color: #FFFFFF;
border-style: solid;
border-width: 1px;
height: 20px;
}
div.block select, div.block input {
width: 310px;
float: left;
padding: 0 4px 0 4px;
margin-left: 4px;
text-align: right;
background-color: #FFFFFF;
border-style: solid;
border-width: 1px;
border-color: #555555;
color: #555555;
height: 20px;
}
div.block input {
height: 17px;
width: 300px;
}
/* ***********************************
* Classes génériques
*********************************** */
@ -419,18 +199,184 @@ span.bold {
font-weight: bold;
}
table {
border-collapse: collapse;
width: 100%;
/* ***********************************
* Search
*********************************** */
div.main_block {
padding: 0;
margin: 0;
width: 1000px;
float: left;
}
th {
background-color: #FFB387;
div.main_block text {
display: block;
font-weight: bold;
margin-bottom: 4px;
}
th, td {
div.button_block {
margin: 0 0 4px 0;
height: 20px;
width: 525px;
}
div.button_block input {
position: relative;
width: 16px;
height: 16px;
border-radius: 2px;
margin-right: 32px;
left: 250px;
}
div.button_block input:hover {
cursor: pointer;
background-color: #FF5D00;
}
div.input_block {
margin: 0 0 4px 0;
height: 20px;
width: 525px;
}
div.input_block label {
display: block;
float: left;
width: 200px;
text-align: center;
font-weight: bold;
background-color: #FF5D00;
height: 20px;
text-align: left;
padding: 8px;
vertical-align: middle;
padding: 0 4px 0 4px;
}
tr:nth-child(even){background-color: #f2f2f2}
div.input_block select, div.input_block input {
width: 310px;
float: right;
padding: 0 4px 0 4px;
margin-left: 4px;
text-align: right;
background-color: #FFFFFF;
border-style: solid;
border-width: 1px;
border-color: #555555;
color: #555555;
height: 20px;
}
div.input_block input {
float: right;
height: 17px;
width: 300px;
}
/* ***********************************
* Result
*********************************** */
.border_bottom {
border-bottom-style: solid;
border-bottom-width: 1px;
}
.border_top {
border-top-style: solid;
border-top-width: 1px;
}
.border_left {
border-left-width: 1px;
border-left-style: solid;
}
div.even {
background-color: #E5E5E5;
}
div.odd {
background-color: #FFFFFF;
}
span.prev_page, span.next_page {
color: #FF5D00;
font-weight: bold;
font-size: 12px;
}
span.prev_page:hover, span.next_page:hover {
color: #FFFFFF;
background-color: #FF5D00;
cursor: pointer;
}
span.page_num {
font-size: 12px;
}
div.row_block {
margin: 0 0 4px 0;
height: 20px;
width: 1000px;
}
div.nav_page_block {
text-align: right;
height: 20px;
width: 1000px;
}
div.action_bar_block {
overflow: hidden;
float: center;
height: 20px;
}
div.row_block label {
display: block;
float: left;
text-align: center;
font-weight: bold;
background-color: #FF5D00;
vertical-align: middle;
}
div.row_block label:hover {
cursor: pointer;
}
div.row_block label.border_left,
div.row_block text.border_left {
border-left-style: solid;
border-left-width: 1;
}
div.row_block text {
display: block;
float: left;
font-weight: normal;
text-align: left;
overflow: hidden;
vertical-align: middle;
padding: 0 5px 0 5px;
white-space: nowrap;
}
div.row_block text.num {
text-align: right;
}
div.nav_page_block text {
display: block;
white-space: nowrap;
}
div.action_bar_block input {
height: 17px;
width: 16px;
margin-left: 20px;
}

View File

@ -20,7 +20,7 @@ CREATE TABLE stock_kits (
CREATE TABLE stock_providers (
id serial primary key,
name text not NULL,
name text unique not NULL,
address text not NULL,
mail text not NULL,
url text not NULL,
@ -58,7 +58,7 @@ insert into stock_providers (name, address, mail, url, comment)
insert into stock_providers (name, address, mail, url, comment)
values ('Aucun', 'N/A', 'N/A', 'N/A', 'N/A');
insert into stock_providers (name, address, mail, url, comment)
values ('China Elec Co', 'Beijing', 'sales@chinaelecco.cc', 'https://chinaelecco', 'Pas cher, mais...');
values ('China Elec Co', 'Beijing', 'sales@chinaelecco.cc', 'https://chinaelecco.cc', 'Pas cher mais délai excessif et composants pourris');
insert into stock_componants (reference, designation, last_price, mean_price, quantity, min_quantity, place, provider_id)
values ('Res-01', 'Resistance 10KΩ', 13.34, 12.42, 73, 0, 'B 43', 3);

View File

@ -3,7 +3,6 @@
{% block top_menu %}
<span class='top_menu_item' onclick='javascript:document.location="/componants";'>Rechercher un composant</span>
<span class='top_menu_item_selected' onclick='javascript:document.location="/componants/{{ componant.id }}";'>Éditer un composant</span>
<span class='top_menu_item' onclick='javascript:document.location="/componants/new";'>Nouveau composant</span>
<span class='top_menu_item' onclick='javascript:document.location="/componants/in";'>Entrée de stock</span>
<span class='top_menu_item' onclick='javascript:document.location="/componants/out";'>Sortie de stock</span>
{% endblock %}
@ -24,111 +23,111 @@
{% endblock %}
{% block content %}
<h3>Note:</h3>
<div id='note' class='main_block'>
<text>Note:</text>
<div class='note'>
<p>Cette page vous permet de modifier directement un composant.</p>
<p>À moins de vouloir corriger une erreur de saisie, ou de saisir un inventaire vous ne devez
<strong>PAS</strong> modifier directement
les quantités d'un composant.</p>
<p>Cliquez sur les liens suivants pour saisir des <a href='/componant/in/{{ componant.id }}'>entrées</a>
ou <a href='/componant/out/{{ componant.id }}'>sorties</a> de stock.</p>
<p>Cette page vous permet de modifier directement un composant.<br/>
À moins de vouloir corriger une erreur de saisie, ou de saisir un inventaire <br/>
vous ne devez <strong>PAS</strong> modifier directement les quantités d'un composant.</p>
<p>Cliquez sur les liens suivants pour saisir des
<span class='top_menu_item_selected' onclick='javascript:document.location="/componant/in/{{ componant.id }}"'>entrées</span>
ou
<span class='top_menu_item_selected' onclick='javascript:document.location="/componant/out/{{ componant.id }}"'>sorties</span> de stock.</p>
</div>
<h3>Composant:</h3>
<div class='block margin_bottom no_border'>
<label class='editable'>Référence (unique)</label>
</div>
<div id='edit' class='main_block'>
<text>Composant:</text>
<div class='input_block'>
<label>Référence (unique)</label>
<input
id='reference'
type='text'
class='editable'
onchange='javascript:update_componant(this, {{ componant.id }}, "text");'
maxlength='20'
title='Référence interne unique (max. 20)'
placeholder='Référence interne unique (max. 20)'
value='{{ componant.reference }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Désignation</label>
<div class='input_block'>
<label>Désignation</label>
<input
id='designation'
type='text'
class='editable'
onchange='javascript:update_componant(this, {{ componant.id }}, "text");'
maxlength='50'
title='Désignation (max. 50)'
placeholder='Désignation (max. 50)'
value='{{ componant.designation }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Dernier prix d'achat</label>
<div class='input_block'>
<label>Dernier prix d'achat</label>
<input
id='last_price'
type='text'
class='editable'
onchange='javascript:update_componant(this, {{ componant.id }}, "numeric");'
maxlength='15'
title="Dernier prix d'achat"
placeholder="Dernier prix d'achat"
value='{{ componant.last_price }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Coût d'achat moyen pondéré</label>
<div class='input_block'>
<label>Coût d'achat moyen</label>
<input
id='mean_price'
type='text'
class='editable'
maxlength='15'
title='CMP (non éditable)'
readonly value='{{ componant.mean_price }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Quantité</label>
<div class='input_block'>
<label>Quantité</label>
<input
id='quantity'
type='text'
class='editable'
onchange='javascript:update_componant(this, {{ componant.id }}, "numeric");'
maxlength='15'
title='Quantité'
placeholder='Quantité'
value='{{ componant.quantity }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Quantité minimum</label>
<div class='input_block'>
<label>Quantité minimum</label>
<input
id='min_quantity'
type='text'
class='editable'
onchange='javascript:update_componant(this, {{ componant.id }}, "numeric");'
maxlength='15'
title='Quantité minimum'
placeholder='Quantité minimum'
value='{{ componant.min_quantity }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Emplacement</label>
<div class='input_block'>
<label>Emplacement</label>
<input
id='place'
type='text'
class='editable'
onchange='javascript:update_componant(this, {{ componant.id }}, "text");'
maxlength='15'
title='Emplacement (max. 15)'
placeholder='Emplacement (max. 15)'
value='{{ componant.place }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Fournisseur</label>
<div class='input_block'>
<label>Fournisseur</label>
<select
id='provider_id'
onchange='javascript:update_componant(this, {{ componant.id }}, "numeric");'
title='Fournisseur'>
{% for prov in providers %}
{% if prov.id > 1 %}
{% set option_selected = '' %}
{% if prov.id == provider.id %}
{% set option_selected = 'selected="selected"' %}
{% endif %}
<option {{ option_selected }} value='{{ prov.id }}'>{{ prov.name }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
{% endblock %}

View File

@ -4,8 +4,7 @@
{% endblock %}
{% block title %}Liste des composants{% endblock %}
{% block top_menu %}
<span class='top_menu_item_selected' onclick='javascript:document.location="/componants/search";'>Rechercher un composant</span>
<span class='top_menu_item' onclick='javascript:document.location="/componants/new";'>Nouveau composant</span>
<span class='top_menu_item_selected' onclick='javascript:document.location="/componants";'>Gestion des composants</span>
<span class='top_menu_item' onclick='javascript:document.location="/componants/in";'>Entrée de stock</span>
<span class='top_menu_item' onclick='javascript:document.location="/componants/out";'>Sortie de stock</span>
{% endblock %}
@ -29,45 +28,43 @@
<!-- ----------------------------------------------------
Recherche
----------------------------------------------------- -->
<h3>Recherche:</h3>
<div class='block margin_bottom no_border'>
<label class='editable'>Référence (unique)</label>
<div id='search' class='main_block'>
<text>Recherche:</text>
<div class='input_block'>
<label>Référence (unique)</label>
<input
id='reference'
type='text'
class='editable'
onkeyup='javascript:search_componants_by_reference(this, "text");'
maxlength='20'
title='Référence interne unique (max. 20)'
placeholder='Référence interne unique (max. 20)'
value='{{ reference }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Désignation</label>
<div class='input_block'>
<label>Désignation</label>
<input
id='designation'
type='text'
class='editable'
onkeyup='javascript:search_componants_by_designation(this, "text");'
maxlength='50'
title='Désignation (max. 50)'
placeholder='Désignation (max. 50)'
value='{{ designation }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Emplacement</label>
<div class='input_block'>
<label>Emplacement</label>
<input
id='place'
type='text'
class='editable'
onkeyup='javascript:search_componants_by_place(this, "text");'
maxlength='15'
title='Emplacement (max. 15)'
placeholder='Emplacement (max. 15)'
value='{{ place }}' />
</div>
<div class='block margin_bottom no_border'>
<label class='editable'>Fournisseur</label>
<div class='input_block'>
<label>Fournisseur</label>
<select
id='provider_id'
onchange='javascript:search_componants_by_provider(this, "numeric");'
@ -81,14 +78,23 @@
{% endfor %}
</select>
</div>
<div class='block margin_bottom no_border center'>
<text title='Rechercher' class='search' onclick='javascript:update_componants("reference");'></text>
<text title='Enregistrer' class='save' onclick='javascript:new_componant();'></text>
<div class='button_block'>
<input
type='image'
src='/static/images/search.png'
title='Rechercher'
onclick='javascript:update_componants("reference");'/>
<input
type='image'
src='/static/images/save.png'
title='Enregistrer'
onclick='javascript:new_componant();'/>
</div>
</div>
<!-- ----------------------------------------------------
Resultat
----------------------------------------------------- -->
<div id='result_container' class='result_container'>
<div id='result_container' class='main_block'>
</div>
{% endblock %}

76
templates/provider.html Normal file
View File

@ -0,0 +1,76 @@
{% extends "index.html" %}
{% block title %}Éditer un fournisseur{% endblock %}
{% block top_menu %}
<span class='top_menu_item' onclick='javascript:document.location="/providers";'>Gérer les fournisseurs</span>
<span class='top_menu_item_selected' onclick='javascript:document.location="/providers/{{ provider.id }}";'>Éditer un fournisseur</span>
{% endblock %}
{% block left_menu %}
<div class='left_menu_item' onclick='javascript:document.location="/";'>
Accueil
</div>
<div class='left_menu_item' onclick='javascript:document.location="/componants";'>
Composants
</div>
<div class='left_menu_item' onclick='javascript:document.location="/kits";'>
Kits
</div>
<div class='left_menu_item_selected' onclick='javascript:document.location="/providers";'>
Fournisseurs
</div>
{% endblock %}
{% block content %}
<div id='edit' class='main_block'>
<text>Composant:</text>
<div class='input_block'>
<label>Nom (unique)</label>
<input
id='name'
type='text'
onchange='javascript:update_provider(this, {{ provider.id }}, "text");'
maxlength='20'
title='Nom unique (max. 20)'
placeholder='Nom unique (max. 20)'
value='{{ provider.name }}' />
</div>
<div class='input_block'>
<label>Adresse</label>
<input
id='address'
type='text'
onchange='javascript:update_provider(this, {{ provider.id }}, "text");'
title='Adresse'
placeholder='Adresse'
value='{{ provider.address }}' />
</div>
<div class='input_block'>
<label>@ mail</label>
<input
id='mail'
type='text'
onchange='javascript:update_provider(this, {{ provider.id }}, "text");'
title="Adresse e-mail"
placeholder="Adresse e-mail"
value='{{ provider.mail }}' />
</div>
<div class='input_block'>
<label>URL</label>
<input
id='url'
type='text'
onchange='javascript:update_provider(this, {{ provider.id }}, "text");'
title="URL"
placeholder="URL"
value='{{ provider.url }}' />
</div>
<div class='input_block'>
<label>Commentaires</label>
<input
id='comment'
type='text'
onchange='javascript:update_provider(this, {{ provider.id }}, "text");'
title='Commentaire'
value='{{ provider.comment }}' />
</div>
</div>
{% endblock %}

90
templates/providers.html Normal file
View File

@ -0,0 +1,90 @@
{% extends "index.html" %}
{% block bodyheader %}
<body onload="javascript:update_providers();">
{% endblock %}
{% block title %}Liste des fournisseurs{% endblock %}
{% block top_menu %}
<span class='top_menu_item_selected' onclick='javascript:document.location="/providers";'>Gérer les fournisseurs</span>
{% endblock %}
{% block left_menu %}
<div class='left_menu_item' onclick='javascript:document.location="/";'>
Accueil
</div>
<div class='left_menu_item' onclick='javascript:document.location="/componants";'>
Composants
</div>
<div class='left_menu_item' onclick='javascript:document.location="/kits";'>
Kits
</div>
<div class='left_menu_item_selected' onclick='javascript:document.location="/providers";'>
Fournisseurs
</div>
{% endblock %}
{% block content %}
<!-- ----------------------------------------------------
Recherche
----------------------------------------------------- -->
<div id='search' class='main_block'>
<text>Recherche:</text>
<div class='input_block'>
<label>Nom (unique)</label>
<input
id='name'
type='text'
onkeyup='javascript:search_providers_by_name(this, "text");'
title='Nom unique'
placeholder='Nom unique'
value='{{ name }}' />
</div>
<div class='input_block'>
<label>Adresse</label>
<input
id='address'
type='text'
onkeyup='javascript:search_providers_by_address(this, "text");'
title='Adresse'
placeholder='Adresse'
value='{{ address }}' />
</div>
<div class='input_block'>
<label>@ mail</label>
<input
id='mail'
type='text'
onkeyup='javascript:search_providers_by_mail(this, "text");'
title='Adresse mail'
placeholder='Adresse mail'
value='{{ mail }}' />
</div>
<div class='input_block'>
<label>URL</label>
<input
id='url'
type='text'
onkeyup='javascript:search_providers_by_url(this, "text");'
title='URL'
placeholder='URL'
value='{{ url }}' />
</div>
<div class='button_block'>
<input
type='image'
src='/static/images/search.png'
title='Rechercher'
onclick='javascript:update_providers("name");'/>
<input
type='image'
src='/static/images/save.png'
title='Enregistrer'
onclick='javascript:new_provider();'/>
</div>
</div>
<!-- ----------------------------------------------------
Resultat
----------------------------------------------------- -->
<div id='result_container' class='result_container'>
</div>
{% endblock %}

View File

@ -1,31 +0,0 @@
<h3>Résultat:</h3>
{% set ss='' %}
{% if row_count > 1 %}
{% set ss='s' %}
{% endif %}
<div class='row_count'>{{ row_count }} objet{{ ss }} selectionné{{ ss }}</div>
<div class='block' style='border-top-style: none;'>
<label onclick='javascript:update_componants_by_reference("{{ order }}");'>Référence</label>
<label onclick='javascript:update_componants_by_designation("{{ order }}");' class='border_left' style='width: 440px;'>Désignation</label>
<label onclick='javascript:update_componants_by_quantity("{{ order }}");' class='border_left' style='width: 100px;'>Quantité</label>
<label onclick='javascript:update_componants_by_place("{{ order }}");' class='border_right border_left' style='width: 160px;'>Emplacement</label>
<label style='width: 106px; cursor: default;'>Action</label>
</div>
{% set row_class = cycler('odd', 'even') %}
{% for componant in componants %}
<div class='block {{ row_class.next() }}'>
<text style='width: 192px;'>{{ componant.reference }}</text>
<text class='border_left' style='width: 432px;'>{{ componant.designation }}</text>
<text class='num border_left' style='width: 92px;'>{{ componant.quantity }}</text>
<text class='num border_right border_left' style='width: 152px;'>{{ componant.place }}</text>
<div class='inner' style='width: 95px;'>
<text class='edit' title='Éditer' onclick='javascript:document.location="/componants/{{ componant.id }}"'></text>
<text class='trash' title='Supprimer' onclick='javascript:confirm_delete()?document.location="/componants/delete/{{ componant.id }}":false;'></text>
</div>
</div>
{% endfor %}
<div class='pages_nav_bar'>
<text><span class='prev_page' onclick='javascript:previous_page({{ prevhop }});'><</span></text>
<text><span class='page_num'>{{ page }} / {{ page_count }}</span></text>
<text><span class='next_page' onclick='javascript:next_page({{ nexthop }})'>></span></text>
</div>

View File

@ -0,0 +1,44 @@
<div class='main_block'>
<text>Résultat:
{% set ss='' %}
{% if row_count > 1 %}
{% set ss='s' %}
{% endif %}
{{ row_count }} objet{{ ss }} selectionné{{ ss }}
</text>
<div class='row_block border_bottom'>
<label style='width: 200px;' onclick='javascript:update_componants_by_reference("{{ order }}");'>Référence</label>
<label class='border_left' style='width: 449px;' onclick='javascript:update_componants_by_designation("{{ order }}");'>Désignation</label>
<label class='border_left' style='width: 99px;' onclick='javascript:update_componants_by_quantity("{{ order }}");'>Quantité</label>
<label class='border_left' style='width: 149px;' onclick='javascript:update_componants_by_place("{{ order }}");'>Emplacement</label>
<label class='border_left' style='width: 99px; cursor: default;'>Action</label>
</div>
{% set row_class = cycler('odd', 'even') %}
{% for componant in componants %}
<div class='row_block {{ row_class.next() }}'>
<text style='width: 190px;'>{{ componant.reference }}</text>
<text class='border_left' style='width: 439px;'>{{ componant.designation }}</text>
<text class='num border_left' style='width: 89px;'>{{ componant.quantity }}</text>
<text class='num border_right border_left' style='width: 139px;'>{{ componant.place }}</text>
<div class='action_bar_block border_left' style='width: 89px;'>
<input
type='image'
src='/static/images/edit.png'
title='Éditer'
onclick='javascript:document.location="/componants/{{ componant.id }}"'/>
<input
type='image'
src='/static/images/trash.png'
title='Supprimer'
onclick='javascript:confirm_componant_delete()?document.location="/componants/delete/{{ componant.id }}":false;'/>
</div>
</div>
{% endfor %}
<div class='nav_page_block border_top'>
<text>
<span class='prev_page' onclick='javascript:c_previous_page({{ prevhop }});'>&lt;</span>
<span class='page_num'>{{ page }} / {{ page_count }}</span>
<span class='next_page' onclick='javascript:c_next_page({{ nexthop }})'>&gt;</span>
</text>
</div>
</div>

View File

@ -0,0 +1,44 @@
<div class='main_block'>
<text>Résultat:
{% set ss='' %}
{% if row_count > 1 %}
{% set ss='s' %}
{% endif %}
{{ row_count }} objet{{ ss }} selectionné{{ ss }}
</text>
<div class='row_block border_bottom'>
<label style='width: 209px;' onclick='javascript:update_providers_by_name("{{ order }}");'>Nom</label>
<label class='border_left' style='width: 199px;' onclick='javascript:update_providers_by_address("{{ order }}");'>Addresse</label>
<label class='border_left' style='width: 199px;' onclick='javascript:update_providers_by_mail("{{ order }}");'>@ Mail</label>
<label class='border_left' style='width: 299px;' onclick='javascript:update_providers_by_url("{{ order }}");'>URL</label>
<label class='border_left' style='width: 89px;' style='cursor: default;'>Action</label>
</div>
{% set row_class = cycler('odd', 'even') %}
{% for provider in providers %}
<div class='row_block {{ row_class.next() }}'>
<text style='width: 199px;'>{{ provider.name }}</text>
<text class='border_left' style='width: 189px;'>{{ provider.address }}</text>
<text class='border_left' style='width: 189px;'>{{ provider.mail }}</text>
<text class='border_left' style='width: 289px;'>{{ provider.url }}</text>
<div class='action_bar_block border_left' style='width: 89px;'>
<input
type='image'
src='/static/images/edit.png'
title='Éditer'
onclick='javascript:document.location="/providers/{{ provider.id }}"'/>
<input
type='image'
src='/static/images/trash.png'
title='Supprimer'
onclick='javascript:confirm_provider_delete()?document.location="/providers/delete/{{ provider.id }}":false;'/>
</div>
</div>
{% endfor %}
<div class='nav_page_block border_top'>
<text>
<span class='prev_page' onclick='javascript:p_previous_page({{ prevhop }});'>&lt;</span>
<span class='page_num'>{{ page }} / {{ page_count }}</span>
<span class='next_page' onclick='javascript:p_next_page({{ nexthop }})'>&gt;</span>
</text>
</div>
</div>

100
templates/test.html Normal file
View File

@ -0,0 +1,100 @@
{% extends "index.html" %}
{% block bodyheader %}
<body onload="javascript:update_componants();">
{% endblock %}
{% block title %}Liste des composants{% endblock %}
{% block top_menu %}
<span class='top_menu_item_selected' onclick='javascript:document.location="/componants";'>Gestion des composants</span>
<span class='top_menu_item' onclick='javascript:document.location="/componants/in";'>Entrée de stock</span>
<span class='top_menu_item' onclick='javascript:document.location="/componants/out";'>Sortie de stock</span>
{% endblock %}
{% block left_menu %}
<div class='left_menu_item' onclick='javascript:document.location="/";'>
Accueil
</div>
<div class='left_menu_item_selected' onclick='javascript:document.location="/componants";'>
Composants
</div>
<div class='left_menu_item' onclick='javascript:document.location="/kits";'>
Kits
</div>
<div class='left_menu_item' onclick='javascript:document.location="/providers";'>
Fournisseurs
</div>
{% endblock %}
{% block content %}
<!-- ----------------------------------------------------
Recherche
----------------------------------------------------- -->
<div id='search' class='main_block'>
<text>Recherche:</text>
<div class='input_block'>
<label>Référence (unique)</label>
<input
id='reference'
type='text'
onkeyup='javascript:search_componants_by_reference(this, "text");'
maxlength='20'
title='Référence interne unique (max. 20)'
placeholder='Référence interne unique (max. 20)'
value='{{ reference }}' />
</div>
<div class='input_block'>
<label>Désignation</label>
<input
id='designation'
type='text'
onkeyup='javascript:search_componants_by_designation(this, "text");'
maxlength='50'
title='Désignation (max. 50)'
placeholder='Désignation (max. 50)'
value='{{ designation }}' />
</div>
<div class='input_block'>
<label>Emplacement</label>
<input
id='place'
type='text'
onkeyup='javascript:search_componants_by_place(this, "text");'
maxlength='15'
title='Emplacement (max. 15)'
placeholder='Emplacement (max. 15)'
value='{{ place }}' />
</div>
<div class='input_block'>
<label>Fournisseur</label>
<select
id='provider_id'
onchange='javascript:search_componants_by_provider(this, "numeric");'
title='Fournisseur'>
{% for prov in providers %}
{% set selected = '' %}
{% if prov.id == provider_id %}
{% set selected = 'selected' %}
{% endif %}
<option value='{{ prov.id }}' {{ selected }}>{{ prov.name }}</option>
{% endfor %}
</select>
</div>
<div class='button_block'>
<input
type='image'
src='/static/images/search.png'
title='Rechercher'
onclick='javascript:update_componants("reference");'/>
<input
type='image'
src='/static/images/save.png'
title='Enregistrer'
onclick='javascript:new_componant();'/>
</div>
</div>
<!-- ----------------------------------------------------
Resultat
----------------------------------------------------- -->
<div id='result_container' class='main_block'>
</div>
{% endblock %}

View File

@ -42,6 +42,7 @@ class Stock_providers(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, nullable=False)
address = db.Column(db.Text)
mail = db.Column(db.Text)
url = db.Column(db.Text)
comment = db.Column(db.Text)
@ -60,16 +61,19 @@ def resume_session(func):
@wraps(func)
def check(*args, **kwargs):
# default
limit = 8
limit = 10
offset = 0
page = 1
nexthop = offset + limit
prevhop = offset
sort = 'reference'
order = 'asc'
order_refresh = 0
c_empty = ''
c_sort = 'reference'
c_provider = 0
c_count = 0
p_empty = ''
p_sort = 'name'
offset_reset = ['c_reference', 'c_designation', 'c_place', 'c_provider']
if not 'session' in session:
session['session'] = ''
@ -78,11 +82,13 @@ def resume_session(func):
if not 'c_offest' in session:
session['c_offset'] = offset
if not 'c_sort' in session:
session['c_sort'] = sort
session['c_sort'] = c_sort
if not 'c_order' in session:
session['c_order'] = order
if not 'c_order_refresh' in session:
session['c_order_refresh'] = order_refresh
if not 'c_page' in session:
session['c_page'] = page
if not 'c_nexthop' in session:
session['c_nexthop'] = nexthop
if not 'c_prevhop' in session:
@ -97,6 +103,33 @@ def resume_session(func):
session['c_provider'] = c_provider
if not 'c_count' in session:
session['c_count'] = c_count
if not 'p_sort' in session:
session['p_sort'] = p_sort
if not 'p_order' in session:
session['p_order'] = order
if not 'p_order_refresh' in session:
session['p_order_refresh'] = order_refresh
if not 'p_page' in session:
session['p_page'] = page
if not 'p_nexthop' in session:
session['p_nexthop'] = nexthop
if not 'p_prevhop' in session:
session['p_prevhop'] = prevhop
if not 'p_offset' in session:
session['p_offset'] = offset
if not 'p_limit' in session:
session['p_limit'] = limit
if not 'p_name' in session:
session['p_name'] = p_empty
if not 'p_address' in session:
session['p_address'] = p_empty
if not 'p_mail' in session:
session['p_mail'] = p_empty
if not 'p_url' in session:
session['p_url'] = p_empty
if not 'p_comment' in session:
session['p_comment'] = p_empty
# Cookies/session sync
for key in request.cookies:
old = str(session[key])
@ -109,7 +142,7 @@ def resume_session(func):
session['c_offset'] = 0
if key != 'session':
print '+', key, request.cookies[key]
print '[s]', key, request.cookies[key]
# Switch sort order
@ -117,6 +150,10 @@ def resume_session(func):
refresh = {'desc': 'asc', 'asc': 'desc'}
session['c_order'] = refresh[session['c_order']]
session['c_order_refresh'] = 0
if session['p_order_refresh'] == 1:
refresh = {'desc': 'asc', 'asc': 'desc'}
session['p_order'] = refresh[session['p_order']]
session['p_order_refresh'] = 0
return func(*args, **kwargs)
return check
@ -149,6 +186,7 @@ def componants():
provider_id=session['c_provider'])
@app.route('/componants/<componant_id>')
@resume_session
def get_componant(componant_id):
""" Edit componant """
try:
@ -164,6 +202,7 @@ def get_componant(componant_id):
return render_template('error.html'), 404
@app.route('/componants/update/<componant_id>', methods=['POST'])
@resume_session
def update_componant(componant_id):
""" Update componant field"""
field = request.form['field']
@ -180,14 +219,17 @@ def update_componant(componant_id):
return 'KO'
@app.route('/componants/delete/<componant_id>')
@resume_session
def delete_componant(componant_id):
""" Delete componant """
try:
componant_id = int(componant_id)
except ValueError as e:
return render_template('error.html'), 404
Stock_componants.query.filter_by(id=componant_id).delete()
db.session.commit()
except ValueError as e:
return render_template('error.html'), 404
except Exception as e:
print "[+] Error at delete_componant:\n------------------------------\n%s------------------------------" % e.message
return componants()
@app.route('/componants/new', methods=['POST'])
@ -206,18 +248,20 @@ def new_componant():
db.session.add(componant)
commit = db.session.commit()
except Exception as e:
print e
print "[+] Error at new_componant:\n------------------------------\n%s------------------------------" % e.message
return 'KO'
if commit != None:
return 'KO'
return 'OK'
@app.route('/componants/in/<componant_id>')
@resume_session
def in_componants():
""" Incoming order """
return render_template('wip.html')
@app.route('/componants/out/<componant_id>')
@resume_session
def out_componants():
""" Outgoing order """
return render_template('wip.html')
@ -246,7 +290,6 @@ def update_componants():
if session['c_page'] > session['c_pagecount']:
session['c_page'] = session['c_pagecount']
session['c_offset'] = 0
print "*****", componants.count(), session['c_pagecount'], session['c_page']
session['c_nexthop'] = session['c_offset'] + session['c_limit']
if session['c_nexthop'] > session['c_count'] - 1:
session['c_nexthop'] = int(session['c_offset'])
@ -265,7 +308,7 @@ def update_componants():
# Get result
componants = componants.all()
response = app.make_response(render_template('result.html',
response = app.make_response(render_template('result_componants.html',
componants=componants,
offset=session['c_offset'] ,
nexthop=session['c_nexthop'],
@ -278,101 +321,160 @@ def update_componants():
for key in session:
response.set_cookie(key, value=str(session[key]))
if key != 'session':
print '++', key, session[key]
print '[c]', key, session[key]
return response
########################################################################
# Providers
########################################################################
@app.route('/providers', methods=['GET', 'POST'])
@resume_session
def providers():
return render_template('providers.html',
name=session['p_name'],
address=session['p_address'],
mail=session['p_mail'],
url=session['p_url'],
comment=session['p_comment'])
@app.route('/providers/<provider_id>')
@resume_session
def get_provider(provider_id):
""" Edit provider """
try:
provider_id = int(provider_id)
except ValueError as e:
return render_template('error.html'), 404
provider = Stock_providers.query.filter_by(id=provider_id).first()
if provider:
return render_template('provider.html', provider=provider)
return render_template('error.html'), 404
@app.route('/providers/update/<provider_id>', methods=['POST'])
@resume_session
def update_provider(provider_id):
""" Update provider field"""
field = request.form['field']
value = request.form['value']
if field and value:
try:
provider = Stock_providers.query.filter_by(id=provider_id).first()
setattr(provider, field, value)
commit = db.session.commit()
if commit == None:
return 'OK'
except Exception as e:
pass
return 'KO'
@app.route('/providers/new', methods=['POST'])
@resume_session
def new_provider():
""" Add provider """
provider = Stock_providers(name=session['p_name'],
address=session['p_address'],
mail=session['p_mail'],
url=session['p_url'],
comment=session['p_comment'])
try:
db.session.add(provider)
commit = db.session.commit()
except Exception as e:
print 'Error at new_provider():', e
print 'Commit = ', commit
return 'KO'
if commit != None:
return 'KO'
return 'OK'
@app.route('/providers/delete/<provider_id>')
@resume_session
def delete_provider(provider_id):
""" Delete provider """
try:
provider_id = int(provider_id)
Stock_providers.query.filter_by(id=provider_id).delete()
db.session.commit()
except ValueError as e:
return render_template('error.html'), 404
except Exception as e:
print "[+] Error at delete_provider:\n-----------------------------\n%s-----------------------------" % e.message
return providers()
@app.route('/providers/update', methods=['POST'])
@resume_session
def search_providers():
""" Display componants list """
# search by reference
like = '%s%s%s' % ('%', str(session['p_name']), '%')
providers = Stock_providers.query.filter(Stock_providers.name.like(like))
# search by designation
like = '%s%s%s' % ('%', str(session['p_address']), '%')
providers = providers.filter(Stock_providers.address.like(like))
# search by place
like = '%s%s%s' % ('%', str(session['p_mail']),'%')
providers = providers.filter(Stock_providers.mail.like(like))
# search by place
like = '%s%s%s' % ('%', str(session['p_url']),'%')
providers = providers.filter(Stock_providers.url.like(like))
# search by place
like = '%s%s%s' % ('%', str(session['p_comment']),'%')
providers = providers.filter(Stock_providers.comment.like(like))
# Don't take 'all' and 'none' entry
providers = providers.filter(Stock_providers.id > 2)
# Pages calculation
session['p_count'] = providers.count()
session['p_pagecount'] = int(math.ceil(session['p_count'] / float(session['p_limit'])))
session['p_page'] = int(math.ceil(float(float(session['p_offset']) + 1) / float(session['p_limit'])))
if session['p_page'] > session['p_pagecount']:
session['p_page'] = session['p_pagecount']
session['p_offset'] = 0
session['p_nexthop'] = session['p_offset'] + session['p_limit']
if session['p_nexthop'] > session['p_count'] - 1:
session['p_nexthop'] = int(session['p_offset'])
session['p_prevhop'] = int(session['p_offset']) - session['p_limit']
if session['p_prevhop'] < 0:
session['p_prevhop'] = 0
# Sorting
sort = getattr(Stock_providers, session['p_sort'])
if session['p_order'] == 'desc':
sort = getattr(Stock_providers, session['p_sort']).desc()
providers = providers.order_by(sort)
# Applying offset
providers = providers.offset(session['p_offset'])
# Applying limit
providers = providers.limit(session['p_limit'])
# Get result
providers = providers.all()
response = app.make_response(render_template('result_providers.html',
providers=providers,
offset=session['p_offset'] ,
nexthop=session['p_nexthop'],
prevhop=session['p_prevhop'],
page_count=session['p_pagecount'],
page=session['p_page'],
sort=session['p_sort'],
order=session['p_order'],
row_count=session['p_count']))
for key in session:
response.set_cookie(key, value=str(session[key]))
if key != 'session':
print '[c]', key, session[key]
return response
########################################################################
# Kits
########################################################################
@app.route('/kits')
def get_kits():
return render_template('kits.html')
@app.route('/kits/<kit_id>')
def get_kit(kit_id):
return render_template('wip.html')
@app.route('/kits/add/<kit_id>')
def add_kit(kit_id):
return render_template('wip.html')
@app.route('/kits/edit/<kit_id>')
def edit_kit(kit_id):
return render_template('wip.html')
@app.route('/kits/delete/<kit_id>')
def delete_kit(kit_id):
return render_template('wip.html')
@app.route('/kits/search')
def search_kits():
return render_template('wip.html')
########################################################################
# Providers
########################################################################
@app.route('/providers')
def get_providers():
return render_template('providers.html')
@app.route('/providers/<provider_id>')
def get_provider(provider_id):
return render_template('wip.html')
@app.route('/providers/add/<provider_id>')
def add_provider(provider_id):
return render_template('wip.html')
@app.route('/providers/edit/<provider_id>')
def edit_provider(provider_id):
return render_template('wip.html')
@app.route('/providers/delete/<provider_id>')
def delete_provider(provider_id):
return render_template('wip.html')
@app.route('/providers/search')
def search_providers():
return render_template('wip.html')
########################################################################
# Users
########################################################################
@app.route('/users')
def get_users():
return render_template('wip.html')
@app.route('/users/<user_id>')
def get_user(user_id):
return render_template('wip.html')
@app.route('/users/add/<user_id>')
def add_user(user_id):
return render_template('wip.html')
@app.route('/users/edit/<user_id>')
def edit_user(user_id):
return render_template('wip.html')
@app.route('/users/delete/<user_id>')
def delete_user(user_id):
return render_template('wip.html')
@app.route('/users/search')
def search_users():
return render_template('wip.html')
##############################################
# SQL
##############################################
def sql_get_distinct(query):
results = []
for result in query:
result = result[0]
if result not in results:
results.append(result)
return results
# Main #######################################