solved merge conflicts
This commit is contained in:
+4
-4
@@ -4,11 +4,11 @@ CORS_ORIGIN=http://localhost:5173
|
||||
JWT_SECRET=supersecretjwtkeythatislongandsecure
|
||||
JWT_EXPIRES_IN=7d
|
||||
|
||||
DB_HOST=127.0.0.1
|
||||
DB_HOST=106.51.105.22
|
||||
DB_PORT=5432
|
||||
DB_NAME=Pim_Maskan
|
||||
DB_USER=postgres
|
||||
DB_PASSWORD=postgres
|
||||
DB_NAME=pc_local
|
||||
DB_USER=pc_user
|
||||
DB_PASSWORD="#TpW@%a&b$[zm"
|
||||
DB_DIALECT=postgres
|
||||
|
||||
# IMPORTANT: Gmail SMTP requires an App Password, NOT your regular password.
|
||||
|
||||
@@ -49,13 +49,13 @@ export class BrandService {
|
||||
action: 'CREATE',
|
||||
resource: 'Brand',
|
||||
resourceId: record.id,
|
||||
userId: userContext.userId || 'system',
|
||||
userId: context.userId || 'system',
|
||||
details: data
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'brand',
|
||||
action: 'created',
|
||||
title: 'New brand added',
|
||||
@@ -89,13 +89,13 @@ export class BrandService {
|
||||
action: 'UPDATE',
|
||||
resource: 'Brand',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || 'system',
|
||||
userId: context.userId || 'system',
|
||||
details: data
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'brand',
|
||||
action: 'updated',
|
||||
title: 'Brand updated',
|
||||
@@ -129,12 +129,12 @@ export class BrandService {
|
||||
action: 'DELETE',
|
||||
resource: 'Brand',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || userContext.id || 'system'
|
||||
userId: context.userId || context.id || 'system'
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'brand',
|
||||
action: 'deleted',
|
||||
title: 'Brand deleted',
|
||||
@@ -162,12 +162,12 @@ export class BrandService {
|
||||
action: 'ARCHIVE',
|
||||
resource: 'Brand',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || userContext.id || 'system'
|
||||
userId: context.userId || context.id || 'system'
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'brand',
|
||||
action: 'deleted',
|
||||
title: 'Brand deleted',
|
||||
|
||||
@@ -40,6 +40,7 @@ export class CatalogController {
|
||||
channelCount: raw.channelCount ?? 0,
|
||||
attributeGroups: raw.attributeGroups ?? 0,
|
||||
canDelete: raw.canDelete ?? true,
|
||||
completeness: raw.completeness ?? 100,
|
||||
lastUpdated: raw.updated_at || raw.updatedAt,
|
||||
createdBy: raw.created_by || 'system'
|
||||
};
|
||||
|
||||
@@ -24,11 +24,11 @@ export class Catalog extends Model {
|
||||
as: 'variantAxes'
|
||||
});
|
||||
|
||||
// M:N with AssetType for required assets
|
||||
Catalog.belongsToMany(models.AssetType, {
|
||||
// M:N with AssetFamily for required assets
|
||||
Catalog.belongsToMany(models.AssetFamily, {
|
||||
through: models.FamilyAssetRequirement,
|
||||
foreignKey: 'family_id',
|
||||
otherKey: 'asset_type_id',
|
||||
otherKey: 'asset_family_id',
|
||||
as: 'assetRequirements'
|
||||
});
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export class CatalogRepository {
|
||||
]
|
||||
},
|
||||
{
|
||||
model: models.AssetType,
|
||||
model: models.AssetFamily,
|
||||
as: 'assetRequirements',
|
||||
through: { attributes: [] }
|
||||
},
|
||||
@@ -106,7 +106,7 @@ export class CatalogRepository {
|
||||
]
|
||||
},
|
||||
{
|
||||
model: models.AssetType,
|
||||
model: models.AssetFamily,
|
||||
as: 'assetRequirements',
|
||||
through: { attributes: [] }
|
||||
},
|
||||
|
||||
@@ -3,7 +3,6 @@ import { models, sequelize } from '../../../shared/database/models.js';
|
||||
import { SocketService } from '../../../shared/services/socket.service.js';
|
||||
import { AuditService } from '../../../shared/services/audit.service.js';
|
||||
import { ApiError } from '../../../utils/helpers/ApiError.utils.js';
|
||||
import { ApiError } from '../../../utils/helpers/ApiError.utils.js';
|
||||
|
||||
export class CatalogService {
|
||||
async attachCounts(record, transaction) {
|
||||
@@ -66,6 +65,32 @@ export class CatalogService {
|
||||
record.setDataValue('attributeGroups', attributeGroupsCount);
|
||||
record.setDataValue('canDelete', productCount === 0);
|
||||
|
||||
// Calculate average completeness for the family
|
||||
let completeness = 100;
|
||||
if (productCount > 0) {
|
||||
const products = await models.Product.findAll({
|
||||
where: { family_id: id },
|
||||
attributes: ['id'],
|
||||
transaction
|
||||
});
|
||||
const productIds = products.map(p => p.id);
|
||||
const completenessRecords = await models.ProductCompleteness.findAll({
|
||||
where: {
|
||||
product_id: productIds,
|
||||
channel: 'default'
|
||||
},
|
||||
attributes: ['percentage'],
|
||||
transaction
|
||||
});
|
||||
if (completenessRecords.length > 0) {
|
||||
const totalPct = completenessRecords.reduce((sum, c) => sum + c.percentage, 0);
|
||||
completeness = Math.round(totalPct / completenessRecords.length);
|
||||
} else {
|
||||
completeness = 0;
|
||||
}
|
||||
}
|
||||
record.setDataValue('completeness', completeness);
|
||||
|
||||
// Load full Brand and Unit objects from completeness_rules IDs
|
||||
const rules = record.completeness_rules || {};
|
||||
let brandIds = rules.allowedBrands || [];
|
||||
@@ -226,26 +251,23 @@ export class CatalogService {
|
||||
variantAxes = uniqueAxes;
|
||||
}
|
||||
|
||||
// 5. Asset Requirement Validation & Deduplication
|
||||
// 5. Asset Family Validation & Deduplication
|
||||
let assetRequirements = [];
|
||||
if (data.assetRequirements && Array.isArray(data.assetRequirements)) {
|
||||
const uniqueAssetTypes = [...new Set(data.assetRequirements)];
|
||||
const existingAssetTypes = await models.AssetType.findAll({
|
||||
where: { id: uniqueAssetTypes },
|
||||
const uniqueAssetFamilies = [...new Set(data.assetRequirements)];
|
||||
const existingAssetFamilies = await models.AssetFamily.findAll({
|
||||
where: { id: uniqueAssetFamilies },
|
||||
transaction
|
||||
});
|
||||
if (existingAssetTypes.length !== uniqueAssetTypes.length) {
|
||||
throw new Error('One or more selected asset types do not exist');
|
||||
if (existingAssetFamilies.length !== uniqueAssetFamilies.length) {
|
||||
throw new Error('One or more selected asset families do not exist');
|
||||
}
|
||||
for (const at of existingAssetTypes) {
|
||||
if (at.status !== 'active') {
|
||||
throw new Error(`Asset type "${at.name}" is inactive`);
|
||||
}
|
||||
if (at.deleted_at || at.deletedAt) {
|
||||
throw new Error(`Asset type "${at.name}" has been deleted`);
|
||||
for (const af of existingAssetFamilies) {
|
||||
if (af.status !== 'active') {
|
||||
throw new Error(`Asset family "${af.name}" is inactive`);
|
||||
}
|
||||
}
|
||||
assetRequirements = uniqueAssetTypes;
|
||||
assetRequirements = uniqueAssetFamilies;
|
||||
}
|
||||
|
||||
// 6. Channel Validation & Deduplication
|
||||
@@ -337,7 +359,7 @@ export class CatalogService {
|
||||
for (const assetTypeId of assetRequirements) {
|
||||
await models.FamilyAssetRequirement.create({
|
||||
family_id: record.id,
|
||||
asset_type_id: assetTypeId
|
||||
asset_family_id: assetTypeId
|
||||
}, { transaction });
|
||||
}
|
||||
|
||||
@@ -362,7 +384,7 @@ export class CatalogService {
|
||||
action: 'CREATE',
|
||||
resource: 'Catalog',
|
||||
resourceId: record.id,
|
||||
userId: userContext.userId || 'system',
|
||||
userId: context.userId || 'system',
|
||||
details: data
|
||||
});
|
||||
|
||||
@@ -477,26 +499,23 @@ export class CatalogService {
|
||||
variantAxes = uniqueAxes;
|
||||
}
|
||||
|
||||
// 5. Asset Requirement Validation & Deduplication
|
||||
// 5. Asset Family Validation & Deduplication
|
||||
let assetRequirements = null;
|
||||
if (data.assetRequirements && Array.isArray(data.assetRequirements)) {
|
||||
const uniqueAssetTypes = [...new Set(data.assetRequirements)];
|
||||
const existingAssetTypes = await models.AssetType.findAll({
|
||||
where: { id: uniqueAssetTypes },
|
||||
const uniqueAssetFamilies = [...new Set(data.assetRequirements)];
|
||||
const existingAssetFamilies = await models.AssetFamily.findAll({
|
||||
where: { id: uniqueAssetFamilies },
|
||||
transaction
|
||||
});
|
||||
if (existingAssetTypes.length !== uniqueAssetTypes.length) {
|
||||
throw new Error('One or more selected asset types do not exist');
|
||||
if (existingAssetFamilies.length !== uniqueAssetFamilies.length) {
|
||||
throw new Error('One or more selected asset families do not exist');
|
||||
}
|
||||
for (const at of existingAssetTypes) {
|
||||
if (at.status !== 'active') {
|
||||
throw new Error(`Asset type "${at.name}" is inactive`);
|
||||
}
|
||||
if (at.deleted_at || at.deletedAt) {
|
||||
throw new Error(`Asset type "${at.name}" has been deleted`);
|
||||
for (const af of existingAssetFamilies) {
|
||||
if (af.status !== 'active') {
|
||||
throw new Error(`Asset family "${af.name}" is inactive`);
|
||||
}
|
||||
}
|
||||
assetRequirements = uniqueAssetTypes;
|
||||
assetRequirements = uniqueAssetFamilies;
|
||||
}
|
||||
|
||||
// 6. Channel Validation & Deduplication
|
||||
@@ -601,7 +620,7 @@ export class CatalogService {
|
||||
for (const assetTypeId of assetRequirements) {
|
||||
await models.FamilyAssetRequirement.create({
|
||||
family_id: id,
|
||||
asset_type_id: assetTypeId
|
||||
asset_family_id: assetTypeId
|
||||
}, { transaction });
|
||||
}
|
||||
await AuditService.log({ action: 'ASSET_REQUIREMENTS_CHANGED', resource: 'Catalog', resourceId: id, userId: context.userId || 'system', details: assetRequirements });
|
||||
@@ -676,7 +695,7 @@ export class CatalogService {
|
||||
action: 'DELETE',
|
||||
resource: 'Catalog',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || 'system'
|
||||
userId: context.userId || 'system'
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
@@ -11,7 +11,7 @@ export default (sequelize) => {
|
||||
allowNull: false,
|
||||
primaryKey: true
|
||||
},
|
||||
asset_type_id: {
|
||||
asset_family_id: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
primaryKey: true
|
||||
|
||||
@@ -199,8 +199,8 @@ export class CategorieService {
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'category',
|
||||
action: 'updated',
|
||||
title: 'Category updated',
|
||||
@@ -262,12 +262,12 @@ export class CategorieService {
|
||||
action: 'DELETE',
|
||||
resource: 'Categorie',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || 'system'
|
||||
userId: context.userId || 'system'
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'category',
|
||||
action: 'deleted',
|
||||
title: 'Category deleted',
|
||||
@@ -303,12 +303,12 @@ export class CategorieService {
|
||||
action: 'ARCHIVE',
|
||||
resource: 'Categorie',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || 'system'
|
||||
userId: context.userId || 'system'
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'category',
|
||||
action: 'deleted',
|
||||
title: 'Category deleted',
|
||||
@@ -342,7 +342,7 @@ export class CategorieService {
|
||||
action: 'RESTORE',
|
||||
resource: 'Categorie',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || 'system'
|
||||
userId: context.userId || 'system'
|
||||
});
|
||||
|
||||
return restored;
|
||||
|
||||
@@ -61,8 +61,8 @@ export class AssetFamilyService {
|
||||
let dbReqIds = [];
|
||||
try {
|
||||
if (models.FamilyAssetRequirement) {
|
||||
const reqs = await models.FamilyAssetRequirement.findAll({ where: { family_id: familyData.id } });
|
||||
dbReqIds = reqs.map(r => r.asset_type_id).filter(Boolean);
|
||||
// FamilyAssetRequirement links Catalog to AssetFamily, so it does not contain asset_type_ids
|
||||
dbReqIds = [];
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
|
||||
@@ -149,7 +149,7 @@ export class AssetService {
|
||||
action: 'CREATE',
|
||||
resource: 'Asset',
|
||||
resourceId: record.id,
|
||||
userId: userContext.userId || 'system',
|
||||
userId: context.userId || 'system',
|
||||
details: data
|
||||
});
|
||||
|
||||
@@ -212,7 +212,7 @@ export class AssetService {
|
||||
action: 'UPDATE',
|
||||
resource: 'Asset',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || 'system',
|
||||
userId: context.userId || 'system',
|
||||
details: data
|
||||
});
|
||||
|
||||
@@ -347,7 +347,7 @@ export class AssetService {
|
||||
action: 'DELETE',
|
||||
resource: 'Asset',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || 'system'
|
||||
userId: context.userId || 'system'
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
@@ -30,7 +30,7 @@ export class CompletenessService {
|
||||
]
|
||||
},
|
||||
{
|
||||
model: models.AssetType,
|
||||
model: models.AssetFamily,
|
||||
as: 'assetRequirements'
|
||||
},
|
||||
{
|
||||
@@ -80,10 +80,36 @@ export class CompletenessService {
|
||||
}
|
||||
const allAttributes = Array.from(attributesMap.values());
|
||||
const requiredAttributes = allAttributes.filter(attr => attr.is_required);
|
||||
const requiredAssetTypes = family.assetRequirements || [];
|
||||
const requiredAssetFamilies = family.assetRequirements || [];
|
||||
const requiredChannels = family.channels || [];
|
||||
|
||||
const totalCount = requiredAttributes.length + requiredAssetTypes.length + requiredChannels.length;
|
||||
// Resolve required asset types dynamically across all assigned asset families
|
||||
const requiredAssetTypes = [];
|
||||
for (const assetFamily of requiredAssetFamilies) {
|
||||
let typeIds = [];
|
||||
const desc = assetFamily.description || '';
|
||||
if (desc.includes('__AT_IDS__:')) {
|
||||
const parts = desc.split('__AT_IDS__:');
|
||||
typeIds = (parts[1] || '').split(',').map(s => s.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
if (typeIds.length > 0) {
|
||||
const types = await models.AssetType.findAll({
|
||||
where: {
|
||||
id: typeIds,
|
||||
is_required: true
|
||||
},
|
||||
transaction
|
||||
});
|
||||
requiredAssetTypes.push(...types);
|
||||
}
|
||||
}
|
||||
// Deduplicate required asset types
|
||||
const uniqueRequiredAssetTypesMap = new Map();
|
||||
requiredAssetTypes.forEach(at => uniqueRequiredAssetTypesMap.set(at.id, at));
|
||||
const uniqueRequiredAssetTypes = Array.from(uniqueRequiredAssetTypesMap.values());
|
||||
|
||||
const totalCount = requiredAttributes.length + uniqueRequiredAssetTypes.length + requiredChannels.length;
|
||||
let fulfilledCount = 0;
|
||||
|
||||
const missingAttributes = [];
|
||||
@@ -102,7 +128,7 @@ export class CompletenessService {
|
||||
|
||||
// 2. Validate required assets
|
||||
const assignedAssetTypeIds = (product.productAssets || []).map(pa => pa.asset?.assetType?.id).filter(Boolean);
|
||||
for (const assetType of requiredAssetTypes) {
|
||||
for (const assetType of uniqueRequiredAssetTypes) {
|
||||
if (assignedAssetTypeIds.includes(assetType.id)) {
|
||||
fulfilledCount++;
|
||||
} else {
|
||||
|
||||
@@ -27,7 +27,7 @@ export class CompletenessResolverService {
|
||||
const familyReqs = await models.FamilyAssetRequirement.findAll({
|
||||
where: { family_id: product.family_id }
|
||||
});
|
||||
const mappedIds = familyReqs.map(r => r.asset_type_id);
|
||||
const mappedIds = familyReqs.map(r => r.asset_family_id);
|
||||
|
||||
const assetFamilies = await models.AssetFamily.findAll({
|
||||
where: { id: mappedIds }
|
||||
@@ -46,8 +46,12 @@ export class CompletenessResolverService {
|
||||
|
||||
const assetFamiliesCompleteness = await Promise.all(
|
||||
assetFamilies.map(async (family) => {
|
||||
const afReqs = await models.FamilyAssetRequirement.findAll({ where: { family_id: family.id } });
|
||||
const typeIds = afReqs.map(r => r.asset_type_id);
|
||||
let typeIds = [];
|
||||
const desc = family.description || '';
|
||||
if (desc.includes('__AT_IDS__:')) {
|
||||
const parts = desc.split('__AT_IDS__:');
|
||||
typeIds = (parts[1] || '').split(',').map(s => s.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
let types = [];
|
||||
if (typeIds.length > 0) {
|
||||
|
||||
@@ -406,13 +406,13 @@ export class ProductService {
|
||||
action: 'CREATE',
|
||||
resource: 'Product',
|
||||
resourceId: product.id,
|
||||
userId: userContext.userId || 'system',
|
||||
userId: context.userId || 'system',
|
||||
details: data
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'product',
|
||||
action: 'created',
|
||||
title: 'New product created',
|
||||
@@ -568,13 +568,13 @@ export class ProductService {
|
||||
action: 'UPDATE',
|
||||
resource: 'Product',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || 'system',
|
||||
userId: context.userId || 'system',
|
||||
details: data
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'product',
|
||||
action: 'updated',
|
||||
title: 'Product updated',
|
||||
@@ -605,12 +605,12 @@ export class ProductService {
|
||||
action: 'DELETE',
|
||||
resource: 'Product',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || userContext.id || 'system'
|
||||
userId: context.userId || context.id || 'system'
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'product',
|
||||
action: 'deleted',
|
||||
title: 'Product deleted',
|
||||
@@ -637,12 +637,12 @@ export class ProductService {
|
||||
action: 'ARCHIVE',
|
||||
resource: 'Product',
|
||||
resourceId: id,
|
||||
userId: userContext.userId || userContext.id || 'system'
|
||||
userId: context.userId || context.id || 'system'
|
||||
});
|
||||
|
||||
// Notify tenant users
|
||||
if (userContext.tenantId) {
|
||||
NotificationService.notifyTenant(userContext.tenantId, userContext.userId, {
|
||||
if (context.tenantId) {
|
||||
NotificationService.notifyTenant(context.tenantId, context.userId, {
|
||||
variant: 'product',
|
||||
action: 'deleted',
|
||||
title: 'Product deleted',
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import http from 'http';
|
||||
|
||||
function request(options, postData) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = http.request(options, (res) => {
|
||||
let body = '';
|
||||
res.on('data', (chunk) => body += chunk);
|
||||
res.on('end', () => {
|
||||
resolve({
|
||||
statusCode: res.statusCode,
|
||||
headers: res.headers,
|
||||
body: body
|
||||
});
|
||||
});
|
||||
});
|
||||
req.on('error', reject);
|
||||
if (postData) {
|
||||
req.write(postData);
|
||||
}
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
// 1. Login
|
||||
console.log('Logging in...');
|
||||
const loginData = JSON.stringify({
|
||||
email: 'superadmin@maskan.com',
|
||||
password: 'Admin@123'
|
||||
});
|
||||
|
||||
const loginRes = await request({
|
||||
hostname: 'localhost',
|
||||
port: 5000,
|
||||
path: '/api/v1/auth/login',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(loginData)
|
||||
}
|
||||
}, loginData);
|
||||
|
||||
console.log('Login Response Status:', loginRes.statusCode);
|
||||
console.log('Login Response Body:', loginRes.body);
|
||||
const loginJson = JSON.parse(loginRes.body);
|
||||
|
||||
// Let's inspect where the token is
|
||||
const token = loginJson.data?.token || loginJson.token || loginJson.data?.accessToken;
|
||||
console.log('Using Token:', token);
|
||||
|
||||
// 2. Try to create attribute
|
||||
console.log('\nCreating attribute...');
|
||||
const attributeData = JSON.stringify({
|
||||
name: `API Test Attribute ${Date.now()}`,
|
||||
code: `api_attr_${Date.now()}`,
|
||||
type: 'text',
|
||||
status: 'draft',
|
||||
isUnique: false,
|
||||
isRequired: false,
|
||||
isVariantEligible: false,
|
||||
isSearchable: false,
|
||||
isFilterable: false,
|
||||
isLocalizable: false,
|
||||
isChannelSpecific: false,
|
||||
minLength: 0,
|
||||
maxLength: 255
|
||||
});
|
||||
|
||||
const createRes = await request({
|
||||
hostname: 'localhost',
|
||||
port: 5000,
|
||||
path: '/api/v1/attributes',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(attributeData),
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
}, attributeData);
|
||||
|
||||
console.log('Create Response Status:', createRes.statusCode);
|
||||
console.log('Create Response Body:', createRes.body);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error running test:', error);
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
@@ -0,0 +1,35 @@
|
||||
import sequelize, { connectDatabase } from './src/shared/database/connection.js';
|
||||
import { models } from './src/shared/database/models.js';
|
||||
import AttributeService from './src/features/attributes/attributes/attribute.service.js';
|
||||
|
||||
async function test() {
|
||||
await connectDatabase();
|
||||
|
||||
const payload = {
|
||||
name: `Test Attribute ${Date.now()}`,
|
||||
code: `test_attr_${Date.now()}`,
|
||||
type: 'text',
|
||||
status: 'draft',
|
||||
isUnique: false,
|
||||
isRequired: false,
|
||||
isVariantEligible: false,
|
||||
isSearchable: false,
|
||||
isFilterable: false,
|
||||
isLocalizable: false,
|
||||
isChannelSpecific: false,
|
||||
minLength: 0,
|
||||
maxLength: 255
|
||||
};
|
||||
|
||||
try {
|
||||
console.log('\nAttempting to create attribute with payload:', JSON.stringify(payload, null, 2));
|
||||
const result = await AttributeService.create(payload);
|
||||
console.log('SUCCESS! Created attribute:', result.id);
|
||||
} catch (e) {
|
||||
console.error('FAILED to create attribute:', e);
|
||||
}
|
||||
|
||||
await sequelize.close();
|
||||
}
|
||||
|
||||
test().catch(console.error);
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
Reference in New Issue
Block a user