magento configurable products are not uploading - excel

we are using an extension to upload the products through csv files.
Its working fine for simple product. But its giving error when we try to upload configurable product.
Error : Skip import row, product with duplicate attribute combination
In the following code ,the above error message is present. I want to know what wrong in excel sheet, so that its giving this error :
for ($i = $totalProcessedRows + 1; $i <= sizeof($data); $i++) {
if(strtolower($data[$i][0]) != "configurable" && $data[$i][0] != "") {
$attributeOptionCheck[] = $data[$i][10];
$associatedSkuCheck[] = $data[$i][5];
$totalProcessedRows++;
} else {
if(count($attributeOptionCheck) != count(array_unique($attributeOptionCheck)))
$errors[] = Mage::helper('mpmassuploadaddons')->__('Skip import row, product with duplicate attribute combination');
elseif(count($associatedSkuCheck) != count(array_unique($associatedSkuCheck)))
$errors[] = Mage::helper('mpmassuploadaddons')->__('Skip import row,associated products with duplicate skus');
break;
}
}
This is complete function for configurable products
public function importConfigurableProducts($profileId,$rowCount) {
$helper = Mage::helper("mpmassuploadaddons");
$collection = Mage::getModel('mpmassuploadaddons/profilesession')->getCollection()
->addFieldToFilter('session_id',array('eq' => $profileId));
$result = array();
$data = array();
$csvFile = "";
$imgDir = "";
if (count($collection) > 0) {
foreach ($collection as $value) {
$csvFile = $value->getCsvFile();
$imgDir = $value->getImageFile();
}
$targetPath = Mage::getBaseDir('media')."/marketplace/massuploaded/".$profileId;
$csvPath = $targetPath.'/'.$csvFile;
$fp = fopen($csvPath, 'r');
while(!feof($fp) ){
$data[] = fgetcsv($fp, 1024);
}
fclose($fp);
$info = $data[$rowCount];
$totalProcessedRows = $rowCount;
$attributeOptionCheck = array();
$associatedSkuCheck = array();
$associatedSkuCheck[] = $info[5];
$errors = array();
for ($i = $totalProcessedRows + 1; $i <= sizeof($data); $i++) {
if(strtolower($data[$i][0]) != "configurable" && $data[$i][0] != "") {
$attributeOptionCheck[] = $data[$i][10];
$associatedSkuCheck[] = $data[$i][5];
$totalProcessedRows++;
} else {
if(count($attributeOptionCheck) != count(array_unique($attributeOptionCheck)))
$errors[] = Mage::helper('mpmassuploadaddons')->__('Skip import row, product with duplicate attribute combination');
elseif(count($associatedSkuCheck) != count(array_unique($associatedSkuCheck)))
$errors[] = Mage::helper('mpmassuploadaddons')->__('Skip import row,associated products with duplicate skus');
break;
}
}
if(empty($errors)) {
$wholedata = array(
'category' => $info[1],
'name' => $info[2],
'description' => $info[3],
'short_description' => $info[4],
'sku' => $info[5],
'price' => $info[6],
'tax_class_id' => $info[10],
'is_in_stock' => $info[11],
'_super_attribute_code' => $info[12],
'images' => $info[17]
);
// $wholedata = array(
// 'category' => $info[0],
// 'name' => $info[1],
// 'description' => $info[2],
// 'short_description' => $info[3],
// 'sku' => $info[4],
// 'price' => $info[5],
// 'tax_class_id' => $info[9],
// 'is_in_stock' => $info[10],
// 'stock' => $info[11],
// 'weight' => $info[12],
// 'images' => $info[13]
// );
if(isset($info[6])){
$specialdata=array(
'special_price' => $info[7],
'special_from_date' => $info[8],
'special_to_date' => $info[9]
);
$wholedata=array_merge($wholedata,$specialdata);
}
if(isset($info[20])){
$systemattribute=$data[0][20];
$othersystemattribute=array(
$systemattribute => $info[20]
);
$wholedata=array_merge($wholedata,$othersystemattribute);
}
list($wholedata, $errors) = $this->validatePost($wholedata);
if(empty($errors)) {
$customAttributeData = array();
$mediaTypeAttributedata = array();
if(isset($data[0][18])) {
$customAttributeCodes = explode('(', $data[0][18]);
if($customAttributeCodes[0] != "") {
list($customAttributeData, $errors) = $this->validateCustomAttributeValues($customAttributeCodes[0],$info[18]);
$mediaTypeAttributedata = $this->getMediaImageAttributesData($customAttributeCodes[0],$info[18]);
}
}
if(empty($errors)) {
$j = $rowCount;
for ($i = $j + 1; $i <= sizeof($data); $i++) {
if(strtolower($data[$i][0]) != "configurable" && $data[$i][0] != "") {
$associateWholedata = array(
'type_id' => $data[$i][0],
'name' => $data[$i][2],
'sku' => $data[$i][5],
'_super_attribute_code' => $data[$i][12],
'_super_attribute_option' => $data[$i][13],
'_super_attribute_price_corr' => $data[$i][14],
'_super_attribute_qty' => $data[$i][15],
'_super_attribute_weight' => $data[$i][16]
);
list($associateWholedata, $errors) = $this->validatePost($associateWholedata);
if(!empty($errors))
break;
} else {
break;
}
}
if(empty($errors)) {
$profile = Mage::getModel('mpmassuploadaddons/profilesession')->load($profileId);
$additionalInfo = array(
'type_id' => 'configurable',
'userid' => $profile->getSellerId(),
'wstoreids' => Mage::app()->getStore()->getStoreId(),
'attribute_set_id' => $profile->getAttributesetId()
);
$wholedata = array_merge($wholedata,$additionalInfo);
$proid = $this->saveConfigNewProduct($wholedata);
$objprod = Mage::getModel('catalog/product')->load($proid);
$websites = array();
foreach(Mage::app()->getWebsites(true) as $website) {
$websites[] = $website->getId();
}
$objprod->setWebsiteIds($websites)->save();
$marketplaceProduct = Mage::getModel('marketplace/product')->getCollection()
->addFieldToFilter("mageproductid",array("eq" => $proid))
->getFirstItem();
$marketplaceProduct->setUserid($profile->getSellerId())->save();
$totalProcessedRows = $rowCount;
$count = 1;
for ($i = $totalProcessedRows + 1; $i <= sizeof($data); $i++) {
if(strtolower($data[$i][0]) != "configurable" && $data[$i][0] != "") {
$associateWholedata = array(
'type_id' => 'simple',
'name' => $data[$i][2],
'sku' => $data[$i][5],
'stock' => $data[$i][15],
'weight' => $data[$i][16],
'status' => 1,
'visibility' => 1,
'mainid' => $proid
);
$configProduct = Mage::getModel("catalog/product")->load($proid);
$associatedPrice = $configProduct->getPrice();
$configattr = Mage::getModel('catalog/product_type_configurable')->getConfigurableAttributesAsArray($configProduct);
foreach (explode(',', $data[$i][12]) as $key => $attribute) {
$optionIds = explode(',', $data[$i][13]);
$optionId = $this->getAttributeOptionIdbyOptionText($attribute , $optionIds[$key]);
$optionPrice = explode(',', $data[$i][14]);
$associatedPrice = $associatedPrice + $optionPrice[$key];
foreach ($configattr as $value) {
if($value['attribute_code'] == $attribute) {
$optionString = $attribute."|price|".$value['id']."|".$optionId;
}
}
$associateWholedata[$attribute] = $optionId;
$associateWholedata[$optionString] = $optionPrice[$key];
$associateWholedata['price'] = $associatedPrice;
}
$this->quickcreate($associateWholedata);
$totalProcessedRows++;
$count++;
} else {
break;
}
}
if(isset($info[17]) && $info[17] != "") {
$images = array_reverse(explode(',',$info[17]));
foreach ($images as $image) {
$objprod = Mage::getModel('catalog/product')->load($proid);
$imgp = Mage::getBaseDir('media')."/marketplace/massuploaded/".$profileId."/".$imgDir."/";
$checkimg = glob($imgp . $image);
if(count($checkimg) != 0) {
$filepath = $imgp.$image;
$objprod->addImageToMediaGallery($filepath, array ('image','small_image','thumbnail'), true, false);
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$objprod->save();
}
}
}
try {
Mage::dispatchEvent('mp_add_customattribute_mass', array('product_id' => $proid,'customattribute' => $customAttributeData));
if(Mage::getModel('customattribute/customattribute')) {
if(count($mediaTypeAttributedata)) {
foreach ($mediaTypeAttributedata as $imageType => $image) {
if($image != "") {
$objprod = Mage::getModel('catalog/product')->load($proid);
$imgp = Mage::getBaseDir('media')."/marketplace/massuploaded/".$profileId."/".$imgDir."/";
$checkimg = glob($imgp . $image);
if(count($checkimg) != 0) {
$filepath = $imgp.$image;
$objprod->addImageToMediaGallery($filepath, array ($imageType), true, false);
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$objprod->save();
}
}
}
}
}
} catch(Exception $e) {
}
if(isset($info[19]) && $info[19] != "") {
$wholedata['id'] = $proid;
$data = json_decode($info[19],true);
$i = 0;
foreach($data as $k => $d) {
foreach ($d as $key => $value) {
if($key == 'values') {
$wholedata['selectoptions'][$i] = $d[$key];
} else {
$wholedata['options'][$i][$key] = $value;
$wholedata['options'][$i]['customoptindex'] = $i;
}
}
$i++;
}
Mage::dispatchEvent('mp_customoption_setdata', $wholedata);
}
$result['savedRows'] = $count;
$result['rowsCount'] = $totalProcessedRows;
$result['success'] = $helper->__("successfully saved.");
} else {
$result['savedRows'] = 0;
$result['rowsCount'] = $totalProcessedRows;
$result['errors'] = current($errors);
}
} else {
$result['savedRows'] = 0;
$result['rowsCount'] = $totalProcessedRows;
$result['errors'] = current($errors);
}
} else {
$result['savedRows'] = 0;
$result['rowsCount'] = $totalProcessedRows;
$result['errors'] = current($errors);
}
} else {
$result['savedRows'] = 0;
$result['rowsCount'] = $totalProcessedRows;
$result['errors'] = current($errors);
}
}
return $result;
}
one more related function for configurable products :
public function getConfigurableSuperAttributes() {
$allowedSets = explode(',',Mage::getStoreConfig('marketplace/marketplace_options/attributesetid'));
$attributeCodes = array();
foreach ($allowedSets as $attributeSetId) {
$attributes = Mage::getModel('catalog/product_attribute_api')->items($attributeSetId);
$attributeCodes[$attributeSetId] = array();
$temp = array();
foreach($attributes as $attribute) {
$data = Mage::getModel('catalog/resource_eav_attribute')->load($attribute['attribute_id']);
if($data['frontend_input'] == 'select' && $data['is_user_defined'] == 1 && $data['is_configurable'] == 1&& $data['is_visible'] == 1 && $data['is_global'] == 1) {
array_push($temp, $data['attribute_code']);
}
}
$attributeCodes[$attributeSetId] = implode(",",$temp);
}
return json_encode($attributeCodes);
}
This is complete code of that file : http://pastebin.com/vZsf0kZG

The problem is that the simple products aren't linked to the configurable product. You need this attribute for that: simples_skus.
In that column you need the place the simple product SKU's, after each one you need an: ;
Hope that works!

Related

Firestore Batch write : 500 maximum writes exceeded

I'm using batch write in order to avoid 500 maximum writes limit. Even if I'm using batchArray in order to process more than 500 writes, I get this error:
Exception from a finished function: Error: 3 INVALID_ARGUMENT: maximum 500 writes allowed per request
Code: https://controlc.com/3c3a59be
exports.checkSchedine2 = functions.pubsub
.schedule('15,45 * * * *')
.onRun(async (context) => {
const batch = firestore.batch();
var currentTime = Math.floor(Date.now() / 1000);
const risultati = await firestore.collection("Risultati").doc("risultati").get();
const ref1 = await firestore.collection("Schedine").get();
let batchArray = [];
batchArray.push(batch);
let operationCounter = 0;
let batchIndex = 0;
let _notcommit = false;
await Promise.all(ref1.docs.map(async (doc) => {
const ref2 = await firestore.collection("Schedine").doc(doc.id).collection("in corso").get();
for (const doc2 of ref2.docs) {
const documentData = doc2.data();
for (matchId in doc2.data()["Match"]) {
try {
for (id in risultati.data()) {
if (matchId == id && risultati.data()[id]["status"] != 0 && doc2.data()["Match"][matchId]["status"] == 0) {
if ((doc2.data()["Match"][matchId]["Bet"] == 1 || doc2.data()["Match"][matchId]["Bet"] == 2 || doc2.data()["Match"][matchId]["Bet"] == 3) && doc2.data()["Match"][matchId]["Bet"] == risultati.data()[id].ris) {
documentData["Match"][matchId]["status"] = 1;
} else if (doc2.data()["Match"][matchId]["Bet"] == 4 && risultati.data()[id].goal == 1) {
documentData["Match"][matchId]["status"] = 1;
} else if (doc2.data()["Match"][matchId]["Bet"] == 5 && risultati.data()[id].goal == 0) {
documentData["Match"][matchId]["status"] = 1;
} else if (doc2.data()["Match"][matchId]["Bet"] == 6 && risultati.data()[id].over == 1) {
documentData["Match"][matchId]["status"] = 1;
} else if (doc2.data()["Match"][matchId]["Bet"] == 7 && risultati.data()[id].over == 0) {
documentData["Match"][matchId]["status"] = 1;
} else {
documentData["Match"][matchId]["status"] = 2;
}
}
}
} catch (e) {}
}
if (_notcommit == false) {
await batchArray[batchIndex].update(doc2.ref, documentData);
operationCounter++;
if (operationCounter > 100) {
batchArray.push(batch);
batchIndex++;
operationCounter = 0;
}
}
};
}));
Promise.all(batchArray.map(batch => batch.commit()));
});
It seems that the code launches too many commits, isn't it?
You are pushing the same batch in that batchArray in every iteration. You should be creating a new batch for every 500 operations:
let batchArray = [firestore.batch()];
// ...
if (operationCounter > 100) {
const newBatch = firestore.batch();
batchArray.push(newBatch);
batchIndex++;
operationCounter = 0;
}

Array push gives empty result node js

I am creating an API for listing trip data with image and pdf base url,
All things are working fine but I can not access the last result array data_to_send out of for loop.
app.js
app.get("/getChallanList/:userId/:role", (req, res) => {
const userData = req.params;
let site_source = "";
let site_destination = "";
var site_from_name = "";
const data_to_send = [];
if (userData.role == "D") {
db.select("trip", "*", `driver_id = '${req.params.userId}'`, (data) => {
for (let i = 0; i < data.data.length; i++) {
site_source = data.data[i].site_from;
site_destination = data.data[i].site_to;
db.select(
"site",
"*",
`id in ('${site_source}','${site_destination}')`,
(data_site) => {
data.data[i].site_from = data_site.data[0].name;
data.data[i].site_to = data_site.data[1].name;
if (data.data[i].truck_challan_pdf != "") {
data.data[i].truck_challan_pdf =
base_url + "truckchallan/" + data.data[i].truck_challan_pdf;
}
if (data.data[i].driver_challan_pdf != "") {
data.data[i].driver_challan_pdf =
base_url + "driverchallan/" + data.data[i].driver_challan_pdf;
}
if (data.data[i].preparer_img != "") {
data.data[i].preparer_img = base_url + data.data[i].preparer_img;
}
if (data.data[i].driver_img != "") {
data.data[i].driver_img = base_url + data.data[i].driver_img;
}
data_to_send.push(data.data);
// console.log(data_to_send); // working
}
);
}
console.log(data_to_send); // empty
});
}
}
db.select
let select = (table, column, condition, callback) => {
try {
let sql = "SELECT " + column + " FROM " + table + " WHERE " + condition;
conn.query(sql, (err, results) => {
if (err) {
let data = {
status: 0,
data: sql,
message: "Something went wrong!",
};
callback(data);
} else {
let data = {
status: 1,
data: results,
message: "Success",
};
callback(data);
}
});
} catch (err) {
let data = {
status: 0,
data: err,
message: "In catch",
};
callback(data);
}
};
async await
app.get("/getChallanList/:userId/:role", async (req, res) => {
const userData = req.params;
let site_source = "";
let site_destination = "";
var site_from_name = "";
const data_to_send = [];
if (userData.role == "D") {
await db.select(
"trip",
"*",
`driver_id = '${req.params.userId}'`,
async (data) => {
// const data_to_send_ = [];
for (let i = 0; i < data.data.length; i++) {
site_source = data.data[i].site_from;
site_destination = data.data[i].site_to;
await db.select(
"site",
"*",
`id in ('${site_source}','${site_destination}')`,
(data_site) => {
data.data[i].site_from = data_site.data[0].name;
data.data[i].site_to = data_site.data[1].name;
if (data.data[i].truck_challan_pdf != "") {
data.data[i].truck_challan_pdf =
base_url + "truckchallan/" + data.data[i].truck_challan_pdf;
}
if (data.data[i].driver_challan_pdf != "") {
data.data[i].driver_challan_pdf =
base_url + "driverchallan/" + data.data[i].driver_challan_pdf;
}
if (data.data[i].preparer_img != "") {
data.data[i].preparer_img =
base_url + data.data[i].preparer_img;
}
if (data.data[i].driver_img != "") {
data.data[i].driver_img = base_url + data.data[i].driver_img;
}
data_to_send.push(data.data);
// console.log(data_to_send); // working
}
);
// data_to_send_.push(data_to_send);
}
console.log(data_to_send); // empty
}
);
}
}
this is because of the asynchronous behavior of NodeJs, so you have to plan things accordingly i.e
console.log(1)
db.select(
"trip",
"*",
`driver_id = '${req.params.userId}'`,
async (data) => {
console.log(2)
})
console.log(3)
The output of the above code would be 1 then 3 and then 2 and this is how NodeJs works it does not wait for I/O calls i.e DB query in your case.
Please check how promises work in NodeJs for more details.
Here is how you can accomplish your task:
const challanList = (userData) => {
return new Promise((resolve, reject) => {
const data_to_send = [];
db.select("trip", "*", `driver_id = '${req.params.userId}'`, data => {
for (let i = 0; i < data.data.length; i++) {
const site_source = data.data[i].site_from;
const site_destination = data.data[i].site_to;
db.select("site", "*", `id in ('${site_source}','${site_destination}')`, data_site => {
data.data[i].site_from = data_site.data[0].name;
data.data[i].site_to = data_site.data[1].name;
if (data.data[i].truck_challan_pdf != "") {
data.data[i].truck_challan_pdf = base_url + "truckchallan/" + data.data[i].truck_challan_pdf;
}
if (data.data[i].driver_challan_pdf != "") {
data.data[i].driver_challan_pdf = base_url + "driverchallan/" + data.data[i].driver_challan_pdf;
}
if (data.data[i].preparer_img != "") {
data.data[i].preparer_img = base_url + data.data[i].preparer_img;
}
if (data.data[i].driver_img != "") {
data.data[i].driver_img = base_url + data.data[i].driver_img;
}
data_to_send.push(data.data);
// console.log(data_to_send); // working
});
}
resolve(data_to_send);
});
});
};
app.get("/getChallanList/:userId/:role", async (req, res) => {
const userData = req.params;
const challanListResult =await challanList(userData);
console.log(challanListResult);
resp.json(challanListResult);
});
Without knowing what database or ORM you are using it is difficult to answer, but my suspicion is that db.select is an asynchronous method, i.e. it is returning a Promise. If so, the second console log is still seeing the "old" data_to_send.
Try adding an await in front of the first db.select call. (Don't forget the async in front of the callback in second argument of app.get.
Your database is asynchronous so console.log(data_to_send) gets called before the query finished executing. Try adding async before (req, res) in line 1 then await before db.select.
This works for me
app.get("/getChallanList/:userId/:role", async (req, res) => {
const userData = req.params;
let site_source = "";
let site_destination = "";
var site_from_name = "";
const data_to_send = [];
if (userData.role == "D") {
const data = await db.query(
`SELECT * FROM trip WHERE driver_id = '${req.params.userId}'`
);
// console.log(data.length);
// const data_to_send_ = [];
for (let i = 0; i < data.length; i++) {
site_source = data[i].site_from;
site_destination = data[i].site_to;
// cons
const site_data = await db.query(
`SELECT * FROM site WHERE id in ('${site_source}','${site_destination}')`
);
// console.log(site_data);
db.select(
"site",
"*",
`id in ('${site_source}','${site_destination}')`,
(data_site) => {
data[i].site_from = data_site.data[0].name;
data[i].site_to = data_site.data[1].name;
if (data[i].truck_challan_pdf != "") {
data[i].truck_challan_pdf =
base_url + "truckchallan/" + data[i].truck_challan_pdf;
}
if (data[i].driver_challan_pdf != "") {
data[i].driver_challan_pdf =
base_url + "driverchallan/" + data[i].driver_challan_pdf;
}
if (data[i].preparer_img != "") {
data[i].preparer_img = base_url + data[i].preparer_img;
}
if (data[i].driver_img != "") {
data[i].driver_img = base_url + data[i].driver_img;
}
data_to_send.push(data);
// console.log(data.data);
// console.log(data_to_send); // working
}
);
// data_to_send_.push(data_to_send);
}
// console.log(data_to_send);
// console.log(data_to_send);
res.send({ success: 1, data: data, message: "" });
}

Getting error 400 from updating a cell by google sheetsAPI

I am trying to update a cell in a spreadsheet through Google spreadsheet API.
Currently, I'm having the following code snippet:
sheetsApi.spreadsheets.values.update({
spreadsheetId: spreadsheetId,
range:"Sheet1!P1",
valueInputOption:'USER_ENTERED'},
{"data":{"values":[[5]],
'majorDimension':"ROWS"}
}
)
And it gives the following error:
{
"error": {
"code": 400,
"message": "Invalid JSON payload received. Unknown name \"data\" at 'data': Cannot find field.",
"status": "INVALID_ARGUMENT",
"details": [
{
"#type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "data",
"description": "Invalid JSON payload received. Unknown name \"data\" at 'data': Cannot find field."
}
]
}
]
}
}
Could someone give me some help with this please?
Thank you very much!
Since I am only testing this 'update' function, the script is very simple, as the following:
function main() {
const credentials = {
accessToken: '',
clientId: '',
clientSecret: '',
refreshToken: ''
};
const spreadsheetId = ''
var sheetsApi = GoogleApis.createSheetsService(credentials);
sheetsApi.spreadsheets.values.update({
spreadsheetId: spreadsheetId,
range: "Sheet1!P1",
valueInputOption: "USER_ENTERED",
resource: {
values: [[5]],
majorDimension: "ROWS"
}
}, function(err, result) {
if (err) {
console.log(err.errors);
return;
}
console.log(result.data);
})
}
var GoogleApis;
(function (GoogleApis) {
function createSheetsService(credentials) {
return createService("https://sheets.googleapis.com/$discovery/rest?version=v4", credentials);
}
GoogleApis.createSheetsService = createSheetsService;
function createDriveService(credentials) {
return createService("https://www.googleapis.com/discovery/v1/apis/drive/v3/rest", credentials);
}
GoogleApis.createDriveService = createDriveService;
function createGmailService(credentials) {
return createService("https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest", credentials);
}
GoogleApis.createGmailService = createGmailService;
// Creation logic based on https://developers.google.com/discovery/v1/using#usage-simple
function createService(url, credentials) {
var content = UrlFetchApp.fetch(url).getContentText();
var discovery = JSON.parse(content);
var baseUrl = discovery['rootUrl'] + discovery['servicePath'];
var accessToken = getAccessToken(credentials);
var service = build(discovery, {}, baseUrl, accessToken);
return service;
}
function createNewMethod(method, baseUrl, accessToken) {
return (urlParams, body) => {
var urlPath = method.path;
var queryArguments = [];
for (var name in urlParams) {
var paramConfg = method.parameters[name];
if (!paramConfg) {
throw `Unexpected url parameter ${name}`;
}
switch (paramConfg.location) {
case 'path':
urlPath = urlPath.replace('{' + name + '}', urlParams[name]);
break;
case 'query':
queryArguments.push(`${name}=${urlParams[name]}`);
break;
default:
throw `Unknown location ${paramConfg.location} for url parameter ${name}`;
}
}
var url = baseUrl + urlPath;
if (queryArguments.length > 0) {
url += '?' + queryArguments.join('&');
}
var httpResponse = UrlFetchApp.fetch(url, { contentType: 'application/json', method: method.httpMethod, payload: JSON.stringify(body), headers: { Authorization: `Bearer ${accessToken}` }, muteHttpExceptions: true });
var responseContent = httpResponse.getContentText();
var responseCode = httpResponse.getResponseCode();
var parsedResult;
try {
parsedResult = JSON.parse(responseContent);
} catch (e) {
parsedResult = false;
}
var response = new Response(parsedResult, responseContent, responseCode);
if (responseCode >= 200 && responseCode <= 299) {
return response;
}
throw response;
}
}
function Response(result, body, status) {
this.result = result;
this.body = body;
this.status = status;
}
Response.prototype.toString = function () {
return this.body;
}
function build(discovery, collection, baseUrl, accessToken) {
for (var name in discovery.resources) {
var resource = discovery.resources[name];
collection[name] = build(resource, {}, baseUrl, accessToken);
}
for (var name in discovery.methods) {
var method = discovery.methods[name];
collection[name] = createNewMethod(method, baseUrl, accessToken);
}
return collection;
}
function getAccessToken(credentials) {
if (credentials.accessToken) {
return credentials.accessToken;
}
var tokenResponse = UrlFetchApp.fetch('https://www.googleapis.com/oauth2/v4/token', { method: 'post', contentType: 'application/x-www-form-urlencoded', muteHttpExceptions: true, payload: { client_id: credentials.clientId, client_secret: credentials.clientSecret, refresh_token: credentials.refreshToken, grant_type: 'refresh_token' } });
var responseCode = tokenResponse.getResponseCode();
var responseText = tokenResponse.getContentText();
if (responseCode >= 200 && responseCode <= 299) {
var accessToken = JSON.parse(responseText)['access_token'];
return accessToken;
}
throw responseText;
}
})(GoogleApis || (GoogleApis = {}));
// Base64 implementation from https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/master/lib/msal-core/src/Utils.ts
class Base64 {
static encode(input) {
const keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
let output = "";
let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = this.utf8Encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
}
else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
}
return output.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
static utf8Encode(input) {
input = input.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < input.length; n++) {
var c = input.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
}
Insert values like this
row.range = "Sheet1!"+"A"+(i+2)+":M"+(i+2)
row.values = [
[....],
[....],
[....],
[....],
[....],
[....],
]

Network Error 12030 using Websockets

Hello there i am integrating Wowza Media Server with Temasys plugin(for crossbrowser support) and the code runs great on Chrome but on IE11+ its is giving me network error.Please see attached image and code for details.
const GO_BUTTON_START = "Publish";
const GO_BUTTON_STOP = "Stop";
var video = document.querySelector('video');
var peerConnection = null;
var peerConnectionConfig = {'iceServers': []};
var localStream = null;
var wsURL = "wss://localhost.streamlock.net/webrtc-session.json";
var wsConnection = null;
var streamInfo = {applicationName:"webrtc", streamName:"myStream", sessionId:"[empty]"};
var userData = {param1:"value1"};
var videoBitrate = 360;
var audioBitrate = 64;
var newAPI = false;
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
window.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.webkitRTCIceCandidate;
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription;
//var constraints = {
//audio: false,
//video: true
//};
function successCallback(stream) {
window.stream = stream; // make stream available to browser console
localStream=stream;
console.log(localStream);
video = attachMediaStream(video, stream);
}
function errorCallback(error) {
console.log('navigator.getUserMedia error: ', error);
}
function pageReady()
{
$("#buttonGo").attr('value', GO_BUTTON_START);
var constraints =
{
video: true,
audio: false,
};
//alert('here');
navigator.getUserMedia(constraints, successCallback, errorCallback);
console.log("newAPI: "+newAPI);
}
function wsConnect(url)
{
wsConnection = new WebSocket(url);
wsConnection.binaryType = 'arraybuffer';
wsConnection.onopen = function()
{
console.log("wsConnection.onopen");
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
if (newAPI)
{
var localTracks = localStream.getTracks();
for(localTrack in localTracks)
{
console.log("video stream"+localStream);
peerConnection.addTrack(localTracks[localTrack], localStream);
}
}
else
{
console.log("video stream"+localStream);
peerConnection.addStream(localStream);
}
peerConnection.createOffer(gotDescription, errorHandler);
}
wsConnection.onmessage = function(evt)
{
console.log("wsConnection.onmessage: "+evt.data);
var msgJSON = JSON.parse(evt.data);
var msgStatus = Number(msgJSON['status']);
var msgCommand = msgJSON['command'];
if (msgStatus != 200)
{
$("#sdpDataTag").html(msgJSON['statusDescription']);
stopPublisher();
}
else
{
$("#sdpDataTag").html("");
var sdpData = msgJSON['sdp'];
if (sdpData !== undefined)
{
console.log('sdp: '+msgJSON['sdp']);
peerConnection.setRemoteDescription(new RTCSessionDescription(sdpData), function() {
//peerConnection.createAnswer(gotDescription, errorHandler);
}, errorHandler);
}
var iceCandidates = msgJSON['iceCandidates'];
if (iceCandidates !== undefined)
{
for(var index in iceCandidates)
{
console.log('iceCandidates: '+iceCandidates[index]);
peerConnection.addIceCandidate(new RTCIceCandidate(iceCandidates[index]));
}
}
}
if (wsConnection != null)
wsConnection.close();
wsConnection = null;
}
wsConnection.onclose = function(error)
{
console.log("wsConnection.onclose"+error);
}
wsConnection.onerror = function(evt)
{
console.log("wsConnection.onerror: "+JSON.stringify(evt));
$("#sdpDataTag").html('WebSocket connection failed: '+wsURL);
stopPublisher();
}
}
function startPublisher()
{
wsURL = $('#sdpURL').val();
streamInfo.applicationName = $('#applicationName').val();
streamInfo.streamName = $('#streamName').val();
videoBitrate = $('#videoBitrate').val();
audioBitrate = $('#audioBitrate').val();
$.cookie("webrtcPublishWSURL", wsURL, { expires: 365 });
$.cookie("webrtcPublishApplicationName", streamInfo.applicationName, { expires: 365 });
$.cookie("webrtcPublishStreamName", streamInfo.streamName, { expires: 365 });
$.cookie("webrtcPublishVideoBitrate", videoBitrate, { expires: 365 });
$.cookie("webrtcPublishAudioBitrate", audioBitrate, { expires: 365 });
console.log("startPublisher: wsURL:"+wsURL+" streamInfo:"+JSON.stringify(streamInfo));
wsConnect(wsURL);
$("#buttonGo").attr('value', GO_BUTTON_STOP);
}
function stopPublisher()
{
if (peerConnection != null)
peerConnection.close();
peerConnection = null;
if (wsConnection != null)
wsConnection.close();
wsConnection = null;
$("#buttonGo").attr('value', GO_BUTTON_START);
console.log("stopPublisher");
}
function btn_start()
{
alert('button clicked');
if (peerConnection == null)
startPublisher();
else
stopPublisher();
}
function gotIceCandidate(event)
{
if(event.candidate != null)
{
//console.log('gotIceCandidate: '+JSON.stringify({'ice': event.candidate}));
}
}
function gotDescription(description)
{
var enhanceData = new Object();
if (audioBitrate !== undefined)
enhanceData.audioBitrate = Number(audioBitrate);
if (videoBitrate !== undefined)
enhanceData.videoBitrate = Number(videoBitrate);
description.sdp = enhanceSDP(description.sdp, enhanceData);
console.log('gotDescription: '+JSON.stringify({'sdp': description}));
peerConnection.setLocalDescription(description, function () {
wsConnection.send('{"direction":"publish", "command":"sendOffer", "streamInfo":'+JSON.stringify(streamInfo)+', "sdp":'+JSON.stringify(description)+', "userData":'+JSON.stringify(userData)+'}');
console.log("stream info"+JSON.stringify(streamInfo));
console.log("stream description"+JSON.stringify(description));
console.log("stream userData"+JSON.stringify(userData));
}, function() {console.log('set description error')});
}
function enhanceSDP(sdpStr, enhanceData)
{
var sdpLines = sdpStr.split(/\r\n/);
var sdpSection = 'header';
var hitMID = false;
var sdpStrRet = '';
for(var sdpIndex in sdpLines)
{
var sdpLine = sdpLines[sdpIndex];
if (sdpLine.length <= 0)
continue;
sdpStrRet += sdpLine+'\r\n';
if (sdpLine.indexOf("m=audio") === 0)
{
sdpSection = 'audio';
hitMID = false;
}
else if (sdpLine.indexOf("m=video") === 0)
{
sdpSection = 'video';
hitMID = false;
}
if (sdpLine.indexOf("a=mid:") === 0)
{
if (!hitMID)
{
if ('audio'.localeCompare(sdpSection) == 0)
{
if (enhanceData.audioBitrate !== undefined)
{
sdpStrRet += 'b=AS:' + enhanceData.audioBitrate + '\r\n';
sdpStrRet += 'b=TIAS:' + (enhanceData.audioBitrate*1024) + '\r\n';
}
}
else if ('video'.localeCompare(sdpSection) == 0)
{
if (enhanceData.videoBitrate !== undefined)
{
sdpStrRet += 'b=AS:' + enhanceData.videoBitrate + '\r\n';
sdpStrRet += 'b=TIAS:' + (enhanceData.videoBitrate*1024) + '\r\n';
}
}
hitMID = true;
}
}
}
return sdpStrRet;
}
function errorHandler(error)
{
console.log(error);
}
Click here to see image

I am trying to export rallygrid data in excel file, but getting only headers not values

I am trying to export rallygrid data in excel file, but getting only headers not values.
Below is my code which I wrote to generate grid and export button
From here [https://github.com/andreano/TaskDelta/blob/master/App.js], I stole the export code
prepareChart: function(iteration_data) {
this.converted_values = [];
this.accept_values = [];
this.commit_values = [];
parents = [];
rootParent = this.getContext().getProject().Name;
sortedArray = [];
var project_hash = {}; // project_by_name, with children
Ext.Array.each(iteration_data, function(iteration){
if ((iteration.ProjectName != rootParent && iteration.ChildCount > 0) || iteration.ParentName == rootParent) {
parents.push(iteration.ProjectName);
}
// make a place for me
if ( ! project_hash[iteration.ProjectName] ) { project_hash[iteration.ProjectName] = []; }
// make a place for my parent so it can know children
if ( iteration.ParentName ) {
if ( ! project_hash[iteration.ParentName]) { project_hash[iteration.ParentName] = []; }
project_hash[iteration.ParentName] = Ext.Array.merge( project_hash[iteration.ParentName], iteration.ProjectName);
}
}, this);
// build order this way:
//console.log("Current: ", this.getContext().getProject().Name );
// order the array by parents to children to grandchildren
sortedArray = this._getTreeArray( this.getContext().getProject().Name , project_hash);
parents = Ext.Array.unique(parents);
sortedData = [];
Ext.Array.each(sortedArray, function(name){
Ext.Array.each(iteration_data, function(ite){
if(ite.ProjectName == name) {
sortedData.push(ite);
};
});
});
Ext.Array.each(iteration_data, function(iteration){
if (iteration.ProjectName == rootParent) {
sortedData.push(iteration);
}
}, this);
iteration_data = sortedData;
sprints = [];
teams = [];
this.ratio = {};
for ( var i=0; i<iteration_data.length; i++ ) {
commit_accept_ratio = 0;
var data_point = iteration_data[i];
this.commit_values.push( data_point.Commit );
this.accept_values.push( data_point.Accept );
if ( data_point.Commit > data_point.Accept ) {
this.converted_values.push( data_point.Commit - data_point.Accept );
} else {
this.converted_values.push( 0 );
}
if (data_point.Commit != 0) {
commit_accept_ratio = (data_point.Accept / data_point.Commit ) * 100;
} else {
commit_accept_ratio = 0;
};
sprints.push(iteration_data[i].Name);
teams.push(iteration_data[i].ProjectName);
teams.push(rootParent);
this.ratio[data_point.ObjectID] = commit_accept_ratio;
}
this.sprints = Ext.Array.unique(sprints).sort();
this.teams = Ext.Array.unique(teams);
removable_teams = [];
for ( var i=0; i<this.teams.length; i++ ) {
team_name = null;
var count = 0;
Ext.Array.each(iteration_data, function(data) {
if (this.teams[i] == data.ProjectName && data.Commit == 0 || null || undefined && data.Accept == 0 || null || undefined) {
count += 1;
team_name = data.ProjectName;
}
}, this);
if (count == this.sprints.length) {
removable_teams.push(team_name);
}
}
removable_teams = Ext.Array.unique(removable_teams);
records = [];
recordHash = {};
summaryHash = {};
Ext.Array.each(iteration_data, function(iter) {
if (!recordHash[iter.ProjectName]) {
recordHash[iter.ProjectName] = {
Team: iter.ProjectName,
Name: '4 Sprint Summary',
Commit: [],
Accept: [],
Perc: [],
Summary: 0
};
}
if (!Ext.Array.contains(removable_teams, iter.ProjectName)) {
recordHash[iter.ProjectName]["Commit-" + iter.Name] = iter.Commit;
recordHash[iter.ProjectName]["Accept-" + iter.Name] = iter.Accept;
recordHash[iter.ProjectName]["Perc-" + iter.Name] = this.ratio[iter.ObjectID];
}
}, this);
var summaryArray = Ext.Array.slice( this.sprints, (this.sprints.length - 4))
var iterated_data = [];
Ext.Array.each(summaryArray, function(summ){
Ext.Array.each(iteration_data, function(team) {
if( summ == team.Name){
iterated_data.push(team);
}
});
});
Ext.Array.each(iteration_data, function(summ){
Ext.Array.each(iterated_data, function(team) {
if (!summaryHash[team.ProjectName]) {
summaryHash[team.ProjectName] = {
Commit: 0,
Accept: 0,
Total: 0
};
};
if (!Ext.Array.contains(removable_teams, team.ProjectName)) {
if( summ.ProjectName == team.ProjectName && summ.Name == team.Name) {
summaryHash[team.ProjectName]["Commit"] += summ.Commit;
summaryHash[team.ProjectName]["Accept"] += summ.Accept;
if (summaryHash[team.ProjectName]["Commit"] != 0) {
summaryHash[team.ProjectName]["Total"] = (summaryHash[team.ProjectName]["Accept"] / summaryHash[team.ProjectName]["Commit"] ) * 100;
} else {
summaryHash[team.ProjectName]["Total"] = 0;
};
};
}
});
}, this);
Ext.Object.each(recordHash, function(key, value) {
if (summaryHash[key]) {
value["Summary"] = summaryHash[key].Total;
records.push(value);
}
});
var cfgsValues = [];
cfgsValues.push({text: 'Team', style:"background-color: #D2EBC8", dataIndex: 'Team', width: 170, renderer: function(value, meta_data, record, row, col) {
if (Ext.Array.contains(parents, value)) {
meta_data.style = "background-color: #FFF09E";
return Ext.String.format("<div style='font-weight:bold;text-align:center'>{0}</div>", value);
} else if (rootParent == value){
meta_data.style = "background-color: #CC6699";
return Ext.String.format("<div style='font-weight:bold;text-align:center'>{0}</div>", value);
} else {
return value;
};
}});
cfgsValues.push({text: '4 Sprint Summary', style:"background-color: #D2EBC8", width: 70, dataIndex: 'Summary', renderer: function(value, meta_data, record) {
var color = null;
if (value >= 80 && value <= 120) {
color = "#00AF4F";
}
else if (value >= 60 && value <= 80) {
color = "#FBFE08";
}
else if (value <= 60) {
color = "#FC0002";
}
else if (value >= 120) {
color = "#98CCFB";
};
meta_data.style = "background-color: "+color+"";
return Ext.Number.toFixed(value, 0)+"%";
}});
Ext.Array.each(this.sprints, function(sprint) {
cfgsValues.push(
{text: sprint, style:'background-color:#D2EBC8;text-align:center;font-weight:bold', defaults: {enableColumnHide:false}, columns:[
{text: "Commit", dataIndex: 'Commit-' + sprint, width: 50, renderer: function(value, meta_data, record) {
if( value ) {
return value;
} else {
return "NA";
}
}},
{text: "Accept", dataIndex: 'Accept-' + sprint, width: 60, renderer: function(value, meta_data, record) {
if( value) {
return value;
} else {
return "NA";
}
}},
{text: "%", dataIndex: 'Perc-'+ sprint, width: 50, renderer: function(value, meta_data, record) {
var color = null;
if (value >= 80 && value <= 120) {
color = "#00AF4F";
}
else if (value >= 60 && value <= 80) {
color = "#FBFE08";
}
else if (value <= 60) {
color = "#FC0002";
}
else if (value >= 120) {
color = "#98CCFB";
}
meta_data.style = "background-color: "+color+"";
if (value) {
return Ext.Number.toFixed(value, 0)+"%";
} else {
return "NA";
};
}}
]}
);
});
var chart = Ext.getCmp('mychart');
if (chart) {
chart.destroy();
};
Ext.Array.each(this.sprints, function(sprint) {
Ext.Array.each(records, function(record) {
if (record["Accept-" + sprint] == undefined) {
record["Accept-" + sprint] = undefined;
}
if (record["Commit-" + sprint] == undefined) {
record["Commit-" + sprint] = undefined;
}
if (record["Perc-" + sprint] == undefined) {
record["Perc-" + sprint] = undefined;
}
});
});
this.add({
xtype: 'rallygrid',
id: 'mychart',
store: Ext.create('Rally.data.custom.Store', {
data: records,
pageSize: 100
}),
//viewConfig: {
//stripeRows: false
//},
columnCfgs: cfgsValues,
//columnLines: true
});
this.globalStore = Ext.getCmp('mychart');
console.log("this.globalStore", this.globalStore);
this.down('#grid_box').add(this.globalStore);
//this.setLoading(false);
},
_addPrintButton: function() {
var me = this;
this.down('#print_button_box').add( {
xtype: 'rallybutton',
itemId: 'print_button',
text: 'Export to Excel',
disabled: false,
margin: '20 10 10 0',
region: "right",
handler: function() {
me._onClickExport();
}
});
},
_onClickExport: function () { //using this function to export to csv
var that = this;
if (this.down('#grid_box')){
//Ext.getBody().mask('Exporting Tasks...');
//console.log('inside export');
setTimeout(function () {
var template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-' +
'microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head>' +
'<!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>' +
'{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>' +
'</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}' +
'</table></body></html>';
var base64 = function (s) {
return window.btoa(unescape(encodeURIComponent(s)));
};
var format = function (s, c) {
return s.replace(/{(\w+)}/g, function (m, p) {
return c[p];
});
};
var table = that.getComponent('grid_box');
//console.log("Exporting table ",table);
var excel_data = '<tr>';
Ext.Array.each(table.getEl().dom.outerHTML.match(/<span .*?x-column-header-text.*?>.*?<\/span>/gm), function (column_header_span) {
excel_data += (column_header_span.replace(/span/g, 'td'));
});
excel_data += '</tr>';
Ext.Array.each(table.getEl().dom.outerHTML.match(/<tr class="x-grid-row.*?<\/tr>/gm), function (line) {
excel_data += line.replace(/[^\011\012\015\040-\177]/g, '>>');
});
//console.log("Excel data ",excel_data);
var ctx = {worksheet: name || 'Worksheet', table: excel_data};
window.location.href = 'data:application/vnd.ms-excel;base64,' + base64(format(template, ctx));
Ext.getBody().unmask();
}, 500);
}else{
console.log("grid_box does not exist");
}
}
There is an example in new AppSDK2 documentation of exporting to CSV.
I also have an example of exporting to CSV in this github repo.

Resources