· 5 years ago · Dec 30, 2020, 01:14 PM
1const functions = require('firebase-functions');
2const admin = require('firebase-admin');
3const axios = require('axios');
4const fs = require('fs');
5const createCsvWriter = require('csv-writer').createObjectCsvWriter;
6const moment = require('moment');
7const { Storage } = require('@google-cloud/storage');
8const serviceAccount = require('./namely-app-firebase-adminsdk-ky2dy-f3d19207be.json');
9const { service } = require('firebase-functions/lib/providers/analytics');
10const JSZip = require('jszip');
11const Bottleneck = require('bottleneck');
12const cors = require('cors')({origin: true});
13
14require('firebase-functions/lib/logger/compat');
15const version = '2020-07';
16const password = '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';
17const bucketName = 'namely-app.appspot.com';
18const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
19const args = process.argv.slice(2);
20const storage = new Storage();
21
22admin.initializeApp({
23 credential: admin.credential.cert(serviceAccount),
24 databaseURL: 'https://namely-app.firebaseio.com',
25 storageBucket: 'namely-app.appspot.com',
26});
27
28const fbStorage = admin.storage();
29
30exports.fetchNamelyDataTest2 = functions.https.onRequest(
31 async (request, response) => {
32 cors(request, response, async () => {
33
34 let { startId, endId, key, storeUrl } = request.body.data;
35 const numberOfOrders = endId - startId;
36 const numberOfRuns = Math.ceil(numberOfOrders / 250);
37 let limit;
38 const limiter = new Bottleneck({
39 reservoir: 30, // initial value
40 reservoirIncreaseAmount: 2,
41 reservoirIncreaseInterval: 1000, // must be divisible by 250
42 reservoirIncreaseMaximum: 30,
43
44 // also use maxConcurrent and/or minTime for safety
45 maxConcurrent: 4,
46 minTime: 500, // pick a value that makes sense for your use case
47 });
48 let runCsv = false;
49 let allOrders = [];
50 let indiaOrders = [];
51 let chinaOrders = [];
52 let australiaOrders = [];
53 let namelyOrders = [];
54 let noFactoryCodeOrders = [];
55
56 const baseUrl = `https://${key}:${password}@${storeUrl}.myshopify.com/admin/api/${version}/orders.json?`;
57 const variantUrl = `https://${key}:${password}@${storeUrl}.myshopify.com/admin/api/${version}/variants`;
58 await axios
59 .get(`${baseUrl}name=${startId}`)
60 .then(async res => {
61
62 let { orders } = res.data;
63 let orderId = orders[0].id;
64
65 for (let i = 0; i < numberOfRuns; i++) {
66 let numOrdersLeft = numberOfOrders - 250 * i;
67 numOrdersLeft >= 250 ? (limit = 250) : (limit = numOrdersLeft);
68
69 await axios
70 .get(`${baseUrl}limit=${limit}&since_id=${orderId}`)
71 .then(async res => {
72 let { orders } = res.data;
73 for (let j = 0; j < limit; j++) {
74 let order = orders[j];
75 if (j === orders.length - 1) orderId = order.id;
76
77
78 for (let k = 0; k < order.line_items.length; k++) {
79 let item = order.line_items[k];
80 let itemData = {};
81 let address, factoryCode;
82 let variantParts = item.variant_title.split('/');
83 let entryDate = new Date();
84 let deliveryDate = new Date();
85
86 deliveryDate.setDate(entryDate.getDate() + 12);
87
88 if (order.note) itemData.notes = order.note;
89
90 itemData.variantId = item.variant_id;
91
92
93 order.shipping_address
94 ? (address = order.shipping_address)
95 : (address = order.billing_address);
96
97 variantParts.forEach(part => {
98 if (part.toLowerCase().includes('base')) {
99 itemData.color = part;
100 } else {
101 itemData.styleAndSize = part;
102 }
103 });
104
105 if (order.line_items.length > 1) {
106 itemData.orderNumber = `${order.order_number}-${alphabet[i]}`;
107 } else {
108 itemData.orderNumber = order.order_number;
109 }
110
111 itemData.entryDate = moment(entryDate).format('DD/MM/YYYY');
112 // itemData.styleAndSize = variantParts[0];
113 // itemData.styleNumber = 'N/A';
114 // itemData.color = variantParts[1];
115 itemData.customerName = `${order.customer.first_name} ${order.customer.last_name}`;
116 itemData.quantityOrdered = item.quantity;
117 itemData.deliveryDate = moment(deliveryDate).format(
118 'DD/MM/YYYY'
119 );
120
121 itemData.address = `
122 ${address.name}
123 ${address.address1}
124 ${address.city} ${address.province_code} ${address.zip}
125 ${address.country}
126 ${address.phone || order.billing_address.phone}
127 ${order.customer.email}
128 `;
129
130 for (let prop of item.properties) {
131 let childName;
132 if (prop.name.toLowerCase().includes('name')) {
133 if (prop.value.includes('.')) {
134 childName = prop.value;
135 } else {
136 childName = `${prop.value}.`;
137 }
138 if (childName.includes(' .')) {
139 childName = childName.replace(' .', '.');
140 }
141 itemData.childName = childName;
142 break;
143 }
144
145 if (prop.name.toLowerCase().includes('to')) {
146 itemData.notes = `
147 ${item.properties[0].value}
148 ${item.properties[1].value}
149 ${item.properties[2].value}
150 `;
151 break;
152 }
153 }
154
155 allOrders.push(itemData);
156
157 // setTimeout(async () => {
158 // // await limiter.schedule(async () => {
159 // await axios
160 // .get(`${variantUrl}/${item.variant_id}.json`)
161 // .then(res => {
162 // let { variant } = res.data;
163 // factoryCode = variant.sku.split('-')[1];
164 // itemData.styleNumber = variant.barcode;
165 // itemData.sku = variant.sku;
166 // allOrders.push(itemData);
167 // })
168 // .catch(err => {
169 // console.log('error inside variant search', err);
170 // });
171 // }, 10000);
172 // });
173 // console.log('factory code', factoryCode);
174 // switch (factoryCode) {
175 // case '1':
176 // indiaOrders.push(itemData);
177 // break;
178 // case '2':
179 // chinaOrders.push(itemData);
180 // break;
181 // case '3':
182 // australiaOrders.push(itemData);
183 // break;
184 // case '4':
185 // namelyOrders.push(itemData);
186 // break;
187 // default:
188 // noFactoryCodeOrders.push(itemData);
189 // break;
190 // }
191 }
192 }
193 })
194 .catch(err => console.log(err));
195 }
196 // console.log('all orders', allOrders)
197 for (let i = 0; i < allOrders.length; i++) {
198 let order = allOrders[i];
199 // for (let order of allOrders) {
200 await limiter.schedule(async () => {
201 return await axios
202 .get(`${variantUrl}/${order.variantId}.json`)
203 .then(res => {
204 let { variant } = res.data;
205 let factoryCode = variant.sku.split('-')[1];
206 order.styleNumber = variant.barcode;
207 order.sku = variant.sku;
208
209 switch (factoryCode) {
210 case '1':
211 indiaOrders.push(order);
212 break;
213 case '2':
214 chinaOrders.push(order);
215 break;
216 case '3':
217 australiaOrders.push(order);
218 break;
219 case '4':
220 namelyOrders.push(order);
221 break;
222 default:
223 noFactoryCodeOrders.push(order);
224 break;
225 }
226 // return;
227 })
228 .catch(err => {
229 return console.log('variant search err', err);
230 });
231 });
232 // }
233 }
234 // limiter.disconnect();
235
236
237 // console.log('india', indiaOrders)
238 // console.log('china', chinaOrders)
239 // console.log('australia', australiaOrders)
240 // console.log('namely', namelyOrders)
241 // console.log('none', noFactoryCodeOrders)
242
243 // let files = await createCsv({
244 // india: indiaOrders,
245 // china: chinaOrders,
246 // australia: australiaOrders,
247 // namely: namelyOrders,
248 // noCode: noFactoryCodeOrders,
249 // });
250
251 // return response.status(200).send(files);
252 })
253 .catch(err => {
254 console.log('error', err);
255
256 // if (err.request.res.statusCode !== 429) {
257 response
258 .status(400)
259 .send(
260 'Something went wrong. Please make sure your API key and store URL are correct'
261 );
262 // }
263 });
264
265 let files = await createCsv({
266 india: indiaOrders,
267 china: chinaOrders,
268 australia: australiaOrders,
269 namely: namelyOrders,
270 noCode: noFactoryCodeOrders,
271 });
272
273 // limiter.disconnect();
274 console.log('sending files');
275 return response.status(200).send(files);
276 })
277 }
278);
279
280const createCsv = async factoryData => {
281 const zip = new JSZip();
282 const date = moment(new Date()).format('DD-MM-YYYY');
283 const time = moment(new Date()).format('HH-mm');
284 const zipFileName = `${date}_${time}.zip`;
285 let filesObj = {};
286
287 for (const factory in factoryData) {
288 const fileName = `${date}_${time}_${factory}-details.csv`;
289 const filePath = `/tmp/${fileName}`;
290
291 let csvWriter = createCsvWriter({
292 path: filePath,
293 header: [
294 { id: 'orderNumber', title: 'Order Number:' },
295 { id: 'lotNumber', title: 'LD Lot No:' },
296 { id: 'entryDate', title: 'Entry Date:' },
297 { id: 'styleAndSize', title: 'Style and Size:' },
298 { id: 'styleNumber', title: 'LD Style No:' },
299 { id: 'sku', title: 'SKU:' },
300 { id: 'color', title: 'Colour:' },
301 { id: 'childName', title: 'Child Name:' },
302 { id: 'customerName', title: 'Customer Name:' },
303 { id: 'quantityOrdered', title: 'Quantity Ordered:' },
304 { id: 'quantitySent', title: 'Quantity Sent:' },
305 { id: 'deliveryDate', title: 'Estimated Delivery Date:' },
306 { id: 'ldDateSent', title: 'LD Date Sent:' },
307 { id: 'invoiceNumber', title: 'Invoice Number:' },
308 { id: 'address', title: 'Address:' },
309 { id: 'notes', title: 'NAMELYCO Notes:' },
310 { id: 'remark', title: 'LD Remark:' },
311 ],
312 });
313
314 await csvWriter
315 .writeRecords(factoryData[factory])
316 .then(async () => {
317 console.log(`created csv for ${factory}`);
318
319 await storage
320 .bucket(bucketName)
321 .upload(`/tmp/${fileName}`, {
322 gzip: false,
323 })
324 .then(async () => {
325 await storage.bucket(bucketName).file(`${fileName}`).makePublic();
326 });
327
328 let url = `storage.googleapis.com/${bucketName}/${fileName}`;
329 filesObj[factory] = url;
330 })
331 .catch(err => console.log('error inside csv writer', err));
332 }
333
334 return filesObj;
335};