Compare commits

...

3 commits

Author SHA1 Message Date
keplyx
d9e799a538 Fixed json generation to work with campus mobile app 2020-02-20 12:50:58 +01:00
keplyx
7bfb239ec4 Generate stock on button press 2020-02-20 12:20:42 +01:00
keplyx
d935a40bcb added stock edition 2020-02-15 19:01:27 +01:00
14 changed files with 365 additions and 71 deletions

6
admin/articles.php Normal file
View file

@ -0,0 +1,6 @@
<?php
$relativePath = "../";
$pageTitle = "Gestion des articles";
$script = "<script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/articles.js\"></script>";
include("template.php");

View file

@ -2,13 +2,28 @@
$relativePath = "../"; $relativePath = "../";
ob_start(); ob_start();
?> ?>
<div class="admin-container"> <div class="admin-container" style="display: flex">
<a href="stock.php"> <div style="margin: auto">
<button class="btn btn-primary btn-large">Gestion des stocks</button> <div style="display: flex" class="my-5">
<a href="stock.php" style="margin: auto">
<button class="btn btn-success btn-lg">Gestion du stocks</button>
</a> </a>
<a href="categories.php"> </div>
<button class="btn btn-primary btn-large">Gestion des catégories</button>
<div class="my-5" style="display: flex">
<a href="articles.php" style="margin: auto" class="mx-1">
<button class="btn btn-primary btn-lg">Créer/Éditer des articles</button>
</a> </a>
<a href="categories.php" style="margin: auto" class="mx-1">
<button class="btn btn-primary btn-lg">Créer/Éditer des catégories</button>
</a>
</div>
<div style="display: flex" class="my-5">
<button id="uploadButton" class="btn btn-warning btn-lg" style="margin: auto">Mettre l'inventaire en ligne
</button>
</div>
</div>
</div> </div>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/admin.css" media="screen,projection"/> <link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/admin.css" media="screen,projection"/>
@ -16,5 +31,12 @@ ob_start();
<?php <?php
$pageContent = ob_get_clean(); $pageContent = ob_get_clean();
$pageTitle = "Admin"; $pageTitle = "Admin";
$pageScripts =
"
<script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/jquery-confirm-defaults.js\"></script>
<script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/index.js\"></script>
";
include($relativePath . "includes/template.php"); include($relativePath . "includes/template.php");
?> ?>

View file

@ -1,6 +1,7 @@
<?php <?php
$relativePath = "../"; $relativePath = "../";
$pageTitle = "Gestion des articles"; $isStock = true;
$script = "<script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/articles.js\"></script>"; $pageTitle = "Gestion des stocks";
$script = "<script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/stock.js\"></script>";
include("template.php"); include("template.php");

View file

@ -1,35 +1,61 @@
<?php <?php
$relativePath = "../"; $relativePath = "../";
if (!isset($isStock))
$isStock = false;
ob_start(); ob_start();
?> ?>
<div class="admin-container"> <div class="admin-container">
<a href="index.php"> <a href="index.php">
<button class="btn btn-primary btn-large">Retour</button> <button class="btn btn-primary btn-large">
<span class="mdi mdi-chevron-left"></span>
Retour
</button>
</a> </a>
<h1 class="text-center"><?= $pageTitle ?></h1> <h1 class="text-center"><?= $pageTitle ?></h1>
<?php if (!$isStock): ?>
<div style="display: flex"> <div style="display: flex">
<button class="btn btn-success" style="margin: auto" onclick="listManager.showEditPopup(-1)"> <button class="btn btn-success" style="margin: auto" onclick="listManager.showEditPopup(-1)">
<i class="mdi mdi-plus"></i> <i class="mdi mdi-plus"></i>
</button> </button>
</div> </div>
<div id="listContainer"> <div id="listContainer">
<ul id="dataList"> <ul id="dataList">
</ul> </ul>
</div> </div>
<?php else: ?>
<div>
<h3 class="text-center">Mode</h3>
<div class="button-container">
<button id="buyButton" class="btn mr-0">Achat</button>
<button id="sellButton" class="btn ml-0">Vente</button>
</div>
</div>
<div id="dataList">
</div>
<div style="display: flex">
<button id="saveButton" style="margin: auto" class="btn btn-lg my-2">Sauvegarder</button>
</div>
<?php endif; ?>
</div> </div>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/libs/materialdesignicons.min.css" media="screen,projection"/> <link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/libs/materialdesignicons.min.css"
media="screen,projection"/>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/admin.css" media="screen,projection"/> <link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/admin.css" media="screen,projection"/>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/categories.css" media="screen,projection"/>
<?php if (!$isStock): ?>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/list.css" media="screen,projection"/>
<?php else: ?>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/stock.css" media="screen,projection"/>
<?php endif; ?>
<?php <?php
$pageContent = ob_get_clean(); $pageContent = ob_get_clean();

View file

@ -1,22 +1,7 @@
<?php <?php
$rest_json = file_get_contents("php://input"); $relativePath = "../";
$_POST = json_decode($rest_json, true); require_once $relativePath.'classes/postHandler.php';
$handler = new PostHandler(null, null);
//var_dump($_POST); echo json_encode($handler->write_json());
$fp = fopen('../data/stock-v2.json', 'w');
$result = fwrite($fp, json_encode($_POST["v2"]));
fclose($fp);
$fp = fopen('../data/stock.json', 'w');
$result = fwrite($fp, json_encode($_POST["v1"]));
fclose($fp);
if ($result) {
echo 'Réussite !';
} else {
echo 'Echec!
'; // Allows to create a newline
var_dump($_POST);
}

View file

@ -33,13 +33,13 @@
margin: 20px 0 20px 0; margin: 20px 0 20px 0;
} }
.mdi { #listContainer .mdi {
font-size: 2rem; font-size: 2rem;
} }
.list-name { .list-name {
font-weight: bold; font-weight: bold;
width: 150px; width: 200px;
height: 50px; height: 50px;
overflow: hidden; overflow: hidden;
} }
@ -61,7 +61,15 @@
text-align: right; text-align: right;
} }
.list-image img { .list-image {
width: 50px; width: 50px;
height: 50px; height: 50px;
display: flex;
}
.list-image img {
width: 45px;
height: 45px;
margin: auto;
} }

View file

@ -1,33 +1,43 @@
#dataList {
.name-column { display: grid;
width: 200px; grid-template-columns: auto auto ;
width: 100%;
} }
.quantity-column, .price-column { .img-container {
width: 150px; display: flex;
width: 100%;
} }
.code-column { .grid-item {
width: 200px; display: flex;
padding: 5px;
} }
.type-column {
width: 200px; .grid-container {
overflow-x: auto; width: 100px;
margin: auto;
display: block;
} }
.image-column { .grid-container input {
width: 150px;
}
.actions-column {
width: 100px; width: 100px;
} }
#stockTable tr { .grid-container p {
border-bottom: 1px solid #dedede; text-align: center;
} }
.row-img { .grid-container img {
height: 50px; width : 100px;
margin: auto;
}
.button-container {
display: flex;
}
.button-container button {
margin: auto;
} }

View file

@ -78,6 +78,23 @@ class AjaxManager {
} else } else
return 1; return 1;
} }
static async saveStockChange(data, isSell) {
let formattedData = {
type: 'stock',
action: isSell ? 'sell' : 'buy',
data: data,
};
let response = await $.ajax({
type: "POST",
url: "json_ajax.php",
data: JSON.stringify(formattedData),
dataType: "json",
contentType: "application/json; charset=utf-8",
});
console.log(response);
return response['data'];
}
} }

43
assets/js/index.js Normal file
View file

@ -0,0 +1,43 @@
async function sendRequest() {
let response = await $.ajax({
type: "POST",
url: "write_json.php",
});
response = JSON.parse(response);
console.log(response);
return response["status"];
}
$('#uploadButton').on('click', function () {
$.confirm({
title: 'Confirmer',
content: "Voulez vous vraiment mettre en ligne le stock actuel du Proximo ? Il sera visible depuis l'application CAMPUS.",
type: "orange",
buttons: {
formSubmit: {
text: 'Confirmer',
btnClass: "btn-warning",
action: async function () {
let result = await sendRequest();
if (result !== 0) {
$.alert({
title: "Erreur",
content: "Une erreur est survenue, merci de réessayer plus tard.",
type: "red",
})
} else {
$.alert({
title: "Succès",
content: "Le stock a bien été mis à jour.",
type: "green",
})
}
}
},
cancel: {
text: 'Annuler',
}
}
});
});

View file

@ -1,7 +1,7 @@
jconfirm.defaults = { jconfirm.defaults = {
title: 'Title', title: 'Title',
titleClass: '', titleClass: '',
type: 'red', type: 'blue',
typeAnimated: true, typeAnimated: true,
draggable: false, draggable: false,
dragWindowGap: 15, dragWindowGap: 15,

View file

@ -138,7 +138,9 @@ class ListManager {
} }
getImagePicker(id, index) { getImagePicker(id, index) {
let imageSrc = $(this.displayedData[index].find("img")[0]).attr('src'); let imageSrc = undefined;
if (index !== -1)
imageSrc = $(this.displayedData[index].find("img")[0]).attr('src');
return ( return (
'<img style="width: 50px; height: 50px" src="' + imageSrc + '" id="image_' + id + '"/>' + '<img style="width: 50px; height: 50px" src="' + imageSrc + '" id="image_' + id + '"/>' +
'<div class="custom-file">\n' + '<div class="custom-file">\n' +

106
assets/js/stock.js Normal file
View file

@ -0,0 +1,106 @@
let listContainer = $("#dataList");
let displayedItems = [];
let fetchedData = {};
let currentMode = "sell";
let sellCLass = 'btn-danger';
let buyClass = 'btn-success';
$(document).ready(async function () {
fetchedData = await AjaxManager.getAll();
$('#sellButton').addClass(sellCLass);
$('#saveButton').addClass(sellCLass);
generateList();
$('#buyButton').on('click', function () {
if (!$(this).hasClass(buyClass)) {
$(this).addClass(buyClass);
$('#sellButton').removeClass(sellCLass);
$('#saveButton').removeClass(sellCLass).addClass(buyClass);
currentMode = "buy";
}
});
$('#sellButton').on('click', function () {
if (!$(this).hasClass(sellCLass)) {
$(this).addClass(sellCLass);
$('#buyButton').removeClass(buyClass);
$('#saveButton').removeClass(buyClass).addClass(sellCLass);
currentMode = "sell";
}
});
$('#saveButton').on('click', function () {
let values = getValues();
let message = 'Voulez vous vraimer ajouter ces articles au stock ?<br><ul>';
let color = 'green';
if (currentMode === "sell"){
message = 'Voulez vous vraiment supprimer ces articles du stock ?<br><ul>';
color = 'red';
}
for (let i = 0; i < values.length; i++) {
if (values[i]['value'] > 0){
message += '<li>' + fetchedData['articles'][i]['name'] + ' : ' + values[i]['value'] + '</li>'
}
}
message += '</ul>';
$.confirm({
title: 'Confirmer',
content: message,
type: color,
buttons: {
formSubmit: {
text: 'Confirmer',
action: function () {
window.location.reload();
}
},
cancel: {
text: 'Annuler',
}
}
});
AjaxManager.saveStockChange(getFormattedValues(values), currentMode === "sell");
});
});
function getListItem(item) {
return (
'<div class="grid-item">' +
'<div class="grid-container">' +
'<img class="list-image" src="../uploaded_images/' + item['id'] + '.jpg"/>' +
'<p>' + item['name'] + '</p>' +
'<p>Quantité : ' + item['quantity'] + '</p>' +
'<input placeholder="Nombre" type="number" value="0" class="form-control"/>' +
'</div>' +
'</div>');
}
function generateList() {
for (let i = 0; i < fetchedData['articles'].length; i++) {
let listItem = getListItem(fetchedData['articles'][i]);
displayedItems.push($(listItem));
listContainer.append(displayedItems[i]);
}
}
function getValues() {
let values = [];
for (let i = 0; i < displayedItems.length; i++) {
let value = displayedItems[i].find('input').val();
let id = fetchedData['articles'][i]['id'];
values.push({id: id, value: value});
}
return values;
}
function getFormattedValues(values) {
let newValues = [];
for (let i = 0; i < values.length; i++) {
if (values[i]['value'] > 0)
newValues.push(values[i]);
}
return newValues;
}

View file

@ -35,6 +35,19 @@ class Dao
return $cursor->fetchAll(PDO::FETCH_ASSOC); return $cursor->fetchAll(PDO::FETCH_ASSOC);
} }
public function get_categories_of_article($articleid)
{
$sql = 'SELECT category_id FROM article_categories WHERE article_id=?';
$cursor = $this->conn->prepare($sql);
$cursor->execute([$articleid]);
$result = $cursor->fetchAll(PDO::FETCH_ASSOC);
$final = [];
foreach ($result as $row) {
array_push($final, $row["category_id"]);
}
return $final;
}
public function get_article_categories() public function get_article_categories()
{ {
$sql = 'SELECT * FROM article_categories'; $sql = 'SELECT * FROM article_categories';
@ -137,4 +150,12 @@ class Dao
} else } else
return 0; return 0;
} }
public function update_article_stock($articleid, $diff)
{
$sql = 'UPDATE articles SET quantity=quantity+? WHERE id=?';
$cursor = $this->conn->prepare($sql);
$data = [$diff, $articleid];
return $cursor->execute($data);
}
} }

View file

@ -3,8 +3,8 @@ require_once 'dao.php';
class PostHandler class PostHandler
{ {
private $valid_types = ["article", "category", "article_categories", 'image']; private $valid_types = ["article", "category", "article_categories", "image", "stock"];
private $valid_actions = ["create", "update", "remove", "get"]; private $valid_actions = ["create", "update", "remove", "get", "buy", "sell"];
private $action; private $action;
private $type; private $type;
@ -13,6 +13,8 @@ class PostHandler
private $data; private $data;
private $dao; private $dao;
private $uploadBaseDir = '../uploaded_images/'; private $uploadBaseDir = '../uploaded_images/';
private $stockFile = "../data/stock-v2.json";
private $imageBaseUrl = "https://etud.insa-toulouse.fr/~proximo/uploaded_images/";
private $responseArray = array( private $responseArray = array(
"status" => 0, "status" => 0,
@ -35,6 +37,8 @@ class PostHandler
$result = -1; $result = -1;
if ($this->type == "image") { if ($this->type == "image") {
$result = $this->save_image(); $result = $this->save_image();
} else if ($this->type == "stock") {
$result = $this->updateStock();
} else if (count($this->data) > 0) { } else if (count($this->data) > 0) {
if ($this->action == "create") if ($this->action == "create")
$result = $this->create(); $result = $this->create();
@ -57,6 +61,34 @@ class PostHandler
return $this->responseArray; return $this->responseArray;
} }
public function write_json()
{
$result = 0;
$fp = fopen($this->stockFile, "w");
$array = array(
"types" => $this->dao->get_categories(),
"articles" => $this->get_articles_json_list(),
);
fwrite($fp, json_encode($array));
fclose($fp);
$this->responseArray["data"] = $result;
return $this->responseArray;
}
public function get_articles_json_list()
{
$articles = $this->dao->get_articles();
$formatted_articles = [];
foreach ($articles as $article) {
$article["type"] = $this->dao->get_categories_of_article($article["id"]);
$article["image"] = $this->imageBaseUrl . $article["id"] . ".jpg";
array_push($formatted_articles, $article);
}
return $formatted_articles;
}
private function save_image() private function save_image()
{ {
$success = true; $success = true;
@ -81,7 +113,8 @@ class PostHandler
return json_encode($this->filesData) . "id: " . $this->data; return json_encode($this->filesData) . "id: " . $this->data;
} }
private function remove_image() { private function remove_image()
{
$uploadPath = $this->uploadBaseDir . $this->data["id"] . ".jpg"; $uploadPath = $this->uploadBaseDir . $this->data["id"] . ".jpg";
if (file_exists($uploadPath) && unlink($uploadPath)) { if (file_exists($uploadPath) && unlink($uploadPath)) {
$this->responseArray["message"] = "Success: Deleted image"; $this->responseArray["message"] = "Success: Deleted image";
@ -151,6 +184,20 @@ class PostHandler
return $result; return $result;
} }
function updateStock()
{
$result = 0;
foreach ($this->data as $row) {
$value = $row["value"];
if ($this->action == "sell")
$value = -$value;
$result = $this->dao->update_article_stock($row["id"], $value);
if (!$result)
break;
}
return $result;
}
function setUnknownTypeResponse() function setUnknownTypeResponse()
{ {
$this->responseArray["status"] = 1; $this->responseArray["status"] = 1;