Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion backend/internal/data/repo/repo_entities.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ type (
Name string `json:"name" validate:"required,min=1,max=255"`
Quantity float64 `json:"quantity"`
Description string `json:"description" validate:"max=1000"`
UPC string `json:"upc" validate:"max=64"`
AssetID AssetID `json:"-"`
EntityTypeID uuid.UUID `json:"entityTypeId"`

Expand All @@ -116,6 +117,7 @@ type (
TagIDs []uuid.UUID `json:"tagIds"`

// Identifications
UPC string `json:"upc" validate:"max=64"`
SerialNumber string `json:"serialNumber"`
ModelNumber string `json:"modelNumber"`
Manufacturer string `json:"manufacturer"`
Expand Down Expand Up @@ -156,6 +158,7 @@ type (
AssetID AssetID `json:"assetId,string"`
Name string `json:"name"`
Description string `json:"description"`
UPC string `json:"upc"`
Quantity float64 `json:"quantity"`
Insured bool `json:"insured"`
Archived bool `json:"archived"`
Expand Down Expand Up @@ -187,6 +190,7 @@ type (
SyncChildEntityLocations bool `json:"syncChildEntityLocations"`

SerialNumber string `json:"serialNumber"`
UPC string `json:"upc"`
ModelNumber string `json:"modelNumber"`
Manufacturer string `json:"manufacturer"`

Expand Down Expand Up @@ -258,6 +262,7 @@ func mapEntitySummary(e *ent.Entity) EntitySummary {
AssetID: AssetID(e.AssetID),
Name: e.Name,
Description: e.Description,
UPC: e.ImportRef,
ImportRef: e.ImportRef,
Quantity: e.Quantity,
CreatedAt: e.CreatedAt,
Expand Down Expand Up @@ -336,6 +341,7 @@ func mapEntityOut(e *ent.Entity) EntityOut {
SyncChildEntityLocations: e.SyncChildEntityLocations,

// Identification
UPC: e.ImportRef,
SerialNumber: e.SerialNumber,
ModelNumber: e.ModelNumber,
Manufacturer: e.Manufacturer,
Expand Down Expand Up @@ -587,6 +593,7 @@ func (r *EntityRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q En
entity.Or(
entity.NameContainsFold(q.Search),
entity.DescriptionContainsFold(q.Search),
entity.ImportRefContainsFold(q.Search),
entity.SerialNumberContainsFold(q.Search),
entity.ModelNumberContainsFold(q.Search),
entity.ManufacturerContainsFold(q.Search),
Expand Down Expand Up @@ -993,8 +1000,13 @@ func (r *EntityRepository) Create(ctx context.Context, gid uuid.UUID, data Entit
return EntityOut{}, err
}

importRef := data.ImportRef
if data.UPC != "" {
importRef = data.UPC
}

q := r.db.Entity.Create().
SetImportRef(data.ImportRef).
SetImportRef(importRef).
SetName(data.Name).
SetQuantity(data.Quantity).
SetDescription(data.Description).
Expand Down Expand Up @@ -1425,6 +1437,7 @@ func (r *EntityRepository) UpdateByGroup(ctx context.Context, gid uuid.UUID, dat
q := r.db.Entity.Update().Where(entity.ID(data.ID), entity.HasGroupWith(group.ID(gid))).
SetName(data.Name).
SetDescription(data.Description).
SetImportRef(data.UPC).
SetSerialNumber(data.SerialNumber).
SetModelNumber(data.ModelNumber).
SetManufacturer(data.Manufacturer).
Expand Down Expand Up @@ -2113,6 +2126,7 @@ func (r *EntityRepository) Duplicate(ctx context.Context, gid, id uuid.UUID, opt
SetQuantity(originalEntity.Quantity).
SetGroupID(gid).
SetAssetID(int64(nextAssetID)).
SetImportRef(originalEntity.ImportRef).
SetSerialNumber(originalEntity.SerialNumber).
SetModelNumber(originalEntity.ModelNumber).
SetManufacturer(originalEntity.Manufacturer).
Expand Down
29 changes: 28 additions & 1 deletion frontend/components/Item/BarcodeModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@
<DialogTitle>{{ $t("components.item.product_import.title") }}</DialogTitle>
</DialogHeader>

<div
v-if="existingItems.length > 0"
class="flex flex-col gap-2 rounded-md border border-amber-500/40 bg-amber-500/10 p-4 text-amber-700 dark:text-amber-300"
role="alert"
>
<span class="text-sm font-medium">
Found {{ existingItems.length }} existing item(s) with UPC {{ barcode }}.
</span>
<div class="flex flex-wrap gap-2">
<Button v-for="existing in existingItems" :key="existing.id" size="sm" variant="outline" @click="navigateToItem(existing.id)">
Open {{ existing.name }}
</Button>
</div>
</div>

<div
v-if="errorMessage"
class="flex items-center gap-2 rounded-md border border-destructive bg-destructive/10 p-4 text-destructive"
Expand Down Expand Up @@ -112,7 +127,7 @@
import { useI18n } from "vue-i18n";
import { DialogID } from "@/components/ui/dialog-provider/utils";
import { Button } from "~/components/ui/button";
import type { BarcodeProduct } from "~~/lib/api/types/data-contracts";
import type { BarcodeProduct, EntitySummary } from "~~/lib/api/types/data-contracts";
import { useDialog } from "~/components/ui/dialog-provider";
import MdiAlertCircleOutline from "~icons/mdi/alert-circle-outline";
import MdiBarcode from "~icons/mdi/barcode";
Expand All @@ -129,6 +144,7 @@
const searching = ref(false);
const barcode = ref<string>("");
const products = ref<BarcodeProduct[] | null>(null);
const existingItems = ref<EntitySummary[]>([]);
const selectedRow = ref(-1);
const errorMessage = ref<string | null>(null);

Expand Down Expand Up @@ -159,6 +175,7 @@
selectedRow.value = -1;
searching.value = false;
errorMessage.value = null;
existingItems.value = [];

if (params?.barcode) {
// Reset if the barcode is different
Expand Down Expand Up @@ -196,6 +213,7 @@

async function retrieveProductInfo(barcode: string) {
errorMessage.value = null;
existingItems.value = [];

if (!barcode || barcode.trim().length === 0 || !/^[0-9]+$/.test(barcode)) {
errorMessage.value = t("components.item.product_import.error_invalid_barcode");
Expand All @@ -207,6 +225,11 @@
searching.value = true;

try {
const existingResult = await api.items.getAll({ q: barcode.trim(), page: 1, pageSize: 10 });
if (!existingResult.error && existingResult.data?.items) {
existingItems.value = existingResult.data.items.filter(item => item.upc === barcode.trim());
}

const result = await api.products.searchFromBarcode(barcode.trim());
if (result.error) {
errorMessage.value = t("errors.api_failure") + result.error;
Expand All @@ -226,6 +249,10 @@
}
}

function navigateToItem(itemId: string) {
navigateTo(`/item/${itemId}`);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function extractValue(data: Record<string, any>, value: string) {
const parts = value.split(".");
Expand Down
4 changes: 4 additions & 0 deletions frontend/components/Item/CreateModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@
parentId: null,
name: "",
quantity: 1,
upc: "",
description: "",
color: "",
tags: [] as string[],
Expand Down Expand Up @@ -602,6 +603,7 @@
if (params?.product) {
form.name = params.product.item.name;
form.description = params.product.item.description;
form.upc = params.product.barcode;

if (params.product.imageURL) {
form.photos.push({
Expand Down Expand Up @@ -660,6 +662,7 @@
parentId: form.parentId || form.location.id as string,
name: form.name,
quantity: form.quantity,
upc: form.upc,
description: form.description,
tagIds: form.tags,
entityTypeId: selectedEntityType.value?.id,
Expand Down Expand Up @@ -705,6 +708,7 @@

form.name = "";
form.quantity = 1;
form.upc = "";
form.description = "";
form.color = "";
form.photos = [];
Expand Down
4 changes: 4 additions & 0 deletions frontend/lib/api/types/data-contracts.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@
"select_field": "Select a field",
"select_value": "Select a value",
"serial_number": "Serial Number",
"upc": "UPC",
"show_advanced_view_options": "Show Advanced View Options",
"show_empty": "Show Empty",
"sold_at": "Sold At",
Expand Down
6 changes: 6 additions & 0 deletions frontend/pages/item/[id]/index/edit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@
ref: "description",
maxLength: 1000,
},
{
type: "text",
label: "items.upc",
ref: "upc",
maxLength: 64,
},
{
type: "text",
label: "items.serial_number",
Expand Down
Loading