Skip to content

Commit

Permalink
Merge pull request #46 from curiosta/feat/add-product-sync
Browse files Browse the repository at this point in the history
Feat/add product sync
  • Loading branch information
Labham-Jain authored Oct 30, 2023
2 parents 111a256 + 8cc8162 commit 5867fab
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 21 deletions.
Binary file modified dump.rdb
Binary file not shown.
63 changes: 63 additions & 0 deletions env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
type BackendSecrets = {
MEDUSA_BACKEND_SERVICE_EMAIL: string,
MEDUSA_BACKEND_SERVICE_PASSWORD: string
}

type DatabaseEnv = {
REDIS_URL: string;
DATABASE_TYPE: string;
DATABASE_URL: string;
DB_USER: string;
DB_PASSWORD: string;
DB_HOST: string;
DB_PORT: string;
DB_NAME: string;
}


type SessionSecret = {
JWT_SECRET: string;
COOKIE_SECRET: string
}

type CORSSecret = {
STORE_CORS: string;
ADMIN_CORS: string;
}

type ServicesAPIKeys = {
// openai
OPENAI_API_KEY: string;

// sendgrid
SENDGRID_API_KEY: string;
SENDGRID_FROM: string;
SEGMENT_WRITE_KEY: string;

// meilisearch
MEILISEARCH_API_KEY: string;
MEILISEARCH_HOST: string;

// google
KEY_FILE_PATH: string;
}

type AWSEnv = {
AWS_ACCESS_KEY_ID: string,
AWS_BUCKET: string,
AWS_REGION: string,
AWS_SECRET_ACCESS_KEY: string,
AWS_URL: string,
}

type GoogleSheetEnv = {
GSHEET_ID: string;
PRODUCT_SHEET_NAME: string;
DROPDOWN_LIST_SHEET_NAME: string;
}

declare namespace NodeJS {
interface ProcessEnv extends BackendSecrets, DatabaseEnv, SessionSecret, CORSSecret, ServicesAPIKeys, AWSEnv, GoogleSheetEnv {
BASE_URL: string;
}
}
1 change: 1 addition & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { SheetsSyncProductsRouter } from "./routes/admin/sheets/sync-products";
export default (rootDirectory: string): Router | Router[] => {
const { configModule: { projectConfig } } = getConfigFile<ConfigModule>(rootDirectory, "medusa-config")


// aws s3 initialization
const s3Client = new S3Client({ region: process.env.AWS_REGION })

Expand Down
5 changes: 3 additions & 2 deletions src/api/routes/admin/sheets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ export const SheetsRouter = (router: Router) => {
const categoryService = req.scope.resolve('categoryService') as CategoryService;
const productService = req.scope.resolve('productService') as ProductService

googleSheetService.sheetId = (req.query.sheetId as string) || '1TaiFMTqYGirhLrjUkEfCGbV3hCrX9po_tduFw_sETUg';

if (typeof req.query.sheetId === 'string') {
googleSheetService.sheetId = req.query.sheetId
}
try {
const sheetData = await googleSheetService.getProductDataBySheetId();

Expand Down
6 changes: 5 additions & 1 deletion src/api/routes/admin/sheets/sync-categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ export const SheetsSyncCategoriesRouter = (router: Router) => {
const googleSheetService = req.scope.resolve('googleSheetApiService') as GoogleSheetAPIService;
const categoryService = req.scope.resolve('categoryService') as CategoryService;

googleSheetService.sheetId = (req.query.sheetId as string) || '1TaiFMTqYGirhLrjUkEfCGbV3hCrX9po_tduFw_sETUg'
console.log('\n\n\n\n', process.env, '\n\n\n\n');

if (typeof req.query.sheetId === 'string') {
googleSheetService.sheetId = req.query.sheetId
}

try {

Expand Down
4 changes: 3 additions & 1 deletion src/api/routes/admin/sheets/sync-locations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ export const SheetsSyncLocationsRouter = (router: Router) => {
const googleSheetService = req.scope.resolve('googleSheetApiService') as GoogleSheetAPIService;
const categoryService = req.scope.resolve('categoryService') as CategoryService;

googleSheetService.sheetId = (req.query.sheetId as string) || '1TaiFMTqYGirhLrjUkEfCGbV3hCrX9po_tduFw_sETUg'
if (typeof req.query.sheetId === 'string') {
googleSheetService.sheetId = req.query.sheetId
}

try {

Expand Down
6 changes: 4 additions & 2 deletions src/api/routes/admin/sheets/sync-products.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ export const SheetsSyncProductsRouter = (router: Router) => {
const googleSheetService = req.scope.resolve('googleSheetApiService') as GoogleSheetAPIService;
const productService = req.scope.resolve('productService') as ProductService;

googleSheetService.sheetId = (req.query.sheetId as string) || '1TaiFMTqYGirhLrjUkEfCGbV3hCrX9po_tduFw_sETUg'
if (typeof req.query.sheetId === 'string') {
googleSheetService.sheetId = req.query.sheetId
}

try {
const products = await productService.list({}, { relations: ['categories'] })
const products = await productService.list({}, { relations: ['categories', 'variants'] })

googleSheetService.syncProducts(products)

Expand Down
30 changes: 17 additions & 13 deletions src/services/google-sheet-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class GoogleSheetAPIService extends TransactionBaseService {

constructor(container) {
super(container);

this.sheetId = process.env.GSHEET_ID;

// Initialize Google Authentication and create the Google Sheets service
const auth = new google.auth.GoogleAuth({
keyFile: process.env.KEY_FILE_PATH, // Specify the path to your service account key file
Expand All @@ -37,7 +40,7 @@ class GoogleSheetAPIService extends TransactionBaseService {

// Retrieve data from a Google Sheet by its ID, specifying sheet name and cell range
// Original function for retrieving data as an object of arrays
async getProductDataBySheetId(sheetName = 'Sheet1', cellSelection = 'A1:Z') {
async getProductDataBySheetId(sheetName = process.env.PRODUCT_SHEET_NAME, cellSelection = 'A1:Z') {
// Fetch data from the specified Google Sheet
const response = await this.sheets.spreadsheets.values.get({
spreadsheetId: this.sheetId,
Expand All @@ -56,7 +59,7 @@ class GoogleSheetAPIService extends TransactionBaseService {
filteredData.slice(1).forEach((row, index) => {
const itemData = {
rowNumber: index + 2 // 1 for index, 2nd for header. so adding 2.
}; // Create an object to represent an item
};

row.forEach((cell, columnIndex) => {
const header = headers[columnIndex];
Expand All @@ -65,6 +68,7 @@ class GoogleSheetAPIService extends TransactionBaseService {
if (!header) throw new Error('Header not found but data is present. Failed to map data!');

// Process cell values and add them to the itemData object

switch (cell) {
case 'TRUE':
itemData[header] = true;
Expand Down Expand Up @@ -94,7 +98,7 @@ class GoogleSheetAPIService extends TransactionBaseService {

async updateProductId(payload: { id: string; rowNumber: number }[]) {

const valueUpdates = payload.map(p => ({ range: `A${p.rowNumber}`, values: [[p.id]] }));
const valueUpdates = payload.map(p => ({ range: `${process.env.PRODUCT_SHEET_NAME}!A${p.rowNumber}`, values: [[p.id]] }));

const response = await this.sheets.spreadsheets.values.batchUpdate({
spreadsheetId: this.sheetId,
Expand All @@ -113,7 +117,6 @@ class GoogleSheetAPIService extends TransactionBaseService {
const location = product.categories?.filter(c => c.handle.startsWith('loc:'))[0];
const category = product.categories?.filter(c => !c.handle.startsWith('loc:'))[0];


return [
// product id
product.id,
Expand All @@ -134,12 +137,13 @@ class GoogleSheetAPIService extends TransactionBaseService {
product.status === ProductStatus.DRAFT,

// Stocks

product.variants?.[0].inventory_quantity || ''
]
})).then(async (sheetProducts) => {
const response = await this.sheets.spreadsheets.values.get({
spreadsheetId: this.sheetId,
range: `Sheet1!A2:A`,
range: `${process.env.PRODUCT_SHEET_NAME}!A2:A`,
})

const cellLength = response.data.values?.length || 0;
Expand All @@ -150,9 +154,9 @@ class GoogleSheetAPIService extends TransactionBaseService {

return this.sheets.spreadsheets.values.update({
spreadsheetId: this.sheetId,
range: `Sheet1!A2:G`,
range: `${process.env.PRODUCT_SHEET_NAME}!A2:G`,
valueInputOption: 'RAW',
requestBody: { range: `Sheet1!A2:G`, values }
requestBody: { range: `${process.env.PRODUCT_SHEET_NAME}!A2:G`, values }
})
});

Expand All @@ -161,7 +165,7 @@ class GoogleSheetAPIService extends TransactionBaseService {
async syncCategories(categories: string[] = []) {
const response = await this.sheets.spreadsheets.values.get({
spreadsheetId: this.sheetId,
range: `Sheet2!A2:A`,
range: `${process.env.DROPDOWN_LIST_SHEET_NAME}!A2:A`,
})

const cellLength = response.data.values?.length;
Expand All @@ -170,16 +174,16 @@ class GoogleSheetAPIService extends TransactionBaseService {
const values = Array(targetedLength).fill(null).map((_, i) => categories[i] || '').sort((a, z) => !a.length ? 0 : a > z ? 1 : -1).map(c => [c]);
return this.sheets.spreadsheets.values.update({
spreadsheetId: this.sheetId,
range: `Sheet2!A2:A`,
range: `${process.env.DROPDOWN_LIST_SHEET_NAME}!A2:A`,
valueInputOption: 'RAW',
requestBody: { range: `Sheet2!A2:A`, values }
requestBody: { range: `${process.env.DROPDOWN_LIST_SHEET_NAME}!A2:A`, values }
})
}

async syncLocations(locations: string[] = []) {
const response = await this.sheets.spreadsheets.values.get({
spreadsheetId: this.sheetId,
range: `Sheet2!B2:B`,
range: `${process.env.DROPDOWN_LIST_SHEET_NAME}!B2:B`,
})

const cellLength = response.data.values?.length || 0;
Expand All @@ -188,9 +192,9 @@ class GoogleSheetAPIService extends TransactionBaseService {
const values = Array(targetedLength).fill(null).map((_, i) => locations[i] || '').sort((a, z) => !a.length ? 0 : a > z ? 1 : -1).map(c => [c]);
return this.sheets.spreadsheets.values.update({
spreadsheetId: this.sheetId,
range: `Sheet2!B2:B`,
range: `${process.env.DROPDOWN_LIST_SHEET_NAME}!B2:B`,
valueInputOption: 'RAW',
requestBody: { range: `Sheet2!B2:B`, values }
requestBody: { range: `${process.env.DROPDOWN_LIST_SHEET_NAME}!B2:B`, values }
})
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/subscribers/productdescription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ class ProductDescriptionSubscriber {
return response.data.choices[0].message.content

} catch (error) {
if (error.response.data.error.code === 'invalid_api_key') return '';
if (!(retries >= 3)) {
this.prepareDescription(prompt, { retries: retries + 1 });
} else {
throw new Error('No description provided!');
console.warn('No description provided!')
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"rootDir": "src",
"baseUrl": "src"
},
"include": ["src"],
"include": ["src", "env.d.ts"],
"exclude": [
"**/__tests__",
"**/__fixtures__",
Expand Down

0 comments on commit 5867fab

Please sign in to comment.