summaryrefslogtreecommitdiffstats
path: root/src/pdf-stock
diff options
context:
space:
mode:
authorSebastian Reichel <sre@ring0.de>2015-03-08 16:10:59 +0100
committerSebastian Reichel <sre@ring0.de>2015-03-08 16:10:59 +0100
commitb87976793e0f45328d563eb80c4001a717a49563 (patch)
treeff1e60515dcea7b1e9b9cc05e7241e016e23f1e9 /src/pdf-stock
parent0585c78a6edc9b1fcc7c1bbbd66097d5a50016f7 (diff)
downloadserial-barcode-scanner-b87976793e0f45328d563eb80c4001a717a49563.tar.bz2
pdf-stock: new tool for stocktaking
Diffstat (limited to 'src/pdf-stock')
-rw-r--r--src/pdf-stock/.gitignore3
-rw-r--r--src/pdf-stock/Makefile19
-rw-r--r--src/pdf-stock/main.vala36
-rw-r--r--src/pdf-stock/pdf-stock-interface.vala19
-rw-r--r--src/pdf-stock/pdf-stock.vala218
-rw-r--r--src/pdf-stock/test.vala28
6 files changed, 323 insertions, 0 deletions
diff --git a/src/pdf-stock/.gitignore b/src/pdf-stock/.gitignore
new file mode 100644
index 0000000..58a1e54
--- /dev/null
+++ b/src/pdf-stock/.gitignore
@@ -0,0 +1,3 @@
+pdf-stock
+test
+test.pdf
diff --git a/src/pdf-stock/Makefile b/src/pdf-stock/Makefile
new file mode 100644
index 0000000..e0e190e
--- /dev/null
+++ b/src/pdf-stock/Makefile
@@ -0,0 +1,19 @@
+include ../../config.mk
+
+LIBCAIROBARCODE=-X -I../../libcairobarcode -X -L../../libcairobarcode -X -lcairobarcode
+
+all: pdf-stock
+
+pdf-stock: main.vala pdf-stock.vala ../database/db-interface.vala ../price.vapi ../../libcairobarcode/libcairobarcode.vapi
+ ${VALAC} -X -w ${LIBCAIROBARCODE} -o $@ --pkg cairo --pkg pangocairo --pkg gio-2.0 --pkg posix $^
+
+test: test.vala pdf-stock-interface.vala
+ ${VALAC} -X -w -o $@ --pkg gio-2.0 $^
+
+run: pdf-stock
+ LD_LIBRARY_PATH=../../libcairobarcode ./pdf-stock
+
+clean:
+ rm -rf pdf-stock test
+
+.PHONY: all clean run
diff --git a/src/pdf-stock/main.vala b/src/pdf-stock/main.vala
new file mode 100644
index 0000000..fee62af
--- /dev/null
+++ b/src/pdf-stock/main.vala
@@ -0,0 +1,36 @@
+/* Copyright 2015, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public static int main(string[] args) {
+ Bus.own_name(
+ BusType.SESSION,
+ "io.mainframe.shopsystem.StockPDF",
+ BusNameOwnerFlags.NONE,
+ on_bus_aquired,
+ () => {},
+ () => stderr.printf("Could not aquire name\n"));
+
+ new MainLoop().run();
+
+ return 0;
+}
+
+void on_bus_aquired(DBusConnection conn) {
+ try {
+ conn.register_object("/io/mainframe/shopsystem/stockpdf", new StockPDF());
+ } catch(IOError e) {
+ stderr.printf("Could not register service\n");
+ }
+}
diff --git a/src/pdf-stock/pdf-stock-interface.vala b/src/pdf-stock/pdf-stock-interface.vala
new file mode 100644
index 0000000..415916f
--- /dev/null
+++ b/src/pdf-stock/pdf-stock-interface.vala
@@ -0,0 +1,19 @@
+/* Copyright 2015, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.StockPDF")]
+public interface PDFStock : Object {
+ public abstract uint8[] generate() throws IOError;
+}
diff --git a/src/pdf-stock/pdf-stock.vala b/src/pdf-stock/pdf-stock.vala
new file mode 100644
index 0000000..c1e9b6a
--- /dev/null
+++ b/src/pdf-stock/pdf-stock.vala
@@ -0,0 +1,218 @@
+/* Copyright 2015, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.StockPDF")]
+public class StockPDF {
+ /* A4 sizes (in points, 72 DPI) */
+ private const double a4w = 595.27559; /* 210mm */
+ private const double a4h = 841.88976; /* 297mm */
+
+ private const double eanw = 100.0;
+ private const double eanh = 15.0;
+
+ private const double col1 = 40;
+ private const double col2 = 145;
+ private const double col3 = 400;
+ private const double col4 = 480;
+ private const double col5 = 550;
+
+ private const double row0 = 50;
+ private const double row1 = 65;
+
+ private const double padding = 3;
+
+ private int64 timestamp;
+ uint page;
+ double y;
+
+ EAN ean;
+ Cairo.Context ctx;
+ Pango.Layout layout;
+ StockEntry[] stock;
+
+ /* pdf data */
+ private uint8[] data;
+ private uint useddatalength;
+
+ private void render_page_header() {
+ var dt = new DateTime.from_unix_local(timestamp);
+ ctx.move_to(145, 25);
+ ctx.set_font_size(15.0);
+ var date = dt.format("%Y-%m-%d %H:%M:%S");
+ ctx.show_text(@"Shopsystem Stock - State: $date");
+ }
+
+ private void render_page_footer() {
+ ctx.move_to(277, 820);
+ ctx.set_font_size(12.0);
+ ctx.show_text(@"Page $page");
+ }
+
+ private void render_table_header() {
+ ctx.save();
+
+ /* border & font color */
+ ctx.set_source_rgb(0, 0, 0);
+
+ /* line width of the border */
+ ctx.set_line_width(0.8);
+
+ /* header font */
+ ctx.select_font_face("LMSans10", Cairo.FontSlant.NORMAL, Cairo.FontWeight.BOLD);
+ ctx.set_font_size(12);
+
+ ctx.move_to(col1, row0);
+ ctx.line_to(col5, row0);
+ ctx.line_to(col5, row1);
+ ctx.line_to(col1, row1);
+ ctx.line_to(col1, row0);
+ ctx.move_to(col2, row0);
+ ctx.line_to(col2, row1);
+ ctx.move_to(col3, row0);
+ ctx.line_to(col3, row1);
+ ctx.move_to(col4, row0);
+ ctx.line_to(col4, row1);
+ ctx.stroke();
+
+ /* header text */
+ ctx.move_to(col1 + padding, row1 - padding);
+ ctx.show_text("EAN");
+ ctx.move_to(col2 + padding, row1 - padding);
+ ctx.show_text("Produkt");
+ ctx.move_to(col3 + padding, row1 - padding);
+ ctx.show_text("Anzahl");
+ ctx.move_to(col4 + padding, row1 - padding);
+ ctx.show_text("Zählung");
+
+ ctx.restore();
+ }
+
+ private void render_table_row(StockEntry product) throws BarcodeError {
+ ctx.set_line_width(0.8);
+
+ /* borders */
+ ctx.move_to(col1, y);
+ ctx.line_to(col1, y + eanh + 2*padding);
+ ctx.line_to(col5, y + eanh + 2*padding);
+ ctx.line_to(col5, y);
+ ctx.move_to(col2, y);
+ ctx.line_to(col2, y + eanh + 2*padding);
+ ctx.move_to(col3, y);
+ ctx.line_to(col3, y + eanh + 2*padding);
+ ctx.move_to(col4, y);
+ ctx.line_to(col4, y + eanh + 2*padding);
+ ctx.stroke();
+
+ /* EAN */
+ ctx.move_to(col1 + padding, y + padding);
+ ean.draw(product.id);
+
+ /* Product Name */
+ ctx.move_to(col2 + padding, y);
+ layout.set_alignment(Pango.Alignment.LEFT);
+ layout.set_wrap(Pango.WrapMode.WORD_CHAR);
+ layout.set_spacing((int) (-padding * Pango.SCALE));
+ layout.set_width((int) (col3-col2) * Pango.SCALE);
+ var text = @"$(product.id)\n$(product.name)";
+ layout.set_text(text, text.length);
+ Pango.cairo_update_layout(ctx, layout);
+ Pango.cairo_show_layout(ctx, layout);
+
+ /* Amount */
+ ctx.set_font_size(16.0);
+ ctx.move_to(col3 + padding, y + eanh + 1);
+ ctx.show_text(@"$(product.amount)");
+ }
+
+ private Cairo.Status pdf_write(uchar[] newdata) {
+ if(data == null) {
+ data = newdata;
+ useddatalength = newdata.length;
+ } else {
+ if(useddatalength + newdata.length > data.length) {
+ uint8[] alldata = new uint8[data.length + newdata.length + 512];
+ Posix.memcpy(alldata, data, data.length);
+ data = alldata;
+ }
+
+ Posix.memcpy((uint8*) data + useddatalength, newdata, newdata.length);
+ useddatalength += newdata.length;
+ }
+
+ return Cairo.Status.SUCCESS;
+ }
+
+ public uint8[] generate() {
+ data = null;
+
+ var surface = new Cairo.PdfSurface.for_stream(pdf_write, a4w, a4h);
+ ctx = new Cairo.Context(surface);
+ ean = new EAN(ctx, eanw, eanh);
+ layout = Pango.cairo_create_layout(ctx);
+
+ var font = new Pango.FontDescription();
+ font.set_family("LMRoman8");
+ font.set_size((int) 6.0 * Pango.SCALE);
+ layout.set_font_description(font);
+
+ /* get stock */
+ try {
+ Database db = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Database", "/io/mainframe/shopsystem/database");
+ stock = db.get_stock();
+ timestamp = new DateTime.now_local().to_unix();
+ } catch(IOError e) {
+ return data;
+ }
+
+ /* render pdf */
+ ctx.select_font_face("LMSans10", Cairo.FontSlant.NORMAL, Cairo.FontWeight.NORMAL);
+
+ try {
+ y = row1;
+ page = 1;
+
+ render_page_header();
+ render_table_header();
+
+ foreach(var p in stock) {
+ render_table_row(p);
+ y += eanh + 6;
+
+ if(y > 780) {
+ y = row1;
+ render_page_footer();
+ ctx.show_page();
+ page++;
+ render_page_header();
+ render_table_header();
+ }
+ }
+ render_page_footer();
+ } catch(BarcodeError e) {
+ stderr.printf(e.message + "\n");
+ }
+
+ surface.finish();
+ surface.flush();
+
+ /* cleanup */
+ ean = null;
+ ctx = null;
+ surface = null;
+
+ return data;
+ }
+
+}
diff --git a/src/pdf-stock/test.vala b/src/pdf-stock/test.vala
new file mode 100644
index 0000000..9cd3a7e
--- /dev/null
+++ b/src/pdf-stock/test.vala
@@ -0,0 +1,28 @@
+/* Copyright 2015, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public static int main(string args[]) {
+ try {
+ PDFStock stock = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.StockPDF", "/io/mainframe/shopsystem/stockpdf");
+ var pdfdata = stock.generate();
+ FileUtils.set_contents("test.pdf", (string) pdfdata, pdfdata.length);
+ } catch(IOError e) {
+ error("IOError: %s", e.message);
+ } catch(FileError e) {
+ error("FileError: %s", e.message);
+ }
+
+ return 0;
+}