Add catalog option sets
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "CatalogProductTypeSetting" ADD COLUMN "colorOptions" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||||
|
ADD COLUMN "labelOptions" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||||
|
ADD COLUMN "lengthOptionsM" INTEGER[] DEFAULT ARRAY[]::INTEGER[],
|
||||||
|
ADD COLUMN "sleeveOptions" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||||
|
ADD COLUMN "thicknessOptionsMicron" INTEGER[] DEFAULT ARRAY[]::INTEGER[],
|
||||||
|
ADD COLUMN "widthOptionsMm" INTEGER[] DEFAULT ARRAY[]::INTEGER[];
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "CatalogProductTypeSetting" ADD COLUMN "colorOptions" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||||
|
ADD COLUMN "labelOptions" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||||
|
ADD COLUMN "lengthOptionsM" INTEGER[] DEFAULT ARRAY[]::INTEGER[],
|
||||||
|
ADD COLUMN "sleeveOptions" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||||
|
ADD COLUMN "thicknessOptionsMicron" INTEGER[] DEFAULT ARRAY[]::INTEGER[],
|
||||||
|
ADD COLUMN "widthOptionsMm" INTEGER[] DEFAULT ARRAY[]::INTEGER[];
|
||||||
@@ -200,6 +200,12 @@ model CatalogProductTypeSetting {
|
|||||||
customLengthStepM Int?
|
customLengthStepM Int?
|
||||||
allowCustomSleeveBrand Boolean @default(false)
|
allowCustomSleeveBrand Boolean @default(false)
|
||||||
allowCustomLabel Boolean @default(false)
|
allowCustomLabel Boolean @default(false)
|
||||||
|
widthOptionsMm Int[] @default([])
|
||||||
|
lengthOptionsM Int[] @default([])
|
||||||
|
thicknessOptionsMicron Int[] @default([])
|
||||||
|
sleeveOptions String[] @default([])
|
||||||
|
colorOptions String[] @default([])
|
||||||
|
labelOptions String[] @default([])
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -441,6 +441,57 @@ function presentCatalogProductTypeSetting(setting) {
|
|||||||
customLengthStepM: setting.customLengthStepM ?? null,
|
customLengthStepM: setting.customLengthStepM ?? null,
|
||||||
allowCustomSleeveBrand: Boolean(setting.allowCustomSleeveBrand),
|
allowCustomSleeveBrand: Boolean(setting.allowCustomSleeveBrand),
|
||||||
allowCustomLabel: Boolean(setting.allowCustomLabel),
|
allowCustomLabel: Boolean(setting.allowCustomLabel),
|
||||||
|
widthOptionsMm: [...(setting.widthOptionsMm ?? [])],
|
||||||
|
lengthOptionsM: [...(setting.lengthOptionsM ?? [])],
|
||||||
|
thicknessOptionsMicron: [...(setting.thicknessOptionsMicron ?? [])],
|
||||||
|
sleeveOptions: [...(setting.sleeveOptions ?? [])],
|
||||||
|
colorOptions: [...(setting.colorOptions ?? [])],
|
||||||
|
labelOptions: [...(setting.labelOptions ?? [])],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePositiveIntList(values) {
|
||||||
|
return [...new Set((values ?? [])
|
||||||
|
.map((value) => normalizeOptionalPositiveInt(value))
|
||||||
|
.filter((value) => value !== null))]
|
||||||
|
.sort((a, b) => a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeTextList(values) {
|
||||||
|
return [...new Set((values ?? [])
|
||||||
|
.map((value) => normalizeText(value))
|
||||||
|
.filter(Boolean))]
|
||||||
|
.sort((a, b) => a.localeCompare(b, 'ru'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectProductTypeOptionDefaults(products) {
|
||||||
|
const colorOptions = [];
|
||||||
|
const labelOptions = [];
|
||||||
|
|
||||||
|
for (const product of products) {
|
||||||
|
for (const tag of product.tags ?? []) {
|
||||||
|
const normalizedTag = normalizeText(tag);
|
||||||
|
if (!normalizedTag) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['прозрачный', 'коричневый', 'белый', 'черный', 'желтый', 'зеленый', 'красный', 'синий', 'оранжевый', 'красно-белый'].includes(normalizedTag)) {
|
||||||
|
colorOptions.push(normalizedTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['хрупкое', 'подарок', 'акция'].includes(normalizedTag)) {
|
||||||
|
labelOptions.push(normalizedTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
widthOptionsMm: normalizePositiveIntList(products.map((product) => product.widthMm)),
|
||||||
|
lengthOptionsM: normalizePositiveIntList(products.map((product) => product.lengthM)),
|
||||||
|
thicknessOptionsMicron: normalizePositiveIntList(products.map((product) => product.thicknessMicron)),
|
||||||
|
sleeveOptions: normalizeTextList(products.map((product) => product.sleeveBrand)),
|
||||||
|
colorOptions: normalizeTextList(colorOptions),
|
||||||
|
labelOptions: normalizeTextList(labelOptions),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,6 +525,12 @@ function normalizeCatalogProductTypeSettingInput(input) {
|
|||||||
customLengthStepM,
|
customLengthStepM,
|
||||||
allowCustomSleeveBrand: Boolean(input.allowCustomSleeveBrand),
|
allowCustomSleeveBrand: Boolean(input.allowCustomSleeveBrand),
|
||||||
allowCustomLabel: Boolean(input.allowCustomLabel),
|
allowCustomLabel: Boolean(input.allowCustomLabel),
|
||||||
|
widthOptionsMm: normalizePositiveIntList(input.widthOptionsMm),
|
||||||
|
lengthOptionsM: normalizePositiveIntList(input.lengthOptionsM),
|
||||||
|
thicknessOptionsMicron: normalizePositiveIntList(input.thicknessOptionsMicron),
|
||||||
|
sleeveOptions: normalizeTextList(input.sleeveOptions),
|
||||||
|
colorOptions: normalizeTextList(input.colorOptions),
|
||||||
|
labelOptions: normalizeTextList(input.labelOptions),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,24 +543,49 @@ async function listCatalogProductTypeSettings(prisma) {
|
|||||||
productType: null,
|
productType: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
select: { productType: true },
|
select: {
|
||||||
distinct: ['productType'],
|
productType: true,
|
||||||
orderBy: { productType: 'asc' },
|
widthMm: true,
|
||||||
|
lengthM: true,
|
||||||
|
thicknessMicron: true,
|
||||||
|
sleeveBrand: true,
|
||||||
|
tags: true,
|
||||||
|
},
|
||||||
|
orderBy: [{ productType: 'asc' }, { name: 'asc' }],
|
||||||
}),
|
}),
|
||||||
prisma.catalogProductTypeSetting.findMany({
|
prisma.catalogProductTypeSetting.findMany({
|
||||||
orderBy: { productType: 'asc' },
|
orderBy: { productType: 'asc' },
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const productsByType = new Map();
|
||||||
|
for (const product of products) {
|
||||||
|
const productType = normalizeText(product.productType);
|
||||||
|
if (!productType) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = productsByType.get(productType);
|
||||||
|
if (existing) {
|
||||||
|
existing.push(product);
|
||||||
|
} else {
|
||||||
|
productsByType.set(productType, [product]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const productTypes = new Set([
|
const productTypes = new Set([
|
||||||
...products.map((item) => normalizeText(item.productType)).filter(Boolean),
|
...productsByType.keys(),
|
||||||
...persistedSettings.map((item) => item.productType),
|
...persistedSettings.map((item) => item.productType),
|
||||||
]);
|
]);
|
||||||
const settingsByType = new Map(persistedSettings.map((item) => [item.productType, item]));
|
const settingsByType = new Map(persistedSettings.map((item) => [item.productType, item]));
|
||||||
|
|
||||||
return [...productTypes]
|
return [...productTypes]
|
||||||
.sort((a, b) => a.localeCompare(b, 'ru'))
|
.sort((a, b) => a.localeCompare(b, 'ru'))
|
||||||
.map((productType) => presentCatalogProductTypeSetting({
|
.map((productType) => {
|
||||||
|
const persisted = settingsByType.get(productType);
|
||||||
|
const fallbackOptions = collectProductTypeOptionDefaults(productsByType.get(productType) ?? []);
|
||||||
|
|
||||||
|
return presentCatalogProductTypeSetting(persisted ?? {
|
||||||
productType,
|
productType,
|
||||||
showQuantityPerBox: false,
|
showQuantityPerBox: false,
|
||||||
allowCustomLength: false,
|
allowCustomLength: false,
|
||||||
@@ -512,8 +594,9 @@ async function listCatalogProductTypeSettings(prisma) {
|
|||||||
customLengthStepM: null,
|
customLengthStepM: null,
|
||||||
allowCustomSleeveBrand: false,
|
allowCustomSleeveBrand: false,
|
||||||
allowCustomLabel: false,
|
allowCustomLabel: false,
|
||||||
...settingsByType.get(productType),
|
...fallbackOptions,
|
||||||
}));
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const cartInclude = {
|
const cartInclude = {
|
||||||
|
|||||||
@@ -257,6 +257,12 @@ type CatalogProductTypeSetting {
|
|||||||
customLengthStepM: Int
|
customLengthStepM: Int
|
||||||
allowCustomSleeveBrand: Boolean!
|
allowCustomSleeveBrand: Boolean!
|
||||||
allowCustomLabel: Boolean!
|
allowCustomLabel: Boolean!
|
||||||
|
widthOptionsMm: [Int!]!
|
||||||
|
lengthOptionsM: [Int!]!
|
||||||
|
thicknessOptionsMicron: [Int!]!
|
||||||
|
sleeveOptions: [String!]!
|
||||||
|
colorOptions: [String!]!
|
||||||
|
labelOptions: [String!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type CartItem {
|
type CartItem {
|
||||||
@@ -512,6 +518,12 @@ input UpsertCatalogProductTypeSettingInput {
|
|||||||
customLengthStepM: Int
|
customLengthStepM: Int
|
||||||
allowCustomSleeveBrand: Boolean!
|
allowCustomSleeveBrand: Boolean!
|
||||||
allowCustomLabel: Boolean!
|
allowCustomLabel: Boolean!
|
||||||
|
widthOptionsMm: [Int!]!
|
||||||
|
lengthOptionsM: [Int!]!
|
||||||
|
thicknessOptionsMicron: [Int!]!
|
||||||
|
sleeveOptions: [String!]!
|
||||||
|
colorOptions: [String!]!
|
||||||
|
labelOptions: [String!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input ReadyOrderItemInput {
|
input ReadyOrderItemInput {
|
||||||
|
|||||||
Reference in New Issue
Block a user