diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index cfb0aa9f15..e3e8fd75c2 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1126,4 +1126,43 @@ class Helper return $settings; } + /** + * Conversion between units of measurement + * + * @author Grant Le Roux + * @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 + * @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'); + } + } + } diff --git a/app/Http/Controllers/Api/LabelsController.php b/app/Http/Controllers/Api/LabelsController.php new file mode 100644 index 0000000000..6576ec0373 --- /dev/null +++ b/app/Http/Controllers/Api/LabelsController.php @@ -0,0 +1,71 @@ + + * @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 + * @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); + } + +} diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index b0fde82c5e..545d874d4b 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -13,6 +13,7 @@ use App\Models\Company; use App\Models\Location; use App\Models\Setting; use App\Models\User; +use App\View\Label; use Auth; use Carbon\Carbon; use DB; @@ -441,11 +442,12 @@ class AssetsController extends Controller * @since [v3.0] * @return Redirect */ - public function getAssetByTag(Request $request) + public function getAssetByTag($tag=null, Request $request) { + $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); @@ -542,9 +544,10 @@ class AssetsController extends Controller $asset = Asset::find($assetId); $this->authorize('view', $asset); - return view('hardware/labels') + return (new Label()) ->with('assets', collect([ $asset ])) ->with('settings', Setting::getSettings()) + ->with('offset', request()->get('offset')) ->with('bulkedit', false) ->with('count', 0); } diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index ca48d91f43..b9a3a39cf5 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -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; @@ -44,7 +45,7 @@ class BulkAssetsController extends Controller if ($request->filled('bulk_actions')) { switch ($request->input('bulk_actions')) { case 'labels': - return view('hardware/labels') + return (new Label) ->with('assets', Asset::find($asset_ids)) ->with('settings', Setting::getSettings()) ->with('bulkedit', true) diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 111eb1baed..6c286330b4 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -844,6 +844,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'); diff --git a/app/Http/Transformers/LabelsTransformer.php b/app/Http/Transformers/LabelsTransformer.php new file mode 100644 index 0000000000..f575f91d6c --- /dev/null +++ b/app/Http/Transformers/LabelsTransformer.php @@ -0,0 +1,70 @@ +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_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; + } +} diff --git a/app/Models/Labels/DefaultLabel.php b/app/Models/Labels/DefaultLabel.php new file mode 100644 index 0000000000..103e3181e0 --- /dev/null +++ b/app/Models/Labels/DefaultLabel.php @@ -0,0 +1,224 @@ +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 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 = Asset::find($record->get('id')); + $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++; + } + } + + } +} + +?> \ No newline at end of file diff --git a/app/Models/Labels/Label.php b/app/Models/Labels/Label.php new file mode 100644 index 0000000000..2480441631 --- /dev/null +++ b/app/Models/Labels/Label.php @@ -0,0 +1,591 @@ +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($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(); + }); + } + + + +} diff --git a/app/Models/Labels/RectangleSheet.php b/app/Models/Labels/RectangleSheet.php new file mode 100644 index 0000000000..f5fe5cda98 --- /dev/null +++ b/app/Models/Labels/RectangleSheet.php @@ -0,0 +1,48 @@ +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 ]; + } +} + +?> \ No newline at end of file diff --git a/app/Models/Labels/Sheet.php b/app/Models/Labels/Sheet.php new file mode 100644 index 0000000000..83e363591a --- /dev/null +++ b/app/Models/Labels/Sheet.php @@ -0,0 +1,209 @@ +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; } +} + +?> \ No newline at end of file diff --git a/app/Models/Labels/Sheets/Avery/L7162.php b/app/Models/Labels/Sheets/Avery/L7162.php new file mode 100644 index 0000000000..e1097db9b2 --- /dev/null +++ b/app/Models/Labels/Sheets/Avery/L7162.php @@ -0,0 +1,71 @@ +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; } +} + +?> \ No newline at end of file diff --git a/app/Models/Labels/Sheets/Avery/L7162_Example.php b/app/Models/Labels/Sheets/Avery/L7162_Example.php new file mode 100644 index 0000000000..10d1a4f9e2 --- /dev/null +++ b/app/Models/Labels/Sheets/Avery/L7162_Example.php @@ -0,0 +1,91 @@ +getLabelPrintableArea(); + + $x = $pa->x1; + $y = $pa->y1; + $w = $pa->w; + + static::write1DBarcode( + $pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type, + $pa->x1, $pa->y2 - self::BARCODE1D_SIZE, + $pa->w, self::BARCODE1D_SIZE + ); + + if ($record->get('logo')) { + $logoMaxHeight = $pa->h - self::BARCODE1D_SIZE - self::LOGO_MARGIN; + $logoSize = static::writeImage( + $pdf, $record->get('logo'), + $x, $y, + self::LOGO_MAX_WIDTH, $logoMaxHeight, + 'L', 'T', 300, + true, false, 0 + ); + $x += $logoSize[0] + self::LOGO_MARGIN; + $w -= ($logoSize[0] + self::LOGO_MARGIN); + } + + if ($record->get('title')) { + static::writeText( + $pdf, $record->get('title'), + $x, $y, + 'freesans', '', self::TITLE_SIZE, 'L', + $w, self::TITLE_SIZE, true, 0 + ); + $y += self::TITLE_SIZE + self::TITLE_MARGIN; + } + + foreach ($record->get('fields') as $label => $value) { + static::writeText( + $pdf, $label, + $x, $y, + 'freesans', '', self::LABEL_SIZE, 'L', + $w, self::LABEL_SIZE, true, 0 + ); + $y += self::LABEL_SIZE + self::LABEL_MARGIN; + + static::writeText( + $pdf, $value, + $x, $y, + 'freemono', 'B', self::FIELD_SIZE, 'L', + $w, self::FIELD_SIZE, true, 0, 0.3 + ); + $y += self::FIELD_SIZE + self::FIELD_MARGIN; + } + + } +} + + +?> \ No newline at end of file diff --git a/app/Models/Labels/Sheets/Avery/L7162_Example_QR.php b/app/Models/Labels/Sheets/Avery/L7162_Example_QR.php new file mode 100644 index 0000000000..54c886e6e4 --- /dev/null +++ b/app/Models/Labels/Sheets/Avery/L7162_Example_QR.php @@ -0,0 +1,77 @@ +getLabelPrintableArea(); + + static::write2DBarcode( + $pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type, + $pa->x1, $pa->y1, + $pa->h, $pa->h + ); + + $x = $pa->x1 + $pa->h + self::BARCODE2D_MARGIN; + $y = $pa->y1; + $w = $pa->w - $pa->h - self::BARCODE2D_MARGIN; + + if ($record->get('title')) { + static::writeText( + $pdf, $record->get('title'), + $x, $y, + 'freesans', '', self::TITLE_SIZE, 'L', + $w, self::TITLE_SIZE, true, 0 + ); + $y += self::TITLE_SIZE + self::TITLE_MARGIN; + } + + foreach ($record->get('fields') as $label => $value) { + static::writeText( + $pdf, $label, + $x, $y, + 'freesans', '', self::LABEL_SIZE, 'L', + $w, self::LABEL_SIZE, true, 0 + ); + $y += self::LABEL_SIZE + self::LABEL_MARGIN; + + static::writeText( + $pdf, $value, + $x, $y, + 'freemono', 'B', self::FIELD_SIZE, 'L', + $w, self::FIELD_SIZE, true, 0, 0.3 + ); + $y += self::FIELD_SIZE + self::FIELD_MARGIN; + } + + } +} + + +?> \ No newline at end of file diff --git a/app/Presenters/LabelPresenter.php b/app/Presenters/LabelPresenter.php new file mode 100644 index 0000000000..387118432a --- /dev/null +++ b/app/Presenters/LabelPresenter.php @@ -0,0 +1,88 @@ + '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_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); + } +} diff --git a/app/View/Label.php b/app/View/Label.php new file mode 100644 index 0000000000..c720f5a8dd --- /dev/null +++ b/app/View/Label.php @@ -0,0 +1,243 @@ +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'); + + // If disabled, pass to legacy view + if (!$settings->label2_enable) { + return view('hardware/labels') + ->with('assets', $assets) + ->with('settings', $settings) + ->with('bulkedit', $this->data->get('bulkedit')) + ->with('count', $this->data->get('count')); + } + + + $template = LabelModel::find($settings->label2_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); + + // 'Label1=field1|Alt1=altfield1;Label2=field2;Alt1=altfield1|Label3=field3' + $fieldDefinitions = (new Collection()) + ->merge(explode(';', $settings->label2_fields)) + ->filter(function ($defString) { + return strpos($defString, '=') !== false; + }) + ->map(function ($defString) { + return (new Collection()) + ->merge(explode('|', $defString)) // ['Label1=field1', 'Alt1=altfield1'] + ->mapWithKeys(function ($altString) { + $parts = explode('=', $altString); + if (count($parts) != 2) throw new \Exception(var_export($parts, true)); + return [ $parts[0] => $parts[1] ]; + }); + }); + /* + $fieldDefinitions should now look like: + [ + [ + 'Label1'=>'field1', + 'Alt1'=>'altfield1' + ], + [ + 'Label2'=>'field2' + ], + [ + 'Alt1'=>'altfield1', + 'Label3'=>'field3' + ] + ] + */ + + // Prepare data + $data = $assets + ->map(function ($asset) use ($template, $settings, $fieldDefinitions) { + + $assetData = new Collection(); + + $assetData->put('id', $asset->id); + $assetData->put('tag', $asset->asset_tag); + + if ($template->getSupportTitle()) { + $assetData->put('title', !empty($settings->label2_title) ? + str_ireplace(':company', $asset->company->name, $settings->label2_title) : + $settings->qr_text + ); + } + + if ($template->getSupportLogo()) { + $assetData->put('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 ($template->getSupport1DBarcode()) { + $barcode1DType = $settings->label2_1d_type; + $barcode1DType = ($barcode1DType == 'default') ? + (($settings->alt_barcode_enabled) ? $settings->alt_barcode : null) : + $barcode1DType; + if ($barcode1DType) { + $assetData->put('barcode1d', (object)[ + 'type' => $barcode1DType, + 'content' => $asset->asset_tag, + ]); + } + } + + if ($template->getSupport2DBarcode()) { + $barcode2DType = $settings->label2_2d_type; + $barcode2DType = ($barcode2DType == 'default') ? + (($settings->qr_code) ? $settings->barcode_type : null) : + $barcode2DType; + if ($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(function ($group, $index) use ($asset) { + return $group->mapWithKeys(function ($definition, $label) use ($asset) { + $value = collect(explode('.', $definition)) + ->reduce(function ($carry, $chunk) { + return $carry ? $carry->{$chunk} : ${$carry}; + }, $asset); + return [ $label => $value ]; + }); + }) + ->reduce(function ($carry, $group, $index) { + $values = $group + ->filter(function ($value, $label) use ($carry) { + if (empty($value)) return false; + if ($carry->has($label)) return false; + return true; + }) + ->take(1); + return $carry->merge($values); + }, 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; + } + +} \ No newline at end of file diff --git a/composer.json b/composer.json index 07dbf20639..ccddd5ab2f 100644 --- a/composer.json +++ b/composer.json @@ -68,6 +68,7 @@ "rollbar/rollbar-laravel": "^7.0", "spatie/laravel-backup": "^6.16", "tecnickcom/tc-lib-barcode": "^1.15", + "tecnickcom/tcpdf": "^6.5.0", "unicodeveloper/laravel-password": "^1.0", "watson/validating": "^6.1" }, diff --git a/database/migrations/2022_10_25_215520_add_label2_settings.php b/database/migrations/2022_10_25_215520_add_label2_settings.php new file mode 100644 index 0000000000..66b0a08718 --- /dev/null +++ b/database/migrations/2022_10_25_215520_add_label2_settings.php @@ -0,0 +1,51 @@ +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.tag').'=asset_tag;'. + 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'); + }); + } +} diff --git a/resources/lang/en/admin/labels/message.php b/resources/lang/en/admin/labels/message.php new file mode 100644 index 0000000000..96785f0754 --- /dev/null +++ b/resources/lang/en/admin/labels/message.php @@ -0,0 +1,11 @@ + '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', + +]; diff --git a/resources/lang/en/admin/labels/table.php b/resources/lang/en/admin/labels/table.php new file mode 100644 index 0000000000..bc0ab7a977 --- /dev/null +++ b/resources/lang/en/admin/labels/table.php @@ -0,0 +1,12 @@ + 'Labels', + 'support_fields' => 'Fields', + 'support_1d_barcode' => '1D', + 'support_2d_barcode' => '2D', + 'support_logo' => 'Logo', + 'support_title' => 'Title', + +]; \ No newline at end of file diff --git a/resources/lang/en/admin/settings/general.php b/resources/lang/en/admin/settings/general.php index f5542d505b..e969dd93c5 100644 --- a/resources/lang/en/admin/settings/general.php +++ b/resources/lang/en/admin/settings/general.php @@ -320,4 +320,31 @@ return [ 'setup_migration_create_user' => 'Next: Create User', 'ldap_settings_link' => 'LDAP Settings Page', 'slack_test' => 'Test Integration', + + 'label2_enable' => 'New Label Engine', + 'label2_enable_help' => 'Switch to the new label engine. Note: You will need to save this setting before setting others.', + '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 :company will be replaced with the asset's company name', + 'label2_asset_logo' => 'Use Asset Logo', + 'label2_asset_logo_help' => 'Use the logo of the asset's assigned company, rather than the value at :setting_name', + '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' => 'Fields Definition', + 'label2_fields_help' => 'Fields to show on the label in the format Label=asset_field', + 'label2_fields_help_semi' => 'Use ; to separate fields', + 'label2_fields_help_pipe' => 'Use | to allow multiple options in each field. For example Name=name|Nickname=_snipeit_my_custom_field_2 will use name if a value is set, otherwise it will use _snipeit_my_custom_field_2. This is useful to ensure field order', + 'label2_fields_help_once' => 'Each field will only be selected once per label', + + 'help_asterisk_bold' => 'Text entered as **text** will be displayed as bold', + 'help_blank_to_use' => 'Leave blank to use the value from :setting_name', + 'help_default_will_use' => ':default will use the value from :setting_name', + 'default' => 'Default', + 'none' => 'None', ]; diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 57ac6a4d7e..de888dbe7f 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -663,6 +663,25 @@ } } + function labelPerPageFormatter(value, row, index, field) { + if (row) { + if (row.sheet_labels) { 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; diff --git a/resources/views/settings/labels.blade.php b/resources/views/settings/labels.blade.php index a509769dee..dd9b302b2d 100644 --- a/resources/views/settings/labels.blade.php +++ b/resources/views/settings/labels.blade.php @@ -40,160 +40,363 @@
-
+ +
- {{ Form::label('labels_per_page', trans('admin/settings/general.labels_per_page')) }} + {{ Form::label('label2_enable', trans('admin/settings/general.label2_enable')) }}
- {{ 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', '') !!} + {{ Form::checkbox('label2_enable', '1', old('label2_enable', $setting->label2_enable, [ 'class'=>'minimal', 'aria-label'=>'label2_enable' ])) }} + {{ trans('general.yes') }} + {!! $errors->first('label2_enable', '') !!} +

{!! trans('admin/settings/general.label2_enable_help') !!}

-
-
- {{ Form::label('labels_fontsize', trans('admin/settings/general.labels_fontsize')) }} -
-
-
- {{ Form::text('labels_fontsize', old('labels_fontsize', $setting->labels_fontsize), ['class' => 'form-control', 'aria-label'=>'labels_fontsize']) }} -
{{ trans('admin/settings/general.text_pt') }}
-
-
-
- {!! $errors->first('labels_fontsize', '') !!} -
-
+ @if ($setting->label2_enable) + -
-
- {{ Form::label('labels_width', trans('admin/settings/general.label_dimensions')) }} -
-
-
- {{ Form::text('labels_width', old('labels_width', $setting->labels_width), ['class' => 'form-control', 'aria-label'=>'labels_width']) }} -
{{ trans('admin/settings/general.width_w') }}
+ +
+
+ {{ Form::label('label2_template', trans('admin/settings/general.label2_template')) }} +
+
+
-
-
- {{ Form::text('labels_height', old('labels_height', $setting->labels_height), ['class' => 'form-control', 'aria-label'=>'labels_height']) }} -
{{ trans('admin/settings/general.height_h') }}
-
-
-
- {!! $errors->first('labels_width', '') !!} - {!! $errors->first('labels_height', '') !!} -
-
-
-
- {{ Form::label('labels_display_sgutter', trans('admin/settings/general.label_gutters')) }} -
-
-
- {{ Form::text('labels_display_sgutter', old('labels_display_sgutter', $setting->labels_display_sgutter), ['class' => 'form-control', 'aria-label'=>'labels_display_sgutter']) }} -
{{ trans('admin/settings/general.horizontal') }}
+ +
+
+ {{ Form::label('label2_title', trans('admin/settings/general.label2_title')) }} +
+
+ {{ 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', '') !!} +

{!! trans('admin/settings/general.label2_title_help') !!}

+

+ {!! trans('admin/settings/general.label2_title_help_phold') !!}.
+ {!! trans('admin/settings/general.help_asterisk_bold') !!}.
+ {!! + trans('admin/settings/general.help_blank_to_use', [ + 'setting_name' => trans('admin/settings/general.barcodes').' > '.trans('admin/settings/general.qr_text') + ]) + !!} +

-
-
- {{ Form::text('labels_display_bgutter', old('labels_display_bgutter', $setting->labels_display_bgutter), ['class' => 'form-control', 'aria-label'=>'labels_display_bgutter']) }} -
{{ trans('admin/settings/general.vertical') }}
-
-
-
- {!! $errors->first('labels_display_sgutter', '') !!} - {!! $errors->first('labels_display_bgutter', '') !!} -
-
-
-
- {{ Form::label('labels_pmargin_top', trans('admin/settings/general.page_padding')) }} -
-
-
- {{ Form::text('labels_pmargin_top', old('labels_pmargin_top', $setting->labels_pmargin_top), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_top']) }} -
{{ trans('admin/settings/general.top') }}
+ +
+
+ {{ Form::label('label2_asset_logo', trans('admin/settings/general.label2_asset_logo')) }}
-
- {{ Form::text('labels_pmargin_right', old('labels_pmargin_right', $setting->labels_pmargin_right), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_right']) }} -
{{ trans('admin/settings/general.right') }}
+
+ {{ 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', '') !!} +

{!! trans('admin/settings/general.label2_asset_logo_help', ['setting_name' => trans('admin/settings/general.brand').' > '.trans('admin/settings/general.label_logo')]) !!}

-
-
- {{ Form::text('labels_pmargin_bottom', old('labels_pmargin_bottom', $setting->labels_pmargin_bottom), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_bottom']) }} -
{{ trans('admin/settings/general.bottom') }}
+ + +
+
+ {{ Form::label('label2_1d_type', trans('admin/settings/general.label2_1d_type')) }}
-
- {{ Form::text('labels_pmargin_left', old('labels_pmargin_left', $setting->labels_pmargin_left), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_left']) }} -
{{ trans('admin/settings/general.left') }}
-
- -
-
- {!! $errors->first('labels_width', '') !!} - {!! $errors->first('labels_height', '') !!} -
-
- -
-
- {{ Form::label('labels_pagewidth', trans('admin/settings/general.page_dimensions')) }} -
-
-
- {{ Form::text('labels_pagewidth', old('labels_pagewidth', $setting->labels_pagewidth), ['class' => 'form-control', 'aria-label'=>'labels_pagewidth']) }} -
{{ trans('admin/settings/general.width_w') }}
+
+ @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', '') !!} +

+ {{ 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').' > '.trans('admin/settings/general.alt_barcode_type'), + ]) + !!} +

-
-
- {{ Form::text('labels_pageheight', old('labels_pageheight', $setting->labels_pageheight), ['class' => 'form-control', 'aria-label'=>'labels_pageheight']) }} -
{{ trans('admin/settings/general.height_h') }}
+ + +
+
+ {{ Form::label('label2_2d_type', trans('admin/settings/general.label2_2d_type')) }} +
+
+ @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', '') !!} +

+ {{ 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').' > '.trans('admin/settings/general.barcode_type'), + ]) + !!} +

-
- {!! $errors->first('labels_pagewidth', '') !!} - {!! $errors->first('labels_pageheight', '') !!} + + +
+
+ {{ Form::label('label2_2d_target', trans('admin/settings/general.label2_2d_target')) }} +
+
+ {{ 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', '') !!} +

{!! trans('admin/settings/general.label2_2d_target_help') !!}

+
-
-
-
- {{ Form::label('labels_display', trans('admin/settings/general.label_fields')) }} + +
+
+ {{ Form::label('label2_fields', trans('admin/settings/general.label2_fields')) }} +
+
+ {{ Form::text('label2_fields', old('label2_fields', $setting->label2_fields), [ 'class'=>'form-control', 'aria-label'=>'label2_fields' ]) }} + {!! $errors->first('label2_fields', '') !!} +

{!! trans('admin/settings/general.label2_fields_help') !!}

+

+ {!! trans('admin/settings/general.label2_fields_help_semi') !!}.
+ {!! trans('admin/settings/general.label2_fields_help_pipe') !!}.
+ {!! trans('admin/settings/general.label2_fields_help_once') !!}. +

+
-
-
- - - - - -
-
-
+ @include('partials.bootstrap-table') + + @else + + {{ 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')) + + {{ 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 + +
+
+ {{ Form::label('labels_per_page', trans('admin/settings/general.labels_per_page')) }} +
+
+ {{ 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', '') !!} +
+
+ +
+
+ {{ Form::label('labels_fontsize', trans('admin/settings/general.labels_fontsize')) }} +
+
+
+ {{ Form::text('labels_fontsize', old('labels_fontsize', $setting->labels_fontsize), ['class' => 'form-control', 'aria-label'=>'labels_fontsize']) }} +
{{ trans('admin/settings/general.text_pt') }}
+
+
+
+ {!! $errors->first('labels_fontsize', '') !!} +
+
+ +
+
+ {{ Form::label('labels_width', trans('admin/settings/general.label_dimensions')) }} +
+
+
+ {{ Form::text('labels_width', old('labels_width', $setting->labels_width), ['class' => 'form-control', 'aria-label'=>'labels_width']) }} +
{{ trans('admin/settings/general.width_w') }}
+
+
+
+
+ {{ Form::text('labels_height', old('labels_height', $setting->labels_height), ['class' => 'form-control', 'aria-label'=>'labels_height']) }} +
{{ trans('admin/settings/general.height_h') }}
+
+
+
+ {!! $errors->first('labels_width', '') !!} + {!! $errors->first('labels_height', '') !!} +
+
+ +
+
+ {{ Form::label('labels_display_sgutter', trans('admin/settings/general.label_gutters')) }} +
+
+
+ {{ Form::text('labels_display_sgutter', old('labels_display_sgutter', $setting->labels_display_sgutter), ['class' => 'form-control', 'aria-label'=>'labels_display_sgutter']) }} +
{{ trans('admin/settings/general.horizontal') }}
+
+
+
+
+ {{ Form::text('labels_display_bgutter', old('labels_display_bgutter', $setting->labels_display_bgutter), ['class' => 'form-control', 'aria-label'=>'labels_display_bgutter']) }} +
{{ trans('admin/settings/general.vertical') }}
+
+
+
+ {!! $errors->first('labels_display_sgutter', '') !!} + {!! $errors->first('labels_display_bgutter', '') !!} +
+
+ +
+
+ {{ Form::label('labels_pmargin_top', trans('admin/settings/general.page_padding')) }} +
+
+
+ {{ Form::text('labels_pmargin_top', old('labels_pmargin_top', $setting->labels_pmargin_top), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_top']) }} +
{{ trans('admin/settings/general.top') }}
+
+
+ {{ Form::text('labels_pmargin_right', old('labels_pmargin_right', $setting->labels_pmargin_right), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_right']) }} +
{{ trans('admin/settings/general.right') }}
+
+
+
+
+ {{ Form::text('labels_pmargin_bottom', old('labels_pmargin_bottom', $setting->labels_pmargin_bottom), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_bottom']) }} +
{{ trans('admin/settings/general.bottom') }}
+
+
+ {{ Form::text('labels_pmargin_left', old('labels_pmargin_left', $setting->labels_pmargin_left), ['class' => 'form-control', 'aria-label'=>'labels_pmargin_left']) }} +
{{ trans('admin/settings/general.left') }}
+
+ +
+
+ {!! $errors->first('labels_width', '') !!} + {!! $errors->first('labels_height', '') !!} +
+
+ +
+
+ {{ Form::label('labels_pagewidth', trans('admin/settings/general.page_dimensions')) }} +
+
+
+ {{ Form::text('labels_pagewidth', old('labels_pagewidth', $setting->labels_pagewidth), ['class' => 'form-control', 'aria-label'=>'labels_pagewidth']) }} +
{{ trans('admin/settings/general.width_w') }}
+
+
+
+
+ {{ Form::text('labels_pageheight', old('labels_pageheight', $setting->labels_pageheight), ['class' => 'form-control', 'aria-label'=>'labels_pageheight']) }} +
{{ trans('admin/settings/general.height_h') }}
+
+
+
+ {!! $errors->first('labels_pagewidth', '') !!} + {!! $errors->first('labels_pageheight', '') !!} +
+
+ +
+
+ {{ Form::label('labels_display', trans('admin/settings/general.label_fields')) }} +
+
+
+ + + + + +
+
+
+ + @endif
diff --git a/routes/api.php b/routes/api.php index d27f146013..19ec4fd74a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -611,6 +611,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 diff --git a/routes/web/hardware.php b/routes/web/hardware.php index 09811d17d7..9f28434107 100644 --- a/routes/web/hardware.php +++ b/routes/web/hardware.php @@ -181,4 +181,8 @@ Route::resource('hardware', 'middleware' => ['auth'], 'parameters' => ['asset' => 'asset_id' ], -]); \ No newline at end of file +]); + +Route::get('ht/{any?}', + [AssetsController::class, 'getAssetByTag'] +)->where('any', '.*')->name('ht/assetTag'); \ No newline at end of file