Add xlsxwriter-based Excel generation scripts with openpyxl implementation
- Created create_excel_xlsxwriter.py and update_excel_xlsxwriter.py - Uses openpyxl exclusively to preserve Excel formatting and formulas - Updated server.js to use new xlsxwriter scripts for form submissions - Maintains all original functionality while ensuring proper Excel file handling 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
187
index.js
Normal file
187
index.js
Normal file
@@ -0,0 +1,187 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Function to update config.json with form data
|
||||
async function updateConfig(formData) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const configPath = path.join(__dirname, 'config.json');
|
||||
|
||||
// Read the existing config file
|
||||
fs.readFile(configPath, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
reject(new Error(`Failed to read config file: ${err.message}`));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Parse the existing config
|
||||
const configData = JSON.parse(data);
|
||||
|
||||
// Update user_data in the config with form data
|
||||
configData.user_data = {
|
||||
// Contact information
|
||||
first_name: formData.firstName || "",
|
||||
last_name: formData.lastName || "",
|
||||
company_name: formData.company || "",
|
||||
email: formData.email || "",
|
||||
phone: formData.phone || "",
|
||||
store_name: formData.storeName || "",
|
||||
country: formData.country || "",
|
||||
starting_date: formData.startingDate || "",
|
||||
duration: parseInt(formData.duration) || 36,
|
||||
|
||||
// Store information
|
||||
store_types: getSelectedStoreTypes(formData),
|
||||
open_days_per_month: parseInt(formData.openDays) || 0,
|
||||
|
||||
// Store type specific data
|
||||
convenience_store_type: {
|
||||
stores_number: isStoreTypeSelected(formData, 'Convenience') ? parseInt(formData.convenience_stores) || 0 : 0,
|
||||
monthly_transactions: isStoreTypeSelected(formData, 'Convenience') ? parseInt(formData.convenience_transactions) || 0 : 0,
|
||||
has_digital_screens: isStoreTypeSelected(formData, 'Convenience') ? formData.convenience_screens === "Yes" : false,
|
||||
screen_count: isStoreTypeSelected(formData, 'Convenience') ? parseInt(formData.convenience_screen_count) || 0 : 0,
|
||||
screen_percentage: isStoreTypeSelected(formData, 'Convenience') ? parseInt(formData.convenience_screen_percentage) || 0 : 0,
|
||||
has_in_store_radio: isStoreTypeSelected(formData, 'Convenience') ? formData.convenience_radio === "Yes" : false,
|
||||
radio_percentage: isStoreTypeSelected(formData, 'Convenience') ? parseInt(formData.convenience_radio_percentage) || 0 : 0,
|
||||
open_days_per_month: parseInt(formData.openDays) || 0
|
||||
},
|
||||
|
||||
supermarket_store_type: {
|
||||
stores_number: isStoreTypeSelected(formData, 'Supermarket') ? parseInt(formData.supermarket_stores) || 0 : 0,
|
||||
monthly_transactions: isStoreTypeSelected(formData, 'Supermarket') ? parseInt(formData.supermarket_transactions) || 0 : 0,
|
||||
has_digital_screens: isStoreTypeSelected(formData, 'Supermarket') ? formData.supermarket_screens === "Yes" : false,
|
||||
screen_count: isStoreTypeSelected(formData, 'Supermarket') ? parseInt(formData.supermarket_screen_count) || 0 : 0,
|
||||
screen_percentage: isStoreTypeSelected(formData, 'Supermarket') ? parseInt(formData.supermarket_screen_percentage) || 0 : 0,
|
||||
has_in_store_radio: isStoreTypeSelected(formData, 'Supermarket') ? formData.supermarket_radio === "Yes" : false,
|
||||
radio_percentage: isStoreTypeSelected(formData, 'Supermarket') ? parseInt(formData.supermarket_radio_percentage) || 0 : 0,
|
||||
open_days_per_month: parseInt(formData.openDays) || 0
|
||||
},
|
||||
|
||||
hypermarket_store_type: {
|
||||
stores_number: isStoreTypeSelected(formData, 'Hypermarket') ? parseInt(formData.hypermarket_stores) || 0 : 0,
|
||||
monthly_transactions: isStoreTypeSelected(formData, 'Hypermarket') ? parseInt(formData.hypermarket_transactions) || 0 : 0,
|
||||
has_digital_screens: isStoreTypeSelected(formData, 'Hypermarket') ? formData.hypermarket_screens === "Yes" : false,
|
||||
screen_count: isStoreTypeSelected(formData, 'Hypermarket') ? parseInt(formData.hypermarket_screen_count) || 0 : 0,
|
||||
screen_percentage: isStoreTypeSelected(formData, 'Hypermarket') ? parseInt(formData.hypermarket_screen_percentage) || 0 : 0,
|
||||
has_in_store_radio: isStoreTypeSelected(formData, 'Hypermarket') ? formData.hypermarket_radio === "Yes" : false,
|
||||
radio_percentage: isStoreTypeSelected(formData, 'Hypermarket') ? parseInt(formData.hypermarket_radio_percentage) || 0 : 0,
|
||||
open_days_per_month: parseInt(formData.openDays) || 0
|
||||
},
|
||||
|
||||
// On-site channels
|
||||
on_site_channels: getSelectedChannels(formData, 'onSiteChannels'),
|
||||
website_visitors: isChannelSelected(formData, 'onSiteChannels', 'Website') ? parseInt(formData.websiteVisitors) || 0 : 0,
|
||||
app_users: isChannelSelected(formData, 'onSiteChannels', 'Mobile App') ? parseInt(formData.appUsers) || 0 : 0,
|
||||
loyalty_users: isChannelSelected(formData, 'onSiteChannels', 'Loyalty Program') ? parseInt(formData.loyaltyUsers) || 0 : 0,
|
||||
|
||||
// Off-site channels
|
||||
off_site_channels: getSelectedChannels(formData, 'offSiteChannels'),
|
||||
facebook_followers: isChannelSelected(formData, 'offSiteChannels', 'Facebook Business') ? parseInt(formData.facebookFollowers) || 0 : 0,
|
||||
instagram_followers: isChannelSelected(formData, 'offSiteChannels', 'Instagram Business') ? parseInt(formData.instagramFollowers) || 0 : 0,
|
||||
google_views: isChannelSelected(formData, 'offSiteChannels', 'Google Business Profile') ? parseInt(formData.googleViews) || 0 : 0,
|
||||
email_subscribers: isChannelSelected(formData, 'offSiteChannels', 'Email') ? parseInt(formData.emailSubscribers) || 0 : 0,
|
||||
sms_users: isChannelSelected(formData, 'offSiteChannels', 'SMS') ? parseInt(formData.smsUsers) || 0 : 0,
|
||||
whatsapp_contacts: isChannelSelected(formData, 'offSiteChannels', 'WhatsApp') ? parseInt(formData.whatsappContacts) || 0 : 0,
|
||||
|
||||
// Preserve existing calculation results if they exist
|
||||
potential_reach_in_store: 0,
|
||||
unique_impressions_in_store: 0,
|
||||
potential_reach_on_site: 0,
|
||||
unique_impressions_on_site: 0,
|
||||
potential_reach_off_site: 0,
|
||||
unique_impressions_off_site: 0
|
||||
};
|
||||
|
||||
// Write the updated config back to the file
|
||||
const updatedConfig = JSON.stringify(configData, null, 2);
|
||||
|
||||
fs.writeFile(configPath, updatedConfig, 'utf8', (writeErr) => {
|
||||
if (writeErr) {
|
||||
reject(new Error(`Failed to write to config file: ${writeErr.message}`));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
} catch (parseError) {
|
||||
reject(new Error(`Failed to parse config file: ${parseError.message}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to check if a channel is selected
|
||||
function isChannelSelected(formData, channelType, channelName) {
|
||||
const selectedChannels = getSelectedChannels(formData, channelType);
|
||||
return selectedChannels.includes(channelName);
|
||||
}
|
||||
|
||||
// Helper function to get selected channels from form data
|
||||
function getSelectedChannels(formData, channelType) {
|
||||
console.log(`Getting selected channels for ${channelType} from formData:`, formData[channelType]);
|
||||
|
||||
let channels = [];
|
||||
|
||||
if (formData[channelType]) {
|
||||
if (Array.isArray(formData[channelType])) {
|
||||
channels = formData[channelType];
|
||||
} else {
|
||||
channels = [formData[channelType]];
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Selected ${channelType}:`, channels);
|
||||
return channels;
|
||||
}
|
||||
|
||||
// Helper function to check if a store type is selected
|
||||
function isStoreTypeSelected(formData, storeType) {
|
||||
const selectedTypes = getSelectedStoreTypes(formData);
|
||||
return selectedTypes.includes(storeType);
|
||||
}
|
||||
|
||||
// Helper function to get selected store types from form data
|
||||
function getSelectedStoreTypes(formData) {
|
||||
console.log('Getting selected store types from formData:', formData);
|
||||
|
||||
// Check if storeTypes is an array or single value
|
||||
let storeTypes = [];
|
||||
|
||||
if (formData.storeTypes) {
|
||||
if (Array.isArray(formData.storeTypes)) {
|
||||
storeTypes = formData.storeTypes;
|
||||
} else {
|
||||
storeTypes = [formData.storeTypes];
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Selected store types:', storeTypes);
|
||||
return storeTypes;
|
||||
}
|
||||
|
||||
// Function to fetch config.json
|
||||
async function fetchConfig() {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(path.join(__dirname, 'config.json'), 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
reject(new Error(`Failed to read config file: ${err.message}`));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const config = JSON.parse(data);
|
||||
resolve(config);
|
||||
} catch (parseError) {
|
||||
reject(new Error(`Failed to parse config file: ${parseError.message}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// For Node.js environment, export the functions
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
updateConfig,
|
||||
fetchConfig
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user