|
| 1 | +import type { ApiError } from '@cloudcommerce/api'; |
| 2 | +import { logger } from '@cloudcommerce/firebase/lib/config'; |
| 3 | +import api from '@cloudcommerce/api'; |
| 4 | +import getAppData from '@cloudcommerce/firebase/lib/helpers/get-app-data'; |
| 5 | +import { sendEmail } from '@cloudcommerce/emails'; |
| 6 | +import { getStore, getMailRender } from './util/emails-utils'; |
| 7 | +import getMailTempl from './util/get-mail-templ'; |
| 8 | + |
| 9 | +const sendCartEmails = async () => { |
| 10 | + const appData = await getAppData('emails', ['data']); |
| 11 | + const mailOptions = appData.abandoned_cart || {}; |
| 12 | + if (mailOptions.disable_customer === true) { |
| 13 | + return; |
| 14 | + } |
| 15 | + const daysDelay = parseInt(appData.is_abandoned_after_days, 10) || 1; |
| 16 | + const d = new Date(); |
| 17 | + d.setDate(d.getDate() - daysDelay); |
| 18 | + const { |
| 19 | + data: { result: abandonedCarts }, |
| 20 | + } = await api.get('carts', { |
| 21 | + params: { |
| 22 | + 'completed': false, |
| 23 | + 'available': true, |
| 24 | + 'flags': 'open-checkout', |
| 25 | + 'updated_at<': d.toISOString(), |
| 26 | + }, |
| 27 | + fields: ['_id', 'flags', 'completed', 'customers'] as const, |
| 28 | + sort: ['-updated_at'], |
| 29 | + limit: 100, |
| 30 | + }); |
| 31 | + if (!abandonedCarts.length) { |
| 32 | + return; |
| 33 | + } |
| 34 | + const store = getStore(); |
| 35 | + const lang = appData.lang === 'Inglês' ? 'en_us' : (store.lang || 'pt_br'); |
| 36 | + const mailTempl = getMailTempl('abandoned_cart')!; |
| 37 | + const subject = mailTempl.subject[lang as 'pt_br']; |
| 38 | + const customMessage = mailOptions.custom_message; |
| 39 | + const render = await getMailRender(mailTempl?.templ); |
| 40 | + for (let i = 0; i < abandonedCarts.length; i++) { |
| 41 | + const cart = abandonedCarts[i]; |
| 42 | + if (cart.completed || !cart.flags?.includes('open-checkout')) { |
| 43 | + logger.warn(`Invalid cart ${cart._id}`, { cart }); |
| 44 | + continue; |
| 45 | + } |
| 46 | + const customerId = cart.customers?.[0]; |
| 47 | + const flags: string[] = []; |
| 48 | + if (!customerId) { |
| 49 | + logger.info(`Cart ${cart._id} skipped without customer ID`); |
| 50 | + flags.push('email-skipped'); |
| 51 | + } else { |
| 52 | + try { |
| 53 | + // eslint-disable-next-line no-await-in-loop |
| 54 | + const { data: customer } = await api.get(`customers/${customerId}`); |
| 55 | + // eslint-disable-next-line no-await-in-loop |
| 56 | + const html = await render( |
| 57 | + store, |
| 58 | + customer, |
| 59 | + { |
| 60 | + ...cart, |
| 61 | + permalink: `https://${store.domain}/app/#/cart/` |
| 62 | + + '?utm_source=ecomplus&utm_medium=email&utm_campaign=abandoned_cart' |
| 63 | + + `#/cart/${cart._id}`, |
| 64 | + }, |
| 65 | + lang, |
| 66 | + customMessage, |
| 67 | + ); |
| 68 | + if (html) { |
| 69 | + // eslint-disable-next-line no-await-in-loop |
| 70 | + await sendEmail( |
| 71 | + { |
| 72 | + to: [{ |
| 73 | + name: customer.display_name, |
| 74 | + email: customer.main_email, |
| 75 | + }], |
| 76 | + subject, |
| 77 | + html, |
| 78 | + templateId: mailOptions.template_id, |
| 79 | + templateData: { |
| 80 | + store, |
| 81 | + customer, |
| 82 | + cart, |
| 83 | + lang, |
| 84 | + customMessage, |
| 85 | + }, |
| 86 | + }, |
| 87 | + ); |
| 88 | + flags.push('email-sent'); |
| 89 | + } |
| 90 | + } catch (err: any) { |
| 91 | + const error: ApiError = err; |
| 92 | + if (error.statusCode === 404) { |
| 93 | + logger.warn(`Customer not found by id ${customerId}`, { cart }); |
| 94 | + } else { |
| 95 | + logger.error(err); |
| 96 | + continue; |
| 97 | + } |
| 98 | + } |
| 99 | + } |
| 100 | + api.patch(`carts/${cart._id}`, { flags }); |
| 101 | + } |
| 102 | +}; |
| 103 | + |
| 104 | +export default sendCartEmails; |
0 commit comments