Merge remote-tracking branch 'origin/develop'

Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/mix-manifest.json
This commit is contained in:
snipe 2023-08-15 18:21:51 +01:00
commit 28b1461cb4
50 changed files with 3629 additions and 142 deletions

View file

@ -2952,6 +2952,15 @@
"contributions": [
"code"
]
},
{
"login": "cram42",
"name": "Grant Le Roux",
"avatar_url": "https://avatars.githubusercontent.com/u/5396871?v=4",
"profile": "https://github.com/cram42",
"contributions": [
"code"
]
}
]
}

View file

@ -1,5 +1,5 @@
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=snipe/snipe-it&amp;utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-325-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
[![All Contributors](https://img.shields.io/badge/all_contributors-326-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
## Snipe-IT - Open Source Asset Management System
@ -145,7 +145,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/28321?v=4" width="110px;"/><br /><sub>Chris Hartjes</sub>](http://www.littlehart.net/atthekeyboard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chartjes "Code") | [<img src="https://avatars.githubusercontent.com/u/2404584?v=4" width="110px;"/><br /><sub>geo-chen</sub>](https://github.com/geo-chen)<br />[💻](https://github.com/snipe/snipe-it/commits?author=geo-chen "Code") | [<img src="https://avatars.githubusercontent.com/u/6006620?v=4" width="110px;"/><br /><sub>Phan Nguyen</sub>](https://github.com/nh314)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nh314 "Code") | [<img src="https://avatars.githubusercontent.com/u/115993812?v=4" width="110px;"/><br /><sub>Iisakki Jaakkola</sub>](https://github.com/StarlessNights)<br />[💻](https://github.com/snipe/snipe-it/commits?author=StarlessNights "Code") | [<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="110px;"/><br /><sub>Ikko Ashimine</sub>](https://bandism.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=eltociear "Code") | [<img src="https://avatars.githubusercontent.com/u/56871540?v=4" width="110px;"/><br /><sub>Lukas Fehling</sub>](https://github.com/lukasfehling)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lukasfehling "Code") | [<img src="https://avatars.githubusercontent.com/u/1975990?v=4" width="110px;"/><br /><sub>Fernando Almeida</sub>](https://github.com/fernando-almeida)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fernando-almeida "Code") |
| [<img src="https://avatars.githubusercontent.com/u/116301219?v=4" width="110px;"/><br /><sub>akemidx</sub>](https://github.com/akemidx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akemidx "Code") | [<img src="https://avatars.githubusercontent.com/u/144778?v=4" width="110px;"/><br /><sub>Oguz Bilgic</sub>](http://oguz.site)<br />[💻](https://github.com/snipe/snipe-it/commits?author=oguzbilgic "Code") | [<img src="https://avatars.githubusercontent.com/u/9262438?v=4" width="110px;"/><br /><sub>Scooter Crawford</sub>](https://github.com/scoo73r)<br />[💻](https://github.com/snipe/snipe-it/commits?author=scoo73r "Code") | [<img src="https://avatars.githubusercontent.com/u/5957345?v=4" width="110px;"/><br /><sub>subdriven</sub>](https://github.com/subdriven)<br />[💻](https://github.com/snipe/snipe-it/commits?author=subdriven "Code") | [<img src="https://avatars.githubusercontent.com/u/658865?v=4" width="110px;"/><br /><sub>Andrew Savinykh</sub>](https://github.com/AndrewSav)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AndrewSav "Code") | [<img src="https://avatars.githubusercontent.com/u/1155067?v=4" width="110px;"/><br /><sub>Tadayuki Onishi</sub>](https://kenchan0130.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kenchan0130 "Code") | [<img src="https://avatars.githubusercontent.com/u/112496896?v=4" width="110px;"/><br /><sub>Florian</sub>](https://github.com/floschoepfer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=floschoepfer "Code") |
| [<img src="https://avatars.githubusercontent.com/u/7305753?v=4" width="110px;"/><br /><sub>Spencer Long</sub>](http://spencerlong.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=spencerrlongg "Code") | [<img src="https://avatars.githubusercontent.com/u/1141514?v=4" width="110px;"/><br /><sub>Marcus Moore</sub>](https://github.com/marcusmoore)<br />[💻](https://github.com/snipe/snipe-it/commits?author=marcusmoore "Code") | [<img src="https://avatars.githubusercontent.com/u/570639?v=4" width="110px;"/><br /><sub>Martin Meredith</sub>](https://github.com/Mezzle)<br /> | [<img src="https://avatars.githubusercontent.com/u/5731963?v=4" width="110px;"/><br /><sub>dboth</sub>](http://dboth.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dboth "Code") | [<img src="https://avatars.githubusercontent.com/u/87536651?v=4" width="110px;"/><br /><sub>Zachary Fleck</sub>](https://github.com/zacharyfleck)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zacharyfleck "Code") | [<img src="https://avatars.githubusercontent.com/u/74609912?v=4" width="110px;"/><br /><sub>VIKAAS-A</sub>](https://github.com/vikaas-cyper)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vikaas-cyper "Code") | [<img src="https://avatars.githubusercontent.com/u/88882041?v=4" width="110px;"/><br /><sub>Abdul Kareem</sub>](https://github.com/ak-piracha)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ak-piracha "Code") |
| [<img src="https://avatars.githubusercontent.com/u/111287779?v=4" width="110px;"/><br /><sub>NojoudAlshehri</sub>](https://github.com/NojoudAlshehri)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") | [<img src="https://avatars.githubusercontent.com/u/54367449?v=4" width="110px;"/><br /><sub>Stefan Stidl</sub>](https://github.com/stefanstidlffg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [<img src="https://avatars.githubusercontent.com/u/87803479?v=4" width="110px;"/><br /><sub>Quentin Aymard</sub>](https://github.com/qay21)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/111287779?v=4" width="110px;"/><br /><sub>NojoudAlshehri</sub>](https://github.com/NojoudAlshehri)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") | [<img src="https://avatars.githubusercontent.com/u/54367449?v=4" width="110px;"/><br /><sub>Stefan Stidl</sub>](https://github.com/stefanstidlffg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [<img src="https://avatars.githubusercontent.com/u/87803479?v=4" width="110px;"/><br /><sub>Quentin Aymard</sub>](https://github.com/qay21)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") | [<img src="https://avatars.githubusercontent.com/u/5396871?v=4" width="110px;"/><br /><sub>Grant Le Roux</sub>](https://github.com/cram42)<br />[💻](https://github.com/snipe/snipe-it/commits?author=cram42 "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View file

@ -1220,10 +1220,60 @@ class Helper
return true;
\Log::debug('app locked!');
}
return false;
}
/**
* Conversion between units of measurement
*
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
* @since 5.0
* @param float $value Measurement value to convert
* @param string $srcUnit Source unit of measurement
* @param string $dstUnit Destination unit of measurement
* @param int $round Round the result to decimals (Default false - No rounding)
* @return float
*/
public static function convertUnit($value, $srcUnit, $dstUnit, $round=false) {
$srcFactor = static::getUnitConversionFactor($srcUnit);
$dstFactor = static::getUnitConversionFactor($dstUnit);
$output = $value * $srcFactor / $dstFactor;
return ($round !== false) ? round($output, $round) : $output;
}
/**
* Get conversion factor from unit of measurement to mm
*
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
* @since 5.0
* @param string $unit Unit of measurement
* @return float
*/
public static function getUnitConversionFactor($unit) {
switch (strtolower($unit)) {
case 'mm':
return 1.0;
case 'cm':
return 10.0;
case 'm':
return 1000.0;
case 'in':
return 25.4;
case 'ft':
return 12 * static::getUnitConversionFactor('in');
case 'yd':
return 3 * static::getUnitConversionFactor('ft');
case 'pt':
return (1 / 72) * static::getUnitConversionFactor('in');
default:
throw new \InvalidArgumentException('Unit: \'' . $unit . '\' is not supported');
return false;
}
}
/*
* I know it's gauche to return a shitty HTML string, but this is just a helper and since it will be the same every single time,

View file

@ -0,0 +1,71 @@
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Transformers\LabelsTransformer;
use App\Models\Labels\Label;
use Illuminate\Http\Request;
use Illuminate\Support\ItemNotFoundException;
use Auth;
class LabelsController extends Controller
{
/**
* Returns JSON listing of all labels.
*
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
* @return JsonResponse
*/
public function index(Request $request)
{
$this->authorize('view', Label::class);
$labels = Label::find();
if ($request->filled('search')) {
$search = $request->get('search');
$labels = $labels->filter(function ($label, $index) use ($search) {
return stripos($label->getName(), $search) !== false;
});
}
$total = $labels->count();
$offset = $request->get('offset', 0);
$offset = ($offset > $total) ? $total : $offset;
$maxLimit = config('app.max_results');
$limit = $request->get('limit', $maxLimit);
$limit = ($limit > $maxLimit) ? $maxLimit : $limit;
$labels = $labels->skip($offset)->take($limit);
return (new LabelsTransformer)->transformLabels($labels, $total, $request);
}
/**
* Returns JSON with information about a label for detail view.
*
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
* @param string $labelName
* @return JsonResponse
*/
public function show(string $labelName)
{
$labelName = str_replace('/', '\\', $labelName);
try {
$label = Label::find($labelName);
} catch(ItemNotFoundException $e) {
return response()
->json(
Helper::formatStandardApiResponse('error', null, trans('admin/labels/message.does_not_exist')),
404
);
}
$this->authorize('view', $label);
return (new LabelsTransformer)->transformLabel($label);
}
}

View file

@ -14,6 +14,7 @@ use App\Models\Location;
use App\Models\Setting;
use App\Models\Statuslabel;
use App\Models\User;
use App\View\Label;
use Auth;
use Carbon\Carbon;
use DB;
@ -453,11 +454,12 @@ class AssetsController extends Controller
* @since [v3.0]
* @return Redirect
*/
public function getAssetByTag(Request $request)
public function getAssetByTag(Request $request, $tag=null)
{
$tag = $tag ? $tag : $request->get('assetTag');
$topsearch = ($request->get('topsearch') == 'true');
if (! $asset = Asset::where('asset_tag', '=', $request->get('assetTag'))->first()) {
if (! $asset = Asset::where('asset_tag', '=', $tag)->first()) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('view', $asset);
@ -554,9 +556,11 @@ class AssetsController extends Controller
$asset = Asset::find($assetId);
$this->authorize('view', $asset);
return view('hardware/labels')
->with('assets', Asset::find($asset))
return (new Label())
->with('assets', collect([ $asset ]))
->with('settings', Setting::getSettings())
->with('template', request()->get('template'))
->with('offset', request()->get('offset'))
->with('bulkedit', false)
->with('count', 0);
}

View file

@ -8,6 +8,7 @@ use App\Http\Controllers\CheckInOutRequest;
use App\Http\Controllers\Controller;
use App\Models\Asset;
use App\Models\Setting;
use App\View\Label;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
@ -45,7 +46,7 @@ class BulkAssetsController extends Controller
switch ($request->input('bulk_actions')) {
case 'labels':
$this->authorize('view', Asset::class);
return view('hardware/labels')
return (new Label)
->with('assets', Asset::find($asset_ids))
->with('settings', Setting::getSettings())
->with('bulkedit', true)

View file

@ -0,0 +1,77 @@
<?php
namespace App\Http\Controllers;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\Company;
use App\Models\Labels\Label;
use App\Models\Manufacturer;
use App\Models\Setting;
use App\Models\User;
use App\View\Label as LabelView;
use Illuminate\Support\Facades\Storage;
class LabelsController extends Controller
{
/**
* Returns the Label view with test data
*
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
* @param string $labelName
* @return \Illuminate\Contracts\View\View
*/
public function show(string $labelName)
{
$labelName = str_replace('/', '\\', $labelName);
$template = Label::find($labelName);
$exampleAsset = new Asset();
$exampleAsset->id = 999999;
$exampleAsset->name = 'AST-AB-CD-1234';
$exampleAsset->asset_tag = 'TCA-00001';
$exampleAsset->serial = 'SN9876543210';
$exampleAsset->company = new Company();
$exampleAsset->company->id = 999999;
$exampleAsset->company->name = 'Test Company Limited';
$exampleAsset->company->image = 'company-image-test.png';
$exampleAsset->assignedto = new User();
$exampleAsset->assignedto->id = 999999;
$exampleAsset->assignedto->first_name = 'Test';
$exampleAsset->assignedto->last_name = 'Person';
$exampleAsset->assignedto->username = 'Test.Person';
$exampleAsset->assignedto->employee_num = '0123456789';
$exampleAsset->model = new AssetModel();
$exampleAsset->model->id = 999999;
$exampleAsset->model->name = 'Test Model';
$exampleAsset->model->model_number = 'MDL5678';
$exampleAsset->model->manufacturer = new Manufacturer();
$exampleAsset->model->manufacturer->id = 999999;
$exampleAsset->model->manufacturer->name = 'Test Manufacturing Inc.';
$exampleAsset->model->category = new Category();
$exampleAsset->model->category->id = 999999;
$exampleAsset->model->category->name = 'Test Category';
$settings = Setting::getSettings();
if (request()->has('settings')) {
$overrides = request()->get('settings');
foreach ($overrides as $key => $value) {
$settings->$key = $value;
}
}
return (new LabelView())
->with('assets', collect([$exampleAsset]))
->with('settings', $settings)
->with('template', $template)
->with('bulkedit', false)
->with('count', 0);
return redirect()->route('home')->with('error', trans('admin/labels/message.does_not_exist'));
}
}

View file

@ -827,6 +827,14 @@ class SettingsController extends Controller
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
$setting->label2_enable = $request->input('label2_enable');
$setting->label2_template = $request->input('label2_template');
$setting->label2_title = $request->input('label2_title');
$setting->label2_asset_logo = $request->input('label2_asset_logo');
$setting->label2_1d_type = $request->input('label2_1d_type');
$setting->label2_2d_type = $request->input('label2_2d_type');
$setting->label2_2d_target = $request->input('label2_2d_target');
$setting->label2_fields = $request->input('label2_fields');
$setting->labels_per_page = $request->input('labels_per_page');
$setting->labels_width = $request->input('labels_width');
$setting->labels_height = $request->input('labels_height');

View file

@ -0,0 +1,71 @@
<?php
namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Labels\Label;
use App\Models\Labels\Sheet;
use App\Models\Labels\RectangleSheet;
use Illuminate\Support\Collection;
class LabelsTransformer
{
public function transformLabels(Collection $labels, $total)
{
$array = [];
foreach ($labels as $label) {
$array[] = self::transformLabel($label);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
public function transformLabel(Label $label)
{
$array = [
'name' => $label->getName(),
'unit' => $label->getUnit(),
'width' => $label->getWidth(),
'height' => $label->getHeight(),
'margin_top' => $label->getMarginTop(),
'margin_bottom' => $label->getMarginBottom(),
'margin_left' => $label->getMarginLeft(),
'margin_right' => $label->getMarginRight(),
'support_asset_tag' => $label->getSupportAssetTag(),
'support_1d_barcode' => $label->getSupport1DBarcode(),
'support_2d_barcode' => $label->getSupport2DBarcode(),
'support_fields' => $label->getSupportFields(),
'support_logo' => $label->getSupportLogo(),
'support_title' => $label->getSupportTitle(),
];
if ($label instanceof Sheet) {
$array['sheet_info'] = [
'label_width' => $label->getLabelWidth(),
'label_height' => $label->getLabelHeight(),
'label_margin_top' => $label->getLabelMarginTop(),
'label_margin_bottom' => $label->getLabelMarginBottom(),
'label_margin_left' => $label->getLabelMarginLeft(),
'label_margin_right' => $label->getLabelMarginRight(),
'labels_per_page' => $label->getLabelsPerPage(),
'label_border' => $label->getLabelBorder(),
];
}
if ($label instanceof RectangleSheet) {
$array['rectanglesheet_info'] = [
'columns' => $label->getColumns(),
'rows' => $label->getRows(),
'column_spacing' => $label->getLabelColumnSpacing(),
'row_spacing' => $label->getLabelRowSpacing(),
];
}
return $array;
}
}

View file

@ -0,0 +1,224 @@
<?php
namespace App\Models\Labels;
use App\Helpers\Helper;
use App\Models\Setting;
class DefaultLabel extends RectangleSheet
{
private const BARCODE1D_SIZE = 0.15;
private const BARCODE2D_SIZE = 0.76;
private const BARCODE2D_MARGIN = 0.075;
private const LOGO_SIZE = [0.75, 0.50];
private const LOGO_MARGIN = 0.05;
private const TEXT_MARGIN = 0.04;
private float $textSize;
private float $labelWidth;
private float $labelHeight;
private float $labelSpacingH;
private float $labelSpacingV;
private float $pageMarginTop;
private float $pageMarginBottom;
private float $pageMarginLeft;
private float $pageMarginRight;
private float $pageWidth;
private float $pageHeight;
private int $columns;
private int $rows;
public function __construct() {
$settings = Setting::getSettings();
$this->textSize = Helper::convertUnit($settings->labels_fontsize, 'pt', 'in');
$this->labelWidth = $settings->labels_width;
$this->labelHeight = $settings->labels_height;
$this->labelSpacingH = $settings->labels_display_sgutter;
$this->labelSpacingV = $settings->labels_display_bgutter;
$this->pageMarginTop = $settings->labels_pmargin_top;
$this->pageMarginBottom = $settings->labels_pmargin_bottom;
$this->pageMarginLeft = $settings->labels_pmargin_left;
$this->pageMarginRight = $settings->labels_pmargin_right;
$this->pageWidth = $settings->labels_pagewidth;
$this->pageHeight = $settings->labels_pageheight;
$usableWidth = $this->pageWidth - $this->pageMarginLeft - $this->pageMarginRight;
$usableHeight = $this->pageHeight - $this->pageMarginTop - $this->pageMarginBottom;
$this->columns = ($usableWidth + $this->labelSpacingH) / ($this->labelWidth + $this->labelSpacingH);
$this->rows = ($usableHeight + $this->labelSpacingV) / ($this->labelHeight + $this->labelSpacingV);
}
public function getUnit() { return 'in'; }
public function getPageWidth() { return $this->pageWidth; }
public function getPageHeight() { return $this->pageHeight; }
public function getPageMarginTop() { return $this->pageMarginTop; }
public function getPageMarginBottom() { return $this->pageMarginBottom; }
public function getPageMarginLeft() { return $this->pageMarginLeft; }
public function getPageMarginRight() { return $this->pageMarginRight; }
public function getColumns() { return $this->columns; }
public function getRows() { return $this->rows; }
public function getLabelBorder() { return 0.01; }
public function getLabelWidth() { return $this->labelWidth; }
public function getLabelHeight() { return $this->labelHeight; }
public function getLabelMarginTop() { return 0; }
public function getLabelMarginBottom() { return 0; }
public function getLabelMarginLeft() { return 0; }
public function getLabelMarginRight() { return 0; }
public function getLabelColumnSpacing() { return $this->labelSpacingH; }
public function getLabelRowSpacing() { return $this->labelSpacingV; }
public function getSupportAssetTag() { return false; }
public function getSupport1DBarcode() { return true; }
public function getSupport2DBarcode() { return true; }
public function getSupportFields() { return 4; }
public function getSupportTitle() { return true; }
public function getSupportLogo() { return true; }
public function preparePDF($pdf) {}
public function write($pdf, $record) {
$asset = $record->get('asset');
$settings = Setting::getSettings();
$textY = 0;
$textX1 = 0;
$textX2 = $this->getLabelWidth();
// 1D Barcode
if ($record->get('barcode1d')) {
static::write1DBarcode(
$pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type,
0.05, $this->getLabelHeight() - self::BARCODE1D_SIZE,
$this->getLabelWidth() - 0.1, self::BARCODE1D_SIZE
);
}
// 2D Barcode
if ($record->get('barcode2d')) {
static::write2DBarcode(
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
0, 0, self::BARCODE2D_SIZE, self::BARCODE2D_SIZE
);
$textX1 += self::BARCODE2D_SIZE + self::BARCODE2D_MARGIN;
}
// Logo
if ($record->get('logo')) {
$logoSize = static::writeImage(
$pdf, $record->get('logo'),
$this->labelWidth - self::LOGO_SIZE[0], 0,
self::LOGO_SIZE[0], self::LOGO_SIZE[1],
'R', 'T', 300, true, false, 0
);
$textX2 -= ($logoSize[0] + self::LOGO_MARGIN);
}
$textW = $textX2 - $textX1;
// Title
if ($record->get('title')) {
static::writeText(
$pdf, $record->get('title'),
$textX1, 0,
'freesans', 'b', $this->textSize, 'L',
$textW, $this->textSize,
true, 0
);
$textY += $this->textSize + self::TEXT_MARGIN;
}
// Fields
$fieldsDone = 0;
if ($settings->labels_display_name && $fieldsDone < $this->getSupportFields()) {
if ($asset->name) {
static::writeText(
$pdf, 'N: '.$asset->name,
$textX1, $textY,
'freesans', '', $this->textSize, 'L',
$textW, $this->textSize,
true, 0
);
$textY += $this->textSize + self::TEXT_MARGIN;
$fieldsDone++;
}
}
if ($settings->labels_display_company_name && $fieldsDone < $this->getSupportFields()) {
if ($asset->company) {
static::writeText(
$pdf, 'C: '.$asset->company->name,
$textX1, $textY,
'freesans', '', $this->textSize, 'L',
$textW, $this->textSize,
true, 0
);
$textY += $this->textSize + self::TEXT_MARGIN;
$fieldsDone++;
}
}
if ($settings->labels_display_tag && $fieldsDone < $this->getSupportFields()) {
if ($asset->asset_tag) {
static::writeText(
$pdf, 'T: '.$asset->asset_tag,
$textX1, $textY,
'freesans', '', $this->textSize, 'L',
$textW, $this->textSize,
true, 0
);
$textY += $this->textSize + self::TEXT_MARGIN;
$fieldsDone++;
}
}
if ($settings->labels_display_serial && $fieldsDone < $this->getSupportFields()) {
if ($asset->serial) {
static::writeText(
$pdf, 'S: '.$asset->serial,
$textX1, $textY,
'freesans', '', $this->textSize, 'L',
$textW, $this->textSize,
true, 0
);
$textY += $this->textSize + self::TEXT_MARGIN;
$fieldsDone++;
}
}
if ($settings->labels_display_model && $fieldsDone < $this->getSupportFields()) {
if ($asset->model) {
static::writeText(
$pdf, 'M: '.$asset->model->name,
$textX1, $textY,
'freesans', '', $this->textSize, 'L',
$textW, $this->textSize,
true, 0
);
$textY += $this->textSize + self::TEXT_MARGIN;
$fieldsDone++;
}
}
}
}
?>

View file

@ -0,0 +1,39 @@
<?php
namespace App\Models\Labels;
use App\Models\Asset;
use Illuminate\Support\Collection;
class Field {
protected Collection $options;
public function getOptions() { return $this->options; }
public function setOptions($options) {
$tempCollect = collect($options);
if (!$tempCollect->contains(fn($o) => !is_subclass_of($o, FieldOption::class))) {
$this->options = $options;
}
}
public function toArray(Asset $asset) { return Field::makeArray($this, $asset); }
/* Statics */
public static function makeArray(Field $field, Asset $asset) {
return $field->getOptions()
->map(fn($option) => $option->toArray($asset))
->filter(fn($result) => $result['value'] != null);
}
public static function makeString(Field $option) {
return implode('|', $option->getOptions());
}
public static function fromString(string $theString) {
$field = new Field();
$field->options = collect(explode('|', $theString))
->filter(fn($optionString) => !empty($optionString))
->map(fn($optionString) => FieldOption::fromString($optionString));
return $field;
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace App\Models\Labels;
use App\Models\Asset;
use Illuminate\Support\Collection;
class FieldOption {
protected string $label;
public function getLabel() { return $this->label; }
protected string $dataSource;
public function getDataSource() { return $this->dataSource; }
public function getValue(Asset $asset) {
$dataPath = collect(explode('.', $this->dataSource));
return $dataPath->reduce(function ($myValue, $path) {
try { return $myValue ? $myValue->{$path} : ${$myValue}; }
catch (\Exception $e) { return $myValue; }
}, $asset);
}
public function toArray(Asset $asset=null) { return FieldOption::makeArray($this, $asset); }
public function toString() { return FieldOption::makeString($this); }
/* Statics */
public static function makeArray(FieldOption $option, Asset $asset=null) {
return [
'label' => $option->getLabel(),
'dataSource' => $option->getDataSource(),
'value' => $asset ? $option->getValue($asset) : null
];
}
public static function makeString(FieldOption $option) {
return $option->getLabel() . '=' . $option->getDataSource();
}
public static function fromString(string $theString) {
$parts = explode('=', $theString);
if (count($parts) == 2) {
$option = new FieldOption();
$option->label = $parts[0];
$option->dataSource = $parts[1];
return $option;
}
}
}

598
app/Models/Labels/Label.php Normal file
View file

@ -0,0 +1,598 @@
<?php
namespace App\Models\Labels;
use App\Helpers\Helper;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
use TCPDF;
use TCPDF_STATIC;
/**
* Model for Labels.
*
* @version v1.0
*/
abstract class Label
{
/**
* Returns the unit of measure used
* 'pt', 'mm', 'cm', 'in'
*
* @return string
*/
public abstract function getUnit();
/**
* Returns the label's width in getUnit() units
*
* @return float
*/
public abstract function getWidth();
/**
* Returns the label's height in getUnit() units
*
* @return float
*/
public abstract function getHeight();
/**
* Returns the label's top margin in getUnit() units
*
* @return float
*/
public abstract function getMarginTop();
/**
* Returns the label's bottom margin in getUnit() units
*
* @return float
*/
public abstract function getMarginBottom();
/**
* Returns the label's left margin in getUnit() units
*
* @return float
*/
public abstract function getMarginLeft();
/**
* Returns the label's right margin in getUnit() units
*
* @return float
*/
public abstract function getMarginRight();
/**
* Returns whether the template supports an asset tag.
*
* @return bool
*/
public abstract function getSupportAssetTag();
/**
* Returns whether the template supports a 1D barcode.
*
* @return bool
*/
public abstract function getSupport1DBarcode();
/**
* Returns whether the template supports a 2D barcode.
*
* @return bool
*/
public abstract function getSupport2DBarcode();
/**
* Returns the number of fields the template supports.
*
* @return int
*/
public abstract function getSupportFields();
/**
* Returns whether the template supports a logo.
*
* @return bool
*/
public abstract function getSupportLogo();
/**
* Returns whether the template supports a title.
*
* @return bool
*/
public abstract function getSupportTitle();
/**
* Make changes to the PDF properties here. OPTIONAL.
*
* @param TCPDF $pdf The TCPDF instance
*/
public abstract function preparePDF(TCPDF $pdf);
/**
* Write single data record as content here.
*
* @param TCPDF $pdf The TCPDF instance
* @param Collection $record A data record
*/
public abstract function write(TCPDF $pdf, Collection $record);
/**
* Handle the data here. Override for multiple-per-page handling
*
* @param TCPDF $pdf The TCPDF instance
* @param Collection $data The data
*/
public function writeAll(TCPDF $pdf, Collection $data) {
$data->each(function ($record, $index) use ($pdf) {
$pdf->AddPage();
$this->write($pdf, $record);
});
}
/**
* Returns the qualified class name relative to the Label class's namespace.
*
* @return string
*/
public final function getName() {
$refClass = new \ReflectionClass(Label::class);
return str_replace($refClass->getNamespaceName() . '\\', '', get_class($this));
}
/**
* Returns the label's orientation as a string.
* 'L' = Landscape
* 'P' = Portrait
*
* @return string
*/
public final function getOrientation() {
return ($this->getWidth() >= $this->getHeight()) ? 'L' : 'P';
}
/**
* Returns the label's printable area as an object.
*
* @return object [ 'x1'=>0.00, 'y1'=>0.00, 'x2'=>0.00, 'y2'=>0.00, 'w'=>0.00, 'h'=>0.00 ]
*/
public final function getPrintableArea() {
return (object)[
'x1' => $this->getMarginLeft(),
'y1' => $this->getMarginTop(),
'x2' => $this->getWidth() - $this->getMarginRight(),
'y2' => $this->getHeight() - $this->getMarginBottom(),
'w' => $this->getWidth() - $this->getMarginLeft() - $this->getMarginRight(),
'h' => $this->getHeight() - $this->getMarginTop() - $this->getMarginBottom(),
];
}
/**
* Write a text cell.
*
* @param TCPDF $pdf The TCPDF instance
* @param string $text The text to write. Supports 'some **bold** text'.
* @param float $x X position of top-left
* @param float $y Y position of top-left
* @param string $font The font family
* @param string $style The font style
* @param int $size The font size in getUnit() units
* @param string $align Align text in the box. 'L' left, 'R' right, 'C' center.
* @param float $width Force text box width. NULL to auto-fit.
* @param float $height Force text box height. NULL to auto-fit.
* @param bool $squash Squash text if it's too big
* @param int $border Thickness of border. Default = 0.
* @param int $spacing Letter spacing. Default = 0.
*/
public final function writeText(TCPDF $pdf, $text, $x, $y, $font=null, $style=null, $size=null, $align='L', $width=null, $height=null, $squash=false, $border=0, $spacing=0) {
$prevFamily = $pdf->getFontFamily();
$prevStyle = $pdf->getFontStyle();
$prevSizePt = $pdf->getFontSizePt();
$text = !empty($text) ? $text : '';
$fontFamily = !empty($font) ? $font : $prevFamily;
$fontStyle = !empty($style) ? $style : $prevStyle;
if ($size) $fontSizePt = Helper::convertUnit($size, $this->getUnit(), 'pt', true);
else $fontSizePt = $prevSizePt;
$pdf->SetFontSpacing($spacing);
$parts = collect(explode('**', $text))
->map(function ($part, $index) use ($pdf, $fontFamily, $fontStyle, $fontSizePt) {
$modStyle = ($index % 2 == 1) ? 'B' : $fontStyle;
$pdf->setFont($fontFamily, $modStyle, $fontSizePt);
return [
'text' => $part,
'text_width' => $pdf->GetStringWidth($part),
'font_family' => $fontFamily,
'font_style' => $modStyle,
'font_size' => $fontSizePt,
];
});
$textWidth = $parts->reduce(function ($carry, $part) { return $carry += $part['text_width']; });
$cellWidth = !empty($width) ? $width : $textWidth;
if ($squash && ($textWidth > 0)) {
$scaleFactor = min(1.0, $cellWidth / $textWidth);
$parts = $parts->map(function ($part, $index) use ($scaleFactor) {
$part['text_width'] = $part['text_width'] * $scaleFactor;
return $part;
});
}
$cellHeight = !empty($height) ? $height : Helper::convertUnit($fontSizePt, 'pt', $this->getUnit());
if ($border) {
$prevLineWidth = $pdf->getLineWidth();
$pdf->setLineWidth($border);
$pdf->Rect($x, $y, $cellWidth, $cellHeight);
$pdf->setLineWidth($prevLineWidth);
}
switch($align) {
case 'R': $startX = ($x + $cellWidth) - min($cellWidth, $textWidth); break;
case 'C': $startX = ($x + ($cellWidth / 2)) - (min($cellWidth, $textWidth) / 2); break;
case 'L':
default: $startX = $x; break;
}
$parts->reduce(function ($currentX, $part) use ($pdf, $y, $cellHeight) {
$pdf->SetXY($currentX, $y);
$pdf->setFont($part['font_family'], $part['font_style'], $part['font_size']);
$pdf->Cell($part['text_width'], $cellHeight, $part['text'], 0, 0, '', false, '', 1, true);
return $currentX += $part['text_width'];
}, $startX);
$pdf->SetFont($prevFamily, $prevStyle, $prevSizePt);
$pdf->SetFontSpacing(0);
}
/**
* Write an image.
*
* @param TCPDF $pdf The TCPDF instance
* @param string $image The image to write
* @param float $x X position of top-left
* @param float $y Y position of top-left
* @param float $width The container width
* @param float $height The container height
* @param string $halign Align text in the box. 'L' left, 'R' right, 'C' center. Default 'L'.
* @param string $valign Align text in the box. 'T' top, 'B' bottom, 'C' center. Default 'T'.
* @param int $dpi Pixels per inch
* @param bool $resize Resize to fit container
* @param bool $stretch Stretch (vs Scale) to fit container
* @param int $border Thickness of border. Default = 0.
*
* @return array Returns the final calculated size [w,h]
*/
public final function writeImage(TCPDF $pdf, $image, $x, $y, $width=null, $height=null, $halign='L', $valign='L', $dpi=300, $resize=false, $stretch=false, $border=0) {
if (empty($image)) return [0,0];
$imageInfo = getimagesize($image);
if (!$imageInfo) return [0,0]; // TODO: SVG or other
$imageWidthPx = $imageInfo[0];
$imageHeightPx = $imageInfo[1];
$imageType = image_type_to_extension($imageInfo[2], false);
$imageRatio = $imageWidthPx / $imageHeightPx;
$dpu = Helper::convertUnit($dpi, $this->getUnit(), 'in');
$imageWidth = $imageWidthPx / $dpu;
$imageHeight = $imageHeightPx / $dpu;
$outputWidth = $imageWidth;
$outputHeight = $imageHeight;
if ($resize) {
// Assign specified parameters
$limitWidth = $width;
$limitHeight = $height;
// If not, try calculating from the other dimension
$limitWidth = ($limitWidth > 0) ? $limitWidth : ($limitHeight / $imageRatio);
$limitHeight = ($limitHeight > 0) ? $limitHeight : ($limitWidth * $imageRatio);
// If not, just use the image size
$limitWidth = ($limitWidth > 0) ? $limitWidth : $imageWidth;
$limitHeight = ($limitHeight > 0) ? $limitHeight : $imageHeight;
$scaleWidth = $limitWidth / $imageWidth;
$scaleHeight = $limitHeight / $imageHeight;
// If non-stretch, make both scales factors equal
if (!$stretch) {
// Do we need to scale down at all? That's most important.
if (($scaleWidth < 1.0) || ($scaleHeight < 1.0)) {
// Choose largest scale-down
$scaleWidth = min($scaleWidth, $scaleHeight);
} else {
// Choose smallest scale-up
$scaleWidth = min(max($scaleWidth, 1.0), max($scaleHeight, 1.0));
}
$scaleHeight = $scaleWidth;
}
$outputWidth = $imageWidth * $scaleWidth;
$outputHeight = $imageHeight * $scaleHeight;
}
// Container
$containerWidth = !empty($width) ? $width : $outputWidth;
$containerHeight = !empty($height) ? $height : $outputHeight;
// Horizontal Position
switch ($halign) {
case 'R': $originX = ($x + $containerWidth) - $outputWidth; break;
case 'C': $originX = ($x + ($containerWidth / 2)) - ($outputWidth / 2); break;
case 'L':
default: $originX = $x; break;
}
// Vertical Position
switch ($valign) {
case 'B': $originY = ($y + $containerHeight) - $outputHeight; break;
case 'C': $originY = ($y + ($containerHeight / 2)) - ($outputHeight / 2); break;
case 'T':
default: $originY = $y; break;
}
// Actual Image
$pdf->Image($image, $originX, $originY, $outputWidth, $outputHeight, $imageType, '', '', true);
// Border
if ($border) {
$prevLineWidth = $pdf->getLineWidth();
$pdf->setLineWidth($border);
$pdf->Rect($x, $y, $containerWidth, $containerHeight);
$pdf->setLineWidth($prevLineWidth);
}
return [ $outputWidth, $outputHeight ];
}
/**
* Write a 1D barcode.
*
* @param TCPDF $pdf The TCPDF instance
* @param string $value The barcode content
* @param string $type The barcode type
* @param float $x X position of top-left
* @param float $y Y position of top-left
* @param float $width The container width
* @param float $height The container height
*/
public final function write1DBarcode(TCPDF $pdf, $value, $type, $x, $y, $width, $height) {
if (empty($value)) return;
$pdf->write1DBarcode($value, $type, $x, $y, $width, $height, null, ['stretch'=>true]);
}
/**
* Write a 2D barcode.
*
* @param TCPDF $pdf The TCPDF instance
* @param string $value The barcode content
* @param string $type The barcode type
* @param float $x X position of top-left
* @param float $y Y position of top-left
* @param float $width The container width
* @param float $height The container height
*/
public final function write2DBarcode(TCPDF $pdf, $value, $type, $x, $y, $width, $height) {
if (empty($value)) return;
$pdf->write2DBarcode($value, $type, $x, $y, $width, $height, null, ['stretch'=>true]);
}
/**
* Checks the template is internally valid
*/
public final function validate() {
$this->validateUnits();
$this->validateSize();
$this->validateMargins();
$this->validateSupport();
}
private function validateUnits() {
$validUnits = [ 'pt', 'mm', 'cm', 'in' ];
$unit = $this->getUnit();
if (!in_array(strtolower($unit), $validUnits)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_value', [
'name' => 'getUnit()',
'expected' => '[ \''.implode('\', \'', $validUnits).'\' ]',
'actual' => '\''.$unit.'\''
]));
}
}
private function validateSize() {
$width = $this->getWidth();
if (!is_numeric($width) || is_string($width)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getWidth()',
'expected' => 'float',
'actual' => gettype($width)
]));
}
$height = $this->getHeight();
if (!is_numeric($height) || is_string($height)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getHeight()',
'expected' => 'float',
'actual' => gettype($height)
]));
}
}
private function validateMargins() {
$marginTop = $this->getMarginTop();
if (!is_numeric($marginTop) || is_string($marginTop)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getMarginTop()',
'expected' => 'float',
'actual' => gettype($marginTop)
]));
}
$marginBottom = $this->getMarginBottom();
if (!is_numeric($marginBottom) || is_string($marginBottom)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getMarginBottom()',
'expected' => 'float',
'actual' => gettype($marginBottom)
]));
}
$marginLeft = $this->getMarginLeft();
if (!is_numeric($marginLeft) || is_string($marginLeft)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getMarginLeft()',
'expected' => 'float',
'actual' => gettype($marginLeft)
]));
}
$marginRight = $this->getMarginRight();
if (!is_numeric($marginRight) || is_string($marginRight)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getMarginRight()',
'expected' => 'float',
'actual' => gettype($marginRight)
]));
}
}
private function validateSupport() {
$support1D = $this->getSupport1DBarcode();
if (!is_bool($support1D)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getSupport1DBarcode()',
'expected' => 'boolean',
'actual' => gettype($support1D)
]));
}
$support2D = $this->getSupport2DBarcode();
if (!is_bool($support2D)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getSupport2DBarcode()',
'expected' => 'boolean',
'actual' => gettype($support2D)
]));
}
$supportFields = $this->getSupportFields();
if (!is_int($supportFields)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getSupportFields()',
'expected' => 'integer',
'actual' => gettype($supportFields)
]));
}
$supportLogo = $this->getSupportLogo();
if (!is_bool($supportLogo)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getSupportLogo()',
'expected' => 'boolean',
'actual' => gettype($supportLogo)
]));
}
$supportTitle = $this->getSupportTitle();
if (!is_bool($supportTitle)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
'name' => 'getSupportTitle()',
'expected' => 'boolean',
'actual' => gettype($supportTitle)
]));
}
}
/**
* Public Static Functions
*/
/**
* Find size of a page by its format.
*
* @param string $format Format name (eg: 'A4', 'LETTER', etc.)
* @param string $orientation 'L' for Landscape, 'P' for Portrait ('L' default)
* @param string $unit Unit of measure to return in ('mm' default)
*
* @return object (object)[ 'width' => (float)123.4, 'height' => (float)123.4 ]
*/
public static function fromFormat($format, $orientation='L', $unit='mm', $round=false) {
$size = collect(TCPDF_STATIC::getPageSizeFromFormat(strtoupper($format)))
->sort()
->map(function ($value) use ($unit) {
return Helper::convertUnit($value, 'pt', $unit);
})
->toArray();
$width = ($orientation == 'L') ? $size[1] : $size[0];
$height = ($orientation == 'L') ? $size[0] : $size[1];
return (object)[
'width' => ($round !== false) ? round($width, $round) : $width,
'height' => ($round !== false) ? round($height, $round) : $height,
];
}
/**
* Find a Label by its path (or just return them all).
*
* Unlike most Models, these are defined by their existence as non-
* abstract classes stored in Models\Labels.
*
* @param string|Arrayable|array|null $path Label path[s]
* @return Collection|Label|null
*/
public static function find($name=null) {
// Find many
if (is_array($name) || $name instanceof Arrayable) {
$labels = collect($name)
->map(function ($thisname) {
return static::find($thisname);
})
->whereNotNull();
return ($labels->count() > 0) ? $labels : null;
}
// Find one
if ($name !== null) {
return static::find()
->sole(function ($label) use ($name) {
return $label->getName() == $name;
});
}
// Find all
return collect(File::allFiles(__DIR__))
->map(function ($file) {
preg_match_all('/\/*(.+?)(?:\/|\.)/', $file->getRelativePathName(), $matches);
return __NAMESPACE__ . '\\' . implode('\\', $matches[1]);
})
->filter(function ($name) {
if (!class_exists($name)) return false;
$refClass = new \ReflectionClass($name);
if ($refClass->isAbstract()) return false;
return $refClass->isSubclassOf(Label::class);
})
->map(function ($name) {
return new $name();
});
}
}

View file

@ -0,0 +1,48 @@
<?php
namespace App\Models\Labels;
abstract class RectangleSheet extends Sheet
{
/**
* Returns the number of columns per sheet
*
* @return int
*/
public abstract function getColumns();
/**
* Returns the number of rows per sheet
*
* @return int
*/
public abstract function getRows();
/**
* Returns the spacing between columns
*
* @return int
*/
public abstract function getLabelColumnSpacing();
/**
* Returns the spacing between rows
*
* @return int
*/
public abstract function getLabelRowSpacing();
public function getLabelsPerPage() { return $this->getColumns() * $this->getRows(); }
public function getLabelPosition($index) {
$printIndex = $index + $this->getLabelIndexOffset();
$row = (int)($printIndex / $this->getColumns());
$col = $printIndex - ($row * $this->getColumns());
$x = $this->getPageMarginLeft() + (($this->getLabelWidth() + $this->getLabelColumnSpacing()) * $col);
$y = $this->getPageMarginTop() + (($this->getLabelHeight() + $this->getLabelRowSpacing()) * $row);
return [ $x, $y ];
}
}
?>

209
app/Models/Labels/Sheet.php Normal file
View file

@ -0,0 +1,209 @@
<?php
namespace App\Models\Labels;
abstract class Sheet extends Label
{
protected int $indexOffset = 0;
public function getWidth() { return $this->getPageWidth(); }
public function getHeight() { return $this->getPageHeight(); }
public function getMarginTop() { return $this->getPageMarginTop(); }
public function getMarginBottom() { return $this->getPageMarginBottom(); }
public function getMarginLeft() { return $this->getPageMarginLeft(); }
public function getMarginRight() { return $this->getPageMarginRight(); }
/**
* Returns the page width in getUnit() units
*
* @return float
*/
public abstract function getPageWidth();
/**
* Returns the page height in getUnit() units
*
* @return float
*/
public abstract function getPageHeight();
/**
* Returns the page top margin in getUnit() units
*
* @return float
*/
public abstract function getPageMarginTop();
/**
* Returns the page bottom margin in getUnit() units
*
* @return float
*/
public abstract function getPageMarginBottom();
/**
* Returns the page left margin in getUnit() units
*
* @return float
*/
public abstract function getPageMarginLeft();
/**
* Returns the page right margin in getUnit() units
*
* @return float
*/
public abstract function getPageMarginRight();
/**
* Returns the page width in getUnit() units
*
* @return float
*/
public abstract function getLabelWidth();
/**
* Returns each label's height in getUnit() units
*
* @return float
*/
public abstract function getLabelHeight();
/**
* Returns each label's top margin in getUnit() units
*
* @return float
*/
public abstract function getLabelMarginTop();
/**
* Returns each label's bottom margin in getUnit() units
*
* @return float
*/
public abstract function getLabelMarginBottom();
/**
* Returns each label's left margin in getUnit() units
*
* @return float
*/
public abstract function getLabelMarginLeft();
/**
* Returns each label's right margin in getUnit() units
*
* @return float
*/
public abstract function getLabelMarginRight();
/**
* Returns the number of labels each page supports
*
* @return int
*/
public abstract function getLabelsPerPage();
/**
* Returns label position based on its index
*
* @param int $index
*
* @return array [x,y]
*/
public abstract function getLabelPosition(int $index);
/**
* Returns the border to draw around labels
*
* @return int
*/
public abstract function getLabelBorder();
/**
* Handle the data here. Override for multiple-per-page handling
*
* @param TCPDF $pdf The TCPDF instance
* @param Collection $data The data
*/
public function writeAll($pdf, $data) {
$prevPageNumber = -1;
foreach ($data->toArray() as $recordIndex => $record) {
$pageNumber = (int)($recordIndex / $this->getLabelsPerPage());
if ($pageNumber != $prevPageNumber) {
$pdf->AddPage();
$prevPageNumber = $pageNumber;
}
$pageIndex = $recordIndex - ($this->getLabelsPerPage() * $pageNumber);
$position = $this->getLabelPosition($pageIndex);
$pdf->StartTemplate();
$this->write($pdf, $data->get($recordIndex));
$template = $pdf->EndTemplate();
$pdf->printTemplate($template, $position[0], $position[1]);
if ($this->getLabelBorder()) {
$prevLineWidth = $pdf->GetLineWidth();
$borderThickness = $this->getLabelBorder();
$borderOffset = $borderThickness / 2;
$borderX = $position[0]- $borderOffset;
$borderY = $position[1] - $borderOffset;
$borderW = $this->getLabelWidth() + $borderThickness;
$borderH = $this->getLabelHeight() + $borderThickness;
$pdf->setLineWidth($borderThickness);
$pdf->Rect($borderX, $borderY, $borderW, $borderH);
$pdf->setLineWidth($prevLineWidth);
}
}
}
/**
* Returns each label's orientation as a string.
* 'L' = Landscape
* 'P' = Portrait
*
* @return string
*/
public final function getLabelOrientation() {
return ($this->getLabelWidth() >= $this->getLabelHeight()) ? 'L' : 'P';
}
/**
* Returns each label's printable area as an object.
*
* @return object [ 'x1'=>0.00, 'y1'=>0.00, 'x2'=>0.00, 'y2'=>0.00, 'w'=>0.00, 'h'=>0.00 ]
*/
public final function getLabelPrintableArea() {
return (object)[
'x1' => $this->getLabelMarginLeft(),
'y1' => $this->getLabelMarginTop(),
'x2' => $this->getLabelWidth() - $this->getLabelMarginRight(),
'y2' => $this->getLabelHeight() - $this->getLabelMarginBottom(),
'w' => $this->getLabelWidth() - $this->getLabelMarginLeft() - $this->getLabelMarginRight(),
'h' => $this->getLabelHeight() - $this->getLabelMarginTop() - $this->getLabelMarginBottom(),
];
}
/**
* Returns label index offset (skip positions)
*
* @return int
*/
public function getLabelIndexOffset() { return $this->indexOffset; }
/**
* Sets label index offset (skip positions)
*
* @param int $offset
*
*/
public function setLabelIndexOffset(int $offset) { $this->indexOffset = $offset; }
}
?>

View file

@ -0,0 +1,71 @@
<?php
namespace App\Models\Labels\Sheets\Avery;
use App\Helpers\Helper;
use App\Models\Labels\RectangleSheet;
abstract class L7162 extends RectangleSheet
{
private const PAPER_FORMAT = 'A4';
private const PAPER_ORIENTATION = 'P';
/* Data in pt from Word Template */
private const COLUMN1_X = 13.25;
private const COLUMN2_X = 301.25;
private const ROW1_Y = 37.00;
private const ROW2_Y = 133.00;
private const LABEL_W = 280.80;
private const LABEL_H = 96.00;
private float $pageWidth;
private float $pageHeight;
private float $pageMarginLeft;
private float $pageMarginTop;
private float $columnSpacing;
private float $rowSpacing;
private float $labelWidth;
private float $labelHeight;
public function __construct() {
$paperSize = static::fromFormat(self::PAPER_FORMAT, self::PAPER_ORIENTATION, $this->getUnit(), 0);
$this->pageWidth = $paperSize->width;
$this->pageHeight = $paperSize->height;
$this->pageMarginLeft = Helper::convertUnit(self::COLUMN1_X, 'pt', $this->getUnit());
$this->pageMarginTop = Helper::convertUnit(self::ROW1_Y, 'pt', $this->getUnit());
$columnSpacingPt = self::COLUMN2_X - self::COLUMN1_X - self::LABEL_W;
$this->columnSpacing = Helper::convertUnit($columnSpacingPt, 'pt', $this->getUnit());
$rowSpacingPt = self::ROW2_Y - self::ROW1_Y - self::LABEL_H;
$this->rowSpacing = Helper::convertUnit($rowSpacingPt, 'pt', $this->getUnit());
$this->labelWidth = Helper::convertUnit(self::LABEL_W, 'pt', $this->getUnit());
$this->labelHeight = Helper::convertUnit(self::LABEL_H, 'pt', $this->getUnit());
}
public function getPageWidth() { return $this->pageWidth; }
public function getPageHeight() { return $this->pageHeight; }
public function getPageMarginTop() { return $this->pageMarginTop; }
public function getPageMarginBottom() { return $this->pageMarginTop; }
public function getPageMarginLeft() { return $this->pageMarginLeft; }
public function getPageMarginRight() { return $this->pageMarginLeft; }
public function getColumns() { return 2; }
public function getRows() { return 8; }
public function getLabelColumnSpacing() { return $this->columnSpacing; }
public function getLabelRowSpacing() { return $this->rowSpacing; }
public function getLabelWidth() { return $this->labelWidth; }
public function getLabelHeight() { return $this->labelHeight; }
public function getLabelBorder() { return 0; }
}
?>

View file

@ -0,0 +1,100 @@
<?php
namespace App\Models\Labels\Sheets\Avery;
class L7162_A extends L7162
{
private const BARCODE_MARGIN = 1.60;
private const TAG_SIZE = 4.60;
private const TITLE_SIZE = 4.20;
private const TITLE_MARGIN = 1.40;
private const LABEL_SIZE = 2.20;
private const LABEL_MARGIN = - 0.50;
private const FIELD_SIZE = 4.60;
private const FIELD_MARGIN = 0.30;
public function getUnit() { return 'mm'; }
public function getLabelMarginTop() { return 1.0; }
public function getLabelMarginBottom() { return 1.0; }
public function getLabelMarginLeft() { return 1.0; }
public function getLabelMarginRight() { return 1.0; }
public function getSupportAssetTag() { return true; }
public function getSupport1DBarcode() { return false; }
public function getSupport2DBarcode() { return true; }
public function getSupportFields() { return 4; }
public function getSupportLogo() { return false; }
public function getSupportTitle() { return true; }
public function preparePDF($pdf) {}
public function write($pdf, $record) {
$pa = $this->getLabelPrintableArea();
$usableWidth = $pa->w;
$usableHeight = $pa->h;
$currentX = $pa->x1;
$currentY = $pa->y1;
$titleShiftX = 0;
$barcodeSize = $pa->h - self::TAG_SIZE;
if ($record->has('barcode2d')) {
static::writeText(
$pdf, $record->get('tag'),
$pa->x1, $pa->y2 - self::TAG_SIZE,
'freemono', 'b', self::TAG_SIZE, 'C',
$barcodeSize, self::TAG_SIZE, true, 0
);
static::write2DBarcode(
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
$pa->x1, $pa->y1,
$barcodeSize, $barcodeSize
);
$currentX += $barcodeSize + self::BARCODE_MARGIN;
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
} else {
static::writeText(
$pdf, $record->get('tag'),
$pa->x1, $pa->y1,
'freemono', 'b', self::TITLE_SIZE, 'L',
$barcodeSize, self::TITLE_SIZE, true, 0
);
$titleShiftX = $barcodeSize;
}
if ($record->has('title')) {
static::writeText(
$pdf, $record->get('title'),
$currentX + $titleShiftX, $currentY,
'freesans', '', self::TITLE_SIZE, 'L',
$usableWidth, self::TITLE_SIZE, true, 0
);
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
}
foreach ($record->get('fields') as $field) {
static::writeText(
$pdf, $field['label'],
$currentX, $currentY,
'freesans', '', self::LABEL_SIZE, 'L',
$usableWidth, self::LABEL_SIZE, true, 0
);
$currentY += self::LABEL_SIZE + self::LABEL_MARGIN;
static::writeText(
$pdf, $field['value'],
$currentX, $currentY,
'freemono', 'B', self::FIELD_SIZE, 'L',
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
);
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
}
}
}
?>

View file

@ -0,0 +1,103 @@
<?php
namespace App\Models\Labels\Sheets\Avery;
class L7162_B extends L7162
{
private const BARCODE_SIZE = 6.00;
private const BARCODE_MARGIN = 1.40;
private const TAG_SIZE = 3.20;
private const LOGO_MAX_WIDTH = 25.00;
private const LOGO_MARGIN = 2.20;
private const TITLE_SIZE = 4.20;
private const TITLE_MARGIN = 1.20;
private const LABEL_SIZE = 2.20;
private const LABEL_MARGIN = - 0.50;
private const FIELD_SIZE = 4.20;
private const FIELD_MARGIN = 0.30;
public function getUnit() { return 'mm'; }
public function getLabelMarginTop() { return 1.0; }
public function getLabelMarginBottom() { return 0; }
public function getLabelMarginLeft() { return 1.0; }
public function getLabelMarginRight() { return 1.0; }
public function getSupportAssetTag() { return true; }
public function getSupport1DBarcode() { return true; }
public function getSupport2DBarcode() { return false; }
public function getSupportFields() { return 3; }
public function getSupportLogo() { return true; }
public function getSupportTitle() { return true; }
public function preparePDF($pdf) {}
public function write($pdf, $record) {
$pa = $this->getLabelPrintableArea();
$usableWidth = $pa->w;
$usableHeight = $pa->h;
$currentX = $pa->x1;
$currentY = $pa->y1;
if ($record->has('barcode1d')) {
static::write1DBarcode(
$pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type,
$pa->x1, $pa->y2 - self::BARCODE_SIZE,
$usableWidth, self::BARCODE_SIZE
);
$usableHeight -= self::BARCODE_SIZE + self::BARCODE_MARGIN;
}
if ($record->has('logo')) {
$logoSize = static::writeImage(
$pdf, $record->get('logo'),
$pa->x1, $pa->y1,
self::LOGO_MAX_WIDTH, $usableHeight,
'L', 'T', 300, true, false, 0.1
);
$currentX += $logoSize[0] + self::LOGO_MARGIN;
$usableWidth -= $logoSize[0] + self::LOGO_MARGIN;
}
if ($record->has('title')) {
static::writeText(
$pdf, $record->get('title'),
$currentX, $currentY,
'freesans', '', self::TITLE_SIZE, 'L',
$usableWidth, self::TITLE_SIZE, true, 0
);
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
}
foreach ($record->get('fields') as $field) {
static::writeText(
$pdf, $field['label'],
$currentX, $currentY,
'freesans', '', self::LABEL_SIZE, 'L',
$usableWidth, self::LABEL_SIZE, true, 0
);
$currentY += self::LABEL_SIZE + self::LABEL_MARGIN;
static::writeText(
$pdf, $field['value'],
$currentX, $currentY,
'freemono', 'B', self::FIELD_SIZE, 'L',
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
);
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
}
static::writeText(
$pdf, $record->get('tag'),
$currentX, $pa->y2 - self::BARCODE_SIZE - self::BARCODE_MARGIN - self::TAG_SIZE,
'freemono', 'b', self::TAG_SIZE, 'R',
$usableWidth, self::TAG_SIZE, true, 0, 0.3
);
}
}
?>

View file

@ -0,0 +1,71 @@
<?php
namespace App\Models\Labels\Sheets\Avery;
use App\Helpers\Helper;
use App\Models\Labels\RectangleSheet;
abstract class L7163 extends RectangleSheet
{
private const PAPER_FORMAT = 'A4';
private const PAPER_ORIENTATION = 'P';
/* Data in pt from Word Template */
private const COLUMN1_X = 13.25;
private const COLUMN2_X = 301.25;
private const ROW1_Y = 43.05;
private const ROW2_Y = 151.05;
private const LABEL_W = 280.80;
private const LABEL_H = 108.00;
private float $pageWidth;
private float $pageHeight;
private float $pageMarginLeft;
private float $pageMarginTop;
private float $columnSpacing;
private float $rowSpacing;
private float $labelWidth;
private float $labelHeight;
public function __construct() {
$paperSize = static::fromFormat(self::PAPER_FORMAT, self::PAPER_ORIENTATION, $this->getUnit(), 0);
$this->pageWidth = $paperSize->width;
$this->pageHeight = $paperSize->height;
$this->pageMarginLeft = Helper::convertUnit(self::COLUMN1_X, 'pt', $this->getUnit());
$this->pageMarginTop = Helper::convertUnit(self::ROW1_Y, 'pt', $this->getUnit());
$columnSpacingPt = self::COLUMN2_X - self::COLUMN1_X - self::LABEL_W;
$this->columnSpacing = Helper::convertUnit($columnSpacingPt, 'pt', $this->getUnit());
$rowSpacingPt = self::ROW2_Y - self::ROW1_Y - self::LABEL_H;
$this->rowSpacing = Helper::convertUnit($rowSpacingPt, 'pt', $this->getUnit());
$this->labelWidth = Helper::convertUnit(self::LABEL_W, 'pt', $this->getUnit());
$this->labelHeight = Helper::convertUnit(self::LABEL_H, 'pt', $this->getUnit());
}
public function getPageWidth() { return $this->pageWidth; }
public function getPageHeight() { return $this->pageHeight; }
public function getPageMarginTop() { return $this->pageMarginTop; }
public function getPageMarginBottom() { return $this->pageMarginTop; }
public function getPageMarginLeft() { return $this->pageMarginLeft; }
public function getPageMarginRight() { return $this->pageMarginLeft; }
public function getColumns() { return 2; }
public function getRows() { return 7; }
public function getLabelColumnSpacing() { return $this->columnSpacing; }
public function getLabelRowSpacing() { return $this->rowSpacing; }
public function getLabelWidth() { return $this->labelWidth; }
public function getLabelHeight() { return $this->labelHeight; }
public function getLabelBorder() { return 0; }
}
?>

View file

@ -0,0 +1,98 @@
<?php
namespace App\Models\Labels\Sheets\Avery;
class L7163_A extends L7163
{
private const BARCODE_MARGIN = 1.80;
private const TAG_SIZE = 4.80;
private const TITLE_SIZE = 5.00;
private const TITLE_MARGIN = 1.80;
private const LABEL_SIZE = 2.35;
private const LABEL_MARGIN = - 0.30;
private const FIELD_SIZE = 4.80;
private const FIELD_MARGIN = 0.30;
public function getUnit() { return 'mm'; }
public function getLabelMarginTop() { return 1.0; }
public function getLabelMarginBottom() { return 1.0; }
public function getLabelMarginLeft() { return 1.0; }
public function getLabelMarginRight() { return 1.0; }
public function getSupportAssetTag() { return true; }
public function getSupport1DBarcode() { return false; }
public function getSupport2DBarcode() { return true; }
public function getSupportFields() { return 4; }
public function getSupportLogo() { return false; }
public function getSupportTitle() { return true; }
public function preparePDF($pdf) {}
public function write($pdf, $record) {
$pa = $this->getLabelPrintableArea();
$usableWidth = $pa->w;
$usableHeight = $pa->h;
$currentX = $pa->x1;
$currentY = $pa->y1;
if ($record->has('title')) {
static::writeText(
$pdf, $record->get('title'),
$currentX, $currentY,
'freesans', '', self::TITLE_SIZE, 'C',
$usableWidth, self::TITLE_SIZE, true, 0
);
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
}
$barcodeSize = $pa->h - self::TITLE_SIZE - self::TITLE_MARGIN - self::TAG_SIZE;
if ($record->has('barcode2d')) {
static::writeText(
$pdf, $record->get('tag'),
$pa->x1, $pa->y2 - self::TAG_SIZE,
'freemono', 'b', self::TAG_SIZE, 'C',
$barcodeSize, self::TAG_SIZE, true, 0
);
static::write2DBarcode(
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
$pa->x1, $currentY,
$barcodeSize, $barcodeSize
);
$currentX += $barcodeSize + self::BARCODE_MARGIN;
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
} else {
static::writeText(
$pdf, $record->get('tag'),
$pa->x1, $pa->y2 - self::TAG_SIZE,
'freemono', 'b', self::TAG_SIZE, 'R',
$usableWidth, self::TAG_SIZE, true, 0
);
}
foreach ($record->get('fields') as $field) {
static::writeText(
$pdf, $field['label'],
$currentX, $currentY,
'freesans', '', self::LABEL_SIZE, 'L',
$usableWidth, self::LABEL_SIZE, true, 0
);
$currentY += self::LABEL_SIZE + self::LABEL_MARGIN;
static::writeText(
$pdf, $field['value'],
$currentX, $currentY,
'freemono', 'B', self::FIELD_SIZE, 'L',
$usableWidth, self::FIELD_SIZE, true, 0, 0.5
);
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
}
}
}
?>

View file

@ -0,0 +1,71 @@
<?php
namespace App\Models\Labels\Sheets\Avery;
use App\Helpers\Helper;
use App\Models\Labels\RectangleSheet;
abstract class _5267 extends RectangleSheet
{
private const PAPER_FORMAT = 'LETTER';
private const PAPER_ORIENTATION = 'P';
/* Data in pt from Word Template */
private const COLUMN1_X = 21.60;
private const COLUMN2_X = 169.20;
private const ROW1_Y = 36.10;
private const ROW2_Y = 72.10;
private const LABEL_W = 126.00;
private const LABEL_H = 36.00;
private float $pageWidth;
private float $pageHeight;
private float $pageMarginLeft;
private float $pageMarginTop;
private float $columnSpacing;
private float $rowSpacing;
private float $labelWidth;
private float $labelHeight;
public function __construct() {
$paperSize = static::fromFormat(self::PAPER_FORMAT, self::PAPER_ORIENTATION, $this->getUnit(), 2);
$this->pageWidth = $paperSize->width;
$this->pageHeight = $paperSize->height;
$this->pageMarginLeft = Helper::convertUnit(self::COLUMN1_X, 'pt', $this->getUnit());
$this->pageMarginTop = Helper::convertUnit(self::ROW1_Y, 'pt', $this->getUnit());
$columnSpacingPt = self::COLUMN2_X - self::COLUMN1_X - self::LABEL_W;
$this->columnSpacing = Helper::convertUnit($columnSpacingPt, 'pt', $this->getUnit());
$rowSpacingPt = self::ROW2_Y - self::ROW1_Y - self::LABEL_H;
$this->rowSpacing = Helper::convertUnit($rowSpacingPt, 'pt', $this->getUnit());
$this->labelWidth = Helper::convertUnit(self::LABEL_W, 'pt', $this->getUnit());
$this->labelHeight = Helper::convertUnit(self::LABEL_H, 'pt', $this->getUnit());
}
public function getPageWidth() { return $this->pageWidth; }
public function getPageHeight() { return $this->pageHeight; }
public function getPageMarginTop() { return $this->pageMarginTop; }
public function getPageMarginBottom() { return $this->pageMarginTop; }
public function getPageMarginLeft() { return $this->pageMarginLeft; }
public function getPageMarginRight() { return $this->pageMarginLeft; }
public function getColumns() { return 4; }
public function getRows() { return 20; }
public function getLabelColumnSpacing() { return $this->columnSpacing; }
public function getLabelRowSpacing() { return $this->rowSpacing; }
public function getLabelWidth() { return $this->labelWidth; }
public function getLabelHeight() { return $this->labelHeight; }
public function getLabelBorder() { return 0; }
}
?>

View file

@ -0,0 +1,68 @@
<?php
namespace App\Models\Labels\Sheets\Avery;
class _5267_A extends _5267
{
private const BARCODE_SIZE = 0.175;
private const BARCODE_MARGIN = 0.000;
private const TAG_SIZE = 0.125;
private const TITLE_SIZE = 0.140;
private const FIELD_SIZE = 0.150;
private const FIELD_MARGIN = 0.012;
public function getUnit() { return 'in'; }
public function getLabelMarginTop() { return 0.02; }
public function getLabelMarginBottom() { return 0.00; }
public function getLabelMarginLeft() { return 0.04; }
public function getLabelMarginRight() { return 0.04; }
public function getSupportAssetTag() { return false; }
public function getSupport1DBarcode() { return true; }
public function getSupport2DBarcode() { return false; }
public function getSupportFields() { return 1; }
public function getSupportLogo() { return false; }
public function getSupportTitle() { return true; }
public function preparePDF($pdf) {}
public function write($pdf, $record) {
$pa = $this->getLabelPrintableArea();
if ($record->has('barcode1d')) {
static::write1DBarcode(
$pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type,
$pa->x1, $pa->y2 - self::BARCODE_SIZE,
$pa->w, self::BARCODE_SIZE
);
}
if ($record->has('title')) {
static::writeText(
$pdf, $record->get('title'),
$pa->x1, $pa->y1,
'freesans', '', self::TITLE_SIZE, 'L',
$pa->w, self::TITLE_SIZE, true, 0
);
}
$fieldY = $pa->y2 - self::BARCODE_SIZE - self::BARCODE_MARGIN - self::FIELD_SIZE;
if ($record->has('fields')) {
if ($record->get('fields')->count() >= 1) {
$field = $record->get('fields')->first();
static::writeText(
$pdf, $field['value'],
$pa->x1, $fieldY,
'freemono', 'B', self::FIELD_SIZE, 'C',
$pa->w, self::FIELD_SIZE, true, 0, 0.01
);
}
}
}
}
?>

View file

@ -0,0 +1,71 @@
<?php
namespace App\Models\Labels\Sheets\Avery;
use App\Helpers\Helper;
use App\Models\Labels\RectangleSheet;
abstract class _5520 extends RectangleSheet
{
private const PAPER_FORMAT = 'LETTER';
private const PAPER_ORIENTATION = 'P';
/* Data in pt from Word Template */
private const COLUMN1_X = 13.55;
private const COLUMN2_X = 211.55;
private const ROW1_Y = 36.10;
private const ROW2_Y = 108.10;
private const LABEL_W = 189.35;
private const LABEL_H = 72.00;
private float $pageWidth;
private float $pageHeight;
private float $pageMarginLeft;
private float $pageMarginTop;
private float $columnSpacing;
private float $rowSpacing;
private float $labelWidth;
private float $labelHeight;
public function __construct() {
$paperSize = static::fromFormat(self::PAPER_FORMAT, self::PAPER_ORIENTATION, $this->getUnit(), 2);
$this->pageWidth = $paperSize->width;
$this->pageHeight = $paperSize->height;
$this->pageMarginLeft = Helper::convertUnit(self::COLUMN1_X, 'pt', $this->getUnit());
$this->pageMarginTop = Helper::convertUnit(self::ROW1_Y, 'pt', $this->getUnit());
$columnSpacingPt = self::COLUMN2_X - self::COLUMN1_X - self::LABEL_W;
$this->columnSpacing = Helper::convertUnit($columnSpacingPt, 'pt', $this->getUnit());
$rowSpacingPt = self::ROW2_Y - self::ROW1_Y - self::LABEL_H;
$this->rowSpacing = Helper::convertUnit($rowSpacingPt, 'pt', $this->getUnit());
$this->labelWidth = Helper::convertUnit(self::LABEL_W, 'pt', $this->getUnit());
$this->labelHeight = Helper::convertUnit(self::LABEL_H, 'pt', $this->getUnit());
}
public function getPageWidth() { return $this->pageWidth; }
public function getPageHeight() { return $this->pageHeight; }
public function getPageMarginTop() { return $this->pageMarginTop; }
public function getPageMarginBottom() { return $this->pageMarginTop; }
public function getPageMarginLeft() { return $this->pageMarginLeft; }
public function getPageMarginRight() { return $this->pageMarginLeft; }
public function getColumns() { return 3; }
public function getRows() { return 10; }
public function getLabelColumnSpacing() { return $this->columnSpacing; }
public function getLabelRowSpacing() { return $this->rowSpacing; }
public function getLabelWidth() { return $this->labelWidth; }
public function getLabelHeight() { return $this->labelHeight; }
public function getLabelBorder() { return 0; }
}
?>

View file

@ -0,0 +1,85 @@
<?php
namespace App\Models\Labels\Sheets\Avery;
class _5520_A extends _5520
{
private const BARCODE_MARGIN = 0.075;
private const TAG_SIZE = 0.125;
private const TITLE_SIZE = 0.140;
private const TITLE_MARGIN = 0.040;
private const LABEL_SIZE = 0.090;
private const LABEL_MARGIN = -0.015;
private const FIELD_SIZE = 0.150;
private const FIELD_MARGIN = 0.012;
public function getUnit() { return 'in'; }
public function getLabelMarginTop() { return 0.06; }
public function getLabelMarginBottom() { return 0.06; }
public function getLabelMarginLeft() { return 0.06; }
public function getLabelMarginRight() { return 0.06; }
public function getSupportAssetTag() { return false; }
public function getSupport1DBarcode() { return false; }
public function getSupport2DBarcode() { return true; }
public function getSupportFields() { return 3; }
public function getSupportLogo() { return false; }
public function getSupportTitle() { return true; }
public function preparePDF($pdf) {}
public function write($pdf, $record) {
$pa = $this->getLabelPrintableArea();
$currentX = $pa->x1;
$currentY = $pa->y1;
$usableWidth = $pa->w;
$usableHeight = $pa->h;
if ($record->has('title')) {
static::writeText(
$pdf, $record->get('title'),
$pa->x1, $pa->y1,
'freesans', '', self::TITLE_SIZE, 'C',
$pa->w, self::TITLE_SIZE, true, 0
);
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
$usableHeight -= self::TITLE_SIZE + self::TITLE_MARGIN;
}
$barcodeSize = $usableHeight;
if ($record->has('barcode2d')) {
static::write2DBarcode(
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
$currentX, $currentY,
$barcodeSize, $barcodeSize
);
$currentX += $barcodeSize + self::BARCODE_MARGIN;
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
}
foreach ($record->get('fields') as $field) {
static::writeText(
$pdf, $field['label'],
$currentX, $currentY,
'freesans', '', self::LABEL_SIZE, 'L',
$usableWidth, self::LABEL_SIZE, true, 0
);
$currentY += self::LABEL_SIZE + self::LABEL_MARGIN;
static::writeText(
$pdf, $field['value'],
$currentX, $currentY,
'freemono', 'B', self::FIELD_SIZE, 'L',
$usableWidth, self::FIELD_SIZE, true, 0, 0.01
);
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
}
}
}
?>

View file

@ -0,0 +1,19 @@
<?php
namespace App\Models\Labels\Tapes\Brother;
use App\Helpers\Helper;
use App\Models\Labels\Label;
abstract class TZe_12mm extends Label
{
private const HEIGHT = 12.00;
private const MARGIN_SIDES = 3.20;
private const MARGIN_ENDS = 3.20;
public function getHeight() { return Helper::convertUnit(self::HEIGHT, 'mm', $this->getUnit()); }
public function getMarginTop() { return Helper::convertUnit(self::MARGIN_SIDES, 'mm', $this->getUnit()); }
public function getMarginBottom() { return Helper::convertUnit(self::MARGIN_SIDES, 'mm', $this->getUnit());}
public function getMarginLeft() { return Helper::convertUnit(self::MARGIN_ENDS, 'mm', $this->getUnit()); }
public function getMarginRight() { return Helper::convertUnit(self::MARGIN_ENDS, 'mm', $this->getUnit()); }
}

View file

@ -0,0 +1,56 @@
<?php
namespace App\Models\Labels\Tapes\Brother;
class TZe_12mm_A extends TZe_12mm
{
private const BARCODE_SIZE = 3.20;
private const BARCODE_MARGIN = 0.30;
private const TEXT_SIZE_MOD = 1.00;
public function getUnit() { return 'mm'; }
public function getWidth() { return 50.0; }
public function getSupportAssetTag() { return true; }
public function getSupport1DBarcode() { return true; }
public function getSupport2DBarcode() { return false; }
public function getSupportFields() { return 1; }
public function getSupportLogo() { return false; }
public function getSupportTitle() { return false; }
public function preparePDF($pdf) {}
public function write($pdf, $record) {
$pa = $this->getPrintableArea();
if ($record->has('barcode1d')) {
static::write1DBarcode(
$pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type,
$pa->x1, $pa->y1, $pa->w, self::BARCODE_SIZE
);
}
$currentY = $pa->y1 + self::BARCODE_SIZE + self::BARCODE_MARGIN;
$usableHeight = $pa->h - self::BARCODE_SIZE - self::BARCODE_MARGIN;
$fontSize = $usableHeight + self::TEXT_SIZE_MOD;
$tagWidth = $pa->w / 3;
$fieldWidth = $pa->w / 3 * 2;
static::writeText(
$pdf, $record->get('tag'),
$pa->x1, $currentY,
'freemono', 'b', $fontSize, 'L',
$tagWidth, $usableHeight, true, 0, 0
);
if ($record->get('fields')->count() >= 1) {
static::writeText(
$pdf, $record->get('fields')->values()->get(0)['value'],
$pa->x1 + ($tagWidth), $currentY,
'freemono', 'b', $fontSize, 'R',
$fieldWidth, $usableHeight, true, 0, 0
);
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Models\Labels\Tapes\Brother;
use App\Helpers\Helper;
use App\Models\Labels\Label;
abstract class TZe_24mm extends Label
{
private const HEIGHT = 24.00;
private const MARGIN_SIDES = 3.20;
private const MARGIN_ENDS = 3.20;
public function getHeight() { return Helper::convertUnit(self::HEIGHT, 'mm', $this->getUnit()); }
public function getMarginTop() { return Helper::convertUnit(self::MARGIN_SIDES, 'mm', $this->getUnit()); }
public function getMarginBottom() { return Helper::convertUnit(self::MARGIN_SIDES, 'mm', $this->getUnit());}
public function getMarginLeft() { return Helper::convertUnit(self::MARGIN_ENDS, 'mm', $this->getUnit()); }
public function getMarginRight() { return Helper::convertUnit(self::MARGIN_ENDS, 'mm', $this->getUnit()); }
}

View file

@ -0,0 +1,87 @@
<?php
namespace App\Models\Labels\Tapes\Brother;
class TZe_24mm_A extends TZe_24mm
{
private const BARCODE_MARGIN = 1.40;
private const TAG_SIZE = 2.80;
private const TITLE_SIZE = 2.80;
private const TITLE_MARGIN = 0.50;
private const LABEL_SIZE = 2.00;
private const LABEL_MARGIN = - 0.35;
private const FIELD_SIZE = 3.20;
private const FIELD_MARGIN = 0.15;
public function getUnit() { return 'mm'; }
public function getWidth() { return 65.0; }
public function getSupportAssetTag() { return true; }
public function getSupport1DBarcode() { return false; }
public function getSupport2DBarcode() { return true; }
public function getSupportFields() { return 3; }
public function getSupportLogo() { return false; }
public function getSupportTitle() { return true; }
public function preparePDF($pdf) {}
public function write($pdf, $record) {
$pa = $this->getPrintableArea();
$currentX = $pa->x1;
$currentY = $pa->y1;
$usableWidth = $pa->w;
$barcodeSize = $pa->h - self::TAG_SIZE;
if ($record->has('barcode2d')) {
static::writeText(
$pdf, $record->get('tag'),
$pa->x1, $pa->y2 - self::TAG_SIZE,
'freemono', 'b', self::TAG_SIZE, 'C',
$barcodeSize, self::TAG_SIZE, true, 0
);
static::write2DBarcode(
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
$currentX, $currentY,
$barcodeSize, $barcodeSize
);
$currentX += $barcodeSize + self::BARCODE_MARGIN;
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
} else {
static::writeText(
$pdf, $record->get('tag'),
$pa->x1, $pa->y2 - self::TAG_SIZE,
'freemono', 'b', self::TAG_SIZE, 'R',
$usableWidth, self::TAG_SIZE, true, 0
);
}
if ($record->has('title')) {
static::writeText(
$pdf, $record->get('title'),
$currentX, $currentY,
'freesans', '', self::TITLE_SIZE, 'L',
$usableWidth, self::TITLE_SIZE, true, 0
);
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
}
foreach ($record->get('fields') as $field) {
static::writeText(
$pdf, $field['label'],
$currentX, $currentY,
'freesans', '', self::LABEL_SIZE, 'L',
$usableWidth, self::LABEL_SIZE, true, 0, 0
);
$currentY += self::LABEL_SIZE + self::LABEL_MARGIN;
static::writeText(
$pdf, $field['value'],
$currentX, $currentY,
'freemono', 'B', self::FIELD_SIZE, 'L',
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
);
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
}
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace App\Presenters;
/**
* Class LabelPresenter
*/
class LabelPresenter extends Presenter
{
/**
* Json Column Layout for bootstrap table
* @return string
*/
public static function dataTableLayout()
{
$layout = [
[
'field' => 'radio',
'radio' => true,
'formatter' => 'labelRadioFormatter'
], [
'field' => 'name',
'searchable' => true,
'sortable' => true,
'switchable' => true,
'title' => trans('general.name'),
'visible' => true,
], [
'field' => 'size',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('admin/settings/table.size'),
'visible' => true,
'formatter' => 'labelSizeFormatter'
], [
'field' => 'labels_per_page',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('admin/labels/table.labels_per_page'),
'visible' => true,
'formatter' => 'labelPerPageFormatter'
], [
'field' => 'support_fields',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('admin/labels/table.support_fields'),
'visible' => true
], [
'field' => 'support_asset_tag',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('admin/labels/table.support_asset_tag'),
'visible' => true,
'formatter' => 'trueFalseFormatter'
], [
'field' => 'support_1d_barcode',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('admin/labels/table.support_1d_barcode'),
'visible' => true,
'formatter' => 'trueFalseFormatter'
], [
'field' => 'support_2d_barcode',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('admin/labels/table.support_2d_barcode'),
'visible' => true,
'formatter' => 'trueFalseFormatter'
], [
'field' => 'support_logo',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('admin/labels/table.support_logo'),
'visible' => true,
'formatter' => 'trueFalseFormatter'
], [
'field' => 'support_title',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('admin/labels/table.support_title'),
'visible' => true,
'formatter' => 'trueFalseFormatter'
]
];
return json_encode($layout);
}
}

211
app/View/Label.php Normal file
View file

@ -0,0 +1,211 @@
<?php
namespace App\View;
use App\Models\Labels\Field;
use App\Models\Labels\Label as LabelModel;
use App\Models\Labels\Sheet;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Traits\Macroable;
use TCPDF;
class Label implements View
{
use Macroable { __call as macroCall; }
protected const NAME = 'label';
/**
* A Collection of passed data.
*
* @var Collection
*/
protected $data;
public function __construct() {
$this->data = new Collection();
}
/**
* Render the PDF label.
*
* @param callable|null $callback
*/
public function render(callable $callback = null)
{
$settings = $this->data->get('settings');
$assets = $this->data->get('assets');
$offset = $this->data->get('offset');
$template = $this->data->get('template');
// If disabled, pass to legacy view
if ((!$settings->label2_enable) && (!$template)) {
return view('hardware/labels')
->with('assets', $assets)
->with('settings', $settings)
->with('bulkedit', $this->data->get('bulkedit'))
->with('count', $this->data->get('count'));
}
if (empty($template)) $template = LabelModel::find($settings->label2_template);
elseif (is_string($template)) $template = LabelModel::find($template);
$template->validate();
$pdf = new TCPDF(
$template->getOrientation(),
$template->getUnit(),
[ $template->getWidth(), $template->getHeight() ]
);
// Reset parameters
$pdf->SetPrintHeader(false);
$pdf->SetPrintFooter(false);
$pdf->SetAutoPageBreak(false);
$pdf->SetMargins(0, 0, null, true);
$pdf->SetCellMargins(0, 0, 0, 0);
$pdf->SetCellPaddings(0, 0, 0, 0);
$pdf->setCreator('Snipe-IT');
$pdf->SetSubject('Asset Labels');
$template->preparePDF($pdf);
// Get fields from settings
$fieldDefinitions = collect(explode(';', $settings->label2_fields))
->filter(fn($fieldString) => !empty($fieldString))
->map(fn($fieldString) => Field::fromString($fieldString));
// Prepare data
$data = $assets
->map(function ($asset) use ($template, $settings, $fieldDefinitions) {
$assetData = new Collection();
$assetData->put('asset', $asset);
$assetData->put('id', $asset->id);
$assetData->put('tag', $asset->asset_tag);
if ($template->getSupportTitle()) {
$title = !empty($settings->label2_title) ?
str_ireplace(':company', $asset->company->name, $settings->label2_title) :
$settings->qr_text;
if (!empty($title)) $assetData->put('title', $title);
}
if ($template->getSupportLogo()) {
$logo = $settings->label2_asset_logo ?
(
!empty($asset->company->image) ?
Storage::disk('public')->path('companies/'.e($asset->company->image)) :
null
) :
(
!empty($settings->label_logo) ?
Storage::disk('public')->path(''.e($settings->label_logo)) :
null
);
if (!empty($logo)) $assetData->put('logo', $logo);
}
if ($template->getSupport1DBarcode()) {
$barcode1DType = $settings->label2_1d_type;
$barcode1DType = ($barcode1DType == 'default') ?
(($settings->alt_barcode_enabled) ? $settings->alt_barcode : null) :
$barcode1DType;
if ($barcode1DType != 'none') {
$assetData->put('barcode1d', (object)[
'type' => $barcode1DType,
'content' => $asset->asset_tag,
]);
}
}
if ($template->getSupport2DBarcode()) {
$barcode2DType = $settings->label2_2d_type;
$barcode2DType = ($barcode2DType == 'default') ?
$settings->barcode_type :
$barcode2DType;
if (($barcode2DType != 'none') && (!is_null($barcode2DType))) {
switch ($settings->label2_2d_target) {
case 'ht_tag': $barcode2DTarget = route('ht/assetTag', $asset->asset_tag); break;
case 'hardware_id':
default: $barcode2DTarget = route('hardware.show', $asset->id); break;
}
$assetData->put('barcode2d', (object)[
'type' => $barcode2DType,
'content' => $barcode2DTarget,
]);
}
}
$fields = $fieldDefinitions
->map(fn($field) => $field->toArray($asset))
->filter(fn($field) => $field != null)
->reduce(function($myFields, $field) {
// Remove Duplicates
$toAdd = $field
->filter(fn($o) => !$myFields->contains('dataSource', $o['dataSource']))
->first();
return $toAdd ? $myFields->push($toAdd) : $myFields;
}, new Collection());
$assetData->put('fields', $fields->take($template->getSupportFields()));
return $assetData;
});
if ($template instanceof Sheet) {
$template->setLabelIndexOffset($offset ?? 0);
}
$template->writeAll($pdf, $data);
$filename = $assets->count() > 1 ? 'assets.pdf' : $assets->first()->asset_tag.'.pdf';
$pdf->Output($filename, 'I');
}
/**
* Add a piece of data.
*
* @param string|array $key
* @param mixed $value
* @return $this
*/
public function with($key, $value = null)
{
$this->data->put($key, $value);
return $this;
}
/**
* Get the array of view data.
*
* @return array
*/
public function getData()
{
return $this->data;
}
/**
* Get the name of the view.
*
* @return string
*/
public function name()
{
return $this->getName();
}
/**
* Get the name of the view.
*
* @return string
*/
public function getName()
{
return self::NAME;
}
}

View file

@ -70,6 +70,7 @@
"spatie/laravel-backup": "^6.16",
"symfony/polyfill-mbstring": "^1.22",
"tecnickcom/tc-lib-barcode": "^1.15",
"tecnickcom/tcpdf": "^6.5.0",
"unicodeveloper/laravel-password": "^1.0",
"watson/validating": "^6.1"
},

View file

@ -0,0 +1,50 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddLabel2Settings extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('settings', function (Blueprint $table) {
$table->boolean('label2_enable')->default(false);
$table->string('label2_template')->nullable()->default('DefaultLabel');
$table->string('label2_title')->nullable()->default(null);
$table->boolean('label2_asset_logo')->default(false);
$table->string('label2_1d_type')->default('default');
$table->string('label2_2d_type')->default('default');
$table->string('label2_2d_target')->default('hardware_id');
$table->string('label2_fields')->default(
trans('admin/hardware/form.name').'=name;'.
trans('admin/hardware/form.serial').'=serial;'.
trans('admin/hardware/form.model').'=model.name;'
);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('settings', function (Blueprint $table) {
if (Schema::hasColumn('settings', 'label2_enable')) $table->dropColumn('label2_enable');
if (Schema::hasColumn('settings', 'label2_template')) $table->dropColumn('label2_template');
if (Schema::hasColumn('settings', 'label2_title')) $table->dropColumn('label2_title');
if (Schema::hasColumn('settings', 'label2_asset_logo')) $table->dropColumn('label2_asset_logo');
if (Schema::hasColumn('settings', 'label2_1d_type')) $table->dropColumn('label2_1d_type');
if (Schema::hasColumn('settings', 'label2_2d_type')) $table->dropColumn('label2_2d_type');
if (Schema::hasColumn('settings', 'label2_2d_target')) $table->dropColumn('label2_2d_target');
if (Schema::hasColumn('settings', 'label2_fields')) $table->dropColumn('label2_fields');
});
}
}

21
package-lock.json generated
View file

@ -1883,6 +1883,19 @@
}
}
},
"@vue/reactivity": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz",
"integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==",
"requires": {
"@vue/shared": "3.1.5"
}
},
"@vue/shared": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz",
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA=="
},
"@webassemblyjs/ast": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
@ -2187,6 +2200,14 @@
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
},
"alpinejs": {
"version": "3.12.3",
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.12.3.tgz",
"integrity": "sha512-fLz2dfYQ3xCk7Ip8LiIpV2W+9brUyex2TAE7Z0BCvZdUDklJE+n+a8gCgLWzfZ0GzZNZu7HUP8Z0z6Xbm6fsSA==",
"requires": {
"@vue/reactivity": "~3.1.1"
}
},
"ansi-html-community": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",

View file

@ -29,6 +29,7 @@
"acorn-import-assertions": "^1.9.0",
"admin-lte": "^2.4.18",
"ajv": "^6.12.6",
"alpinejs": "^3.10.5",
"blueimp-file-upload": "^9.34.0",
"bootstrap": "^3.4.1",
"bootstrap-colorpicker": "^2.5.3",

BIN
public/js/dist/all-defer.js vendored Normal file

Binary file not shown.

View file

@ -33,6 +33,7 @@
"/js/build/vendor.js": "/js/build/vendor.js?id=3592e07ae9a6d1805a4ea3bd3c034aef",
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=df78f0c4cc93c29c02a41144590f6350",
"/js/dist/all.js": "/js/dist/all.js?id=fc2a78ab0c9ec6ce0961990388a1b23f",
"/js/dist/all-defer.js": "/js/dist/all-defer.js?id=7829a391ab2f89926465398bebb7df8d",
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=b48f4d8af0e1ca5621c161e93951109f",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=44f9320d0739f419c9246f7f39395b02",
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=1f33ca3d860461c1127ec465ab3ebb6b",

View file

@ -1 +1,2 @@
!.gitignore
!company-image-test.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -0,0 +1,11 @@
<?php
return [
'invalid_return_count' => 'Invalid count returned from :name. Expected :expected, got :actual.',
'invalid_return_type' => 'Invalid type returned from :name. Expected :expected, got :actual.',
'invalid_return_value' => 'Invalid value returned from :name. Expected :expected, got :actual.',
'does_not_exist' => 'Label does not exist',
];

View file

@ -0,0 +1,13 @@
<?php
return [
'labels_per_page' => 'Labels',
'support_fields' => 'Fields',
'support_asset_tag' => 'Tag',
'support_1d_barcode' => '1D',
'support_2d_barcode' => '2D',
'support_logo' => 'Logo',
'support_title' => 'Title',
];

View file

@ -330,9 +330,30 @@ return [
'setup_migration_create_user' => 'Next: Create User',
'ldap_settings_link' => 'LDAP Settings Page',
'slack_test' => 'Test <i class="fab fa-slack"></i> Integration',
'label2_enable' => 'New Label Engine',
'label2_enable_help' => 'Switch to the new label engine. <b>Note: You will need to save this setting before setting others.</b>',
'label2_template' => 'Template',
'label2_template_help' => 'Select which template to use for label generation',
'label2_title' => 'Title',
'label2_title_help' => 'The title to show on labels that support it',
'label2_title_help_phold' => 'The placeholder <code>&colon;company</code> will be replaced with the asset&apos;s company name',
'label2_asset_logo' => 'Use Asset Logo',
'label2_asset_logo_help' => 'Use the logo of the asset&apos;s assigned company, rather than the value at <code>:setting_name</code>',
'label2_1d_type' => '1D Barcode Type',
'label2_1d_type_help' => 'Format for 1D barcodes',
'label2_2d_type' => '2D Barcode Type',
'label2_2d_type_help' => 'Format for 2D barcodes',
'label2_2d_target' => '2D Barcode Target',
'label2_2d_target_help' => 'The URL the 2D barcode points to when scanned',
'label2_fields' => 'Field Definitions',
'label2_fields_help' => 'Fields can be added, removed, and reordered in the left column. For each field, multiple options for Label and DataSource can be added, removed, and reordered in the right column.',
'help_asterisk_bold' => 'Text entered as <code>**text**</code> will be displayed as bold',
'help_blank_to_use' => 'Leave blank to use the value from <code>:setting_name</code>',
'help_default_will_use' => '<code>:default</code> will use the value from <code>:setting_name</code>',
'default' => 'Default',
'none' => 'None',
'google_callback_help' => 'This should be entered as the callback URL in your Google OAuth app settings in your organization&apos;s <strong><a href="https://console.cloud.google.com/" target="_blank">Google developer console <i class="fa fa-external-link" aria-hidden="true"></i></a></strong>.',
'google_login' => 'Google Workspace Login Settings',
'enable_google_login' => 'Enable users to login with Google Workspace',
'enable_google_login_help' => 'Users will not be automatically provisioned. They must have an existing account here AND in Google Workspace, and their username here must match their Google Workspace email address. ',
];

View file

@ -947,6 +947,7 @@
{{-- Javascript files --}}
<script src="{{ url(mix('js/dist/all.js')) }}" nonce="{{ csrf_token() }}"></script>
<script defer src="{{ url(mix('js/dist/all-defer.js')) }}" nonce="{{ csrf_token() }}"></script>
<!-- v5-beta: This pGenerator call must remain here for v5 - until fixed - so that the JS password generator works for the user create modal. -->
<script src="{{ url('js/pGenerator.jquery.js') }}"></script>
@ -1022,6 +1023,5 @@
@livewireScripts
</body>
</html>

View file

@ -699,6 +699,25 @@
}
}
function labelPerPageFormatter(value, row, index, field) {
if (row) {
if (!row.hasOwnProperty('sheet_info')) { return 1; }
else { return row.sheet_info.labels_per_page; }
}
}
function labelRadioFormatter(value, row, index, field) {
if (row) {
return row.name == '{{ str_replace("\\", "\\\\", $snipeSettings->label2_template) }}';
}
}
function labelSizeFormatter(value, row) {
if (row) {
return row.width + ' x ' + row.height + ' ' + row.unit;
}
}
function cleanFloat(number) {
if(!number) { // in a JavaScript context, meaning, if it's null or zero or unset
return 0.0;

View file

@ -0,0 +1,334 @@
@once
@push('css')
<style>
:root {
--l2fd-background-color: rgb(246, 250, 255);
--l2fd-border-color: #d2d6de;
--l2fd-font-color: #555555;
--list-padding: 2px;
--listitem-font-color: #555555;
--listitem-padding: 8px;
--listitem-spacing: 2px;
--listitem-background-color: white;
--listitem-border-color: #ccc;
--listitem-border-radius: 2px;
--listitem-hover-font-color: var(--listitem-font-color);
--listitem-hover-background-color: var(--listitem-background-color);
--listitem-hover-border-color: rgb(102, 175, 233);
--listitem-selected-font-color: var(--listitem-font-color);
--listitem-selected-background-color: rgb(236, 240, 245);
--listitem-selected-border-color: var(--listitem-hover-border-color);
--buttonbar-button-font-color: #555555;
--buttonbar-button-background-color: white;
--buttonbar-button-border-color: #ccc;
--buttonbar-button-border-radius: 2px;
--buttonbar-button-hover-font-color: var(--buttonbar-button-font-color);
--buttonbar-button-hover-background-color: var(--buttonbar-button-background-color);
--buttonbar-button-hover-border-color: var(--listitem-hover-border-color);
--buttonbar-button-disabled-font-color: var(--buttonbar-button-font-color);
--buttonbar-button-disabled-background-color: #eee;
--buttonbar-button-disabled-border-color: var(--buttonbar-button-border-color);
}
.l2fd-root,
.l2fd-root * {
box-sizing: border-box;
}
.l2fd-root {
height: 400px;
display: flex;
flex-direction: column;
}
.l2fd-title {
font-size: 1.4em;
padding: 6px;
margin: 0;
}
.l2fd-list {
overflow-y: scroll;
padding: var(--list-padding);
}
.l2fd-main {
flex: 1;
display: grid;
grid-template-areas:
'fields-title options-title'
'fields-list options-list'
'fields-buttons options-buttons';
grid-template-columns: 50% 50%;
grid-template-rows: max-content auto max-content;
background-color: var(--l2fd-background-color);
border: 1px solid var(--l2fd-border-color);
color: var(--l2fd-font-color);
}
.l2fd-listitem {
color: var(--listitem-font-color);
cursor: pointer;
padding: var(--listitem-padding);
margin-bottom: var(--listitem-spacing);
background-color: var(--listitem-background-color);
border: 1px solid var(--listitem-border-color);
border-radius: var(--listitem-border-radius);
}
.l2fd-listitem:hover {
color: var(--listitem-hover-font-color);
background-color: var(--listitem-hover-background-color);
border: 1px solid var(--listitem-hover-border-color);
}
.l2fd-listitem.selected {
color: var(--listitem-selected-font-color);
background-color: var(--listitem-selected-background-color);
border: 1px solid var(--listitem-selected-border-color);
}
.l2fd-itemgrid {
display: grid;
grid-template-areas:
'label-title source-title'
'label-field source-field';
grid-template-columns: 50% 50%;
grid-template-rows: auto auto;
}
.l2fd-listitem label {
cursor: pointer;
font-size: 0.9em;
padding: 0;
margin: 0;
}
.l2fd-buttonbar {
display: flex;
flex-direction: row;
height: 35px;
}
.l2fd-buttonbar > button {
flex: 1 1 100%;
background-color: var(--buttonbar-button-background-color);
border: 1px solid var(--buttonbar-button-border-color);
border-radius: var(--buttonbar-button-border-radius);
color: var(--buttonbar-button-font-color);
}
.l2fd-buttonbar > button:hover {
background-color: var(--buttonbar-button-hover-background-color);
border: 1px solid var(--buttonbar-button-hover-border-color);
color: var(--buttonbar-button-hover-font-color);
}
.l2fd-buttonbar > button.disabled {
background-color: var(--buttonbar-button-disabled-background-color);
border: 1px solid var(--buttonbar-button-disabled-border-color);
color: var(--buttonbar-button-disabled-font-color);
cursor: not-allowed;
}
</style>
@endpush
@endonce
@push('js')
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('{{ $name }}', () => ({
_name: '{{ $name }}',
_defaultValue: '{{ $value }}',
_init: function() {
this.fields = this.fromString(this._defaultValue);
this.$watch('valueString', () => {
this.$refs.input.form.dispatchEvent(new Event('change'));
});
},
/* Fields */
fields: [],
get _templateField() { return ({ options: [ this._templateOption ] }); },
_selectedField: null,
get selectedField() { return this._selectedField; },
set selectedField(field) {
this._selectedField = field;
this.selectedOption = null;
},
get selectedFieldIndex() {
return this.selectedField ? this.fields.indexOf(this.selectedField) : -1;
},
shiftSelectedField: function(offset) {
this.shiftArrayValue(this.fields, this.selectedField, offset);
},
trashSelectedField: function() {
this.fields.splice(this.fields.indexOf(this.selectedField), 1);
this.selectedField = null;
},
addField: function() {
let newField = JSON.parse(JSON.stringify(this._templateField));
this.fields.push(newField);
this.selectedField = newField;
},
/* Options */
get _templateOption() { return ({ label: '', datasource: '' }); },
selectedOption: null,
get selectedOptionIndex() {
return this.selectedOption ? this.selectedField.options.indexOf(this.selectedOption) : -1;
},
shiftSelectedOption: function(offset) {
this.shiftArrayValue(this.selectedField.options, this.selectedOption, offset);
},
trashSelectedOption: function() {
this.selectedField.options.splice(this.selectedField.options.indexOf(this.selectedOption), 1);
this.selectedOption = null;
},
addOption: function() {
let newOption = JSON.parse(JSON.stringify(this._templateOption));
this.selectedField.options.push(newOption);
this.selectedOption = newOption;
},
/* Helpers */
shiftArrayValue: function(array, value, offset) {
let oldIndex = array.indexOf(value);
let newIndex = oldIndex + offset;
newIndex = Math.max(newIndex, 0);
newIndex = Math.min(newIndex, array.length);
array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
},
get valueString() { return this.toString(this.fields); },
onTest: function(a) {
console.log('test', a);
},
getFieldLabel: function(field) {
return field.options.map(option => option.label).join(' | ');
},
fromString: function(string) {
return string
.split(';').filter(fieldString => fieldString !== '')
.map(fieldString => ({
options: fieldString
.split('|').filter(optionString => optionString !== '')
.map(optionString => {
let [l,d] = optionString.split('=');
return { label: l, datasource: d };
})
}));
},
toString: function(fields) {
return fields
.map(field => field.options
.map(option => option.label + '=' + option.datasource)
.join('|')
)
.join(';');
},
}));
});
</script>
@endpush
@php
$selector = '[x-data="'.$name.'"]';
@endphp
@push('css')
<style>
</style>
@endpush
<div x-data="{{ $name }}" x-init="_init" class="l2fd-root">
<input type="hidden" name="{{ $name }}" x-model="valueString" x-ref="input" />
<div class="l2fd-main">
<h1 class="l2fd-title" style="grid-area: fields-title">Fields</h1>
<div class="l2fd-list" style="grid-area: fields-list">
<template x-for="(field, index) in fields">
<div
x-bind:key="'field-' + index"
x-bind:class="{
'l2fd-listitem': true,
'selected': selectedField === field
}"
x-on:click="selectedField = field" >
<label><span x-text="index+1"></span>: <span x-text="getFieldLabel(field)"></span></label>
</div>
</template>
</div>
<div class="l2fd-buttonbar" style="grid-area: fields-buttons">
<button
x-on:click.prevent="if(!$event.target.classList.contains('disabled')) shiftSelectedField(-1)"
x-bind:class="{ 'disabled': !selectedField || selectedFieldIndex == 0 }"
><i class="fa-solid fa-caret-up"></i></button>
<button
x-on:click.prevent="if(!$event.target.classList.contains('disabled')) shiftSelectedField(+1)"
x-bind:class="{ 'disabled': !selectedField || selectedFieldIndex == fields.length - 1 }"
><i class="fa-solid fa-caret-down"></i></button>
<button
x-on:click.prevent="if(!$event.target.classList.contains('disabled')) addField()"
x-bind:class="{}"
><i class="fa-solid fa-plus"></i></button>
<button
x-on:click.prevent="if(!$event.target.classList.contains('disabled')) trashSelectedField()"
x-bind:class="{ 'disabled': !selectedField }"
><i class="fa-solid fa-trash"></i></button>
</div>
<h1 class="l2fd-title" style="grid-area: options-title">Options</h1>
<div class="l2fd-list" style="grid-area: options-list">
<template x-if="selectedField">
<template x-for="(option, index) in selectedField.options">
<div
x-bind:key="'option-' + index"
x-bind:class="{
'l2fd-listitem': true,
'l2fd-itemgrid': true,
'selected': selectedOption == option
}"
x-on:click="selectedOption = option" >
<label style="grid-area: label-title">Label</label>
<input style="grid-area: label-field" x-model="option.label" />
<label style="grid-area: source-title">DataSource</label>
<input style="grid-area: source-field" x-model="option.datasource" />
</div>
</template>
</template>
<template x-if="!selectedField">
<div>Please select a field</div>
</template>
</div>
<div class="l2fd-buttonbar" style="grid-area: options-buttons">
<button
x-on:click.prevent="if(!$event.target.classList.contains('disabled')) shiftSelectedOption(-1)"
x-bind:class="{ 'disabled': !selectedField || !selectedOption || selectedOptionIndex == 0 }"
><i class="fa-solid fa-caret-up"></i></button>
<button
x-on:click.prevent="if(!$event.target.classList.contains('disabled')) shiftSelectedOption(+1)"
x-bind:class="{ 'disabled': !selectedField || !selectedOption || selectedOptionIndex == selectedField.options.length - 1 }"
><i class="fa-solid fa-caret-down"></i></button>
<button
x-on:click.prevent="if(!$event.target.classList.contains('disabled')) addOption()"
x-bind:class="{ 'disabled': !selectedField }"
><i class="fa-solid fa-plus"></i></button>
<button
x-on:click.prevent="if(!$event.target.classList.contains('disabled')) trashSelectedOption()"
x-bind:class="{ 'disabled': !selectedField || !selectedOption }"
><i class="fa-solid fa-trash"></i></button>
</div>
</div>
</div>

View file

@ -0,0 +1,98 @@
@once
@push('css')
<style>
:root {
--l2p-height: 400px;
--l2p-background-color: aliceblue;
}
.l2p-root,
.l2p-root * {
box-sizing: border-box;
}
.l2p-root {
width: 100%;
height: var(--l2p-height);
display: flex;
flex-direction: column;
}
.l2p-root > .l2p-top {
display: flex;
flex-direction: row;
align-items: end;
}
.l2p-root > .l2p-top > label {
flex: 1;
font-size: 0.9em;
padding: 0;
margin: 0;
}
.l2p-root > .l2p-top > .l2p-pop-button {
padding: 3px 6px;
}
.l2p-root > iframe {
flex: 1;
overflow: auto;
background-color: var(--l2p-background-color);
}
</style>
@endpush
@endonce
@push('js')
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('label2_preview', () => ({
_form: null,
_init: function() {
this._form = this.$root.closest('form');
this._form.addEventListener('change', this.updateURL.bind(this));
},
updateURL: function() {
let params = {
settings: Object.assign({}, ...$(this._form)
.serializeArray()
.filter((value, index, all) => value.name.includes('label2_'))
.map((value, index, all) => ({[value.name]: value.value}))
)
};
let template = params.settings.label2_template;
if (!template) return;
this.previewURL = '{{ route("labels.show", ["labelName" => ":label"]) }}'
.replace(':label', template.replaceAll('\\', '/'))
.concat('?', $.param(params), '#toolbar=0');
},
_previewURL: '',
get previewURL() { return this._previewURL; },
set previewURL(url) {
this._previewURL = url;
if (this._popped) this._popped.location = this.previewURL;
},
_popped: null,
popout: function() { this._popped = window.open(this.previewURL); }
}));
});
</script>
@endpush
<div x-data="label2_preview" x-init="_init" class="l2p-root">
<div class="l2p-top">
<label for="label2-preview">Preview</label>
<button class="l2p-pop-button btn btn-default" x-on:click.prevent="popout" title="Pop Out"><i class="fa-solid fa-maximize"></i></button>
</div>
<iframe id="label2-preview" x-bind:src="previewURL"></iframe>
</div>

View file

@ -20,8 +20,7 @@
}
</style>
{{ Form::open(['method' => 'POST', 'files' => false, 'autocomplete' => 'off', 'class' => 'form-horizontal', 'role' => 'form' ]) }}
{{ Form::open(['id' => 'settingsForm', 'method' => 'POST', 'files' => false, 'autocomplete' => 'off', 'class' => 'form-horizontal', 'role' => 'form' ]) }}
<!-- CSRF Token -->
{{csrf_field()}}
@ -40,158 +39,366 @@
<div class="col-md-11 col-md-offset-1">
<div class="form-group {{ $errors->has('labels_per_page') ? 'error' : '' }}">
<!-- New Label Engine -->
<div class="form-group {{ $errors->has('label2_enable') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_per_page', trans('admin/settings/general.labels_per_page')) }}
{{ Form::label('label2_enable', trans('admin/settings/general.label2_enable')) }}
</div>
<div class="col-md-9">
{{ Form::text('labels_per_page', old('labels_per_page', $setting->labels_per_page), ['class' => 'form-control','style' => 'width: 100px;', 'aria-label'=>'labels_per_page']) }}
{!! $errors->first('labels_per_page', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::checkbox('label2_enable', '1', old('label2_enable', $setting->label2_enable, [ 'class'=>'minimal', 'aria-label'=>'label2_enable' ])) }}
{{ trans('general.yes') }}
{!! $errors->first('label2_enable', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<p class="help-block">{!! trans('admin/settings/general.label2_enable_help') !!}</p>
</div>
</div>
<div class="form-group {{ $errors->has('labels_fontsize') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_fontsize', trans('admin/settings/general.labels_fontsize')) }}
</div>
<div class="col-md-2">
<div class="input-group">
{{ Form::text('labels_fontsize', old('labels_fontsize', $setting->labels_fontsize), ['class' => 'form-control', 'aria-label'=>'labels_fontsize']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.text_pt') }}</div>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_fontsize', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
@if ($setting->label2_enable)
<!-- New Settings -->
<div class="form-group {{ $errors->has('labels_width') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_width', trans('admin/settings/general.label_dimensions')) }}
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_width', old('labels_width', $setting->labels_width), ['class' => 'form-control', 'aria-label'=>'labels_width']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.width_w') }}</div>
<!-- Template -->
<div class="form-group {{ $errors->has('label2_template') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('label2_template', trans('admin/settings/general.label2_template')) }}
@include('partials.label2-preview')
</div>
<div class="col-md-9">
<table
data-click-to-select="true"
data-columns="{{ \App\Presenters\LabelPresenter::dataTableLayout() }}"
data-cookie="true"
data-cookie-id-table="label2TemplateTable"
data-id-table="label2TemplateTable"
data-pagination="true"
data-search="true"
data-select-item-name="label2_template"
data-id-field="name"
data-show-columns="true"
data-show-fullscreen="true"
data-show-refresh="true"
data-side-pagination="server"
data-sort-name="name"
data-sort-order="asc"
data-url="{{ route('api.labels.index') }}"
id="label2TemplateTable"
class="table table-striped snipe-table"
></table>
<script>
document.addEventListener('DOMContentLoaded', () => {
$('#label2TemplateTable').on('load-success.bs.table', (e) => {
let form = document.getElementById('settingsForm');
form.dispatchEvent(new Event('change'));
});
});
</script>
</div>
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_height', old('labels_height', $setting->labels_height), ['class' => 'form-control', 'aria-label'=>'labels_height']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.height_h') }}</div>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_width', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{!! $errors->first('labels_height', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="form-group {{ $errors->has('labels_display_sgutter') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_display_sgutter', trans('admin/settings/general.label_gutters')) }}
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_display_sgutter', old('labels_display_sgutter', $setting->labels_display_sgutter), ['class' => 'form-control', 'aria-label'=>'labels_display_sgutter']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.horizontal') }}</div>
<!-- Title -->
<div class="form-group {{ $errors->has('label2_title') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('label2_title', trans('admin/settings/general.label2_title')) }}
</div>
<div class="col-md-9">
{{ Form::text('label2_title', old('label2_title', $setting->label2_title), [ 'class'=>'form-control', 'placeholder'=>$setting->qr_text, 'aria-label'=>'label2_title' ]) }}
{!! $errors->first('label2_title', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<p class="help-block">{!! trans('admin/settings/general.label2_title_help') !!}</p>
<p class="help-block">
{!! trans('admin/settings/general.label2_title_help_phold') !!}.<br />
{!! trans('admin/settings/general.help_asterisk_bold') !!}.<br />
{!!
trans('admin/settings/general.help_blank_to_use', [
'setting_name' => trans('admin/settings/general.barcodes').' &gt; '.trans('admin/settings/general.qr_text')
])
!!}
</p>
</div>
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_display_bgutter', old('labels_display_bgutter', $setting->labels_display_bgutter), ['class' => 'form-control', 'aria-label'=>'labels_display_bgutter']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.vertical') }}</div>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_display_sgutter', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{!! $errors->first('labels_display_bgutter', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="form-group {{ $errors->has('labels_pmargin_top') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_pmargin_top', trans('admin/settings/general.page_padding')) }}
</div>
<div class="col-md-3">
<div class="input-group" style="margin-bottom: 15px;">
{{ Form::text('labels_pmargin_top', old('labels_pmargin_top', $setting->labels_pmargin_top), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_top']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.top') }}</div>
<!-- Use Asset Logo -->
<div class="form-group {{ $errors->has('label2_asset_logo') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('label2_asset_logo', trans('admin/settings/general.label2_asset_logo')) }}
</div>
<div class="input-group">
{{ Form::text('labels_pmargin_right', old('labels_pmargin_right', $setting->labels_pmargin_right), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_right']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.right') }}</div>
<div class="col-md-9">
{{ Form::checkbox('label2_asset_logo', '1', old('label2_asset_logo', $setting->label2_asset_logo, [ 'class'=>'minimal', 'aria-label'=>'label2_asset_logo' ])) }}
{{ trans('general.yes') }}
{!! $errors->first('label2_asset_logo', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<p class="help-block">{!! trans('admin/settings/general.label2_asset_logo_help', ['setting_name' => trans('admin/settings/general.brand').' &gt; '.trans('admin/settings/general.label_logo')]) !!}</p>
</div>
</div>
<div class="col-md-3" style="margin-left: 10px; ">
<div class="input-group" style="margin-bottom: 15px;">
{{ Form::text('labels_pmargin_bottom', old('labels_pmargin_bottom', $setting->labels_pmargin_bottom), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_bottom']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.bottom') }}</div>
<!-- 1D Barcode Type -->
<div class="form-group{{ $errors->has('label2_1d_type') ? ' has-error' : '' }}">
<div class="col-md-3">
{{ Form::label('label2_1d_type', trans('admin/settings/general.label2_1d_type')) }}
</div>
<div class="input-group">
{{ Form::text('labels_pmargin_left', old('labels_pmargin_left', $setting->labels_pmargin_left), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_left']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.left') }}</div>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_width', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{!! $errors->first('labels_height', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="form-group {{ (($errors->has('labels_pageheight')) || $errors->has('labels_pagewidth')) ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_pagewidth', trans('admin/settings/general.page_dimensions')) }}
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_pagewidth', old('labels_pagewidth', $setting->labels_pagewidth), ['class' => 'form-control', 'aria-label'=>'labels_pagewidth']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.width_w') }}</div>
<div class="col-md-9">
@php
$select1DValues = [
'default' => trans('admin/settings/general.default').' [ '.$setting->alt_barcode.' ]',
'none' => trans('admin/settings/general.none'),
'C128' => 'C128',
'C39' => 'C39',
'EAN5' => 'EAN5',
'EAN13' => 'EAN13',
'UPCA' => 'UPCA',
'UPCE' => 'UPCE'
];
@endphp
{{ Form::select('label2_1d_type', $select1DValues, old('label2_1d_type', $setting->label2_1d_type), [ 'class'=>'select2 col-md-4', 'aria-label'=>'label2_1d_type' ]) }}
{!! $errors->first('label2_1d_type', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
<p class="help-block">
{{ trans('admin/settings/general.label2_1d_type_help') }}.
{!!
trans('admin/settings/general.help_default_will_use', [
'default' => trans('admin/settings/general.default'),
'setting_name' => trans('admin/settings/general.barcodes').' &gt; '.trans('admin/settings/general.alt_barcode_type'),
])
!!}
</p>
</div>
</div>
<div class="col-md-3 form-group" style="margin-left: 10px">
<div class="input-group">
{{ Form::text('labels_pageheight', old('labels_pageheight', $setting->labels_pageheight), ['class' => 'form-control', 'aria-label'=>'labels_pageheight']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.height_h') }}</div>
<!-- 2D Barcode Type -->
<div class="form-group{{ $errors->has('label2_2d_type') ? ' has-error' : '' }}">
<div class="col-md-3">
{{ Form::label('label2_2d_type', trans('admin/settings/general.label2_2d_type')) }}
</div>
<div class="col-md-9">
@php
$select2DValues = [
'default' => trans('admin/settings/general.default').' [ '.$setting->barcode_type.' ]',
'none' => trans('admin/settings/general.none'),
'QRCODE' => 'QRCODE',
'DATAMATRIX' => 'DATAMATRIX',
'PDF417' => 'PDF417',
];
@endphp
{{ Form::select('label2_2d_type', $select2DValues, old('label2_2d_type', $setting->label2_2d_type), [ 'class'=>'select2 col-md-4', 'aria-label'=>'label2_2d_type' ]) }}
{!! $errors->first('label2_2d_type', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
<p class="help-block">
{{ trans('admin/settings/general.label2_2d_type_help', ['current' => $setting->barcode_type]) }}.
{!!
trans('admin/settings/general.help_default_will_use', [
'default' => trans('admin/settings/general.default'),
'setting_name' => trans('admin/settings/general.barcodes').' &gt; '.trans('admin/settings/general.barcode_type'),
])
!!}
</p>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_pagewidth', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{!! $errors->first('labels_pageheight', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<!-- 2D Barcode Target -->
<div class="form-group{{ $errors->has('label2_2d_target') ? ' has-error' : '' }}">
<div class="col-md-3">
{{ Form::label('label2_2d_target', trans('admin/settings/general.label2_2d_target')) }}
</div>
<div class="col-md-9">
{{ Form::select('label2_2d_target', ['hardware_id'=>'/hardware/{id} ('.trans('admin/settings/general.default').')', 'ht_tag'=>'/ht/{asset_tag}'], old('label2_2d_target', $setting->label2_2d_target), [ 'class'=>'select2 col-md-4', 'aria-label'=>'label2_2d_target' ]) }}
{!! $errors->first('label2_2d_target', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
<p class="help-block">{{ trans('admin/settings/general.label2_2d_target_help') }}</p>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-3">
{{ Form::label('labels_display', trans('admin/settings/general.label_fields')) }}
<!-- Fields -->
<div class="form-group {{ $errors->has('label2_fields') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('label2_fields', trans('admin/settings/general.label2_fields')) }}
</div>
<div class="col-md-9">
@include('partials.label2-field-definitions', [ 'name' => 'label2_fields', 'value' => old('label2_fields', $setting->label2_fields) ])
{!! $errors->first('label2_fields', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<p class="help-block">{{ trans('admin/settings/general.label2_fields_help') }}</p>
</div>
</div>
<div class="col-md-9">
<label class="form-control">
{{ Form::checkbox('labels_display_name', '1', old('labels_display_name', $setting->labels_display_name),['class' => 'minimal', 'aria-label'=>'labels_display_name']) }}
{{ trans('admin/hardware/form.name') }}
</label>
<label class="form-control">
{{ Form::checkbox('labels_display_serial', '1', old('labels_display_serial', $setting->labels_display_serial),['class' => 'minimal', 'aria-label'=>'labels_display_serial']) }}
{{ trans('admin/hardware/form.serial') }}
</label>
<label class="form-control">
{{ Form::checkbox('labels_display_tag', '1', old('labels_display_tag', $setting->labels_display_tag),['class' => 'minimal', 'aria-label'=>'labels_display_tag']) }}
{{ trans('admin/hardware/form.tag') }}
</label>
<label class="form-control">
{{ Form::checkbox('labels_display_model', '1', old('labels_display_model', $setting->labels_display_model),['class' => 'minimal', 'aria-label'=>'labels_display_model']) }}
{{ trans('admin/hardware/form.model') }}
</label>
<label class="form-control">
{{ Form::checkbox('labels_display_company_name', '1', old('labels_display_company_name', $setting->labels_display_company_name),['class' => 'minimal', 'aria-label'=>'labels_display_company_name']) }}
{{ trans('admin/companies/table.name') }}
</label>
</div> <!--/.col-md-9-->
</div> <!--/.form-group-->
@include('partials.bootstrap-table')
@else
<!-- Hidden version of new settings -->
{{ Form::hidden('label2_template', old('label2_template', $setting->label2_template)) }}
{{ Form::hidden('label2_title', old('label2_title', $setting->label2_title)) }}
{{ Form::hidden('label2_asset_logo', old('label2_asset_logo', $setting->label2_asset_logo)) }}
{{ Form::hidden('label2_1d_type', old('label2_1d_type', $setting->label2_1d_type)) }}
{{ Form::hidden('label2_2d_type', old('label2_2d_type', $setting->label2_2d_type)) }}
{{ Form::hidden('label2_2d_target', old('label2_2d_target', $setting->label2_2d_target)) }}
{{ Form::hidden('label2_fields', old('label2_fields', $setting->label2_fields)) }}
@endif
@if ($setting->label2_enable && ($setting->label2_template != 'DefaultLabel'))
<!-- Hidden version of legacy settings -->
{{ Form::hidden('labels_per_page', old('labels_per_page', $setting->labels_per_page)) }}
{{ Form::hidden('labels_fontsize', old('labels_fontsize', $setting->labels_fontsize)) }}
{{ Form::hidden('labels_width', old('labels_width', $setting->labels_width)) }}
{{ Form::hidden('labels_height', old('labels_height', $setting->labels_height)) }}
{{ Form::hidden('labels_display_sgutter', old('labels_display_sgutter', $setting->labels_display_sgutter)) }}
{{ Form::hidden('labels_display_bgutter', old('labels_display_bgutter', $setting->labels_display_bgutter)) }}
{{ Form::hidden('labels_pmargin_top', old('labels_pmargin_top', $setting->labels_pmargin_top)) }}
{{ Form::hidden('labels_pmargin_bottom', old('labels_pmargin_bottom', $setting->labels_pmargin_bottom)) }}
{{ Form::hidden('labels_pmargin_left', old('labels_pmargin_left', $setting->labels_pmargin_left)) }}
{{ Form::hidden('labels_pmargin_right', old('labels_pmargin_right', $setting->labels_pmargin_right)) }}
{{ Form::hidden('labels_pagewidth', old('labels_pagewidth', $setting->labels_pagewidth)) }}
{{ Form::hidden('labels_pageheight', old('labels_pageheight', $setting->labels_pageheight)) }}
{{ Form::hidden('labels_display_name', old('labels_display_name', $setting->labels_display_name)) }}
{{ Form::hidden('labels_display_serial', old('labels_display_serial', $setting->labels_display_serial)) }}
{{ Form::hidden('labels_display_tag', old('labels_display_tag', $setting->labels_display_tag)) }}
{{ Form::hidden('labels_display_model', old('labels_display_model', $setting->labels_display_model)) }}
{{ Form::hidden('labels_display_company_name', old('labels_display_company_name', $setting->labels_display_company_name)) }}
@else
<!-- Legacy settings -->
<div class="form-group {{ $errors->has('labels_per_page') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_per_page', trans('admin/settings/general.labels_per_page')) }}
</div>
<div class="col-md-9">
{{ Form::text('labels_per_page', old('labels_per_page', $setting->labels_per_page), ['class' => 'form-control','style' => 'width: 100px;', 'aria-label'=>'labels_per_page']) }}
{!! $errors->first('labels_per_page', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="form-group {{ $errors->has('labels_fontsize') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_fontsize', trans('admin/settings/general.labels_fontsize')) }}
</div>
<div class="col-md-2">
<div class="input-group">
{{ Form::text('labels_fontsize', old('labels_fontsize', $setting->labels_fontsize), ['class' => 'form-control', 'aria-label'=>'labels_fontsize']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.text_pt') }}</div>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_fontsize', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="form-group {{ $errors->has('labels_width') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_width', trans('admin/settings/general.label_dimensions')) }}
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_width', old('labels_width', $setting->labels_width), ['class' => 'form-control', 'aria-label'=>'labels_width']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.width_w') }}</div>
</div>
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_height', old('labels_height', $setting->labels_height), ['class' => 'form-control', 'aria-label'=>'labels_height']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.height_h') }}</div>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_width', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{!! $errors->first('labels_height', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="form-group {{ $errors->has('labels_display_sgutter') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_display_sgutter', trans('admin/settings/general.label_gutters')) }}
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_display_sgutter', old('labels_display_sgutter', $setting->labels_display_sgutter), ['class' => 'form-control', 'aria-label'=>'labels_display_sgutter']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.horizontal') }}</div>
</div>
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_display_bgutter', old('labels_display_bgutter', $setting->labels_display_bgutter), ['class' => 'form-control', 'aria-label'=>'labels_display_bgutter']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.vertical') }}</div>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_display_sgutter', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{!! $errors->first('labels_display_bgutter', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="form-group {{ $errors->has('labels_pmargin_top') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_pmargin_top', trans('admin/settings/general.page_padding')) }}
</div>
<div class="col-md-3">
<div class="input-group" style="margin-bottom: 15px;">
{{ Form::text('labels_pmargin_top', old('labels_pmargin_top', $setting->labels_pmargin_top), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_top']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.top') }}</div>
</div>
<div class="input-group">
{{ Form::text('labels_pmargin_right', old('labels_pmargin_right', $setting->labels_pmargin_right), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_right']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.right') }}</div>
</div>
</div>
<div class="col-md-3" style="margin-left: 10px; ">
<div class="input-group" style="margin-bottom: 15px;">
{{ Form::text('labels_pmargin_bottom', old('labels_pmargin_bottom', $setting->labels_pmargin_bottom), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_bottom']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.bottom') }}</div>
</div>
<div class="input-group">
{{ Form::text('labels_pmargin_left', old('labels_pmargin_left', $setting->labels_pmargin_left), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_left']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.left') }}</div>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_width', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{!! $errors->first('labels_height', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="form-group {{ (($errors->has('labels_pageheight')) || $errors->has('labels_pagewidth')) ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('labels_pagewidth', trans('admin/settings/general.page_dimensions')) }}
</div>
<div class="col-md-3">
<div class="input-group">
{{ Form::text('labels_pagewidth', old('labels_pagewidth', $setting->labels_pagewidth), ['class' => 'form-control', 'aria-label'=>'labels_pagewidth']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.width_w') }}</div>
</div>
</div>
<div class="col-md-3 form-group" style="margin-left: 10px">
<div class="input-group">
{{ Form::text('labels_pageheight', old('labels_pageheight', $setting->labels_pageheight), ['class' => 'form-control', 'aria-label'=>'labels_pageheight']) }}
<div class="input-group-addon">{{ trans('admin/settings/general.height_h') }}</div>
</div>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('labels_pagewidth', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{!! $errors->first('labels_pageheight', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="form-group">
<div class="col-md-3">
{{ Form::label('labels_display', trans('admin/settings/general.label_fields')) }}
</div>
<div class="col-md-9">
<label class="form-control">
{{ Form::checkbox('labels_display_name', '1', old('labels_display_name', $setting->labels_display_name),['class' => 'minimal', 'aria-label'=>'labels_display_name']) }}
{{ trans('admin/hardware/form.name') }}
</label>
<label class="form-control">
{{ Form::checkbox('labels_display_serial', '1', old('labels_display_serial', $setting->labels_display_serial),['class' => 'minimal', 'aria-label'=>'labels_display_serial']) }}
{{ trans('admin/hardware/form.serial') }}
</label>
<label class="form-control">
{{ Form::checkbox('labels_display_tag', '1', old('labels_display_tag', $setting->labels_display_tag),['class' => 'minimal', 'aria-label'=>'labels_display_tag']) }}
{{ trans('admin/hardware/form.tag') }}
</label>
<label class="form-control">
{{ Form::checkbox('labels_display_model', '1', old('labels_display_model', $setting->labels_display_model),['class' => 'minimal', 'aria-label'=>'labels_display_model']) }}
{{ trans('admin/hardware/form.model') }}
</label>
<label class="form-control">
{{ Form::checkbox('labels_display_company_name', '1', old('labels_display_company_name', $setting->labels_display_company_name),['class' => 'minimal', 'aria-label'=>'labels_display_company_name']) }}
{{ trans('admin/companies/table.name') }}
</label>
</div> <!--/.col-md-9-->
</div> <!--/.form-group-->
@endif
</div>

View file

@ -606,6 +606,16 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'throttle:api']], functi
); // end imports API routes
/**
* Labels API routes
*/
Route::group(['prefix' => 'labels'], function() {
Route::get('{name}', [ Api\LabelsController::class, 'show'])
->where('name', '.*')
->name('api.labels.show');
Route::get('', [ Api\LabelsController::class, 'index'])
->name('api.labels.index');
});
/**
* Licenses API routes

View file

@ -10,6 +10,7 @@ use App\Http\Controllers\DepreciationsController;
use App\Http\Controllers\GroupsController;
use App\Http\Controllers\HealthController;
use App\Http\Controllers\ImportsController;
use App\Http\Controllers\LabelsController;
use App\Http\Controllers\LocationsController;
use App\Http\Controllers\ManufacturersController;
use App\Http\Controllers\ModalController;
@ -39,8 +40,14 @@ Route::group(['middleware' => 'auth'], function () {
Route::resource('categories', CategoriesController::class, [
'parameters' => ['category' => 'category_id'],
]);
/*
* Labels
*/
Route::get(
'labels/{labelName}',
[LabelsController::class, 'show']
)->where('labelName', '.*')->name('labels.show');
/*
* Locations
@ -68,9 +75,6 @@ Route::group(['middleware' => 'auth'], function () {
]);
/*
* Manufacturers
*/

View file

@ -187,3 +187,7 @@ Route::resource('hardware',
'parameters' => ['asset' => 'asset_id'
],
]);
Route::get('ht/{any?}',
[AssetsController::class, 'getAssetByTag']
)->where('any', '.*')->name('ht/assetTag');

View file

@ -202,6 +202,13 @@ mix
)
.version();
mix
.combine(
['./node_modules/alpinejs/dist/cdn.js'],
'./public/js/dist/all-defer.js'
)
.version();
/**
* Copy, minify and version skins
*/