mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-30 07:56:05 +00:00
barcode field
This commit is contained in:
@@ -40,7 +40,7 @@ use Espo\Core\Utils\Language;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
require('vendor/zordius/lightncandy/src/lightncandy.php');
|
||||
use LightnCandy\LightnCandy as LightnCandy;
|
||||
|
||||
class Htmlizer
|
||||
{
|
||||
@@ -272,46 +272,38 @@ class Htmlizer
|
||||
|
||||
public function render(Entity $entity, $template, $id = null, $additionalData = [], $skipLinks = false)
|
||||
{
|
||||
$code = \LightnCandy::compile($template, [
|
||||
'flags' => \LightnCandy::FLAG_HANDLEBARSJS,
|
||||
$template = str_replace('<tcpdf ', '', $template);
|
||||
|
||||
$code = LightnCandy::compile($template, [
|
||||
'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_ERROR_EXCEPTION,
|
||||
'helpers' => [
|
||||
'file' => function ($context, $options) {
|
||||
if (count($context) && $context[0]) {
|
||||
$id = $context[0];
|
||||
return "?entryPoint=attachment&id=" . $id;
|
||||
}
|
||||
'file' => function () {
|
||||
$args = func_get_args();
|
||||
$id = $args[0] ?? null;
|
||||
if (!$id) return '';
|
||||
return "?entryPoint=attachment&id=" . $id;
|
||||
},
|
||||
'numberFormat' => function ($context, $options) {
|
||||
if ($context && isset($context[0])) {
|
||||
$number = $context[0];
|
||||
'var' => function () {
|
||||
$args = func_get_args();
|
||||
$c = $args[1] ?? [];
|
||||
$key = $args[0] ?? null;
|
||||
if (is_null($key)) return null;
|
||||
return $c[$key] ?? null;
|
||||
},
|
||||
'numberFormat' => function () {
|
||||
$args = func_get_args();
|
||||
if (count($args) !== 2) return null;
|
||||
$context = $args[count($args) - 1];
|
||||
$number = $args[0] ?? null;
|
||||
|
||||
$decimals = 0;
|
||||
$decimalPoint = '.';
|
||||
$thousandsSeparator = ',';
|
||||
if (is_null($number)) return '';
|
||||
|
||||
if (isset($options['decimals'])) {
|
||||
$decimals = $options['decimals'];
|
||||
}
|
||||
if (isset($options['decimalPoint'])) {
|
||||
$decimalPoint = $options['decimalPoint'];
|
||||
}
|
||||
if (isset($options['thousandsSeparator'])) {
|
||||
$thousandsSeparator = $options['thousandsSeparator'];
|
||||
}
|
||||
return number_format($number, $decimals, $decimalPoint, $thousandsSeparator);
|
||||
}
|
||||
return '';
|
||||
$decimals = $context['hash']['decimals'] ?? 0;
|
||||
$decimalPoint = $context['hash']['decimalPoint'] ?? '.';
|
||||
$thousandsSeparator = $context['hash']['thousandsSeparator'] ?? ',';
|
||||
|
||||
return number_format($number, $decimals, $decimalPoint, $thousandsSeparator);
|
||||
},
|
||||
'var' => function ($context, $options) {
|
||||
if ($context && isset($context[0]) && isset($context[1])) {
|
||||
if (isset($context[1][$context[0]])) {
|
||||
return $context[1][$context[0]];
|
||||
}
|
||||
}
|
||||
return;
|
||||
},
|
||||
],
|
||||
'hbhelpers' => [
|
||||
'dateFormat' => function () {
|
||||
$args = func_get_args();
|
||||
if (count($args) !== 2) return null;
|
||||
@@ -326,6 +318,54 @@ class Htmlizer
|
||||
|
||||
return $dateTime->convertSystemDate($dateValue, $format, $language);
|
||||
},
|
||||
'barcodeImage' => function () {
|
||||
$args = func_get_args();
|
||||
if (count($args) !== 2) return null;
|
||||
$context = $args[count($args) - 1];
|
||||
$value = $args[0];
|
||||
|
||||
$codeType = $context['hash']['type'] ?? 'CODE128';
|
||||
|
||||
$typeMap = [
|
||||
"CODE128" => 'C128',
|
||||
"CODE128A" => 'C128A',
|
||||
"CODE128B" => 'C128B',
|
||||
"CODE128C" => 'C128C',
|
||||
"EAN13" => 'EAN13',
|
||||
"EAN8" => 'EAN8',
|
||||
"EAN5" => 'EAN5',
|
||||
"EAN2" => 'EAN2',
|
||||
"UPC" => 'UPCA',
|
||||
"UPCE" => 'UPCE',
|
||||
"ITF14" => 'I25',
|
||||
"pharmacode" => 'PHARMA',
|
||||
];
|
||||
|
||||
$params = [
|
||||
$value,
|
||||
$typeMap[$codeType] ?? null,
|
||||
'', '',
|
||||
$context['hash']['width'] ?? 60,
|
||||
$context['hash']['height'] ?? 30,
|
||||
0.4,
|
||||
[
|
||||
'position' => 'S',
|
||||
'border' => false,
|
||||
'padding' => $context['hash']['padding'] ?? 0,
|
||||
'fgcolor' => $context['hash']['color'] ?? [0,0,0],
|
||||
'bgcolor' => $context['hash']['bgcolor'] ?? [255,255,255],
|
||||
'text' => $context['hash']['text'] ?? true,
|
||||
'font' => 'helvetica',
|
||||
'fontsize' => $context['hash']['fontsize'] ?? 14,
|
||||
'stretchtext' => 4,
|
||||
],
|
||||
'N',
|
||||
];
|
||||
|
||||
$paramsString = urlencode(json_encode($params));
|
||||
|
||||
return new LightnCandy\SafeString("<tcpdf method=\"write1DBarcode\" params=\"{$paramsString}\" />");
|
||||
},
|
||||
'ifEqual' => function () {
|
||||
$args = func_get_args();
|
||||
$context = $args[count($args) - 1];
|
||||
@@ -356,23 +396,10 @@ class Htmlizer
|
||||
return $context['inverse'] ? $context['inverse']() : '';
|
||||
}
|
||||
},
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
$toRemove = false;
|
||||
if ($id === null) {
|
||||
$id = uniqid('', true);
|
||||
$toRemove = true;
|
||||
}
|
||||
|
||||
$fileName = 'data/cache/templates/' . $id . '.php';
|
||||
|
||||
$this->fileManager->putContents($fileName, $code);
|
||||
$renderer = $this->fileManager->getPhpContents($fileName);
|
||||
|
||||
if ($toRemove) {
|
||||
$this->fileManager->removeFile($fileName);
|
||||
}
|
||||
$renderer = LightnCandy::prepare($code);
|
||||
|
||||
$data = $this->getDataFromEntity($entity, $skipLinks, 0, $template);
|
||||
|
||||
@@ -391,6 +418,7 @@ class Htmlizer
|
||||
}
|
||||
|
||||
$data['__dateTime'] = $this->dateTime;
|
||||
$data['__metadata'] = $this->metadata;
|
||||
|
||||
$html = $renderer($data);
|
||||
|
||||
|
||||
@@ -29,6 +29,36 @@
|
||||
|
||||
namespace Espo\Core\Pdf;
|
||||
|
||||
define('K_TCPDF_EXTERNAL_CONFIG', true);
|
||||
|
||||
define('K_TCPDF_CALLS_IN_HTML', true);
|
||||
|
||||
define('K_BLANK_IMAGE', '_blank.png');
|
||||
define('PDF_PAGE_FORMAT', 'A4');
|
||||
define('PDF_PAGE_ORIENTATION', 'P');
|
||||
define('PDF_CREATOR', 'TCPDF');
|
||||
define('PDF_AUTHOR', 'TCPDF');
|
||||
define('PDF_UNIT', 'mm');
|
||||
define('PDF_MARGIN_HEADER', 5);
|
||||
define('PDF_MARGIN_FOOTER', 10);
|
||||
define('PDF_MARGIN_TOP', 27);
|
||||
define('PDF_MARGIN_BOTTOM', 25);
|
||||
define('PDF_MARGIN_LEFT', 15);
|
||||
define('PDF_MARGIN_RIGHT', 15);
|
||||
define('PDF_FONT_NAME_MAIN', 'helvetica');
|
||||
define('PDF_FONT_SIZE_MAIN', 10);
|
||||
define('PDF_FONT_NAME_DATA', 'helvetica');
|
||||
define('PDF_FONT_SIZE_DATA', 8);
|
||||
define('PDF_FONT_MONOSPACED', 'courier');
|
||||
define('PDF_IMAGE_SCALE_RATIO', 1.25);
|
||||
define('HEAD_MAGNIFICATION', 1.1);
|
||||
define('K_CELL_HEIGHT_RATIO', 1.25);
|
||||
define('K_TITLE_MAGNIFICATION', 1.3);
|
||||
define('K_SMALL_RATIO', 2/3);
|
||||
define('K_THAI_TOPCHARS', true);
|
||||
define('K_TCPDF_THROW_EXCEPTION_ERROR', false);
|
||||
define('K_TIMEZONE', 'UTC');
|
||||
|
||||
require "vendor/tecnickcom/tcpdf/tcpdf.php";
|
||||
|
||||
use \TCPDF_STATIC;
|
||||
@@ -42,6 +72,16 @@ class Tcpdf extends \TCPDF
|
||||
|
||||
protected $useGroupNumbers = false;
|
||||
|
||||
public function serializeTCPDFtagParameters($data)
|
||||
{
|
||||
return urlencode(json_encode($data));
|
||||
}
|
||||
|
||||
protected function unserializeTCPDFtagParameters($data)
|
||||
{
|
||||
return json_decode(urldecode($data), true);
|
||||
}
|
||||
|
||||
public function setUseGroupNumbers($value)
|
||||
{
|
||||
$this->useGroupNumbers = $value;
|
||||
@@ -57,7 +97,8 @@ class Tcpdf extends \TCPDF
|
||||
$this->footerPosition = $position;
|
||||
}
|
||||
|
||||
public function Footer() {
|
||||
public function Footer()
|
||||
{
|
||||
$breakMargin = $this->getBreakMargin();
|
||||
$autoPageBreak = $this->AutoPageBreak;
|
||||
|
||||
@@ -80,7 +121,8 @@ class Tcpdf extends \TCPDF
|
||||
$this->SetAutoPageBreak($autoPageBreak, $breakMargin);
|
||||
}
|
||||
|
||||
protected function _putpages() {
|
||||
protected function _putpages()
|
||||
{
|
||||
$filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
|
||||
// get internal aliases for page numbers
|
||||
$pnalias = $this->getAllInternalPageNumberAliases();
|
||||
|
||||
@@ -135,6 +135,7 @@
|
||||
"number": "Number (auto-increment)",
|
||||
"colorpicker": "Color Picker",
|
||||
"checklist": "Checklist",
|
||||
"barcode": "Barcode",
|
||||
"jsonArray": "Json Array",
|
||||
"jsonObject": "Json Object"
|
||||
},
|
||||
@@ -194,6 +195,8 @@
|
||||
"maxCount": "Max Item Count",
|
||||
"accept": "Accept",
|
||||
"viewMap": "View Map Button",
|
||||
"codeType": "Code Type",
|
||||
"lastChar": "Last Character",
|
||||
"displayRawText": "Display raw text (no markdown)"
|
||||
},
|
||||
"messages": {
|
||||
|
||||
@@ -60,6 +60,15 @@
|
||||
"javascript: return this.dateTime.getDateShiftedFromToday(10, 'months');": "+10 months",
|
||||
"javascript: return this.dateTime.getDateShiftedFromToday(11, 'months');": "+11 months",
|
||||
"javascript: return this.dateTime.getDateShiftedFromToday(1, 'year');": "+1 year"
|
||||
},
|
||||
"barcodeType": {
|
||||
"EAN13": "EAN-13",
|
||||
"EAN8": "EAN-8",
|
||||
"EAN5": "EAN-5",
|
||||
"EAN2": "EAN-2",
|
||||
"UPC": "UPC (A)",
|
||||
"UPCE": "UPC (E)",
|
||||
"pharmacode": "Pharmacode"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -75,6 +84,7 @@
|
||||
"after": "The date value should be after the date value of the specified field.",
|
||||
"readOnly": "Field value can't be specified by user. But can be calculated by formula.",
|
||||
"fileAccept": "Which file types to accept. It's possible to add custom items.",
|
||||
"barcodeLastChar": "For EAN-13 type.",
|
||||
"maxFileSize": "If empty or 0 then no limit."
|
||||
},
|
||||
"fieldParts": {
|
||||
|
||||
@@ -43,5 +43,10 @@
|
||||
"path": "client/lib/exif-js.js",
|
||||
"exportsTo": "window",
|
||||
"exportsAs": "EXIF"
|
||||
},
|
||||
"JsBarcode": {
|
||||
"path": "client/lib/JsBarcode.all.min.js",
|
||||
"exportsTo": "window",
|
||||
"exportsAs": "JsBarcode"
|
||||
}
|
||||
}
|
||||
|
||||
50
application/Espo/Resources/metadata/fields/barcode.json
Normal file
50
application/Espo/Resources/metadata/fields/barcode.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"params": [
|
||||
{
|
||||
"name": "required",
|
||||
"type": "bool",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "codeType",
|
||||
"type": "enum",
|
||||
"options": [
|
||||
"CODE128",
|
||||
"CODE128A",
|
||||
"CODE128B",
|
||||
"CODE128C",
|
||||
"EAN13",
|
||||
"EAN8",
|
||||
"EAN5",
|
||||
"EAN2",
|
||||
"UPC",
|
||||
"UPCE",
|
||||
"ITF14",
|
||||
"pharmacode"
|
||||
],
|
||||
"translation": "FieldManager.options.barcodeType"
|
||||
},
|
||||
{
|
||||
"name": "lastChar",
|
||||
"type": "varchar",
|
||||
"maxLength": 1,
|
||||
"default": "",
|
||||
"tooltip": "barcodeLastChar"
|
||||
},
|
||||
{
|
||||
"name":"readOnly",
|
||||
"type":"bool"
|
||||
}
|
||||
],
|
||||
"validationList": [
|
||||
"required"
|
||||
],
|
||||
"filter": true,
|
||||
"textFilter": true,
|
||||
"textFilterForeign": true,
|
||||
"fieldDefs":{
|
||||
"type":"varchar",
|
||||
"len": 255
|
||||
},
|
||||
"validatorClassName": "Espo\\Core\\FieldValidators\\VarcharType"
|
||||
}
|
||||
2
client/lib/JsBarcode.all.min.js
vendored
Normal file
2
client/lib/JsBarcode.all.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
client/res/templates/fields/barcode/detail.tpl
Normal file
6
client/res/templates/fields/barcode/detail.tpl
Normal file
@@ -0,0 +1,6 @@
|
||||
{{#if isNotEmpty}}
|
||||
<svg class="barcode"></svg>
|
||||
|
||||
{{else}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/if}}
|
||||
102
client/src/views/fields/barcode.js
Normal file
102
client/src/views/fields/barcode.js
Normal file
@@ -0,0 +1,102 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2019 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/fields/barcode', ['views/fields/varchar', 'lib!JsBarcode'], function (Dep, JsBarcode) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
type: 'barcode',
|
||||
|
||||
listTemplate: 'fields/barcode/detail',
|
||||
|
||||
detailTemplate: 'fields/barcode/detail',
|
||||
|
||||
setup: function () {
|
||||
this.params.trim = true;
|
||||
|
||||
var maxLength = 255;
|
||||
|
||||
switch (this.params.codeType) {
|
||||
case 'EAN2':
|
||||
maxLength = 2; break;
|
||||
case 'EAN5':
|
||||
maxLength = 5; break;
|
||||
case 'EAN8':
|
||||
maxLength = 8; break;
|
||||
case 'EAN13':
|
||||
maxLength = 13; break;
|
||||
case 'UPC':
|
||||
maxLength = 12; break;
|
||||
case 'UPCE':
|
||||
maxLength = 11; break;
|
||||
case 'ITF14':
|
||||
maxLength = 14; break;
|
||||
case 'pharmacode':
|
||||
maxLength = 6; break;
|
||||
|
||||
}
|
||||
|
||||
this.params.maxLength = maxLength;
|
||||
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
$(window).on('resize.' + this.cid, function () {
|
||||
if (!this.isRendered()) return;
|
||||
this.controlWidth();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
onRemove: function () {
|
||||
$(window).off('resize.' + this.cid);
|
||||
},
|
||||
|
||||
|
||||
afterRender: function () {
|
||||
Dep.prototype.afterRender.call(this);
|
||||
|
||||
if (this.mode === 'list' || this.mode === 'detail') {
|
||||
var value = this.model.get(this.name);
|
||||
if (value) {
|
||||
JsBarcode(this.getSelector() + ' .barcode', value, {
|
||||
format: this.params.codeType,
|
||||
height: 50,
|
||||
fontSize: 14,
|
||||
margin: 0,
|
||||
lastChar: this.params.lastChar,
|
||||
});
|
||||
}
|
||||
this.controlWidth();
|
||||
}
|
||||
},
|
||||
|
||||
controlWidth: function () {
|
||||
this.$el.find('.barcode').css('max-width', this.$el.width() + 'px');
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
@@ -22,7 +22,7 @@
|
||||
"zendframework/zend-servicemanager": "3.3.2",
|
||||
"monolog/monolog": "1.*",
|
||||
"yzalis/identicon": "*",
|
||||
"zordius/lightncandy": "0.*",
|
||||
"zordius/lightncandy": "1.*",
|
||||
"composer/semver": "^1.4",
|
||||
"tecnickcom/tcpdf": "^6.2",
|
||||
"zbateson/mail-mime-parser": "1.1.*",
|
||||
|
||||
29
composer.lock
generated
29
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "58cf37fd7fae2d3b1889cdcc745eca1d",
|
||||
"content-hash": "29e70cca19d64159b8ffefaf04116a84",
|
||||
"packages": [
|
||||
{
|
||||
"name": "cboden/ratchet",
|
||||
@@ -3215,29 +3215,34 @@
|
||||
},
|
||||
{
|
||||
"name": "zordius/lightncandy",
|
||||
"version": "v0.21",
|
||||
"version": "v1.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zordius/lightncandy.git",
|
||||
"reference": "015fed62d0ae6fe7601d3910b8e4b6a6964f86a0"
|
||||
"reference": "dfdb910ae7b59e274f1ff97d29b724871f01b4cc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/zordius/lightncandy/zipball/015fed62d0ae6fe7601d3910b8e4b6a6964f86a0",
|
||||
"reference": "015fed62d0ae6fe7601d3910b8e4b6a6964f86a0",
|
||||
"url": "https://api.github.com/repos/zordius/lightncandy/zipball/dfdb910ae7b59e274f1ff97d29b724871f01b4cc",
|
||||
"reference": "dfdb910ae7b59e274f1ff97d29b724871f01b4cc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.0.17"
|
||||
"phpunit/phpunit": "^7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/lightncandy.php"
|
||||
]
|
||||
"psr-4": {
|
||||
"LightnCandy\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -3246,7 +3251,7 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Zordius Chen",
|
||||
"email": "zordius@yahoo-inc.com"
|
||||
"email": "zordius@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An extremely fast PHP implementation of handlebars ( http://handlebarsjs.com/ ) and mustache ( http://mustache.github.io/ ).",
|
||||
@@ -3258,7 +3263,7 @@
|
||||
"php",
|
||||
"template"
|
||||
],
|
||||
"time": "2015-05-08T01:56:46+00:00"
|
||||
"time": "2019-06-09T04:10:55+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
||||
Reference in New Issue
Block a user