SyntaxError: Unexpected token . in JSON at position 1 - javascript

I'm trying to compile and migrate a solidity code built in an older version of solidity, using a newer solidity. This is the solidity code:
//solium-disable linebreak-style
pragma solidity ^ 0.4 .23;
// Simple Solidity intro/demo contract for BlockGeeks Article
contract Geekt {
address GeektAdmin;
mapping(bytes32 => notarizedImage) notarizedImages; // this allows to look up notarizedImages by their SHA256notaryHash
bytes32[] imagesByNotaryHash; // this is like a whitepages of all images, by SHA256notaryHash
mapping(address => User) Users; // this allows to look up Users by their ethereum address
address[] usersByAddress; // this is like a whitepages of all users, by ethereum address
struct notarizedImage {
string imageURL;
uint timeStamp;
}
struct User {
string handle;
bytes32 city;
bytes32 state;
bytes32 country;
bytes32[] myImages;
}
constructor() public payable {
// this is the CONSTRUCTOR (same name as contract) it gets called ONCE only when contract is first deployed
GeektAdmin = msg.sender; // just set the admin, so they can remove bad users or images if needed, but nobody else can
}
modifier onlyAdmin() {
if (msg.sender != GeektAdmin)
revert("invalid message sender: sender not admin");
// Do not forget the "_;"! It will be replaced by the actual function body when the modifier is used.
_;
}
function removeUser(address badUser) public onlyAdmin returns(bool success) {
delete Users[badUser];
return true;
}
function removeImage(bytes32 badImage) public onlyAdmin returns(bool success) {
delete notarizedImages[badImage];
return true;
}
function registerNewUser(string handle, bytes32 city, bytes32 state, bytes32 country) public returns(bool success) {
address thisNewAddress = msg.sender;
// don't overwrite existing entries, and make sure handle isn't null
if (bytes(Users[msg.sender].handle).length == 0 && bytes(handle).length != 0) {
Users[thisNewAddress].handle = handle;
Users[thisNewAddress].city = city;
Users[thisNewAddress].state = state;
Users[thisNewAddress].country = country;
usersByAddress.push(thisNewAddress); // adds an entry for this user to the user 'whitepages'
return true;
} else {
return false; // either handle was null, or a user with this handle already existed
}
}
function addImageToUser(string imageURL, bytes32 SHA256notaryHash) public returns(bool success) {
address thisNewAddress = msg.sender;
if (bytes(Users[thisNewAddress].handle).length != 0) { // make sure this user has created an account first
if (bytes(imageURL).length != 0) { // ) { // couldn't get bytes32 null check to work, oh well!
// prevent users from fighting over sha->image listings in the whitepages, but still allow them to add a personal ref to any sha
if (bytes(notarizedImages[SHA256notaryHash].imageURL).length == 0) {
imagesByNotaryHash.push(SHA256notaryHash); // adds entry for this image to our image whitepages
}
notarizedImages[SHA256notaryHash].imageURL = imageURL;
notarizedImages[SHA256notaryHash].timeStamp = block.number;
// note that updating an image also updates the timestamp
Users[thisNewAddress].myImages.push(SHA256notaryHash); // add the image hash to this users .myImages array
return true;
} else {
return false; // either imageURL or SHA256notaryHash was null, couldn't store image
}
return true;
} else {
return false; // user didn't have an account yet, couldn't store image
}
}
function getUsers() public view returns(address[]) {
return usersByAddress;
}
function getUser(address userAddress) public view returns(string, bytes32, bytes32, bytes32, bytes32[]) {
return (Users[userAddress].handle, Users[userAddress].city, Users[userAddress].state, Users[userAddress].country, Users[userAddress].myImages);
}
function getAllImages() public view returns(bytes32[]) {
return imagesByNotaryHash;
}
function getUserImages(address userAddress) public view returns(bytes32[]) {
return Users[userAddress].myImages;
}
function getImage(bytes32 SHA256notaryHash) public view returns(string, uint) {
return (notarizedImages[SHA256notaryHash].imageURL, notarizedImages[SHA256notaryHash].timeStamp);
}
}
This is the complete error log showing:
> Using network 'development'.
>
> Running migration: 1_initial_migration.js
>
> C:\Users\Kombos\AppData\Roaming\npm\node_modules\truffle\build\cli.bundled.js:101723
> var artifact = JSON.parse(
> ^ undefined:1 [.ShellClassInfo] ^
>
> SyntaxError: Unexpected token . in JSON at position 1
> at JSON.parse (<anonymous>)
> at FS.getContractName (C:\Users\Kombos\AppData\Roaming\npm\node_modules\truffle\build\cli.bundled.js:101723:25)
> at FS.require (C:\Users\Kombos\AppData\Roaming\npm\node_modules\truffle\build\cli.bundled.js:101698:28)
> at Resolver.require (C:\Users\Kombos\AppData\Roaming\npm\node_modules\truffle\build\cli.bundled.js:59966:25)
> at Object.require (C:\Users\Kombos\AppData\Roaming\npm\node_modules\truffle\build\cli.bundled.js:69602:36)
> at ResolverIntercept.require (C:\Users\Kombos\AppData\Roaming\npm\node_modules\truffle\build\cli.bundled.js:197047:32)
> at D:\Cloud\Google Drive\Knowledge Base\Blockchain\Bitcoin\Blockchain Specialization\Smart
> Contracts\Project 1 - Image based Social
> app\Geek\migrations\1_initial_migration.js:1:28
> at ContextifyScript.Script.runInContext (vm.js:59:29)
> at ContextifyScript.Script.runInNewContext (vm.js:65:15)
> at C:\Users\Kombos\AppData\Roaming\npm\node_modules\truffle\build\cli.bundled.js:101639:14
> at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:511:3)
could you please let me know what the error could be? Thanks in advance.

SyntaxError: Unexpected token . in JSON at position 1 exception happen probably for invalid chars in JSON
already answered here

Try deleting your build folder and start over, you might have leftover files from previous builds.

Related

Issue with metamask when sending money to the smart contract

I am new to solidity and smart contracts and I am bit confused with sending money from metamask to my smart contract. Everything seems to work fine in remix but when I use metamask I get a revert error message. I am using ganache as my local blockchain
My smart contract looks like this: -
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.10;
import "#openzeppelin/contracts/access/Ownable.sol";
contract Bet is Ownable{
uint public Money; // set variable to display balance on contract
bool Odd; // variable to set true or false
uint TotalDiceNumber = 12; // dice numbers from 1 - 12
uint result; // variable to hold the dice roll
mapping(address => uint) allowance; //allowance for non owners of the contract
uint BetValue; //variable for original bet value
uint _amount; //variable to hold value of allowance
bool Active; // is the game active
constructor() {
}
function isOwner() internal view returns(bool) {
return owner() == msg.sender; //returns the address who deployed it
}
event BetMade(address player, uint Bet); //placeholder to send data to front end
function receiveMoney() public payable { // get money(bet) from metamask and put on smart
emit BetMade(msg.sender, BetValue); // send player and value of bet
//Money += BetValue; //added after react
Money += msg.value;
BetValue = msg.value;
if (owner() == msg.sender) {
Active = false; // owner doesnt active contract to protect funds
} else {
Active = true; // player activates contract when bet is placed
require(BetValue <= 20 ether, "Bets must be below 21 Ether"); //player can only
bet under 20 ether/ owner can put as much money as they want on
}
}
event BalanceofContract(uint Balcontract);
function getBalance()public returns(uint) {
uint Bal;
Bal = address(this).balance;
emit BalanceofContract(Bal);
return Bal;
}
event PlayerSelectOddEven(address player, bool OddEven);
function selectOddorEven(bool OddEven) public {
emit PlayerSelectOddEven(msg.sender, OddEven);
require(msg.sender != owner(), "You are the house and cannot bet"); // house cannot bet
require(Active = true, "Game not in play. Please place a bet"); // game must be active
Odd = OddEven; // create field to enter true for odd or false for Even
//default is false
}
function Random() internal view returns(uint) {
return uint(keccak256(abi.encodePacked
(block.difficulty,
block.timestamp,
TotalDiceNumber))); // create a random number from blockchain.
//in production would look at chainlink VR but looks like there is a cost so
//went with a less secure option
}
event RollDiceOutput(address player, uint DiceNumber);
function Rolldice() public returns(uint){
emit RollDiceOutput(msg.sender, result);
uint Outcome;
require(Active = true, "Game not in play. Please place a bet"); //game must be actvie
Outcome = Random() % TotalDiceNumber;
result = Outcome + 1; // use + 1 to remove 0 out of random sequence
return result; // function to create number
}
function OutcomeDice() public view returns (uint) {
uint Outcome1;
Outcome1 = result;
return Outcome1;
// function to view number from above function
}
function numberOddorEven() public view returns (bool) {
bool OddorEven; // true for odd false for even
uint _result;
_result = result;
if (_result == 1 || _result == 3 || _result == 5 || _result == 7 || _result == 9 ||
_result == 11) {
OddorEven = true;
} else {
OddorEven = false;
}
return OddorEven;
}
event Winning(address Player, uint WinningsValue);
function addAllowance() public {
emit Winning(msg.sender, _amount);
require(msg.sender != owner(), "You are the house and cannot bet");
require(Active = true, "Game not in play. Please place a bet");
address _who = msg.sender; // assign player to variable
_amount = BetValue * 2; //assign allowance twice as much original bet
allowance[_who] == _amount; // set allowance in mapping against player
}
event Won(address Player, uint Winnings);
function WinMoney() public {
emit Won(msg.sender, _amount);
bool UserInputOdd = numberOddorEven();
bool decisionOdd = Odd;
address _who = msg.sender; // assign player to variable
require(Active = true, "Game not in play. Please place a bet");
require(_amount > 0, "Add the house's money by adding a allowance to collect winning");
if (UserInputOdd == decisionOdd) {
address payable to = payable(msg.sender); //pay the player's address
to.transfer(_amount); // transfer the winning
_amount = 0; //zeroed the variable for multiplying the bet
allowance[_who] = 0; // zeroed the allowance
BetValue = 0; // zeroed the bet
Odd = false; // resets the odd/even input
Active = false; //disable the game
} else {
_amount = 0; //zeroed the variable for multiplying the bet
allowance[_who] = 0; // zeroed the allowance
BetValue = 0; // zeroed the bet
Odd = false; // resets the odd/even input
Active = false; //disable the game
}
}
receive() external payable {
receiveMoney();
}
}
On the front end I am trying to add funds to the smart contract: -
import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'
import { useState } from "react" //import library for line 9
import { ethers } from "ethers" // import library for ethers
import { abi_file } from "../constants/abi"; // import abi from different file
export default function Home() {
const [isConnected, setIsConnected] = useState(false); //to show a button is not connected
const [signer, setSigner] = useState();
async function connect() { //create function to connect metameask
if (typeof window.ethereum !== "undefined") { // check to see if metamask is installed
try {
await ethereum.request({ method: "eth_requestAccounts"});
setIsConnected(true); // set variable as true
const connectedProvider = new ethers.providers.Web3Provider(window.ethereum);
setSigner(connectedProvider.getSigner());
} catch (e) {
console.log(e); // catch and log and errors in console(F12 in chrome)
}
} else {
setIsConnected(false);
}
}
async function Rolldice() { //execute function
if (typeof window.ethereum !== "undefined") { // check to see if metamask is installed
const contractAddress = "0x89f6D41f87054127066d4639e3Ada3DeEefE5EB7"; // address of the contract
const abi = abi_file;
const contract = new ethers.Contract(contractAddress, abi, signer); // calls the contract from the 3 variables
try {
// await contract.Rolldice(); //function will are calling on the sol contract
const transactionResponse = await contract.Rolldice();
const transactionReceipt = await transactionResponse.wait();
var player = (transactionReceipt.events[0].args.player);
var result = (transactionReceipt.events[0].args.DiceNumber.toString());
//alert("Dice Number pressed");
//var x = document.createElement("H3");
//var t = document.createTextNode("Dice rolled from " + player);
// x.appendChild(t);
// document.body.appendChild(x);
var z = document.createElement("H3");
var w = document.createTextNode("Dice number is " + result);
z.appendChild(w);
document.body.appendChild(z);
} catch (error) {
console.log(error);
}
} else {
document.getElementById("executeButton").innerHTML =
"Please install MetaMask";
}
}
async function receiveMoney() { //execute function
if (typeof window.ethereum !== "undefined") { // check to see if metamask is installed
const contractAddress = "0x89f6D41f87054127066d4639e3Ada3DeEefE5EB7"; // address of the contract
const abi = abi_file;
const contract = new ethers.Contract(contractAddress, abi, signer); // calls the contract from the 3 variables
try {
// await contract.Rolldice(); //function will are calling on the sol contract
const transactionResponse = await contract.receiveMoney();
const transactionReceipt = await transactionResponse.wait();
var Balance = (transactionReceipt.events[0].args.Bet.toString());
//alert("Dice Number pressed");
//var x = document.createElement("H3");
//var t = document.createTextNode("Dice rolled from " + player);
// x.appendChild(t);
// document.body.appendChild(x);
var z = document.createElement("H2");
var w = document.createTextNode("The Balance of the contract is " + Balance);
z.appendChild(w);
document.body.appendChild(z);
} catch (error) {
console.log(error);
}
} else {
document.getElementById("executeButton").innerHTML =
"Please install MetaMask";
}
}
return <div className={styles.container}>
{isConnected ?
<>
<h2>"Connected!" </h2>
<p> Please send money to 0x89f6D41f87054127066d4639e3Ada3DeEefE5EB7 but no higher than 20 ethers</p>
<button onClick= {() => receiveMoney()}>Bet Money</button>
<br></br>
<br></br>
<button onClick= {() => Rolldice()}>Roll dice</button>
<br></br>
<br></br>
</>
: (<button onClick={() =>connect()}>Connect</button>) }
</div>;
}
Can anybody suggest where I am going wrong? Many thanks
First in your solidity can you emit the event after assigned the value for the variable betvalue
Second you need to specify for wich account the signer is like this
let provider = new ethers.providers.Web3Provider(window.ethereum);
const accounts = await provider.listAccounts();
let account = null;
if (accounts.length > 0)
{ account = accounts[0] }
let signer = provider.getSigner(account);
Third you need to pass the value the user send into the smart contract through argument options
const options = { value: ethers.utils.parseEther(value) }
var transactionResponse = await contract.receiveMoney(options);
Value need to ve string like this value="1"
This mean you will send 1 ethers

CefSharp Javascript registration and execution is not working in Release 79.1.36

I tried to upgrade CefSharp from Version 69.0.0.0 to 79.1.36.
I could not get the Javascript interaction working.
The registration changed from
this.Browser.RegisterJsObject
to
this.Browser.JavascriptObjectRepository.Register
according to https://github.com/cefsharp/CefSharp/issues/2990.
When I execute EvaluateScriptAsync, I get a response back with Status Canceled.
Trying to understand how to implement it correctly, I examined the CefSharp.WpfExample and noticed that the Javascript functionality in the example WPF application does not work either.
The Execute Javascript (asynchronously) does not do anything when clicking the Run button.
The Evaluate Javascript (Async) returns:
Uncaught ReferenceError: bound is not defined # about:blank:1:0
Did the Javascript functionality break in the latest release?
Update
Here is how it is used in our code.
This is the registration
public void RegisterJavaScriptHandler(string name, object handler)
{
try
{
CefSharpSettings.LegacyJavascriptBindingEnabled = true;
this.Browser.JavascriptObjectRepository.Register(name, handler, false, new BindingOptions() { CamelCaseJavascriptNames = false });
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
This is the EvaluateScriptAsync part
public void InitializeLayers()
{
try
{
int count = _mapLogic.Layers.Count();
foreach (WMSLayer layer in _mapLogic.Layers)
{
if (!_loadedLayers.Contains(layer))
{
var script = string.Format("addWMSLayer('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}', '{9}')",
layer.ProviderCode.Url, layer.AttributionText, layer.AttributionHref,
layer.Layer, layer.FormatCode.Format, layer.ServerType, layer.Res1, layer.Res2, layer.Res3, layer.Res4);
var response = this.ECBBrowser.Browser.EvaluateScriptAsync(script, new TimeSpan(0, 0, 1));
response.ContinueWith(t =>
{
count--;
if (count == 0) this.initializeMap();
});
_loadedLayers.Add(layer);
}
else
{
count--;
if(count == 0) this.initializeMap();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Update II
I now believe something has changed with the resource loading.
This is what I have (unimportant parts are left out).
public class ECBSchemeHandler : IResourceHandler
{
private string _mimeType;
private Stream _stream;
public bool Open(IRequest request, out bool handleRequest, ICallback callback)
{
var result = open(request, callback);
handleRequest = result;
return result;
}
public bool Read(Stream dataOut, out int bytesRead, IResourceReadCallback callback)
{
return read(dataOut, out bytesRead, callback);
}
public bool ReadResponse(Stream dataOut, out int bytesRead, ICallback callback)
{
return read(dataOut, out bytesRead, callback);
}
private bool open(IRequest request, ICallback callback)
{
var u = new Uri(request.Url);
var file = u.Authority + u.AbsolutePath;
var ass = Assembly.GetExecutingAssembly();
var resourcePath = ECBConfiguration.DEFAULT_ASSEMBLY_NAMESPACE + "." + file.Replace("/", ".");
if (ass.GetManifestResourceInfo(resourcePath) != null)
{
Task.Run(() =>
{
using (callback)
{
_stream = ass.GetManifestResourceStream(resourcePath);
var fileExtension = Path.GetExtension(file);
_mimeType = ResourceHandler.GetMimeType(fileExtension);
callback.Continue();
}
});
return true;
}
else
{
callback.Dispose();
}
return false;
}
private bool read(Stream dataOut, out int bytesRead, IDisposable callback)
{
callback.Dispose();
if (_stream == null)
{
bytesRead = 0;
return false;
}
//Data out represents an underlying buffer (typically 32kb in size).
var buffer = new byte[dataOut.Length];
bytesRead = _stream.Read(buffer, 0, buffer.Length);
dataOut.Write(buffer, 0, buffer.Length);
return bytesRead > 0;
}
}
}
Using the built-in ResourceHandlers as pointed out by #amaitland solved the problem with the Javascript registration.

Truffle test failed with "invalid opcode"

I am writing a unit test for my smart contract using truffle and when I run the test using "truffle test" the test failed with this error "Error: Returned error: VM Exception while processing transaction: invalid opcode".
smart contract code:
pragma solidity ^0.4.3;
contract owned {
address public owner;
/* Initialise contract creator as owner */
function owned() public {
owner = msg.sender;
}
/* Function to dictate that only the designated owner can call a function */
modifier onlyOwner {
require(owner == msg.sender);
_;
}
/* Transfer ownership of this contract to someone else */
function transferOwnership(address newOwner) public onlyOwner() {
owner = newOwner;
}
}
/*
* #title AsnScRegistry
* Open Vote Network
* A self-talling protocol that supports voter privacy.
*
* Author: Shahrul Sharudin
*/
contract AsnScRegistry is owned{
struct IPAddress {
uint128 ip;
uint8 mask;
}
struct MemberAddresses {
address contractAddress;
address walletAddress;
uint index;
}
mapping (uint => IPAddress[]) managedIps;
mapping (uint => MemberAddresses) ethAddresses;
uint[] private registeredAsn;
function getManagedIpByAsn(uint _asn) view public returns (uint128[] _ip, uint8[] _mask){
IPAddress[] memory addresses = managedIps[_asn];
uint128[] memory ips = new uint128[](addresses.length);
uint8[] memory mask = new uint8[](addresses.length);
for (uint i = 0; i < addresses.length; i++) {
ips[i] = addresses[i].ip;
mask[i] = addresses[i].mask;
}
return (ips, mask);
}
function getMemberAddressesByAsn(uint _asn) view public returns (address _contractAddress, address _walletAddress){
MemberAddresses memory memberAddresses = ethAddresses[_asn];
return (memberAddresses.contractAddress, memberAddresses.walletAddress);
}
function addMember(uint _asn, uint128[] _ip, uint8[] _mask, address _contractAddress, address _walletAddress) public {
MemberAddresses memory member = ethAddresses[_asn];
//throw error if member already exist
assert(member.contractAddress != 0);
for(uint i=0; i<_ip.length; i++){
managedIps[_asn].push(IPAddress({ip:_ip[i], mask:_mask[i]}));
}
uint idx = registeredAsn.push(_asn)-1;
ethAddresses[_asn] = MemberAddresses({contractAddress:_contractAddress, walletAddress:_walletAddress, index:idx});
}
function removeMember(uint _asn) public returns (uint[] _registeredAsn){
//uint memory index = ethAddresses[_asn].index;
if (ethAddresses[_asn].index >= registeredAsn.length) return;
for (uint i = ethAddresses[_asn].index; i<registeredAsn.length - 1; i++){
registeredAsn[i] = registeredAsn[i+1];
}
registeredAsn.length--;
delete managedIps[_asn];
delete ethAddresses[_asn];
return registeredAsn;
}
function getTotalMembers() view public returns (uint _totalMembers) {
return (registeredAsn.length);
}
function getRegisteredAsn() view public returns (uint[] _asn){
return (registeredAsn);
}
}
javascript unit test:
const AsnScRegistry = artifacts.require('./AsnScRegistry.sol')
const assert = require('assert')
const ip = [3524503734,3232235776];
const mask = [255,255];
const contractAddress = '0x1234567890123456789012345678901234567891';
const walletAddress = '0x1234567890123456789012345678901234567891';
const asn = 123;
let registryInstance;
contract("AsnScRegistry", accounts => {
it("Should add a new member", () =>
AsnScRegistry.deployed()
.then(instance => {
registryInstance = instance;
return instance.addMember(asn, ip, mask, contractAddress, walletAddress);
})
.then(() => registryInstance.getTotalMembers())
.then(total => assert.equal(total.toNumber(), 1, "xxxxx"))
);
});
the full source is available here: https://github.com/shaza4061/electioncommissioner
I expect the addMember() function to store the information in the smart contract and getTotalMembers() to return the number of record in registeredAsn[] array and the assertion in the unit test to pass.
The following error message:
"Error: Returned error: VM Exception while processing transaction: invalid opcode"
indicates a failed assert statement in solidity.
In your code, you have an assert which causes this error.
//throw error if member already exist
assert(member.contractAddress != 0);
Here is a manual for Solidity Smart contract debugging using Truffle.

SignalR update breaks layout and scripts on page

When a SignalR update comes through to our page to update our modal, our item names change and our scripts seem to break.
Brief overview: Our SignalR update gets sent to the website fine, but the data itself has an invalid name.
Once updated, our items refresh with malformed names. Our names shouldn't be updated by SignalR in the first place, and I can't seem to find any references to it in our code.
Closing the modal, our Highcharts and Angular scripts throw console errors.
Server-side code:
public partial class Device
{
if (device != null)
{
if ((Enumerables.DeviceType)device.Type == Enumerables.DeviceType.Store)
SignalrClient.UpdateStore(device.DeviceID);
else // check if need to update a modal on the dashboard
{
foreach (var key in SignalrClient.DevicesDictionary.Keys)
{
var devices = SignalrClient.DevicesDictionary[key];
if (devices != null)
{
if (devices.Contains(device.DeviceID))
SignalrClient.UpdateModal(key, device.DeviceID);
}
}
}
}
}
class SignalrClient
{
public static async Task Start()
{
if (_hubConnection == null || _hubConnection.State == ConnectionState.Disconnected)
{
_hubConnection = new HubConnection("http://stevessiteofamazingboats.net/");
_dashboardHubProxy = _hubConnection.CreateHubProxy("DashboardHub");
_dashboardHubProxy.On("OnRegisterDevice", new Action<string, int>(OnRegisterDevice));
_dashboardHubProxy.On("OnDeregisterDevices", new Action<string>(OnDeregisterDevices));
_dashboardHubProxy.On("OnDeregisterDevice", new Action<string, int>(OnDeregisterDevice));
await _hubConnection.Start();
}
}
public static async void UpdateModal(string connectionId, int deviceId)
{
await Start();
if (_hubConnection.State == ConnectionState.Connected)
await _dashboardHubProxy.Invoke("UpdateModal", new object[] { connectionId, deviceId });
}
}
public class DashboardHub : Hub
{
private static string EventHubConnectionId {get;set;}
private AlarmDBEntities db = Utils.DbContext;
public void UpdateModal(string connectionId, int deviceId)
{
var db = Utils.DbContext;
var device = db.Device.Find(deviceId);
var modal = new Portal.DeviceModalViewModel()
{
DeviceId = deviceId,
SuctionGroups = device.Device1.Where(x => (Enumerables.DeviceType)x.Type == Enumerables.DeviceType.SuctionGroup).Select(x => new DeviceModalViewModel.SGNode()
{
SubChildren = x.Device1.Where(y => (Enumerables.DeviceType)y.Type == Enumerables.DeviceType.Compressor).Select(y => new DeviceModalViewModel.DeviceNode()
{
DeviceId = y.DeviceID,
Name = y.Name,
Amp = db.Property.Where(z => z.Name == "Amps" && z.DeviceID == y.DeviceID).OrderByDescending(z => z.CreatedOn).Select(z => z.Value).FirstOrDefault()
}).OrderBy(y => y.Name).ToList()
}).OrderBy(x => x.Name).ToList(),
};
}
Client-side javascript. The viewModel contains a malformed name:
Viewable on JSFiddle
https://jsfiddle.net/wmqdyv8r/
This is our Angular console error:
angular.min.js:6 Uncaught Error: [ng:areq]
http://errors.angularjs.org/1.5.7/ng/areq?
p0=HeaderController&p1=not%20a%20function%2C%20got%20undefined
at angular.min.js:6
at sb (angular.min.js:22)
at Qa (angular.min.js:23)
at angular.min.js:89
at ag (angular.min.js:72)
at m (angular.min.js:64)
at g (angular.min.js:58)
at g (angular.min.js:58)
at g (angular.min.js:58)
at g (angular.min.js:58)
angular.min.js:312 WARNING: Tried to load angular more than once.
This Highcharts error shows up if we try to open a chart after the SignalR refresh:
store.js:856 Uncaught TypeError: $(...).highcharts is not a function
at Object.success (store.js:856)
at c (<anonymous>:1:132617)
at Object.fireWith [as resolveWith] (<anonymous>:1:133382)
at b (<anonymous>:1:168933)
at XMLHttpRequest.<anonymous> (<anonymous>:1:173769)
Also, after closing the modal, our main page will refresh and now throws this error:
Exception: Sequence contains no elements
Type: System.InvalidOperationException
The main concern is that the update event is breaking something. The naming issue is a lower priority although I'm sure it's related.
Found and fixed the problem!
The malformed name was found to always be trimming the first 5 characters off of the real name, so I fixed that down near the bottom, although I still don't know where this trimming occurs.
The more serious issue, the breaking of scripts was solved as well.
In the UpdateModal method, one of the scripts was looking for a storeID field, along with the deviceID field. After printing a log to the Chrome javascript console, I could see that storeID was always returning 0, even though it was previously initialized before the UpdateModal method.
All I had to do, was follow the damn train add the storeID field seen here under DeviceId:
public void UpdateModal(string connectionId, int deviceId)
{
var db = Utils.DbContext;
var device = db.Device.Find(deviceId);
var modal = new Portal.DeviceModalViewModel()
{
DeviceId = deviceId,
*THIS*-> StoreId = db.Device.Where(x => device.Name.Contains(x.Name.Replace("-Store", "")) && x.ParentID == null).Select(x => x.DeviceID).FirstOrDefault(),
SuctionGroups = device.Device1.Where(x => (Enumerables.DeviceType)x.Type ==
Enumerables.DeviceType.SuctionGroup).Select(x => new
DeviceModalViewModel.SGNode()
{
SubChildren = x.Device1.Where(y => (Enumerables.DeviceType)y.Type ==
Enumerables.DeviceType.Compressor).Select(y => new
DeviceModalViewModel.DeviceNode()
{
DeviceId = y.DeviceID,
*ALSO THIS*-> Name = "12345Comp " + y.Name.Substring(y.Name.Length - 2),
Amp = db.Property.Where(z => z.Name == "Amps" && z.DeviceID == y.DeviceID).OrderByDescending(z => z.CreatedOn).Select(z => z.Value).FirstOrDefault()
}).OrderBy(y => y.Name).ToList()
}).OrderBy(x => x.Name).ToList(),
};

How to prevent Dynamics CRM 2015 from creating an opportunity when a lead is qualified?

Requirements when clicking the Qualify button in the Lead entity form:
Do not create an Opportunity
Retain original CRM qualify-lead JavaScript
Detect duplicates and show duplicate detection form for leads
Redirect to contact, either merged or created version, when done
The easiest approach is to create a plugin running on Pre-Validation for message "QualifyLead". In this plugin you simply have to set CreateOpportunity input property to false. So it would look like:
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
context.InputParameters["CreateOpportunity"] = false;
}
Or you can go with more fancy way:
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var qualifyRequest = new QualifyLeadRequest();
qualifyRequest.Parameters = context.InputParameters;
qualifyRequest.CreateOpportunity = false;
}
Remember that it should be Pre-Validation to work correctly. Doing it like that allows you to remain with existing "Qualify" button, without any JavaScript modifications.
So Pawel Gradecki already posted how to prevent CRM from creating an Opportunity when a Lead is qualified. The tricky part is to make the UI/client refresh or redirect to the contact, as CRM does nothing if no Opportunity is created.
Before we begin, Pawel pointed out that
some code is not supported, so be careful during upgrades
I don't have experience with any other versions than CRM 2015, but he writes that there are better ways to do this in CRM 2016, so upgrade if you can. This is a fix that's easy to implement now and easy to remove after you've upgraded.
Add a JavaScript-resource and register it in the Lead form's OnSave event. The code below is in TypeScript. TypeScript-output (js-version) is at the end of this answer.
function OnSave(executionContext: ExecutionContext | undefined) {
let eventArgs = executionContext && executionContext.getEventArgs()
if (!eventArgs || eventArgs.isDefaultPrevented() || eventArgs.getSaveMode() !== Xrm.SaveMode.qualify)
return
// Override the callback that's executed when the duplicate detection form is closed after selecting which contact to merge with.
// This callback is not executed if the form is cancelled.
let originalCallback = Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication
Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication = (returnValue) => {
originalCallback(returnValue)
RedirectToContact()
}
// Because Opportunities isn't created, and CRM only redirects if an opportunity is created upon lead qualification,
// we have to write custom code to redirect to the contact instead
RedirectToContact()
}
// CRM doesn't tell us when the contact is created, since its qualifyLead callback does nothing unless it finds an opportunity to redirect to.
// This function tries to redirect whenever the contact is created
function RedirectToContact(retryCount = 0) {
if (retryCount === 10)
return Xrm.Utility.alertDialog("Could not redirect you to the contact. Perhaps something went wrong while CRM tried to create it. Please try again or contact the nerds in the IT department.")
setTimeout(() => {
if ($("iframe[src*=dup_warning]", parent.document).length)
return // Return if the duplicate detection form is visible. This function is called again when it's closed
let leadId = Xrm.Page.data.entity.getId()
$.getJSON(Xrm.Page.context.getClientUrl() + `/XRMServices/2011/OrganizationData.svc/LeadSet(guid'${leadId}')?$select=ParentContactId`)
.then(r => {
if (!r.d.ParentContactId.Id)
return RedirectToContact(retryCount + 1)
Xrm.Utility.openEntityForm("contact", r.d.ParentContactId.Id)
})
.fail((_, __, err) => Xrm.Utility.alertDialog(`Something went wrong. Please try again or contact the IT-department.\n\nGuru meditation:\n${err}`))
}, 1000)
}
TypeScript definitions:
declare var Mscrm: Mscrm
interface Mscrm {
LeadCommandActions: LeadCommandActions
}
interface LeadCommandActions {
performActionAfterHandleLeadDuplication: { (returnValue: any): void }
}
declare var Xrm: Xrm
interface Xrm {
Page: Page
SaveMode: typeof SaveModeEnum
Utility: Utility
}
interface Utility {
alertDialog(message: string): void
openEntityForm(name: string, id?: string): Object
}
interface ExecutionContext {
getEventArgs(): SaveEventArgs
}
interface SaveEventArgs {
getSaveMode(): SaveModeEnum
isDefaultPrevented(): boolean
}
interface Page {
context: Context
data: Data
}
interface Context {
getClientUrl(): string
}
interface Data {
entity: Entity
}
interface Entity {
getId(): string
}
declare enum SaveModeEnum {
qualify
}
TypeScript-output:
function OnSave(executionContext) {
var eventArgs = executionContext && executionContext.getEventArgs();
if (!eventArgs || eventArgs.isDefaultPrevented() || eventArgs.getSaveMode() !== Xrm.SaveMode.qualify)
return;
var originalCallback = Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication;
Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication = function (returnValue) {
originalCallback(returnValue);
RedirectToContact();
};
RedirectToContact();
}
function RedirectToContact(retryCount) {
if (retryCount === void 0) { retryCount = 0; }
if (retryCount === 10)
return Xrm.Utility.alertDialog("Could not redirect you to the contact. Perhaps something went wrong while CRM tried to create it. Please try again or contact the nerds in the IT department.");
setTimeout(function () {
if ($("iframe[src*=dup_warning]", parent.document).length)
return;
var leadId = Xrm.Page.data.entity.getId();
$.getJSON(Xrm.Page.context.getClientUrl() + ("/XRMServices/2011/OrganizationData.svc/LeadSet(guid'" + leadId + "')?$select=ParentContactId"))
.then(function (r) {
if (!r.d.ParentContactId.Id)
return RedirectToContact(retryCount + 1);
Xrm.Utility.openEntityForm("contact", r.d.ParentContactId.Id);
})
.fail(function (_, __, err) { return Xrm.Utility.alertDialog("Something went wrong. Please try again or contact the IT-department.\n\nGuru meditation:\n" + err); });
}, 1000);
}
There is a fully functional and supported solution posted over at our Thrives blog: https://www.thrives.be/dynamics-crm/functional/lead-qualification-well-skip-that-opportunity.
Basically we combine the plugin modification as mentioned by Pawel with a Client Side redirect (using only supported JavaScript) afterwards:
function RefreshOnQualify(eventContext) {
if (eventContext != null && eventContext.getEventArgs() != null) {
if (eventContext.getEventArgs().getSaveMode() == 16) {
setTimeout(function () {
Xrm.Page.data.refresh(false).then(function () {
var contactId = Xrm.Page.getAttribute("parentcontactid").getValue();
if (contactId != null && contactId.length > 0) {
Xrm.Utility.openEntityForm(contactId[0].entityType, contactId[0].id)
}
}, function (error) { console.log(error) });;
}, 1500);
}
}
}

Categories

Resources