From 85fd981b62e201313202c219c61f443305284e81 Mon Sep 17 00:00:00 2001 From: ardean Date: Wed, 24 Feb 2016 17:29:22 +0100 Subject: [PATCH] first commit --- .gitignore | 4 + LICENSE | 21 +++ README.md | 10 ++ demo/index.html | 30 +++++ demo/index.js | 55 ++++++++ dist/pdf-reminder-simple.js | 240 +++++++++++++++++++++++++++++++++++ package.json | 43 +++++++ src/index.js | 178 ++++++++++++++++++++++++++ webpack.development.babel.js | 23 ++++ webpack.production.babel.js | 30 +++++ 10 files changed, 634 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 demo/index.html create mode 100644 demo/index.js create mode 100644 dist/pdf-reminder-simple.js create mode 100644 package.json create mode 100644 src/index.js create mode 100644 webpack.development.babel.js create mode 100644 webpack.production.babel.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b271ae6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +Thumbs.db +node_modules +npm-debug.log diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..051fe16 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Orbin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..39b70d9 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# pdf-reminder-simple +A simple pdf reminder template + +Example: + +```javascript +import simpleReminder from "pdf-reminder-simple"; + +simpleReminder(invoice, reminder, profile).open(); +``` diff --git a/demo/index.html b/demo/index.html new file mode 100644 index 0000000..72e6022 --- /dev/null +++ b/demo/index.html @@ -0,0 +1,30 @@ + + + + + Simple reminder pdf + + + + + + + + + diff --git a/demo/index.js b/demo/index.js new file mode 100644 index 0000000..161826a --- /dev/null +++ b/demo/index.js @@ -0,0 +1,55 @@ +import $ from "jquery"; +import moment from "moment"; +import simpleReminder from "../src"; + +const invoice = { + contactName: "Mein Kontakt", + number: 12, + date: moment(), + dueDate: moment(), + billingAddress: { + street: "Strasse 2", + postCode: "78556", + city: "Andere Stadt" + }, + itemDetails: [{ + name: "Item Name", + quantity: 2, + rate: 200, + total: 400 + }], + subTotal: 400, + taxGroups: [{ + name: "Mehrwertsteuer", + amount: 10 + }], + adjustment: 20, + total: 430, + currencyId: "EUR" +}; + +const reminder = { + typeName: "1. Mahnung", + note: "Sie haben die Rechnung nicht bezahlt!", + feeAmount: 10, + creationDate: moment() +}; + +const profile = { + organizationSettings: { + name: "Orbin", + address: { + street: "Strasse 333", + postCode: "3474", + city: "Stadt" + } + }, + invoiceSettings: { + note: "Meine Notiz" + } +}; + +const pdf = simpleReminder(invoice, reminder, profile); +pdf.getBase64((data) => { + $("iframe").attr("src", `data:application/pdf;base64,${data}`); +}); diff --git a/dist/pdf-reminder-simple.js b/dist/pdf-reminder-simple.js new file mode 100644 index 0000000..9ad0d65 --- /dev/null +++ b/dist/pdf-reminder-simple.js @@ -0,0 +1,240 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("roboto-base64"), require("pdfmake/build/pdfmake")); + else if(typeof define === 'function' && define.amd) + define(["roboto-base64", "pdfmake/build/pdfmake"], factory); + else { + var a = typeof exports === 'object' ? factory(require("roboto-base64"), require("pdfmake/build/pdfmake")) : factory(root["roboto-base64"], root["pdfmake/build/pdfmake"]); + for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; + } +})(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_2__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _robotoBase = __webpack_require__(1); + + var _robotoBase2 = _interopRequireDefault(_robotoBase); + + var _pdfmake = __webpack_require__(2); + + var _pdfmake2 = _interopRequireDefault(_pdfmake); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + + window.pdfMake = { + vfs: _robotoBase2.default + }; + + var defaultStyle = { + fontSize: 10 + }; + + var tableLayout = { + hLineWidth: function hLineWidth(i) { + return i === 1 ? 1 : 0; + }, + vLineWidth: function vLineWidth() { + return 0; + }, + paddingLeft: function paddingLeft() { + return 0; + }, + paddingRight: function paddingRight() { + return 0; + }, + paddingTop: function paddingTop(i) { + return i === 1 ? 15 : 5; + }, + paddingBottom: function paddingBottom() { + return 5; + } + }; + + var footerLayout = { + hLineWidth: function hLineWidth(i, node) { + return i === 0 || i === node.table.body.length || i === node.table.body.length - 1 ? 1 : 0; + }, + vLineWidth: function vLineWidth() { + return 0; + }, + paddingLeft: function paddingLeft() { + return 0; + }, + paddingRight: function paddingRight() { + return 0; + }, + paddingTop: function paddingTop(i, node) { + return i === 0 || i === node.table.body.length - 1 ? 10 : 5; + }, + paddingBottom: function paddingBottom(i, node) { + return i === node.table.body.length - 1 || i === node.table.body.length - 2 ? 10 : 5; + } + }; + + exports.default = function (invoice, reminder, profile) { + return _pdfmake2.default.createPdf(getDoc(invoice, reminder, profile)); + }; + + function getDoc(invoice, reminder, profile) { + var organizationSettings = profile.organizationSettings; + var address = organizationSettings.address; + var billingAddress = invoice.billingAddress; + var totalAmount = invoice.total + reminder.feeAmount; + + var doc = { + defaultStyle: defaultStyle, + content: [{ + text: returnAddressText({ + name: organizationSettings.name, + street: address.street, + postCode: address.postCode, + city: address.city + }), + margin: [0, 120, 0, 0], + fontSize: 8, + color: "gray" + }, { + margin: [0, 10, 0, 0], + layout: "noBorders", + table: { + widths: ["auto", "*", "auto", "auto"], + body: [[invoice.contactName || "", "", "Datum:", { + text: reminder.creationDate.format("DD.MM.YYYY"), + alignment: "right" + }], [billingAddress.street || "", "", "", ""], [(billingAddress.postCode || "") + " " + (billingAddress.city || ""), "", "", ""]] + } + }, { + fontSize: 18, + text: reminder.typeName, + margin: [0, 50, 0, 0] + }, { + margin: [0, 25, 0, 0], + text: reminder.note || "" + }, { + margin: [0, 25, 0, 0], + layout: tableLayout, + table: { + headerRows: 1, + widths: ["*", "auto"], + body: [["Beschreibung", { + text: "Betrag", + alignment: "right" + }]] + } + }] + }; + + doc.content[4].table.body.push([{ + stack: ["Rechnung", { + margin: [0, 2, 0, 0], + text: invoice.date.format("DD.MM.YYYY"), + color: "gray" + }] + }, { + text: invoice.total.toFixed(2), + alignment: "right" + }]); + + if (reminder.feeAmount) { + doc.content[4].table.body.push(["Gebühr", { + text: reminder.feeAmount.toFixed(2), + alignment: "right" + }]); + } + + doc.content.push({ + margin: [0, 25, 0, 0], + layout: footerLayout, + table: { + headerRows: 1, + widths: ["*", "auto"], + body: [["Gesamtsumme " + (invoice.currencyId || "CHF"), { + text: totalAmount.toFixed(2), + alignment: "right" + }]] + } + }); + + doc.content.push({ + text: profile.invoiceSettings.note || "", + margin: [0, 20, 0, 0], + color: "gray", + fontSize: 8 + }); + + return doc; + } + + function returnAddressText(address) { + var location = [address.postCode, address.city].join(" ").trim(); + + return [address.name, address.street, location].filter(function (value) { + return value; + }).join(", "); + } + +/***/ }, +/* 1 */ +/***/ function(module, exports) { + + module.exports = __WEBPACK_EXTERNAL_MODULE_1__; + +/***/ }, +/* 2 */ +/***/ function(module, exports) { + + module.exports = __WEBPACK_EXTERNAL_MODULE_2__; + +/***/ } +/******/ ]) +}); +; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..b41225d --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "pdf-reminder-simple", + "description": "A simple pdf reminder template", + "version": "0.1.0", + "author": "Orbin", + "keywords": [ + "pdf", + "reminder", + "simple" + ], + "repository": { + "type": "git", + "url": "https://github.com/orbin-ch/pdf-reminder-simple" + }, + "main": "dist/pdf-reminder-simple.js", + "license": "MIT", + "dependencies": { + "pdfmake": "orbin-ch/pdfmake#fix-webpack-win", + "roboto-base64": "^0.1.1" + }, + "devDependencies": { + "babel-core": "^6.4.0", + "babel-loader": "^6.2.1", + "babel-polyfill": "^6.3.14", + "babel-preset-es2015": "^6.3.13", + "clean-webpack-plugin": "^0.1.8", + "html-webpack-plugin": "^2.7.1", + "jquery": "^2.2.0", + "jshint-loader": "^0.8.3", + "moment": "^2.11.2", + "webpack": "^1.12.11", + "webpack-dev-server": "^1.14.1" + }, + "scripts": { + "build": "webpack --config webpack.production.babel.js", + "start": "webpack-dev-server --config webpack.development.babel.js" + }, + "babel": { + "presets": [ + "es2015" + ] + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..464823f --- /dev/null +++ b/src/index.js @@ -0,0 +1,178 @@ +import roboto from "roboto-base64"; +import pdfMake from "pdfmake/build/pdfmake"; + +window.pdfMake = { + vfs: roboto +}; + +const defaultStyle = { + fontSize: 10 +}; + +const tableLayout = { + hLineWidth: (i) => { + return (i === 1) ? 1 : 0; + }, + vLineWidth: () => { + return 0; + }, + paddingLeft: () => { + return 0; + }, + paddingRight: () => { + return 0; + }, + paddingTop: (i) => { + return (i === 1) ? 15 : 5; + }, + paddingBottom: () => { + return 5; + } +}; + +const footerLayout = { + hLineWidth: (i, node) => { + return ( + i === 0 || + i === node.table.body.length || + i === node.table.body.length - 1 + ) ? 1 : 0; + }, + vLineWidth: () => { + return 0; + }, + paddingLeft: () => { + return 0; + }, + paddingRight: () => { + return 0; + }, + paddingTop: (i, node) => { + return ( + i === 0 || + i === node.table.body.length - 1 + ) ? 10 : 5; + }, + paddingBottom: (i, node) => { + return ( + i === node.table.body.length - 1 || + i === node.table.body.length - 2 + ) ? 10 : 5; + } +}; + +export default (invoice, reminder, profile) => { + return pdfMake.createPdf(getDoc(invoice, reminder, profile)); +}; + +function getDoc(invoice, reminder, profile) { + const organizationSettings = profile.organizationSettings; + const address = organizationSettings.address; + const billingAddress = invoice.billingAddress; + const totalAmount = invoice.total + reminder.feeAmount; + + const doc = { + defaultStyle: defaultStyle, + content: [{ + text: returnAddressText({ + name: organizationSettings.name, + street: address.street, + postCode: address.postCode, + city: address.city + }), + margin: [0, 120, 0, 0], + fontSize: 8, + color: "gray" + }, { + margin: [0, 10, 0, 0], + layout: "noBorders", + table: { + widths: ["auto", "*", "auto", "auto"], + body: [ + [invoice.contactName || "", "", "Datum:", { + text: reminder.creationDate.format("DD.MM.YYYY"), + alignment: "right" + }], + [billingAddress.street || "", "", "", ""], + [(billingAddress.postCode || "") + " " + (billingAddress.city || ""), "", "", ""] + ] + } + }, { + fontSize: 18, + text: reminder.typeName, + margin: [0, 50, 0, 0] + }, { + margin: [0, 25, 0, 0], + text: reminder.note || "" + }, { + margin: [0, 25, 0, 0], + layout: tableLayout, + table: { + headerRows: 1, + widths: ["*", "auto"], + body: [ + ["Beschreibung", { + text: "Betrag", + alignment: "right" + }] + ] + } + }] + }; + + doc.content[4].table.body.push([{ + stack: [ + "Rechnung", { + margin: [0, 2, 0, 0], + text: invoice.date.format("DD.MM.YYYY"), + color: "gray" + } + ] + }, { + text: invoice.total.toFixed(2), + alignment: "right" + }]); + + if (reminder.feeAmount) { + doc.content[4].table.body.push([ + "Gebühr", { + text: reminder.feeAmount.toFixed(2), + alignment: "right" + } + ]); + } + + doc.content.push({ + margin: [0, 25, 0, 0], + layout: footerLayout, + table: { + headerRows: 1, + widths: ["*", "auto"], + body: [ + [ + "Gesamtsumme " + (invoice.currencyId || "CHF"), { + text: totalAmount.toFixed(2), + alignment: "right" + } + ] + ] + } + }); + + doc.content.push({ + text: profile.invoiceSettings.note || "", + margin: [0, 20, 0, 0], + color: "gray", + fontSize: 8 + }); + + return doc; +} + +function returnAddressText(address) { + const location = [address.postCode, address.city].join(" ").trim(); + + return [address.name, address.street, location].filter((value) => { + return value; + }).join(", "); +} diff --git a/webpack.development.babel.js b/webpack.development.babel.js new file mode 100644 index 0000000..c1568a7 --- /dev/null +++ b/webpack.development.babel.js @@ -0,0 +1,23 @@ +import config from "./webpack.production.babel"; +import HtmlWebpackPlugin from "html-webpack-plugin"; +import path from "path"; + +config.entry = "./demo"; +config.module.loaders[0].include.push(path.resolve(__dirname, "demo")); +config.output.publicPath = "/"; +config.debug = true; +config.devtool = "source-map"; +config.module.preLoaders.shift(); +config.devServer = { + inline: true, + port: 3000, + contentBase: "./dist" +}; +config.plugins.shift(); +config.plugins.unshift(new HtmlWebpackPlugin({ + template: "./demo/index.html", + inject: true +})); +delete config.externals; + +export default config; diff --git a/webpack.production.babel.js b/webpack.production.babel.js new file mode 100644 index 0000000..1d27e32 --- /dev/null +++ b/webpack.production.babel.js @@ -0,0 +1,30 @@ +import path from "path"; +import CleanWebpackPlugin from "clean-webpack-plugin"; + +export default { + entry: "./src", + output: { + path: "./dist", + filename: "pdf-reminder-simple.js", + libraryTarget: "umd" + }, + module: { + preLoaders: [{ + test: /\.js$/, + include: path.resolve(__dirname, "src"), + loader: "jshint-loader" + }], + loaders: [{ + test: /\.js$/, + include: [path.resolve(__dirname, "src")], + loader: "babel-loader" + }] + }, + externals: (context, request, done) => { + if (!request.startsWith("./")) return done(null, request); + done(); + }, + plugins: [ + new CleanWebpackPlugin(["dist"]) + ] +};