7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WebグラフィックスAdvent Calendar 2020

Day 17

SVG + CSS + Node.js + receiptline で電子レシートを発行してみよう

Last updated at Posted at 2020-12-16

マークダウン言語で紙のレシートや電子レシートを簡単に作れる receiptline。
https://github.com/receiptline/receiptline
https://www.npmjs.com/package/receiptline

今回は receiptline 本来の用途と考えられる、電子レシートの発行です!

レシートを設計する

デザインツール

ReceiptLine Designer を使います。使い方はこの連載記事の初回から。
いますぐ試したい方は、開発元のホームページで公開されているのでこちらへ。
01.png

ロゴの背景を透明に

以前の記事で作成したロゴ画像を再利用します。
02.png

GIMP の「色を透明度に」 (Color to Alpha) 機能で、背景色を白から透明にしました。
03.png

2023年度インボイス制度対応

前回の記事で学習した、簡易適格請求書等の記載事項も追加しておきます。

  • ① 適格請求書発行事業者の氏名又は名称及び登録番号
  • ② 課税資産の譲渡等を行った年月日
  • ③ 課税資産の譲渡等に係る資産又は役務の内容(課税資産の譲渡等が軽減対象資産の譲渡等である場合には、資産の内容及び軽減対象資産の譲渡等である旨)
  • ④ 課税資産の譲渡等の税抜価額又は税込価額を税率ごとに区分して合計した金額
  • ⑤ 税率ごとに区分した消費税額等又は適用税率

04.png

作成したレシートデータ

ReceiptLine
{image:iVBORw0KGgoAAAANSUhEUgAAASAAAAAwAgMAAADMTE88AAAACVBMVEVwAAsAAAD///9xeVj9AAAAAXRSTlMAQObYZgAAAdZJREFUSMftlsFu4zAMRMUD73sI/0c59M4Amv//lXJI2XEWaGSgAVrsxuihtqgnmjOk09r7+pcv7esYAEtMM19yrCkWxwnOgEbk1Fc5nwBpRNgCpGdAhKi/4NVYaFmD1qqlYi8ACU6Y6BRo/DaQjk3hiARv4BeB834aVXBDk1bL0lHlCEs0Qz5zP4A89FVW3rgWNwGxWrRuCVIC7Ao3HjBCamY6mt7GHSQ9/rnQVEGZIBmlBPL0Fsvoig8Mg9N6KJAAB5ASFPDYzUcJytgEFXAQzpf2/ajMCMeMjCAwMX8A9ZQjQUJQ7mZs5G4TZMcaXRJd3bKBLOZLz4gC9Q00Y8030FE1Vga5egf5put0rTwDbT4SalV6fQmyp6DZIqCONXe+Aqk/A82mlcF3RO7eQeMRZH0JElePJ3P336BNfjwtdg42CV9PHynu8ldjSO7NIhxAD/Lvo1YDZONPgdIlg26JvwT4BAmud1AZstsOkhz+Fo3pERHhdLxiMCy9z89VgcAmnaCyPfCxg2hqnn4NWr/MtWgD0Fdeqt9qLAwbOyiaNtXRXV3eDeZlfAmKlPrxK6WbD2umR02i0diyyBmTdVEmvhhR3//Mv0H/M8jwIhBWv7ve189enyEmqNlnG50wAAAAAElFTkSuQmCC}
柳都市星降町7丁目8番9号
登録番号 T1234567890123

2020年12月16日(水)12:34  #0903
{border:line; width:22}
^領 収 書
{border:space; width:3,*,3,8; text:nowrap}
166003 |2021葱鏡餅 水引 | 3個| ¥1,620*
691004 |洗面器45RPM N025 | 1個| ¥1,210~
-
{width:auto; text:wrap}
小 計 |4点 | ¥2,830~
(税率10%対象 | ¥1,210)
(内消費税等10% | ¥110)
(税率 8%対象 | ¥1,620)
(内消費税等 8% | ¥120)
-
合 計 | ^¥2,830
お預り | ^¥3,000
お釣り | ^¥170
|*印は軽減税率対象商品です
{code:202012160903; option:code128,2,48}

電子レシート発行サーバーを作る

Node.js

Node.js で電子レシートを発行する HTTP サーバーを作ります。
receipt.js の内部構成は、以下のようになっています。

  • ReceiptLine
    • 作成したレシートデータ (固定) を SVG に変換する
  • HTML
    • 作成した SVG を HTML に埋め込む
  • HTTP サーバー
    • 任意の GET リクエストを受けて、作成した HTML を返す
receipt.js
const http = require('http');
const receiptline = require('receiptline');

// ReceiptLine
const text = `{image:iVBORw0KGgoAAAANSUhEUgAAASAAAAAwAgMAAADMTE88AAAACVBMVEVwAAsAAAD///9xeVj9AAAAAXRSTlMAQObYZgAAAdZJREFUSMftlsFu4zAMRMUD73sI/0c59M4Amv//lXJI2XEWaGSgAVrsxuihtqgnmjOk09r7+pcv7esYAEtMM19yrCkWxwnOgEbk1Fc5nwBpRNgCpGdAhKi/4NVYaFmD1qqlYi8ACU6Y6BRo/DaQjk3hiARv4BeB834aVXBDk1bL0lHlCEs0Qz5zP4A89FVW3rgWNwGxWrRuCVIC7Ao3HjBCamY6mt7GHSQ9/rnQVEGZIBmlBPL0Fsvoig8Mg9N6KJAAB5ASFPDYzUcJytgEFXAQzpf2/ajMCMeMjCAwMX8A9ZQjQUJQ7mZs5G4TZMcaXRJd3bKBLOZLz4gC9Q00Y8030FE1Vga5egf5put0rTwDbT4SalV6fQmyp6DZIqCONXe+Aqk/A82mlcF3RO7eQeMRZH0JElePJ3P336BNfjwtdg42CV9PHynu8ldjSO7NIhxAD/Lvo1YDZONPgdIlg26JvwT4BAmud1AZstsOkhz+Fo3pERHhdLxiMCy9z89VgcAmnaCyPfCxg2hqnn4NWr/MtWgD0Fdeqt9qLAwbOyiaNtXRXV3eDeZlfAmKlPrxK6WbD2umR02i0diyyBmTdVEmvhhR3//Mv0H/M8jwIhBWv7ve189enyEmqNlnG50wAAAAAElFTkSuQmCC}
柳都市星降町7丁目8番9号
登録番号 T1234567890123

2020年12月16日(水)12:34  #0903
{border:line; width:22}
^領 収 書
{border:space; width:3,*,3,8; text:nowrap}
166003 |2021葱鏡餅 水引 | 3個| ¥1,620*
691004 |洗面器45RPM N025 | 1個| ¥1,210~
-
{width:auto; text:wrap}
小 計 |4点 | ¥2,830~
(税率10%対象 | ¥1,210)
(内消費税等10% | ¥110)
(税率 8%対象 | ¥1,620)
(内消費税等 8% | ¥120)
-
合 計 | ^¥2,830
お預り | ^¥3,000
お釣り | ^¥170
|*印は軽減税率対象商品です
{code:202012160903; option:code128,2,48}`;
const svg = receiptline.transform(text, { cpl: 32, encoding: 'cp932', spacing: true });

// HTML
const style = 'float: left; padding: 24px; background: lavender;';
const html = `<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>レシート</title>
    </head>
    <body>
        <div style="${style}">${svg}</div>
    </body>
</html>`;

// HTTP Server
const server = http.createServer((req, res) => {
    switch (req.method) {
        case 'GET':
            res.end(html);
            break;
        default:
            res.end();
            break;
    }
});
server.listen(8080, "127.0.0.1", () => {
    console.log('Server running at http://127.0.0.1:8080/');
});

実行

電子レシート発行サーバーを起動します。

$ node receipt.js

Web ブラウザーで localhost:8080 を開きます。
receiptline ライブラリが動作しない IE11 でも表示 OK。
05.png

作成された SVG データ

レシートデータから生成された SVG データです。
中身はパス、画像、テキスト、Web フォント、フィルター、いろいろ入っています。

SVG
<svg width="384px" height="684px" viewBox="0 0 384 684" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><style type="text/css"><![CDATA[@import url("https://fonts.googleapis.com/css2?family=Kosugi+Maru&display=swap");]]></style><defs><filter id="receiptlineinvert" x="0" y="0" width="100%" height="100%"><feFlood flood-color="#000"/><feComposite in="SourceGraphic" operator="xor"/></filter></defs><g font-family="'Kosugi Maru', 'MS Gothic', 'San Francisco', 'Osaka-Mono', 'Courier New', 'Courier', monospace" fill="#000" font-size="24" dominant-baseline="text-after-edge"><g transform="translate(48,0)"><image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAAwAgMAAADMTE88AAAACVBMVEVwAAsAAAD///9xeVj9AAAAAXRSTlMAQObYZgAAAdZJREFUSMftlsFu4zAMRMUD73sI/0c59M4Amv//lXJI2XEWaGSgAVrsxuihtqgnmjOk09r7+pcv7esYAEtMM19yrCkWxwnOgEbk1Fc5nwBpRNgCpGdAhKi/4NVYaFmD1qqlYi8ACU6Y6BRo/DaQjk3hiARv4BeB834aVXBDk1bL0lHlCEs0Qz5zP4A89FVW3rgWNwGxWrRuCVIC7Ao3HjBCamY6mt7GHSQ9/rnQVEGZIBmlBPL0Fsvoig8Mg9N6KJAAB5ASFPDYzUcJytgEFXAQzpf2/ajMCMeMjCAwMX8A9ZQjQUJQ7mZs5G4TZMcaXRJd3bKBLOZLz4gC9Q00Y8030FE1Vga5egf5put0rTwDbT4SalV6fQmyp6DZIqCONXe+Aqk/A82mlcF3RO7eQeMRZH0JElePJ3P336BNfjwtdg42CV9PHynu8ldjSO7NIhxAD/Lvo1YDZONPgdIlg26JvwT4BAmud1AZstsOkhz+Fo3pERHhdLxiMCy9z89VgcAmnaCyPfCxg2hqnn4NWr/MtWgD0Fdeqt9qLAwbOyiaNtXRXV3eDeZlfAmKlPrxK6WbD2umR02i0diyyBmTdVEmvhhR3//Mv0H/M8jwIhBWv7ve189enyEmqNlnG50wAAAAAElFTkSuQmCC" x="0" y="0" width="288" height="48"/></g><g transform="translate(0,72)"><text x="54,78,102,126,150,174,198,210,234,258,270,294,306">柳都市星降町7丁目8番9号</text></g><g transform="translate(0,102)"><text x="54,78,102,126,150,162,174,186,198,210,222,234,246,258,270,282,294,306,318">登録番号&#xa0;T1234567890123</text></g><g transform="translate(0,132)"><text x="0">&#xa0;</text></g><g transform="translate(0,162)"><text x="12,24,36,48,60,84,96,108,132,144,156,180,192,216,228,240,252,264,276,288,300,312,324,336,348,360">2020年12月16日(水)12:34&#xa0;&#xa0;#0903</text></g><g transform="translate(48,192)"><text x="0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276">╔══════════════════════╗</text></g><g transform="translate(48,216)"><text transform="scale(1,1)" x="0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276">&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;</text><text transform="scale(2,1)" x="24,48,60,84,96">&#xa0;&#xa0;</text></g><g transform="translate(48,240)"><text x="0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276">╚══════════════════════╝</text></g><g transform="translate(0,270)"><text x="0,12,24">166</text><text x="48,60,72,84,96,120,144,168,180,204">2021葱鏡餅&#xa0;水引</text><text x="240,252">3個</text><text x="300,312,324,336,348,360,372">¥1,620*</text></g><g transform="translate(0,300)"><text x="0,12,24">691</text><text x="48,72,96,120,132,144,156,168,180,192,204,216">洗面器45RPM&#xa0;N02</text><text x="240,252">1個</text><text x="300,312,324,336,348,360,372">¥1,210&#xa0;</text></g><g transform="translate(0,330)"><text x="0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276,288,300,312,324,336,348,360,372">════════════════════════════════</text></g><g transform="translate(0,360)"><text x="0,24,48">小 計</text><text x="132,144">4点</text><text x="300,312,324,336,348,360,372">¥2,830&#xa0;</text></g><g transform="translate(0,390)"><text x="0,12,36,60,72,84,96,120">(税率10%対象</text><text x="300,312,324,336,348,360,372">¥1,210)</text></g><g transform="translate(0,420)"><text x="0,12,36,60,84,108,132,144,156">(内消費税等10%</text><text x="324,336,348,360,372">¥110)</text></g><g transform="translate(0,450)"><text x="0,12,36,60,72,84,96,120">(税率&#xa0;8%対象</text><text x="300,312,324,336,348,360,372">¥1,620)</text></g><g transform="translate(0,480)"><text x="0,12,36,60,84,108,132,144,156">(内消費税等&#xa0;8%</text><text x="324,336,348,360,372">¥120)</text></g><g transform="translate(0,510)"><text x="0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276,288,300,312,324,336,348,360,372">════════════════════════════════</text></g><g transform="translate(0,540)"><text x="0,24,48">合 計</text><text transform="scale(2,1)" x="120,132,144,156,168,180">¥2,830</text></g><g transform="translate(0,570)"><text x="0,24,48">お預り</text><text transform="scale(2,1)" x="120,132,144,156,168,180">¥3,000</text></g><g transform="translate(0,600)"><text x="0,24,48">お釣り</text><text transform="scale(2,1)" x="144,156,168,180">¥170</text></g><g transform="translate(0,630)"><text x="0,12,36,60,84,108,132,156,180,204,228,252,276">*印は軽減税率対象商品です</text></g><g transform="translate(91,636)"><path d="M0,0h4v48h-4zM6,0h2v48h-2zM12,0h6v48h-6zM22,0h4v48h-4zM30,0h2v48h-2zM36,0h6v48h-6zM44,0h4v48h-4zM52,0h2v48h-2zM58,0h6v48h-6zM66,0h2v48h-2zM70,0h4v48h-4zM78,0h6v48h-6zM88,0h2v48h-2zM94,0h6v48h-6zM102,0h4v48h-4zM110,0h4v48h-4zM118,0h2v48h-2zM124,0h2v48h-2zM132,0h2v48h-2zM138,0h2v48h-2zM144,0h4v48h-4zM154,0h4v48h-4zM162,0h2v48h-2zM166,0h6v48h-6zM176,0h4v48h-4zM186,0h6v48h-6zM194,0h2v48h-2zM198,0h4v48h-4z" fill="#000"/></g></g></svg>

電子レシートの背景をカスタマイズする

ソースコードの CSS を変更して、電子レシートの背景をカスタマイズします。

単色

お店のキャンペーンでよく使われるピンクレシートと黄色いレシート。

receipt.js
const style = 'float: left; padding: 24px; background: pink;';

06.png

receipt.js
const style = 'float: left; padding: 24px; background: #ff9;';

07.png

多色

サーマルロール紙にはできないグラデーション。

receipt.js
const style = 'float: left; padding: 24px; background: linear-gradient(skyblue, lightyellow);';

08.png

receipt.js
const style = 'float: left; padding: 24px; background: linear-gradient(lightgreen, snow, beige);';

09.png

透かし

「複写」「COPY」の画像をタイル状に並べます。画像は CSS に埋め込みます。
10.png

画像の Data URI 形式への変換は ReceiptLine Designer を使うと簡単です。
画像をロードして image:data:image/png;base64, に置き換えます。
11.png

receipt.js
const style = 'float: left; padding: 24px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANgAAADYAQMAAACz7r+uAAAABlBMVEXc3tv5+/j5MJA8AAADWklEQVRYw+2YPW7bMBSAqTAwMxTmBVwqR2g3G1AiH8W9gYMsCuLGSg3UW3yBwDlElwLNYMGDlza+QFsoMFqvDAy0NCpENQqRj3yCshfRmyh9En8eH98PCamllucih0+wPjT3MFPQZAh5GbQ5YvQ7tH3E2ATaAWK8Ae0MMXEAXUjEgpZpDjGLzCA0TxGTkelSIeal0tP/XSJGk9Uo1t/N0PJGi0UV478nS9MHYiL3Hw2L0fIuWpnF9t3lRQrGTps2GwQS2Fg5O3H88h765NmxzXx//tXowRcDZw18PIVJc2WrpcG5ME8tZ5cYYQKYoLZGOWkEwJpsZg2429hoYA1+mQPrxATWR9gNy0FvpzMvBcOmj3xu2It1aivfy3zYJ38pma18dUzMTP2pcuy8HwDjt1nDOW+Rxc6u8YEzjG3ayCI9YD/P4wrWYNnaZbAk7m8XLuuxpHjB8uHNO3cufFJ0SrMwv3KZr7d3p6M/U2SSLNPsy8Y9q35GivNIPydr5R4BRQoTpVcJOo+7JWjGt3mMfZE2bb5dILJnGNu+x+4mNiy5wgz+W01LTBhvc11i2qewqF1i2lxZEJXmopVBRR+7zEtZ5U2JB4piJbXksyq3sXOG0EVcB8Faaqmllv9TIGW5KMWHGUSKEksh/S3FAAg5CUpHyX7U1SzGaXMz0NFLEMyEiWwBwTGuxWUl6yw0i0p9vp7LcupUyInFephNZLnG0WFzIrsVjOajdjFMm3C3nuCrUccw381twsWHT4UaRT+8ddjbpfILxuXAydLJ2bdMMyaVW2e92T7qisZLpMu8zU2mZ0dTxNZh2jN5Fard7k7BKGLEWmsJuQbKRI7u+sCEW2CG1+Y/SkTDzSM7CsYLnE4l31gs82Pbctn6o3lIVAgm2qAzurT2Mo3ALDiLPSuZG85k36pXnJoztGuEQPRI5GSjkNq1A0mcaia1WCQPbcPj0mIPst+1D0cEIxytlJMfBqGCMmRx65TGEZdQhkxajur7LAUmhEBlP7AgDKpcQ6iGUZVLOZe/ZBV7uP+BS2PD0vkc+RQa6xddNka+iI6hXirdJkD66y7vX0UDllu6TYB5H+BU3DK0V/jGwKqFT7C7GdiWVX1ZEsZVnrZ8IWK7reYTAWC/joG1PBv5C4viMg7LEHCAAAAAAElFTkSuQmCC);';

12.png

地紋

領収書やチケットでよく見かける地紋です。小さな素片をタイル状に並べます。
13.png

const style = 'float: left; padding: 24px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADAQMAAACplL1tAAAABlBMVEX/pQD////52iT3AAAAFElEQVQI12M4l/+AYf/mCQyFdwoAJNIF3T0xRTsAAAAASUVORK5CYII=);';

14.png

また何か作ったら投稿します。ではまた!

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?