Your IP : 216.73.217.100


Current Path : /home/deltalab/PMS/ims-connector/rest/queries/
Upload File :
Current File : //home/deltalab/PMS/ims-connector/rest/queries/product.js

/* eslint-disable no-unused-vars */
const axios = require('axios');
const auth = require('./auth');

const restUrl = process.env.MAGENTO_REST_HOST;

// -------------------------- MAGENTO VISIBILITY VALUES
const VISIBILITY_NOT_VISIBLE = 1;
const VISIBILITY_IN_CATALOG = 2;
const VISIBILITY_IN_SEARCH = 3;
const VISIBILITY_BOTH = 4;

// -------------------------UTILITIES

function getProductCumulativeInventoryLevel(product) {
  let totalQuantity = 0;
  for (let j = 0; j < product.inventoryLevels.length; j++) {
    totalQuantity += product.inventoryLevels[j].amount;
  }
  return totalQuantity;
}

// ------------------------END UTILITIES

/**
 * Return a list of products given a partner ID
 * @param {string} partnerId
 * @returns products
 */
async function readMany(partnerId = undefined) {
  return `you read all products for ${partnerId}`;
}

async function readOne(sku, storeName) {
  try {
    const method = 'get';
    const url = `${restUrl}/${storeName}/V1/products/${sku}`;
    const token = await auth.getOAuthToken(method, url);
    // const token = await auth.getBearerToken();
    const config = {
      method,
      url,
      headers: {
        Authorization: `Oauth ${token}`,
      },
    };

    const result = await axios(config);
    return result.data;
  } catch (error) {
    console.log('##############################################');
    console.log('##################### PRODOTTO NON ESISTENTE #########################');
    console.log('##############################################');
    return false;
  }
}

async function readAllByStore(storeId) {
  const method = 'get';
  const url = `${restUrl}/products-render-info`;
  const criteria = {
    'searchCriteria[pageSize]': 0,
    'searchCriteria[currentPage]': 1,
    currencyCode: 'EUR',
    storeId,
  };
  const strCriteria = [];
  for (const key in criteria) {
    if (Object.prototype.hasOwnProperty.call(criteria, key)) {
      strCriteria.push(`${key}=${criteria[key]}`);
    }
  }
  const token = await auth.getOAuthToken(method, url, criteria);
  // const token = await auth.getBearerToken();
  const config = {
    method,
    url: `${url}?${strCriteria.join('&')}`,
    headers: {
      Authorization: `OAuth ${token}`,
    },
  };

  const result = await axios(config);
  return result.data;
}

function getIMSCategories(categories) {
  const imsCategories = [];
  for (let i = 0; i < categories.length; i++) {
    imsCategories.push({ position: i, category_id: categories[i] });
  }
  return imsCategories;
}

function getVisibilityStatus(product, quantity, partner) {
  if (!product.imsEnabled) {
    console.log('il prodotto non è abilitato alla vendita');
    return VISIBILITY_NOT_VISIBLE;
  }

  if (product.deleted) {
    console.log('il prodotto è cancellato');
    return VISIBILITY_NOT_VISIBLE;
  }

  if (product.isValidFrom && product.isValidUntil && product.validUntil < product.validFrom) {
    console.log('il prodotto non ha un periodo valido');
    return VISIBILITY_NOT_VISIBLE;
  }

  if (product.isValidFrom) {
    const validFrom = new Date(product.validFrom);
    const now = new Date();
    if (now < validFrom) {
      // it's not valid yet
      console.log('il prodotto non è ancora valido');
      return VISIBILITY_NOT_VISIBLE;
    }
  }

  if (product.isValidUntil) {
    const validUntil = new Date(product.validUntil);
    const now = new Date();
    if (now > validUntil) {
      // it's expired
      console.log('il prodotto non è più valido');
      return VISIBILITY_NOT_VISIBLE;
    }
  }

  if (!partner.active) {
    console.log('il partner non è attivo');
    return VISIBILITY_NOT_VISIBLE;
  }

  if (!partner.enabled) {
    console.log('il partner non è abilitato');
    return VISIBILITY_BOTH;
  }

  if (product.customDescription && product.customDescription.includes('*VARIANTE*')) {
    console.log('il prodotto è una variante');
    return VISIBILITY_NOT_VISIBLE;
  }

  console.log('il prodotto non ha problemi, visualizzo');
  return VISIBILITY_BOTH;
}

async function createProduct(productInput) {
  const { product } = productInput;
  const { channel } = productInput;
  const { partner } = productInput;
  const { websiteIds } = productInput;

  const quantity = getProductCumulativeInventoryLevel(product);
  const urlKey = product.urlKey ? product.urlKey : `${product.title.replace(/[^a-zA-Z0-9]/g, '_')}_${product.brand}_${partner.seller}`;
  const productObj = {
    product: {
      sku: product.sku,
      name: product.title,
      price: product.price ? product.price : product.msrp,
      attribute_set_id: product.attributeSetId ? product.attributeSetId : '4',
      type_id: 'simple',
      weight: product.weight,
      visibility: getVisibilityStatus(product, quantity, partner),
      extension_attributes: {
        website_ids: [],
        stock_item: {
          qty: product.sellBelowZero ? 1000 : quantity,
          is_in_stock: (product.sellBelowZero || quantity > 0) && partner.enabled,
          is_qty_decimal: false,
          use_config_backorders: !product.sellBelowZero,
          backorders: product.sellBelowZero ? 1 : 0,
        },
        category_links: getIMSCategories(product.imsCategories),
      },
      custom_attributes: [
        {
          attribute_code: 'special_price',
          value: product.price,
        },
        {
          attribute_code: 'tax_class_id',
          value: product.imsTaxCode,
        },
        { // Custom description (customizable by all vendors)
          attribute_code: 'description',
          value: product.customDescription ? product.customDescription : '',
        },
        { // Product description (Same for all products with the same EAN)
          attribute_code: 'short_description',
          value: product.description ? product.description : '',
        },
        {
          attribute_code: 'url_key',
          value: urlKey.replace(/\s+/g, '-'),
        },
        {
          attribute_code: 'indacoall_partner',
          value: partner.companyName,
        },
        {
          attribute_code: 'indacoall_brand',
          value: product.brand ? product.brand : '',
        },
        {
          attribute_code: 'indacoall_seller',
          value: partner.seller ? partner.seller : '',
        },
        {
          attribute_code: 'indacoall_refrigerated',
          value: product.refrigerated === true ? '1' : '0',
        },
        {
          attribute_code: 'indacoall_packagingfragile',
          value: product.fragile === true ? '1' : '0',
        },
        {
          attribute_code: 'indacoall_packagingbottle',
          value: product.bottle === true ? '1' : '0',
        },
      ],
    },
  };

  // add indaco custom attributes
  for (let i = 0; i < product.attributes.length; i++) {
    productObj.product.custom_attributes.push(
      {
        attribute_code: product.attributes[i].attribute.name,
        value: product.attributes[i].value,
      },
    );
  }

  for (let i = 0; i < websiteIds.length; i++) {
    productObj.product.extension_attributes.website_ids.push(websiteIds[i]);
  }

  const method = 'post';
  const url = `${restUrl}/${channel.storeName}/V1/products`;
  const token = await auth.getOAuthToken(method, url);
  // const token = await auth.getBearerToken(channel.storeName);

  const config = {
    method,
    url,
    headers: {
      Authorization: `OAuth ${token}`,
      'Content-Type': 'application/json',
    },
    data: productObj,
  };
  const result = await axios(config).catch((error) => {
    throw Error(error.response.data.message);
  });
  return result.data;
}

async function resetCategories(referenceInput, sku) {
  const { referenceUpdate } = referenceInput;
  const { channel } = referenceInput;
  const { websiteIds } = referenceInput;
  const productObj = {
    product: {
      sku: referenceUpdate.sku,
      extension_attributes: {
        website_ids: [],
        category_links: [],
      },
    },
  };

  for (let i = 0; i < websiteIds.length; i++) {
    productObj.product.extension_attributes.website_ids.push(websiteIds[i]);
  }

  const method = 'put';
  const url = `${restUrl}/${channel.storeName}/V1/products/${sku}`;
  const token = await auth.getOAuthToken(method, url);
  // const token = await auth.getBearerToken();

  const config = {
    method,
    url,
    headers: {
      Authorization: `OAuth ${token}`,
      'Content-Type': 'application/json',
    },
    data: productObj,
  };
  console.log('axios per reset');
  const result = await axios(config).catch((error) => {
    console.log('Error', error);
    throw Error(error);
  });
  return result.data;
}

async function updateProduct(referenceInput, sku) {
  const { referenceUpdate } = referenceInput;
  const { partner } = referenceInput;
  const { linkedProducts } = referenceInput;
  const { channel } = referenceInput;
  const { websiteIds } = referenceInput;
  const { quantity } = referenceInput;

  // if (!quantity) {
  //   quantity = getProductCumulativeInventoryLevel(referenceUpdate);
  // }

  const mediaGalleryEntries = [];
  for (let i = 0; i < referenceUpdate.media.length; i++) {
    const extension = referenceUpdate.media[i].name.toLowerCase().endsWith('jpeg') || referenceUpdate.media[i].name.toLowerCase().endsWith('jpg') ? 'jpeg' : 'png';
    const entry = {
      mediaType: 'image',
      label: `Product image ${referenceUpdate.sku} - ${new Date()}`,
      position: i,
      disabled: false,
      file: `pms/${referenceUpdate.media[i].name}`,
      types: i === 0 ? [
        'image',
        'thumbnail',
        'small_image',
        'swatch',
      ] : [],
      // TODO: verificare se mettendo i tipi solo sulla prima immagine (saltando il resto) allora viene tutto visualizzato correttamente.
      // types: [],
      content: {
        base64EncodedData: '',
        type: `image/${extension}`,
        name: referenceUpdate.media[i].name,
      },
    };
    mediaGalleryEntries.push(entry);
  }

  const productObj = {
    product: {
      sku: referenceUpdate.sku,
      name: referenceUpdate.title,
      price: referenceUpdate.price ? referenceUpdate.price : referenceUpdate.msrp,
      type_id: 'simple',
      attribute_set_id: referenceUpdate.attributeSetId ? referenceUpdate.attributeSetId : '4',
      weight: referenceUpdate.weight,
      visibility: getVisibilityStatus(referenceUpdate, quantity, partner),
      mediaGalleryEntries: [],
      extension_attributes: {
        website_ids: [],
        stock_item: {
          qty: referenceUpdate.sellBelowZero ? 1000 : quantity,
          is_in_stock: (referenceUpdate.sellBelowZero || quantity > 0) && partner.enabled,
          is_qty_decimal: false,
          use_config_backorders: !referenceUpdate.sellBelowZero,
          backorders: referenceUpdate.sellBelowZero ? 1 : 0,
        },
        category_links: getIMSCategories(referenceUpdate.imsCategories),
      },
      custom_attributes: [
        {
          attribute_code: 'special_price',
          value: referenceUpdate.price,
        },
        {
          attribute_code: 'tax_class_id',
          value: referenceUpdate.imsTaxCode,
        },
        { // Custom description (customizable by all vendors)
          attribute_code: 'description',
          value: referenceUpdate.customDescription ? referenceUpdate.customDescription : '',
        },
        { // Product description (Same for all products with the same EAN)
          attribute_code: 'short_description',
          value: referenceUpdate.description ? referenceUpdate.description : '',
        },
        {
          attribute_code: 'indacoall_partner',
          value: partner.companyName,
        },
        {
          attribute_code: 'indacoall_brand',
          value: referenceUpdate.brand ? referenceUpdate.brand : '',
        },
        {
          attribute_code: 'indacoall_seller',
          value: partner.seller ? partner.seller : '',
        },
        {
          attribute_code: 'indacoall_refrigerated',
          value: referenceUpdate.refrigerated === true ? '1' : '0',
        },
        {
          attribute_code: 'indacoall_refrigerated',
          value: referenceUpdate.refrigerated === true ? '1' : '0',
        },
        {
          attribute_code: 'indacoall_packagingfragile',
          value: referenceUpdate.fragile === true ? '1' : '0',
        },
        {
          attribute_code: 'indacoall_packagingbottle',
          value: referenceUpdate.bottle === true ? '1' : '0',
        },
        {
          attribute_code: 'indacoall_titlerelatedproducts',
          value: referenceUpdate.recomExplanation || '',
        },
      ],
      product_links: [],
    },
  };

  const productMediaObj = {
    product: {
      mediaGalleryEntries,
    },
  };

  for (let i = 0; i < referenceUpdate.attributes.length; i++) {
    productObj.product.custom_attributes.push(
      {
        attribute_code: referenceUpdate.attributes[i].attribute.name,
        value: referenceUpdate.attributes[i].value,
      },
    );
  }

  for (let i = 0; i < websiteIds.length; i++) {
    productObj.product.extension_attributes.website_ids.push(websiteIds[i]);
  }

  // add indaco linked products
  for (let i = 0; i < linkedProducts.length; i++) {
    productObj.product.product_links.push({
      sku: referenceUpdate.sku,
      link_type: 'related',
      linked_product_sku: linkedProducts[i],
    });
  }

  const method = 'put';
  const url = `${restUrl}/${channel.storeName}/V1/products/${sku}`;
  const token = await auth.getOAuthToken(method, url);
  // const token = await auth.getBearerToken();
  const config = {
    method,
    url,
    headers: {
      Authorization: `OAuth ${token}`,
      'Content-Type': 'application/json',
    },
    data: productObj,
  };

  const result = await axios(config).catch((error) => {
    console.log('Error', error);
    throw Error(error);
  });

  const mediaUrl = `${restUrl}/all/V1/products/${sku}`;
  const mediaToken = await auth.getOAuthToken(method, mediaUrl);
  const mediaConfig = {
    method,
    url: mediaUrl,
    headers: {
      Authorization: `OAuth ${mediaToken}`,
      'Content-Type': 'application/json',
    },
    data: productMediaObj,
  };

  const mediaResult = await axios(mediaConfig).catch((error) => {
    console.log('Error', error);
    throw Error(error);
  });


  return result.data;
}

async function uploadImageToProduct(data) {
  const imageObj = {
    entry: {
      media_type: 'image',
      label: `pms_upload${data.filename}`,
      disabled: false,
      types: [
        'image',
        'small_image',
        'thumbnail',
        'swatch_image',
      ],
      file: data.filename,
      content: {
        type: `image/${data.extension.toLowerCase() === 'jpg' ? 'jpeg' : data.extension}`,
        name: data.filename,
        base64_encoded_data: data.data,
      },
    },
  };
  const method = 'post';
  const url = `${restUrl}/all/V1/products/${data.sku}/media`;
  const token = await auth.getOAuthToken(method, url);
  // const token = await auth.getBearerToken();

  const config = {
    method,
    url,
    headers: {
      Authorization: `OAuth ${token}`,
      'Content-Type': 'application/json',
    },
    data: imageObj,
  };

  const result = await axios(config);
  return result.data;
}

async function deleteImageFromProduct(sku, imsgid) {
  const method = 'delete';
  const url = `${restUrl}/all/V1/products/${sku}/media/${imsgid}`;
  const token = await auth.getOAuthToken(method, url);
  // const token = await auth.getBearerToken();
  const config = {
    method,
    url,
    headers: {
      Authorization: `OAuth ${token}`,
      'Content-Type': 'application/json',
    },
  };

  const result = await axios(config);
  return result.data;
}

async function flagProductAsDeleted(product, sku) {
  const productObj = {
    product: {
      sku: product.sku,
      name: product.title,
      price: product.price,
      weight: product.weight,
      visibility: VISIBILITY_NOT_VISIBLE, // no catalog, no cart
      // custom_attributes: [
      //   {
      //     attribute_code: 'deleted',
      //     value: 1,
      //   },
      // ],
    },
  };

  const method = 'put';
  const url = `${restUrl}/all/V1/products/${sku}`;
  const token = await auth.getOAuthToken(method, url);
  // const token = await auth.getBearerToken();
  const config = {
    method,
    url,
    headers: {
      Authorization: `OAuth ${token}`,
      'Content-Type': 'application/json',
    },
    data: productObj,
  };

  const result = await axios(config);
  return result.data;
}

async function deleteProduct(sku) {
  const method = 'delete';
  const url = `${restUrl}/all/V1/products/${sku}`;
  const token = await auth.getOAuthToken(method, url);
  // const token = await auth.getBearerToken();
  const config = {
    method,
    url,
    headers: {
      Authorization: `Oauth ${token}`,
      'Content-Type': 'application/json',
    },
  };

  const result = await axios(config);
  return result.data;
}

async function updateInventorySource(referenceInput, sku) {
  const { channel } = referenceInput;
  const { quantity } = referenceInput;

  const inventoryObj = {
    sourceItems: [
      {
        sku,
        source_code: `WH-${channel.storeName}`,
        quantity,
        status: 1,
      },
    ],
  };

  const method = 'POST';
  const url = `${restUrl}/${channel.storeName}/V1/inventory/source-items`;
  const token = await auth.getOAuthToken(method, url);
  // const token = await auth.getBearerToken();

  const config = {
    method,
    url,
    headers: {
      Authorization: `OAuth ${token}`,
      'Content-Type': 'application/json',
    },
    data: inventoryObj,
  };

  const result = await axios(config).catch((error) => {
    console.log('Error', error);
    throw Error(error);
  });
}

module.exports = {
  readMany,
  readOne,
  readAllByStore,
  createProduct,
  deleteProduct,
  resetCategories,
  updateProduct,
  updateInventorySource,
  flagProductAsDeleted,
  uploadImageToProduct,
  deleteImageFromProduct,
};