Object.entries(require('./common.js')).forEach(([name, exported]) => global[name] = exported);
const url = "https://ocs.ca";
function reqq(level, category, name) {
return request({
url: 'https://u2ghas8n0v-dsn.algolia.net/1/indexes/ocs_products/query?x-algolia-application-id=U2GHAS8N0V&x-algolia-api-key=0fce38bd280fd213b8a14f7a59602b7d',
method: 'POST',
body: '{"params":"hitsPerPage=1000&distinct=0&filters=(NOT tags:%22subsubcategory--Variety Packs%22) AND (NOT tags:subsubcategory--Topicals) AND (tags:language--en) AND (tags:%22' + level + 'category--' + category + '%22)"}'
}).then(obj => {
obj = JSON.parse(obj);
if(obj.nbHits > obj.hitsPerPage) {
console.log("missing " + (obj.nbHits - obj.hitsPerPage) + ' items for ' + category);
}
for(let i = 0; i < obj.hits.length; ++i) {
obj.hits[i].type = name;
}
return obj.hits;
});
}
function ok() {
for(let i = 0; i < arguments.length; ++i) {
if(arguments[i] === undefined || arguments[i] === null) {
return false;
}
}
return true;
}
function pq(item, type) {
let portions;
let quantity;
if(item.variant_title === 'Default Title') {
portions = item.meta.variant.retail_pack_number_of_items
quantity = item.meta.variant.retail_pack_net_content;
} else if(type === 'gummy' || type === 'mint' || type === 'chocolate' || type === 'baked') { portions = item.meta.variant.retail_pack_number_of_items;
if(item.handle === '64-cocoa-dark-chocolate-aurora-drift') {
quantity = '5.2'; } else {
quantity = (new Big(item.meta.variant.retail_pack_net_content)).div(portions).toString();
}
} else {
[, portions, quantity] = item.variant_title.match(qty);
if(portions === undefined && type === 'preroll' && item.meta.variant.retail_pack_number_of_items > 1) {
portions = item.meta.variant.retail_pack_number_of_items;
quantity = (new Big(quantity)).div(portions).toString();
}
}
if(!portions || portions < 2) {
portions = 1;
}
return [portions, quantity];
}
(async function() {
let e = Promise.all([
reqq('sub', 'Dried Flower', 'flower'),
reqq('sub', 'Pre-Rolls', 'preroll'),
reqq('sub', 'Oils', 'oil'),
reqq('sub', 'Capsules', 'capsule'),
reqq('subsub', '510 Thread Pens and Kits', 'cartridge'),
reqq('subsub', 'Disposable Pens and Kits', 'disposable'),
reqq('subsub', 'Proprietary Systems Pens and Kits', 'cartridge'),
reqq('sub', 'Beverages', 'beverage'),
reqq('subsub', 'Soft Chews', 'gummy'),
reqq('subsub', 'Hard Edibles', 'mint'),
reqq('sub', 'Chocolates', 'chocolate'),
reqq('subsub', 'Cookies', 'baked')
]).then(e => Object.values(groupBy(e.flat(), 'handle')));
await postgres.connect();
await postgres.query('begin');
e = await e;
let storeID = (await postgres.query(`select ios_store_id('OCS', 'ontario', 'canada', _url => $1, _delivery => true, _prepayment => true)`, [url])).rows[0].ios_store_id;
await postgres.query(
`insert into store_image (
store_id,
url
) values (
$1,
$2
) on conflict do nothing`,
[storeID, `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4320 4320"><path d="M3739 1805c-165-350-686-262-686 73 0 400 697 132 697 562 0 323-500 448-715 73m-159-1a516 516 0 0 1-436 228 580 580 0 1 1 0-1160c189 0 342 90 437 230m-1177 350a580 580 0 0 1-580 580 580 580 0 0 1-580-580 580 580 0 0 1 580-580 580 580 0 0 1 580 580z" fill="none" stroke="#000" stroke-width="80"/><circle cx="2160" cy="2160" fill="none" stroke="#000" r="2120" stroke-width="80"/></svg>`]
);
let ii = 0;
let progress = 0;
cliProgressBar.start(e.length, progress);
let dup = new Map();
async function deal() {
while(ii < e.length) {
let i = ii++;
let minTHC, maxTHC, minCBD, maxCBD;
if(e[i][0].type === 'flower' || e[i][0].type === 'preroll' || e[i][0].type === 'cartridge' || e[i][0].type === 'disposable') {
minTHC = new Big(e[i][0].meta.product.thc_content_min);
maxTHC = new Big(e[i][0].meta.product.thc_content_max);
minCBD = new Big(e[i][0].meta.product.cbd_content_min);
maxCBD = new Big(e[i][0].meta.product.cbd_content_max);
} else {
minTHC = new Big(e[i][0].meta.variant.thc_min_per);
maxTHC = new Big(e[i][0].meta.variant.thc_max_per);
minCBD = new Big(e[i][0].meta.variant.cbd_min_per);
maxCBD = new Big(e[i][0].meta.variant.cbd_max_per);
}
let quickview = await request({
url: encodeURI(`${url}/products/${e[i][0].handle}?view=quickview`),
headers: {'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36"}
}).then(JSON.parse);
let description = e[i][0].body_html_safe;
let [producer, brand, name, join_name, hack] = normalize(e[i][0].vendor, e[i][0].title, e[i][0].type, quickview.product.metafields.product.licensed_producer, description, quickview.product.metafields.product.street_name);
let species = e[i][0].meta.product.plant_type;
let blend = false;
let f2;
let terpenes = null;
for(let j = 0; j < e[i][0].tags.length; ++j) {
if(e[i][0].tags[j].startsWith('plant_type--')) {
if(f2 !== undefined) {
console.log("I HATE MY LIFE")
}
f2 = e[i][0].tags[j].substring(12);
} else if(e[i][0].tags[j] === 'subsubcategory--Oral Sprays') {
let [, quantity] = pq(e[i][0], e[i][0].type = 'spray'); minTHC = minTHC.div(10).div(quantity);
maxTHC = maxTHC.div(10).div(quantity);
minCBD = minCBD.div(10).div(quantity);
maxCBD = maxCBD.div(10).div(quantity);
} else if(e[i][0].tags[j].startsWith('terpenes--')) {
if(terpenes === null) {
terpenes = [];
}
let terpene = e[i][0].tags[j].substring(10).toLowerCase();
if(terpene) {
if(terpene.includes('remove')) {
if(terpenes.length) {
console.log(terpenes);
console.log(e[i][0].tags);
console.log(`${url}/products/${e[i][0].handle}`);
}
terpenes = [];
} else {
terpenes.push(terpene);
}
}
}
}
if(species === undefined) {
species = f2
}
if(f2 !== species) {
console.log("this is so gay")
console.log(f2)
console.log(species);
}
let spaceIndex = species.search(/\s+/);
if(spaceIndex > 0) { species = species.substring(0, spaceIndex);
}
species = species.toLowerCase();
if(species === '-' && e[i][0].handle === 'indica-1') {
console.log('FUCK OCS FUCK YOU FUCK!!!');
species = 'indica';
}
if(species === 'blend') {
species = description.match(/indica|sativa/i)?.[0]?.toLowerCase() ?? 'hybrid';
if(species !== 'hybrid') { console.log(description); } if(!quickview.product.metafields.product.street_name) {
blend = true;
}
}
if(/blend/i.test(description) && !quickview.product.metafields.product.street_name) {
blend = true;
console.log(name, description, `/products/${e[i][0].handle}`); }
if(typeof description === 'string') {
description = description.replace(/\s+/g, ' ');
let temp = description.toLowerCase();
if(temp.includes('terpene') && temp.includes('remove')) {
terpenes = [];
}
}
let k = ((producer ?? '') + brand + join_name + e[i][0].type).toLowerCase();
let w = dup.get(k);
if(w === undefined) {
dup.set(k, new Set([e[i][0].handle]));
} else {
w.add(e[i][0].handle);
}
if(e[i][0].type === 'beverage') {
let [, quantity] = pq(e[i][0]);
if(quantity > 150) {
e[i][0].type = 'rtd';
} else if(/\btea\b/i.test(e[i][0].title)) {
e[i][0].type = 'tea';
} else if(/\bpowder\b/i.test(e[i][0].title)) {
e[i][0].type = 'powder';
} else if(/\bshot\b/i.test(e[i][0].title)) {
e[i][0].type = 'shot';
} else {
console.error(e[i][0].handle);
cliProgressBar.update(++progress);
continue;
}
}
let productID = (await postgres.query(`select ios_product_id($1, $2, $3, $4, $5, $6, $7, $8, $9, true, $10, $11)`, [
producer,
brand,
name,
join_name,
e[i][0].type,
species,
blend,
strain_clean(quickview.product.metafields.product.street_name),
description,
terpenes,
brand === 'dosist' ? '.00225' : null
])).rows[0].ios_product_id;
if(process.env.CLOUDINARY_URL) {
await images(
new Set((await request({
url: encodeURI(`${url}/products/${e[i][0].handle}.json`),
headers: {'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36"}
}).then(JSON.parse)).product.images.map(({src}) => {
let questionIndex = src.indexOf('?');
if(questionIndex === -1) {
return src;
} else {
return src.substring(0, questionIndex);
}
})),
productID
);
}
for(let j = 0; j < e[i].length; ++j) {
let gram_equivalency = e[i][0].type === 'oil' || e[i][0].type === 'spray' || e[i][0].type === 'capsule' ? new Big(quickview.variants.find(v => v.id == e[i][j].objectID).metafields.variant.gram_equivalency) : null;
let [portions, quantity] = pq(e[i][j], e[i][0].type);
if(e[i][0].type === 'capsule') {
portions = quantity;
quantity = hack;
}
if(e[i][0].handle === 'thc-dark-chocolate-bar-bhang' || e[i][0].handle === 'thc-milk-chocolate-bar-bhang' && quantity === '10' && portions === 1) {
portions = '4';
quantity = '2.5';
} else if(e[i][0].handle === 'balance-solid-milk-chocolate-chowie-wowie' || e[i][0].handle === 'thc-solid-milk-chocolate-chowie-wowie' && quantity === '16' && portions === 1) {
portions = '2';
quantity = '8';
} else if(e[i][0].handle === 'dark-chocolate-bar-foray' && quantity === '40' && portions === 1) {
portions = '4';
quantity = '10';
} else if(e[i][0].handle === 'bakerstreet-peppermint-milk-chocolate-tweed' && quantity === '32' && portions === 1) {
portions = '4';
quantity = '8';
} else if(e[i][0].handle === 'pause-dark-milk-chocolate-bar-tokyo-smoke' || e[i][0].handle === 'go-dark-milk-chocolate-bar-tokyo-smoke' && quantity === '32' && portions === 1) {
portions = '5';
quantity = '6.4';
}
let params = [productID, portions, quantity];
let [variantID, g] = (await postgres.query(
`select ios_variant_id($1, $2, $3${e[i][j].options.flavour ? `, _flavor => $${params.push(e[i][j].options.flavour)}` : ''}${gram_equivalency === null ? '' : `, _gram_equivalency => $${params.push(gram_equivalency.toString())}`})`,
params
)).rows[0].ios_variant_id.slice(1, -1).split(',');
if(g.length && gram_equivalency !== null && !gram_equivalency.eq(g)) {
console.log('warning: gram_equivalency does not match', gram_equivalency.toString(), g, productID, variantID, `${url}/products/${e[i][j].handle}?variant=${e[i][j].objectID}`);
}
await postgres.query(
`insert into variant_identifier (
variant_id,
gtin
) values (
$1,
$2
) on conflict do nothing`,
[variantID, e[i][j].sku]
);
if(minCBD.gt(0) || maxCBD.gt(0) || minTHC.gt(0) || maxTHC.gt(0)) {
if(maxCBD.lt(minCBD)) {
maxCBD = minCBD;
console.log(`you dumbfucks didn't graduate grade 1 equalities ${url}/products/${e[i][j].handle}?variant=${e[i][j].objectID}`);
}
if(maxTHC.lt(minTHC)) {
maxTHC = minTHC;
console.log(`you dumbfucks didn't graduate grade 1 equalities ${url}/products/${e[i][j].handle}?variant=${e[i][j].objectID}`);
}
if(e[i][j].inventory_quantity < 0) {
console.log(`I fucking hate my life ${url}/products/${e[i][j].handle}?variant=${e[i][j].objectID}`);
e[i][j].inventory_quantity = 0;
}
await postgres.query(
`insert into menu_item (
variant_id,
store_id,
cbd,
thc,
price,
stock,
path
) values (
$1,
$2,
$3,
$4,
$5,
$6,
$7
) on conflict (variant_id, store_id) do update set cbd = excluded.cbd, thc = excluded.thc, price = excluded.price, stock = excluded.stock`,
[
variantID,
storeID,
`[${minCBD.toString()},${maxCBD.toString()}]`,
`[${minTHC.toString()},${maxTHC.toString()}]`,
e[i][j].price,
e[i][j].inventory_quantity,
`/products/${e[i][j].handle}?variant=${e[i][j].objectID}`
]
);
} else {
console.error(`why don't you fix your fucking data ocs?? ${url}/products/${e[i][j].handle}?variant=${e[i][j].objectID}`);
}
}
cliProgressBar.update(++progress);
}
}
await Promise.all([
deal(),
deal(),
deal(),
deal(),
deal(),
deal()
])
await postgres.query('commit');
await postgres.end();
for(let [key, value] of dup) {
if(value.size > 1) {
console.log(key, value);
}
}
})();