A wrapping client and label printing
For now, the server does the printing. Later it should probably be split into a different service.
This commit is contained in:
parent
0c9c893237
commit
235d9272ed
45
client/wrap.html
Normal file
45
client/wrap.html
Normal file
@ -0,0 +1,45 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>chikin wrap 0.1</title>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<!-- Compiled and minified CSS -->
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<!-- Compiled and minified JavaScript -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
|
||||
|
||||
<script src="wrap.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header class="page-header center amber brown-text">
|
||||
<h1>Chikin wrap</h1>
|
||||
</header>
|
||||
<main class="container row">
|
||||
<div class="col m6 offset-m3 s12">
|
||||
<div id="appbody"></div>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="page-footer">
|
||||
<div class="container row">
|
||||
<span class="col right">displayed with recycled electrons.</span>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
102
client/wrap.js
Normal file
102
client/wrap.js
Normal file
@ -0,0 +1,102 @@
|
||||
const config = 'dev';
|
||||
const backend_api = {
|
||||
'prod': '/zetikettes/srv/',
|
||||
'dev': 'http://scrawny.local:3000',
|
||||
}[config];
|
||||
|
||||
const token = localStorage.getItem('token');
|
||||
|
||||
async function getBandz() {
|
||||
const uri = `${backend_api}/bandz`;
|
||||
const res = await $.ajax(uri, {headers: {Authorization: `Bearer ${token}`}});
|
||||
return res.bandz;
|
||||
}
|
||||
|
||||
async function wrapAChikin(req) {
|
||||
const uri = `${backend_api}/wrap`;
|
||||
const res = await $.ajax(uri, {
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(req),
|
||||
headers: {Authorization: `Bearer ${token}`},
|
||||
});
|
||||
return res.chikinId;
|
||||
}
|
||||
|
||||
function printLabel(chikinId) {
|
||||
const uri = `${backend_api}/print`;
|
||||
$.ajax(uri, {
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({chikinId}),
|
||||
headers: {Authorization: `Bearer ${token}`},
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(() => {
|
||||
const appbody = $("#appbody");
|
||||
|
||||
const bandSelect = $('<div class="input-field col s12">')
|
||||
.append(
|
||||
$('<select>')
|
||||
.append('<option disabled selected>Choose a band</option>')
|
||||
)
|
||||
.append('<label>Band</label>');
|
||||
|
||||
const block = $('<div class="section">');
|
||||
block
|
||||
.append(bandSelect)
|
||||
.append($('<div class="input-field col s12">')
|
||||
.append('<input type="text" class="datepicker">')
|
||||
.append('<label>Date of wrapping</label>')
|
||||
);
|
||||
|
||||
const loader = $('<div class="progress"><div class="indeterminate"></div></div>')
|
||||
.hide();
|
||||
|
||||
const action = $('<div class="section">')
|
||||
.append(
|
||||
$('<a class="btn">wrap-a-chikin<i class="material-icons right">send</i></a>')
|
||||
.click(async () => {
|
||||
loader.show();
|
||||
$('.btn').addClass("disabled");
|
||||
|
||||
const req = {
|
||||
bandId: $('select').val(),
|
||||
wrapDate: $('.datepicker').val(),
|
||||
weight: $('#weight').val(),
|
||||
};
|
||||
|
||||
try {
|
||||
const chikinId = await wrapAChikin(req);
|
||||
printLabel(chikinId);
|
||||
} finally {
|
||||
loader.hide();
|
||||
$('#weight').val('');
|
||||
$('.btn').removeClass('disabled');
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
block
|
||||
.append(
|
||||
$('<div class="input-field col s12">')
|
||||
.append('<input type="text" inputmode="decimal" id="weight">')
|
||||
.append('<label>weight (g)</label>')
|
||||
)
|
||||
.append(
|
||||
$('<div class="input-field col s12">')
|
||||
.append(action)
|
||||
.append(loader)
|
||||
)
|
||||
;
|
||||
appbody.append(block);
|
||||
|
||||
getBandz().then(bandz => {
|
||||
$('select').append(bandz.map(band => `<option value="${band.id}">${band.name}</option>`));
|
||||
$('select').formSelect();
|
||||
});
|
||||
|
||||
$('select').formSelect();
|
||||
$('.datepicker').datepicker({setDefaultDate: true, defaultDate: new Date()});
|
||||
});
|
56
index.js
56
index.js
@ -1,4 +1,6 @@
|
||||
const bodyParser = require('body-parser');
|
||||
const child_process = require('child_process');
|
||||
const cors = require('cors');
|
||||
const express = require('express');
|
||||
require('express-async-errors');
|
||||
const jwt = require('jsonwebtoken');
|
||||
@ -28,9 +30,9 @@ CREATE TABLE IF NOT EXISTS Chikinz (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
bandId INTEGER NOT NULL,
|
||||
weight REAL NOT NULL,
|
||||
killedDate DATE,
|
||||
wrappedDate DATE NOT NULL,
|
||||
soldDate DATE,
|
||||
killDate DATE,
|
||||
wrapDate DATE NOT NULL,
|
||||
sellDate DATE,
|
||||
misc TEXT
|
||||
);`);
|
||||
|
||||
@ -38,17 +40,15 @@ makeTable(`
|
||||
CREATE TABLE IF NOT EXISTS Bandz (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT,
|
||||
receivedDate DATE,
|
||||
receiveDate DATE,
|
||||
misc TEXT
|
||||
);`);
|
||||
|
||||
const app = express();
|
||||
|
||||
function addChikin(db, chikin) {
|
||||
const sql_insert = 'INSERT INTO Chikinz (bandId, weight, killedDate, wrappedDate) VALUES (?, ?, ?, ?);';
|
||||
const {bandId, weight, killedDate, wrappedDate} = chikin;
|
||||
const sql_insert = 'INSERT INTO Chikinz (bandId, weight, killDate, wrapDate) VALUES (?, ?, ?, ?);';
|
||||
const {bandId, weight, killDate, wrapDate} = chikin;
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run(sql_insert, [bandId, weight, killedDate, wrappedDate], function(err) {
|
||||
db.run(sql_insert, [bandId, weight, killDate, wrapDate], function(err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
@ -74,6 +74,17 @@ function getBandz(db) {
|
||||
});
|
||||
}
|
||||
|
||||
function getChikin(db, chikinId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get('SELECT * from Chikinz where id=?', chikinId, (err, row) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve(row);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const authenticateJWT = (req, res, next) => {
|
||||
const authHeader = req.headers.authorization;
|
||||
|
||||
@ -98,7 +109,10 @@ const authenticateJWT = (req, res, next) => {
|
||||
}
|
||||
};
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(bodyParser.json());
|
||||
app.use(cors());
|
||||
|
||||
app.listen(3000, () => {
|
||||
console.log('Server started (http://localhost:3000/)!');
|
||||
@ -118,7 +132,6 @@ app.get('/bandz', authenticateJWT, async (req, res) => {
|
||||
|
||||
app.post('/toktok', (req, res) => {
|
||||
const {password} = req.body;
|
||||
console.log(req.body);
|
||||
|
||||
if (password != 'goldchocoboisbestchocobo.goldchocoboisonlychocobo') {
|
||||
return res.json({message: 'This is not the way.'});
|
||||
@ -134,9 +147,30 @@ app.post('/wrap', authenticateJWT, async (req, res) => {
|
||||
const chikin = req.body;
|
||||
console.log(chikin);
|
||||
const {lastID} = await addChikin(db, chikin);
|
||||
res.json({message: 'This is the way.', id: lastID});
|
||||
res.json({message: 'This is the way.', chikinId: lastID});
|
||||
});
|
||||
|
||||
app.post('/print', authenticateJWT, async (req, res) => {
|
||||
const {chikinId} = req.body;
|
||||
|
||||
const qr_url = `http://lafermedumalpas.fr/chikinz/${chikinId}`;
|
||||
const chikin = await getChikin(db, chikinId);
|
||||
const line0 = 'Poulet fermier bio';
|
||||
const line1 = `${chikin.weight.toFixed(2)} kg`;
|
||||
|
||||
const pricePerKg = 12;
|
||||
const price = chikin.weight * pricePerKg;
|
||||
const line2 = `${pricePerKg.toFixed(2)} €/kg - ${price.toFixed(2)}`;
|
||||
|
||||
const args = ['/Users/paul/scratch/printer/catprint.py',
|
||||
'--template0', [qr_url, line0, line1, line2].join(';')];
|
||||
|
||||
const proc = child_process.spawn('python', args);
|
||||
proc.stdout.on('data', data => console.log(`stdout: ${data}`));
|
||||
proc.stderr.on('data', data => console.log(`stderr: ${data}`));
|
||||
|
||||
res.json({message: 'This is the way.'});
|
||||
});
|
||||
|
||||
// catch errors
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
"author": "Paul Mathieu <paul@ponteilla.net>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.1",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
|
12
yarn.lock
12
yarn.lock
@ -266,6 +266,14 @@ cookie@0.5.0:
|
||||
resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
|
||||
cors@^2.8.5:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||
dependencies:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
||||
debug@2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
|
||||
@ -980,7 +988,7 @@ npmlog@^6.0.0:
|
||||
gauge "^4.0.3"
|
||||
set-blocking "^2.0.0"
|
||||
|
||||
object-assign@^4.1.1:
|
||||
object-assign@^4, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
|
||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||
@ -1352,7 +1360,7 @@ utils-merge@1.0.1:
|
||||
resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz"
|
||||
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
|
||||
|
||||
vary@~1.1.2:
|
||||
vary@^1, vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
|
||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||
|
Loading…
Reference in New Issue
Block a user